fix(notebooks): registry-sourced thresholds, per-figure citations, honest provenance (refs #597)
This commit is contained in:
@@ -35,6 +35,10 @@ def _(mo):
|
||||
**What this means:** every number below is read live from
|
||||
`pfs.rules.RULES` / `qpp.QPP` (the repo's rule registries) and the
|
||||
`pfs`/`cms` DuckLake schemas — nothing here is a hard-coded figure.
|
||||
All dollar figures use **national, GPCI-unadjusted RVUs (GPCI = 1.0)**
|
||||
— a deliberate scope simplification, disclosed once here rather than
|
||||
on every figure; real payment varies by locality via `pfs.gpci`,
|
||||
which this notebook does not join.
|
||||
""")
|
||||
return
|
||||
|
||||
@@ -168,44 +172,60 @@ def _(RULES, mo, pl):
|
||||
_cy26 = RULES[2026]
|
||||
_prop = _cy26.proposed
|
||||
|
||||
def _reconstruct(annual_update_pct, bn_adjustor):
|
||||
return _cy25_cf * 1.0250 * (1 + annual_update_pct / 100) * bn_adjustor
|
||||
# CMS's own stated CF-update components (90 FR 32802) — a one-time
|
||||
# statutory increase plus the MACRA 2015 sec. 1848(d)(20) annual
|
||||
# updates. NONE of these three percentages is a field anywhere in
|
||||
# `pfs.rules` or `qpp` — there is nothing to attribute-access. They
|
||||
# are kept as literals ONLY because CMS's narrative states them as
|
||||
# bare numbers, not derived from any other registry value; this is a
|
||||
# cited transcription of that narrative, not a second source of
|
||||
# truth for `budget_neutrality_adjustor` or the CFs themselves
|
||||
# (both of which — `bn_adjustor` / `registry_cf` below — ARE read
|
||||
# live from the registry).
|
||||
_ONE_TIME_INCREASE_MULT = 1.0250 # +2.50% single-year statutory increase, 90 FR 32802
|
||||
_ANNUAL_UPDATE_MULT = {
|
||||
"Non-QP": 1.0025, # +0.25%/yr nonqualifying-APM update, 90 FR 32802
|
||||
"QP": 1.0075, # +0.75%/yr qualifying-APM update, 90 FR 32802
|
||||
}
|
||||
|
||||
def _reconstruct(track, bn_adjustor):
|
||||
return _cy25_cf * _ONE_TIME_INCREASE_MULT * _ANNUAL_UPDATE_MULT[track] * bn_adjustor
|
||||
|
||||
_bn_rows = [
|
||||
{
|
||||
"vintage": "CY2026 Proposed",
|
||||
"track": "Non-QP",
|
||||
"one_time_pct": 2.50,
|
||||
"annual_update_pct": 0.25,
|
||||
"one_time_mult": _ONE_TIME_INCREASE_MULT,
|
||||
"annual_update_mult": _ANNUAL_UPDATE_MULT["Non-QP"],
|
||||
"bn_adjustor": _prop.budget_neutrality_adjustor,
|
||||
"reconstructed_cf": round(_reconstruct(0.25, _prop.budget_neutrality_adjustor), 4),
|
||||
"reconstructed_cf": round(_reconstruct("Non-QP", _prop.budget_neutrality_adjustor), 4),
|
||||
"registry_cf": _prop.conversion_factor,
|
||||
},
|
||||
{
|
||||
"vintage": "CY2026 Proposed",
|
||||
"track": "QP",
|
||||
"one_time_pct": 2.50,
|
||||
"annual_update_pct": 0.75,
|
||||
"one_time_mult": _ONE_TIME_INCREASE_MULT,
|
||||
"annual_update_mult": _ANNUAL_UPDATE_MULT["QP"],
|
||||
"bn_adjustor": _prop.budget_neutrality_adjustor,
|
||||
"reconstructed_cf": round(_reconstruct(0.75, _prop.budget_neutrality_adjustor), 4),
|
||||
"reconstructed_cf": round(_reconstruct("QP", _prop.budget_neutrality_adjustor), 4),
|
||||
"registry_cf": _prop.cf_qp,
|
||||
},
|
||||
{
|
||||
"vintage": "CY2026 Final",
|
||||
"track": "Non-QP",
|
||||
"one_time_pct": 2.50,
|
||||
"annual_update_pct": 0.25,
|
||||
"one_time_mult": _ONE_TIME_INCREASE_MULT,
|
||||
"annual_update_mult": _ANNUAL_UPDATE_MULT["Non-QP"],
|
||||
"bn_adjustor": _cy26.budget_neutrality_adjustor,
|
||||
"reconstructed_cf": round(_reconstruct(0.25, _cy26.budget_neutrality_adjustor), 4),
|
||||
"reconstructed_cf": round(_reconstruct("Non-QP", _cy26.budget_neutrality_adjustor), 4),
|
||||
"registry_cf": _cy26.conversion_factor,
|
||||
},
|
||||
{
|
||||
"vintage": "CY2026 Final",
|
||||
"track": "QP",
|
||||
"one_time_pct": 2.50,
|
||||
"annual_update_pct": 0.75,
|
||||
"one_time_mult": _ONE_TIME_INCREASE_MULT,
|
||||
"annual_update_mult": _ANNUAL_UPDATE_MULT["QP"],
|
||||
"bn_adjustor": _cy26.budget_neutrality_adjustor,
|
||||
"reconstructed_cf": round(_reconstruct(0.75, _cy26.budget_neutrality_adjustor), 4),
|
||||
"reconstructed_cf": round(_reconstruct("QP", _cy26.budget_neutrality_adjustor), 4),
|
||||
"registry_cf": _cy26.cf_qp,
|
||||
},
|
||||
]
|
||||
@@ -216,13 +236,17 @@ def _(RULES, mo, pl):
|
||||
mo.vstack(
|
||||
[
|
||||
bn_decomp,
|
||||
mo.md("""
|
||||
`reconstructed_cf = CY2025_CF × 1.0250 × (1 + annual_update) × bn_adjustor`
|
||||
— `bn_adjustor` and `registry_cf` are read from `RULES[2026]` /
|
||||
`RULES[2026].proposed`; the 2.50% one-time increase and the
|
||||
0.25%/0.75% annual updates are CMS's own stated components
|
||||
(90 FR 32802), not registry fields, transcribed here only for
|
||||
the cross-check.
|
||||
mo.md(f"""
|
||||
`reconstructed_cf = CY2025_CF × one_time_mult × annual_update_mult × bn_adjustor`
|
||||
— `bn_adjustor` and `registry_cf` are read live from
|
||||
`RULES[2026]` / `RULES[2026].proposed`. `one_time_mult`
|
||||
({_ONE_TIME_INCREASE_MULT}) and `annual_update_mult`
|
||||
({_ANNUAL_UPDATE_MULT["Non-QP"]} non-QP /
|
||||
{_ANNUAL_UPDATE_MULT["QP"]} QP) are **cited transcriptions of
|
||||
CMS's NPRM narrative (90 FR 32802)**, not registry fields —
|
||||
no field in `pfs.rules` or `qpp` models the 2.50%/0.25%/0.75%
|
||||
statutory update components individually, only their combined
|
||||
effect on `conversion_factor` / `cf_qp`.
|
||||
"""),
|
||||
]
|
||||
)
|
||||
@@ -337,7 +361,7 @@ def _(mo):
|
||||
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(AMBER, TEAL, alt, baseline_picker, mo, rvu_delta):
|
||||
def _(AMBER, RULES, TEAL, alt, baseline_picker, mo, rvu_delta):
|
||||
_col = baseline_picker.value
|
||||
_n = 20
|
||||
|
||||
@@ -370,7 +394,18 @@ def _(AMBER, TEAL, alt, baseline_picker, mo, rvu_delta):
|
||||
)
|
||||
)
|
||||
|
||||
mo.vstack([winners_losers_chart])
|
||||
mo.vstack(
|
||||
[
|
||||
winners_losers_chart,
|
||||
mo.md(f"""
|
||||
**Sources:** `pfs.rvu_proposed` — CMS-1832-P NPRM,
|
||||
{RULES[2026].proposed.federal_register_citation}. Baseline —
|
||||
`pfs.rvu` CY2025 Final ({RULES[2025].federal_register_citation})
|
||||
or CY2026 Final ({RULES[2026].federal_register_citation}), per
|
||||
the comparison selected above.
|
||||
"""),
|
||||
]
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
@@ -581,16 +616,21 @@ def _(alt, apm_thresholds, mo):
|
||||
.properties(title="APM Incentive Payment Sunset", width=600, height=300)
|
||||
)
|
||||
|
||||
_citations = ", ".join(sorted(set(_df["citation"])))
|
||||
|
||||
mo.vstack(
|
||||
[
|
||||
incentive_chart,
|
||||
mo.md("""
|
||||
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.
|
||||
|
||||
**Sources:** `qpp.QPP` performance years 2023–2026
|
||||
({_citations}).
|
||||
"""),
|
||||
]
|
||||
)
|
||||
@@ -599,20 +639,28 @@ def _(alt, apm_thresholds, mo):
|
||||
|
||||
@app.cell(hide_code=True)
|
||||
def _(QPP, mo):
|
||||
_proposed = QPP[2026].proposed
|
||||
_cy = QPP[2026]
|
||||
_proposed = _cy.proposed
|
||||
_qp = _cy.qp_thresholds
|
||||
_partial = _cy.partial_qp_thresholds
|
||||
mo.md(f"""
|
||||
### CY2026 NPRM proposed QPP changes — proposed vs. finalized disposition
|
||||
|
||||
Every FR page-pincite in the "Disposition" column below is quoted
|
||||
**verbatim from `qpp.QPP[2026].proposed.changes`**
|
||||
({_proposed.federal_register_citation}, {_proposed.cms_rule_id}) — that
|
||||
field is the single source of truth for this table; nothing here is a
|
||||
second, independently-typed citation.
|
||||
|
||||
| Proposal | Disposition |
|
||||
|---|---|
|
||||
| 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 75%/50% (QP), 50%/35% (Partial QP) |
|
||||
| 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) |
|
||||
| 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`
|
||||
({_proposed.federal_register_citation}, {_proposed.cms_rule_id}).
|
||||
Full sourced narrative: `qpp.QPP[2026].proposed.changes`.
|
||||
""")
|
||||
return
|
||||
|
||||
@@ -708,8 +756,11 @@ def _(mo):
|
||||
## 5. Provenance
|
||||
|
||||
Ingest-log entries (`cms.ingest_log`) for every table this notebook
|
||||
reads from, so every figure above can be traced back to a specific
|
||||
ingest run, source file, and Federal Register citation.
|
||||
reads from — `pfs.rvu` and `pfs.rvu_proposed` — so every figure above
|
||||
can be traced back to a specific ingest run, source file, and Federal
|
||||
Register citation. (`pfs.gpci` is not queried anywhere in this
|
||||
notebook — see the intro's GPCI = 1.0 scope note — so it is
|
||||
deliberately excluded here rather than claimed as a source.)
|
||||
""")
|
||||
return
|
||||
|
||||
@@ -720,7 +771,7 @@ def _(mo, q):
|
||||
SELECT run_id, ingested_at, module, table_name, rule_id,
|
||||
source_file, sha256, rows, fr_citation, pincite_key
|
||||
FROM cms.ingest_log
|
||||
WHERE table_name IN ('pfs.rvu', 'pfs.rvu_proposed', 'pfs.gpci')
|
||||
WHERE table_name IN ('pfs.rvu', 'pfs.rvu_proposed')
|
||||
ORDER BY ingested_at DESC
|
||||
""")
|
||||
mo.ui.table(provenance.to_pandas(), label="Ingest Log — Tables Used in This Notebook")
|
||||
|
||||
Reference in New Issue
Block a user