fix(notebooks,qpp): partition-filter P36 notebook; post-#620 narrative; cron-safe refarm (refs #616 #620 #615)

This commit is contained in:
kert
2026-08-14 00:26:13 -04:00
parent cb235a2036
commit d3750ce4ff
4 changed files with 67 additions and 32 deletions

View File

@@ -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) ==="

View File

@@ -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`.

View File

@@ -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'."
),
),
),

View File

@@ -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