Files
stack/docs/superpowers/plans/2026-08-13-cy2027-pfs-proposed-rule-p37.md
kert c48cab92ba
All checks were successful
CI / lint (push) Successful in 45s
CI / notebooks-smoke (push) Successful in 1m33s
Deploy / notebooks (push) Has been skipped
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Has been skipped
Deploy / api (push) Has been skipped
Deploy / llm (push) Has been skipped
Deploy / mc (push) Has been skipped
Infra CI / notebooks (push) Successful in 8m12s
Infra CI / zotero (push) Successful in 20s
Infra CI / docs (push) Successful in 18s
Infra CI / api (push) Successful in 20s
Infra CI / llm (push) Successful in 12s
Infra CI / mc (push) Successful in 14s
Deploy / report (push) Successful in 16s
CI / test (push) Successful in 19m16s
docs(plan): P37 CY2027 PFS proposed rule implementation plan (refs #607-#616)
2026-08-13 19:48:20 -04:00

88 lines
8.5 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 (P37) Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Run CY2027's NPRM (CMS-1848-P, docket CMS-2026-2377, FR doc 2026-14327, pub 2026-07-16) through the pipeline P36 built, with the four deltas from the spec (PROPOSED registry, #607 rename first, multi-rule ingest, open-comment-period farm + scheduled re-farm).
**Architecture / Tech Stack:** identical to P36 — see `docs/superpowers/plans/2026-08-12-cy2026-pfs-proposed-rule-p36.md` for the detailed patterns; this plan states only what differs.
**Tracker:** milestone P37 (id 38) — issues #607#616. Spec: `docs/superpowers/specs/2026-08-13-cy2027-pfs-proposed-rule-design.md`
## Global Constraints
Same as P36's plan (branch `p37-cy2027-rule` off main; conventional commits `refs #NNN`, **no Co-Authored-By trailers**; 99% coverage, stdlib mocking; ruff E,F,I/88; lazy conf imports; generated workflows untouched; llm local-only; `duckdb_batch` for writes; **never transcribe rule parameters from memory** — grep the captured text with `-a` (HTML-wrapped, hard-wrapped lines, stray NULs) and pincite everything; transcription-then-test allowed only for FR values). Plus, learned in P36: stage only your own files (`git add <paths>`, never `-A`); retry once on commit HEAD/index races; pyproject-touching commits trigger the full-suite hook (~14 min parallel) — serialize around them.
---
### Task 1: Align rvu_proposed column names (#607)
**Files:** Modify `src/pfs/nprm.py`, `tests/pfs/test_nprm.py`, `notebooks/cy2026_pfs_proposed_rule.py` (its SQL aliases).
**Produces:** `pfs.rvu_proposed` columns exactly `hcpcs, mod, description, status_code, work_rvu, non_fac_pe_rvu, fac_pe_rvu, mp_rvu, cms_rule_id` (audit against `pfs.pipe._RVU_COLUMNS` and match `pfs.rvu` verbatim — verify with `DESCRIBE pfs.rvu` on the replica first).
- [ ] Update tests to the new names (they pin the schema) → run → FAIL → rename in `nprm.py` (target columns + DDL + normalization map) → PASS.
- [ ] Simplify the P36 notebook's join SQL (drop the alias juggling); `uvx marimo check` + layout tests.
- [ ] Host run `uv run python dev/scripts/ingest_pfs.py --nprm --no-lake` (delete-and-reload recreates the table with new names; `DROP TABLE pfs.rvu_proposed` first since CREATE IF NOT EXISTS won't alter columns — do it inside the same duckdb_batch), then full run with lake; verify replica + lake schema.
- [ ] Commit `fix(pfs): align rvu_proposed columns with pfs.rvu (refs #607)`.
### Task 2: Docket mapping (#608)
**Files:** `src/rex/comments/classify.py`, `tests/rex/comments/test_classify.py`.
- [ ] Failing test: `DOCKET_RULES["CMS-2026-2377"] == "CMS-1848-P"` → add the entry (comment: CY2027 PFS NPRM, verified via FR API 2026-08-13) → PASS → commit `feat(comments): register CMS-2026-2377 (CY2027 PFS NPRM) (refs #608)`.
### Task 3: Discover + capture rule text (#609) — ops
- [ ] `uv run stack bib discover-pfs-rules` (registers/tags the CY2027 items; note the new item key for 2026-14327 — find via `store.list_items(item_type="rule")` filtering document_number).
- [ ] `uv run python dev/scripts/fetch_fr_attachments.py --key <KEY>`; verify PDF+TXT in data/fr_downloads and attachments on the item; `grep -a -c "conversion factor" data/fr_downloads/2026-14327.txt` > 0.
- [ ] Record the item key in the ledger + issue comment (later tasks need it). No commit.
### Task 4: NPRM addenda capture (#610)
**Files:** Modify `dev/scripts/fetch_nprm_addenda.py` (add `--year` selecting a per-year config dict: detail-page URL, ZIP URL, dest dir, rule item key, tag set; 2026 entry keeps current values; 2027 entry → CMS-1848-P page, `data/cms/pfs_nprm/2027/`, tags `sup:2027_PFS_NPRM, module:pfs, file:rvu, year:2027`).
- [ ] Resolve the CMS-1848-P addenda ZIP URL from `https://www.cms.gov/medicare/payment/fee-schedules/physician/federal-regulation-notices/cms-1848-p` (fallback: the notices index). Download, verify Addendum B columns, `--register` (idempotency guard already exists — parameterize it by item key), tag-scoped zotero sync.
- [ ] Commit `feat(pfs): CY2027 NPRM addenda capture — fetch_nprm_addenda --year (refs #610)`.
### Task 5: PROPOSED registry + CY2027 parameters (#611)
**Files:** `src/pfs/rules/__init__.py`, `tests/pfs/test_rules.py`.
**Produces:** `PROPOSED: dict[int, ProposedRule]`; `proposed_for(year) -> ProposedRule | None` (`RULES[year].proposed` if year in RULES else `PROPOSED.get(year)`); `PROPOSED[2027]` populated.
- [ ] Transcribe from `data/fr_downloads/2026-14327.txt` (grep `-a`, short fragments): proposed CFs (QP/non-QP + anesthesia pair), BN adjustor, telehealth originating-site fee, published/comment-close (DATES block — **this close date drives #615's schedule**), FR citation from the header (`[Pages …]`). Record verbatim quotes + file lines + FR pages in the report.
- [ ] Structural tests first (helper resolves both paths; 2027 in PROPOSED not RULES), then exact-value tests pinning transcriptions. Docstrings follow the file's `:pincite:` style citing the new item key.
- [ ] Commit `feat(pfs): PROPOSED registry + proposed_for — CY2027 NPRM parameters (refs #611)`.
### Task 6: Multi-rule NPRM ingest (#612)
**Files:** `src/pfs/nprm.py`, `dev/scripts/ingest_pfs.py`, `tests/pfs/test_nprm.py`.
**Produces:** `_discover_addendum_b(tag: str)`; `NPRM_SOURCES: list of (year, sup_tag, cms_rule_id)` (2026 + 2027); `load_rvu_proposed(con, *, year)` resolving tag/rule/citation via `NPRM_SOURCES` + `proposed_for(year)`; `--nprm` loads every source, one `ingest_log` row each, same run_id.
- [ ] Tests: two fixture partitions load side by side; reloading one rule leaves the other intact; discovery raises naming the missing tag.
- [ ] Host run (both partitions; verify `SELECT cms_rule_id, count(*) FROM pfs.rvu_proposed GROUP BY 1` shows CMS-1832-P + CMS-1848-P) + replica + lake; `cms.ingest_log` rows for both.
- [ ] Commit `feat(pfs): multi-rule NPRM ingest — CY2026+CY2027 partitions (refs #612)`.
### Task 7: qpp PY2027 (#613)
**Files:** `src/qpp/__init__.py`, `tests/qpp/test_rules.py`.
- [ ] Transcribe PY2027 current-law thresholds/standards and CMS-1848-P's proposed Advanced-APM changes from `2026-14327.txt` (both greps and quotes in the report; re-verify PY2026 only where restated). `QPP[2027]` + `QppProposed(cms_rule_id="CMS-1848-P", …)`; unstated values → `None` + notes (P36 precedent).
- [ ] Structural + exact-value tests; commit `feat(qpp): PY2027 registry + CMS-1848-P proposed changes (refs #613)`.
### Task 8: Initial comment farm (#614) — ops, long-running
- [ ] `uv run stack bib fetch-pfs-comments` (discovers CMS-1848-P → resolves docket → pulls comments to date; rate-limited ~970/hr — with an open period expect a partial set; run detached `setsid nohup`, log to `.state/comments/fetch-CMS-2026-2377.log`, Monitor for errors).
- [ ] Then `backfill-comments` (export REGULATIONS_GOV_API_KEY), `comments extract --docket CMS-2026-2377`, `extract-ocr`, then `stack llm index --collection comments --docket CMS-2026-2377` and `--collection rules --key <2027 item key>` (detached + monitored; all resumable).
- [ ] Post counts on #614. No commit.
### Task 9: Post-close re-farm (#615) — scheduled, blocks milestone close
- [ ] After Task 5 lands, set the local cron reminder for close-date+1 (CronCreate) to re-run Task 8's commands verbatim; comment the exact date + commands on #615.
- [ ] On firing: re-run, post final counts, close #615, then close milestone P37.
### Task 10: CY2027 notebook (#616)
**Files:** `notebooks/cy2027_pfs_proposed_rule.py`.
- [ ] Clone the P36 notebook's structure (dataviz skill first): CF walk CY2026-final → CY2027-proposed (columns labeled "final rule pending"), RVU deltas `rvu_proposed[CMS-1848-P]` vs CY2026 final `pfs.rvu` (aligned columns from Task 1), APM section from `qpp` PY2027 via `for_payment_year(2029)`/`QPP[2027]`, provenance from `cms.ingest_log`. Registry-sourced values only; FR citation attached to every figure (P36 review standard); GPCI=1.0 scope note.
- [ ] marimo check + layout tests + scoped headless integration; commit `feat(notebooks): CY2027 proposed-rule financial changes + APM (refs #616)`.
### Task 11: Close-out
- [ ] Full gates; merge `p37-cy2027-rule` → main (`Merge P37: …`), push (remote is `gitea`).
- [ ] Close #607#614, #616 with substantiation; #615 + milestone stay open until the post-close re-farm.
- [ ] Append `## P37 build outcomes` to the spec; update ledger; keep the re-farm cron armed.