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

8.5 KiB
Raw Blame History

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.