fix(notebooks,qpp): partition-filter P36 notebook; post-#620 narrative; cron-safe refarm (refs #616 #620 #615)
This commit is contained in:
@@ -6,18 +6,22 @@
|
||||
# Every step is resumable/incremental — safe to re-run on partial failure.
|
||||
set -uo pipefail
|
||||
cd "$(dirname "$0")/../.."
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
set -a; source .env; set +a
|
||||
|
||||
mkdir -p .state/comments
|
||||
LOG=.state/comments/refarm-CMS-2026-2377.log
|
||||
exec >>"$LOG" 2>&1
|
||||
echo "=== re-farm run $(date -Is) ==="
|
||||
|
||||
uv run stack bib fetch-pfs-comments || echo "WARN: fetch-pfs-comments rc=$?"
|
||||
uv run stack bib backfill-comments || echo "WARN: backfill rc=$?"
|
||||
uv run stack comments extract --docket CMS-2026-2377 || echo "WARN: extract rc=$?"
|
||||
uv run stack comments extract-ocr --docket CMS-2026-2377 || echo "WARN: ocr rc=$?"
|
||||
FAILURES=0
|
||||
|
||||
uv run stack bib fetch-pfs-comments || { echo "WARN: fetch-pfs-comments rc=$?"; FAILURES=$((FAILURES+1)); }
|
||||
uv run stack bib backfill-comments || { echo "WARN: backfill rc=$?"; FAILURES=$((FAILURES+1)); }
|
||||
uv run stack comments extract --docket CMS-2026-2377 || { echo "WARN: extract rc=$?"; FAILURES=$((FAILURES+1)); }
|
||||
uv run stack comments extract-ocr --docket CMS-2026-2377 || { echo "WARN: ocr rc=$?"; FAILURES=$((FAILURES+1)); }
|
||||
uv run stack llm index --collection comments --docket CMS-2026-2377 \
|
||||
|| echo "WARN: index rc=$?"
|
||||
|| { echo "WARN: index rc=$?"; FAILURES=$((FAILURES+1)); }
|
||||
|
||||
COUNTS=$(uv run python - <<'EOF'
|
||||
from conf import connect
|
||||
@@ -30,14 +34,20 @@ total, enriched = con.execute(
|
||||
print(f"comments={total} enriched={enriched}")
|
||||
s.close()
|
||||
EOF
|
||||
)
|
||||
) || { echo "WARN: counts rc=$?"; FAILURES=$((FAILURES+1)); }
|
||||
echo "$COUNTS"
|
||||
|
||||
if [ "$FAILURES" -eq 0 ]; then
|
||||
RESULT_MSG="Automated post-close re-farm ran $(date -I): $COUNTS."
|
||||
else
|
||||
RESULT_MSG="Automated post-close re-farm ran $(date -I) — completed with $FAILURES failed steps — check log. $COUNTS."
|
||||
fi
|
||||
|
||||
curl -sf -X POST \
|
||||
"https://git.fhirworx.io/api/v1/repos/homelab/stack/issues/615/comments" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "User-Agent: curl/8.5.0" \
|
||||
-d "{\"body\": \"Automated post-close re-farm ran $(date -I): $COUNTS. Log: .state/comments/refarm-CMS-2026-2377.log. Review counts, spot-check indexing, then close this issue and milestone P37.\"}" \
|
||||
-d "{\"body\": \"$RESULT_MSG Log: .state/comments/refarm-CMS-2026-2377.log. Review counts, spot-check indexing, then close this issue and milestone P37.\n\nIf complete: close #615, close milestone P37, and REMOVE the crontab line (re-fires annually).\"}" \
|
||||
|| echo "WARN: gitea comment failed"
|
||||
echo "=== done $(date -Is) ==="
|
||||
|
||||
@@ -295,7 +295,8 @@ def _(q):
|
||||
ELSE 'Other'
|
||||
END AS category
|
||||
FROM pfs.rvu_proposed
|
||||
WHERE (mod IS NULL OR mod = '')
|
||||
WHERE cms_rule_id = 'CMS-1832-P'
|
||||
AND (mod IS NULL OR mod = '')
|
||||
AND status_code = 'A'
|
||||
AND non_fac_pe_rvu IS NOT NULL
|
||||
QUALIFY row_number() OVER (PARTITION BY hcpcs ORDER BY hcpcs) = 1
|
||||
@@ -433,13 +434,13 @@ def _(mo, rvu_delta):
|
||||
def _(con, mo):
|
||||
_new = con.execute("""
|
||||
SELECT count(*) FROM pfs.rvu_proposed p
|
||||
WHERE (p.mod IS NULL OR p.mod='') AND p.status_code='A' AND p.non_fac_pe_rvu IS NOT NULL
|
||||
WHERE p.cms_rule_id = 'CMS-1832-P' AND (p.mod IS NULL OR p.mod='') AND p.status_code='A' AND p.non_fac_pe_rvu IS NOT NULL
|
||||
AND NOT EXISTS (SELECT 1 FROM pfs.rvu f WHERE f.year=2025 AND f.hcpcs=p.hcpcs AND (f.mod IS NULL OR f.mod=''))
|
||||
""").fetchone()[0]
|
||||
_dropped = con.execute("""
|
||||
SELECT count(*) FROM pfs.rvu f
|
||||
WHERE f.year=2025 AND (f.mod IS NULL OR f.mod='') AND f.status_code='A'
|
||||
AND NOT EXISTS (SELECT 1 FROM pfs.rvu_proposed p WHERE p.hcpcs=f.hcpcs AND (p.mod IS NULL OR p.mod=''))
|
||||
AND NOT EXISTS (SELECT 1 FROM pfs.rvu_proposed p WHERE p.cms_rule_id = 'CMS-1832-P' AND p.hcpcs=f.hcpcs AND (p.mod IS NULL OR p.mod=''))
|
||||
""").fetchone()[0]
|
||||
mo.md(f"""
|
||||
> **Coverage caveat:** {_new} HCPCS codes appear in `pfs.rvu_proposed`
|
||||
@@ -603,7 +604,7 @@ def _(QPP, pl):
|
||||
def _(alt, apm_thresholds, mo):
|
||||
_df = apm_thresholds.to_pandas()
|
||||
_df["apm_incentive_pct"] = _df["apm_incentive_pct"].fillna(0.0)
|
||||
_df["status"] = _df["apm_incentive_pct"].apply(lambda v: "Paid" if v > 0 else "Sunset")
|
||||
_df["status"] = _df["apm_incentive_pct"].apply(lambda v: "Paid" if v > 0 else "None under current law")
|
||||
|
||||
incentive_chart = (
|
||||
alt.Chart(_df)
|
||||
@@ -611,10 +612,14 @@ def _(alt, apm_thresholds, mo):
|
||||
.encode(
|
||||
x=alt.X("payment_year:O", title="Payment year"),
|
||||
y=alt.Y("apm_incentive_pct:Q", title="APM incentive payment (% of base-year Part B paid claims)"),
|
||||
color=alt.Color("status:N", title=None, scale=alt.Scale(domain=["Paid", "Sunset"])),
|
||||
color=alt.Color(
|
||||
"status:N",
|
||||
title=None,
|
||||
scale=alt.Scale(domain=["Paid", "None under current law"]),
|
||||
),
|
||||
tooltip=["performance_year", "payment_year", "apm_incentive_pct", "status"],
|
||||
)
|
||||
.properties(title="APM Incentive Payment Sunset", width=600, height=300)
|
||||
.properties(title="APM Incentive Payment — Not a Clean Sunset", width=600, height=300)
|
||||
)
|
||||
|
||||
_citations = ", ".join(sorted(set(_df["citation"])))
|
||||
@@ -623,12 +628,18 @@ def _(alt, apm_thresholds, mo):
|
||||
[
|
||||
incentive_chart,
|
||||
mo.md(f"""
|
||||
Payment year 2026 (QP Performance Period 2024) is, under
|
||||
current law, the **last** year with a lump-sum APM incentive
|
||||
payment (1.88% of base-year paid claims). From payment year
|
||||
2027 onward, QP status stops paying a bonus and starts
|
||||
(instead) determining *which conversion factor applies* — see
|
||||
below.
|
||||
The lump-sum APM Incentive Payment does **not** sunset
|
||||
cleanly after payment year 2026. Payment year 2027 (QP
|
||||
Performance Period 2025) has no incentive under current
|
||||
law. The Consolidated Appropriations Act, 2026 (CAA 2026,
|
||||
Pub. L. 119-75) then **revives a 3.1% incentive for payment
|
||||
year 2028 only** (`QPP[2026]`) — CMS-1848-P proposes to
|
||||
codify that revival into 42 CFR 414.1450(b)(1) (91 FR
|
||||
44218-44219, 44286), superseding the CY2026 Final Rule's
|
||||
then-accurate "no incentive after 2026" narrative reflected
|
||||
in the disposition table below. So the pattern across
|
||||
payment years 2025-2028 is paid / paid / gap / revived, not
|
||||
a single cutoff.
|
||||
|
||||
**Sources:** `qpp.QPP` performance years 2023–2026
|
||||
({_citations}).
|
||||
@@ -642,8 +653,21 @@ def _(alt, apm_thresholds, mo):
|
||||
def _(QPP, mo):
|
||||
_cy = QPP[2026]
|
||||
_proposed = _cy.proposed
|
||||
_qp = _cy.qp_thresholds
|
||||
_partial = _cy.partial_qp_thresholds
|
||||
|
||||
# As of the CY2026 PFS Final Rule (90 FR 49980), the payment-year-2028
|
||||
# QP/Partial QP thresholds were understood to be 75%/50% (QP) and
|
||||
# 50%/35% (Partial QP) -- CMS-1832-P proposed, and the Final Rule
|
||||
# finalized, "no numeric change" from those then-current-law figures.
|
||||
# These two literals are a CITED TRANSCRIPTION of that now-superseded
|
||||
# disposition, not a live read of `QPP[2026].qp_thresholds` /
|
||||
# `partial_qp_thresholds` -- those fields were corrected under task
|
||||
# #620 (CAA 2026 legislatively restored 50%/35% QP, 40%/25% Partial
|
||||
# QP for payment year 2028; see the `qpp` module docstring "CAA 2026
|
||||
# supersession"). Pinning the historical values here rather than
|
||||
# reading the registry live preserves what CMS actually said in this
|
||||
# disposition table instead of retroactively rewriting it.
|
||||
_qp_then = "75%/50%"
|
||||
_partial_then = "50%/35%"
|
||||
mo.md(f"""
|
||||
### CY2026 NPRM proposed QPP changes — proposed vs. finalized disposition
|
||||
|
||||
@@ -658,7 +682,7 @@ def _(QPP, mo):
|
||||
| Individual-level QP determination (new Threshold Score calc, Sec. 414.1425(b)(3)) | **Finalized as proposed** (90 FR 49923–49928, 49980) |
|
||||
| Attribution-eligible beneficiary definition — expand 6th criterion beyond E/M services | **Finalized WITH MODIFICATION** — dual E/M + covered-professional-services methodology (90 FR 49980) |
|
||||
| Sunset the Medical Home Model 50-clinician limit (Sec. 414.1415(c)(7)) after the 2025 QP Performance Period | **Finalized as proposed** (90 FR 49929) |
|
||||
| QP / Partial QP percentage thresholds | **No numeric change proposed** — remain `qp_thresholds` {_qp.payment_amount_pct:.0f}%/{_qp.patient_count_pct:.0f}% (QP), `partial_qp_thresholds` {_partial.payment_amount_pct:.0f}%/{_partial.patient_count_pct:.0f}% (Partial QP) |
|
||||
| QP / Partial QP percentage thresholds | **No numeric change proposed** — remained `qp_thresholds` {_qp_then} (QP), `partial_qp_thresholds` {_partial_then} (Partial QP) as understood at CY2026 Final Rule publication (90 FR 49980) — **CITED TRANSCRIPTION, since SUPERSEDED for payment year 2028 by CAA 2026; see `QPP[2026].qp_thresholds`/`partial_qp_thresholds` for current law** |
|
||||
| Nominal-amount risk standards (42 CFR 414.1415(c)(3)(i)) / CEHRT requirement | **No change proposed** — cross-referenced by section only |
|
||||
|
||||
Full sourced narrative: `qpp.QPP[2026].proposed.changes`.
|
||||
|
||||
@@ -751,16 +751,13 @@ QPP: dict[int, QppYear] = {
|
||||
"subparagraph list for readability, with no "
|
||||
"substantive change to any other year's percentage "
|
||||
"(NPRM 91 FR 44218-44219; RIA 91 FR 44260; amendatory "
|
||||
"text 91 FR 44286). CONCERN: this amendatory text lists "
|
||||
"no applicable percentage for payment years 2027 or "
|
||||
"2029 (i.e., no incentive payment in those years) and "
|
||||
"3.1 percent for payment year 2028 -- the latter "
|
||||
"directly bears on QPP[2026].apm_incentive_pct "
|
||||
"(payment year 2028), which is currently coded as "
|
||||
"None; this transcription task is scoped not to "
|
||||
"silently correct that entry -- see module docstring "
|
||||
"'Concern - PY2026 ... restatement discrepancy' and "
|
||||
"task-7-report.md."
|
||||
"text 91 FR 44286). This amendatory text lists no "
|
||||
"applicable percentage for payment years 2027 or 2029 "
|
||||
"(i.e., no incentive payment in those years) and 3.1 "
|
||||
"percent for payment year 2028 -- the latter directly "
|
||||
"bears on QPP[2026].apm_incentive_pct (payment year "
|
||||
"2028), which was corrected under task #620; see "
|
||||
"module docstring 'CAA 2026 supersession'."
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -152,6 +152,10 @@ DOCKET_RULES: dict[str, str] = {
|
||||
"CMS-2026-2377": "CMS-1848-P",
|
||||
}
|
||||
|
||||
# This prompt is scoped to docket CMS-2025-0304 only (skin-substitute
|
||||
# reclassification). DOCKET_RULES above maps more dockets (e.g.
|
||||
# CMS-2026-2377) to their CMS rule IDs, but do not reuse this prompt
|
||||
# for CMS-2026-2377 or any other docket without rewriting it.
|
||||
_SYSTEM = """\
|
||||
You classify public comments submitted on CMS's CY2026 PFS proposed rule
|
||||
(CMS-1832-P, docket CMS-2025-0304), specifically regarding the proposal to
|
||||
|
||||
Reference in New Issue
Block a user