122 lines
6.6 KiB
Markdown
122 lines
6.6 KiB
Markdown
# 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); 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).
|