6.6 KiB
CY2027 PFS Proposed Rule (CMS-1848-P) — capture, ingestion, APM analysis
Status: Designed — repeat of the P36 pattern per standing directive
Date: 2026-08-13
Part of: P37 (CY2027 PFS Proposed Rule)
Related: P36 (#588–#597, merged 53b97b8), #607 (rvu_proposed column alignment — folded in here), spec 2026-08-12-cy2026-pfs-proposed-rule-design.md
Goal
Run the CY2027 PFS proposed rule (CMS-1848-P, docket CMS-2026-2377, FR doc
2026-14327, published 2026-07-16) through the pipeline P36 built: capture
files, ingest proposed parameters and Addendum B with provenance, farm the
comments (period is open — initial pull now, scheduled re-farm after
close), index the rule text for RAG, extend the QPP/Advanced-APM registry to
PY2027, and analyze financial changes in a notebook. Tracked as Gitea
milestone P37.
Current state (verified 2026-08-13)
- CY2027 NPRM published 2026-07-16: FR
2026-14327, CMS-1848-P, reg.gov docket CMS-2026-2377 (per the FR API). Not yet in bib; no comments pulled; comment period open (close date to be transcribed from the DATES block). - P36 infrastructure exists and is merged:
ProposedRulemodel,pfs.nprmloader +pfs.rvu_proposed(keyed bycms_rule_id— designed for multi-rule),cms.ingest_log,qppregistry,llm.source.iter_rule_docs+rulespgvector collection,rex.comments.classify.DOCKET_RULES, notebook pattern. - No CY2027 final rule exists, so there is no
RULES[2027]to hang aproposedblock on — andRuleYearrequires final fields (conversion_factoris load-bearing forpfs.pipe's RVU-file selection). The registry needs a home for proposed-only years. - #607 is open:
pfs.rvu_proposedcolumn names deviate frompfs.rvu(modifier/mod,nonfac_pe_rvu/non_fac_pe_rvu); fixing it before a second consumer cycle joins against the table halves the migration cost.
Design deltas vs P36
A. Proposed-only registry home (pfs.rules)
PROPOSED: dict[int, ProposedRule] module-level registry for years whose
final rule hasn't published, plus proposed_for(year) -> ProposedRule | None
returning RULES[year].proposed when the year exists in RULES, else
PROPOSED.get(year). When the CY2027 final rule ships, RULES[2027] is
created and the entry migrates onto it (P36 shape); proposed_for keeps
consumers stable across that move. RuleYear itself is untouched — no
optional-final-fields surgery, pfs.pipe semantics unchanged.
B. Column alignment first (#607)
Rename pfs.rvu_proposed columns to match pfs.rvu (mod,
non_fac_pe_rvu, fac_pe_rvu — audit the full set against _RVU_COLUMNS)
in pfs.nprm, the P36 notebook's SQL, and tests, then reload the table
(delete-and-reload makes this cheap). Done before any CY2027 consumer exists.
C. Multi-rule NPRM ingest
load_rvu_proposed is parameterized by rule already; generalize discovery:
_discover_addendum_b(tag) takes the supplement tag (sup:2027_PFS_NPRM),
and dev/scripts/ingest_pfs.py --nprm loads every configured
(tag, cms_rule_id) pair — CY2026 and CY2027 partitions coexist keyed by
cms_rule_id, each with its own ingest_log row and FR citation from
proposed_for(year).
D. Open comment period
Initial farm now (stack bib fetch-pfs-comments discovers CMS-1848-P →
resolves CMS-2026-2377 → pulls comments to date), then backfill/extract/
index. A post-close re-farm (same commands — everything is resumable/
incremental) is scheduled after the DATES close date; the P37 milestone
stays open until that re-farm's counts are posted. A local cron reminder
fires the re-farm; the Gitea issue carries the close date.
E. Everything else is a repeat
- Rule-text capture:
fetch_fr_attachments.py --key <2027 item>afterdiscover-pfs-rulesregisters/tags the item (cms-rule:CMS-1848-P). - Addenda: CMS-1848-P detail page →
data/cms/pfs_nprm/2027/; Addendum B attached + taggedsup:2027_PFS_NPRM,module:pfs,file:rvu,year:2027(fetch script gains a--year 2027mode instead of a clone). DOCKET_RULES["CMS-2026-2377"] = "CMS-1848-P"+ regression test.- CY2027
ProposedRulevalues transcribed from the captured text with pincites — never memory; comment-close date transcribed from DATES. qpp: PY2027QppYear(current law) +QppProposedfor CMS-1848-P changes, both-file citations; re-verify PY2026 values only where the CY2027 NPRM restates them.- Rule text →
rulescollection (stack llm index --collection rules --key <item>); comments →commentscollection scoped to the docket. - Notebook
notebooks/cy2027_pfs_proposed_rule.py: CY2026-final → CY2027-proposed CF walk (no final column — labeled "final rule pending"); RVU deltasrvu_proposed[CMS-1848-P]vs CY2026 finalpfs.rvu; Advanced-APM section fromqppPY2027; provenance section. Same registry-sourced/citation-per-figure rules the P36 review enforced.
Milestones and issues
P37: CY2027 PFS Proposed Rule — capture, ingest, APM analysis
pfs: align rvu_proposed column names with pfs.rvu— existing #607, added to P37 (delta B)comments: register CMS-2026-2377 ↔ CMS-1848-P mapping— delta Ebib: discover + capture CY2027 rule text (2026-14327) into fr_downloads + bib— delta Epfs: capture CMS-1848-P proposed addenda (sup:2027_PFS_NPRM)— delta Epfs: PROPOSED registry + proposed_for helper, CY2027 NPRM parameters + pincites— delta Apfs: multi-rule NPRM ingest (CY2026 + CY2027 partitions)— delta Cqpp: PY2027 registry + CMS-1848-P proposed changes— delta Ecomments: initial farm of CMS-2026-2377 (fetch/backfill/extract/index)— delta Dcomments: post-close re-farm + re-index of CMS-2026-2377— delta D (blocks milestone close; scheduled)notebooks: CY2027 proposed-rule financial changes + Advanced APM notebook— delta E
Dependency order: 1 first (schema); 2–4 independent; 5 needs 3; 6 needs 1+4+5; 7 needs 3; 8 needs 2; 9 after close date; 10 needs 5+6+7.
Testing
Same bars as P36: pytest 99% coverage, stdlib mocking; exact-value tests pin transcribed CY2027 parameters; multi-rule loader tests cover both partitions + the renamed columns; qpp structural tests extend to PY2027; notebook through layout tests + marimo check + headless integration; RAG spot-checks on the docket and rule-text chunks. Regression: P36 notebook still green after the #607 rename.
Out of scope
- CY2027 OPPS/other rules; the CY2027 final rule (a future milestone
creates
RULES[2027]and migrates the PROPOSED entry). - Comment classification/sentiment (P30).
- Cloud LLM usage (llm stays local-only).