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

122 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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).