Files
stack/docs/superpowers/specs/2026-08-13-cy2027-pfs-proposed-rule-design.md

6.6 KiB
Raw Blame History

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: ProposedRule model, pfs.nprm loader + pfs.rvu_proposed (keyed by cms_rule_id — designed for multi-rule), cms.ingest_log, qpp registry, llm.source.iter_rule_docs + rules pgvector collection, rex.comments.classify.DOCKET_RULES, notebook pattern.
  • No CY2027 final rule exists, so there is no RULES[2027] to hang a proposed block on — and RuleYear requires final fields (conversion_factor is load-bearing for pfs.pipe's RVU-file selection). The registry needs a home for proposed-only years.
  • #607 is open: pfs.rvu_proposed column names deviate from pfs.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> after discover-pfs-rules registers/tags the item (cms-rule:CMS-1848-P).
  • Addenda: CMS-1848-P detail page → data/cms/pfs_nprm/2027/; Addendum B attached + tagged sup:2027_PFS_NPRM, module:pfs, file:rvu, year:2027 (fetch script gains a --year 2027 mode instead of a clone).
  • DOCKET_RULES["CMS-2026-2377"] = "CMS-1848-P" + regression test.
  • CY2027 ProposedRule values transcribed from the captured text with pincites — never memory; comment-close date transcribed from DATES.
  • qpp: PY2027 QppYear (current law) + QppProposed for CMS-1848-P changes, both-file citations; re-verify PY2026 values only where the CY2027 NPRM restates them.
  • Rule text → rules collection (stack llm index --collection rules --key <item>); comments → comments collection 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 deltas rvu_proposed[CMS-1848-P] vs CY2026 final pfs.rvu; Advanced-APM section from qpp PY2027; 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

  1. pfs: align rvu_proposed column names with pfs.rvu — existing #607, added to P37 (delta B)
  2. comments: register CMS-2026-2377 ↔ CMS-1848-P mapping — delta E
  3. bib: discover + capture CY2027 rule text (2026-14327) into fr_downloads + bib — delta E
  4. pfs: capture CMS-1848-P proposed addenda (sup:2027_PFS_NPRM) — delta E
  5. pfs: PROPOSED registry + proposed_for helper, CY2027 NPRM parameters + pincites — delta A
  6. pfs: multi-rule NPRM ingest (CY2026 + CY2027 partitions) — delta C
  7. qpp: PY2027 registry + CMS-1848-P proposed changes — delta E
  8. comments: initial farm of CMS-2026-2377 (fetch/backfill/extract/index) — delta D
  9. comments: post-close re-farm + re-index of CMS-2026-2377 — delta D (blocks milestone close; scheduled)
  10. notebooks: CY2027 proposed-rule financial changes + Advanced APM notebook — delta E

Dependency order: 1 first (schema); 24 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).