pfs: exposure calendar from code lineage — effective dates, exposure types, control code sets #693

Closed
opened 2026-09-09 14:30:05 +00:00 by kert · 1 comment
Owner

Spec docs/superpowers/specs/2026-09-09-code-family-longitudinal-design.md (§P50).

Derive from pfs.code_event (P49): one row per (code or family, effective date, exposure kind ∈ becomes-payable | revalued | status-change | ends | telehealth-listed). Effective date = 1 January of the rule year, or the correction-rule date where a correction changed the row (pfs.rules.RULES knows the FR cites; corrections are anchored items, e.g. 6N8FPFHF CY2015 correction). Control sets = families with no event in the window, matched on status and RVU band.

Fixture events: 99490 payable 2015-01-01; 99487/99489 A-status 2017-01-01; 99439 replaces G2058 2021-01-01; 99424–99427 replace G2064/G2065 2022-01-01; G2211 A-status 2024-01-01; G0556–G0558 payable 2025-01-01; 99441–99443 end 2025-01-01.

Done when the calendar is a DuckDB table with anchors carried through from the lineage rows and a notebook lists every exposure with its FR jump link.

Spec docs/superpowers/specs/2026-09-09-code-family-longitudinal-design.md (§P50). Derive from `pfs.code_event` (P49): one row per (code or family, effective date, exposure kind ∈ becomes-payable | revalued | status-change | ends | telehealth-listed). Effective date = 1 January of the rule year, or the correction-rule date where a correction changed the row (`pfs.rules.RULES` knows the FR cites; corrections are anchored items, e.g. `6N8FPFHF` CY2015 correction). Control sets = families with no event in the window, matched on status and RVU band. Fixture events: 99490 payable 2015-01-01; 99487/99489 A-status 2017-01-01; 99439 replaces G2058 2021-01-01; 99424–99427 replace G2064/G2065 2022-01-01; G2211 A-status 2024-01-01; G0556–G0558 payable 2025-01-01; 99441–99443 end 2025-01-01. Done when the calendar is a DuckDB table with anchors carried through from the lineage rows and a notebook lists every exposure with its FR jump link.
kert added this to the P50: Legal epidemiology — outcome series around code-family events (utilization, BLS wages, industry markets) milestone 2026-09-09 14:30:05 +00:00
kert added the pfsdata labels 2026-09-09 14:30:05 +00:00
Author
Owner

Merged to main as 4bd86b0 (branch commits 79ab2eb feature, 4894acd + 57ed2c7 CLI docs). Live calendar built and published the same day.

What landed

  • pfs.code_exposure (DDL + ExposureRow/write_exposures/read_exposures in pfs.codetables): one row per (code, effective date, kind) for becomes-payable / revalued / status-change / ends / telehealth-listed, with family key, the year's RVU status, prior status, decile band of non_fac_total among that year's payable codes, revaluation delta, and the FR anchor (item_key/p_id/page/anchor_kind) carried from pfs.code_event.
  • pfs.exposure: rvu_series/rvu_bands/derive (pure) + build(con, store) + control_codes(con, code, year, window=2) — never-treated codes with the same status + band and no exposure within ±window.
  • Rules: payable = A/R/T (pfs.valuation.PAID_STATUSES); left-censored at the 2015 file (a first-year payable code needs an FR created/adopted_cpt/replaces event that year); right-censored at the newest file; telehealth listed once per run of consecutive years; anchors prefer non-correction rules, then nearest year, then kind-matched, then lowest ¶. Effective date is 1 January of the rule year, or the correction notice's publication date when the event's own year is anchored only by a correction (32 rows, all CY2015 6N8FPFHF).
  • stack pfs exposure [--code|--family] [--write] [--controls N --year Y --window W]; notebook code_families.py section 7c lists a family's exposures with FR jump links and a control-set preview; provenance counts include the table.

Live numbers (stack pfs exposure --write, 1.3 s): 6,314 rows / 4,796 codes — revalued 3,738, becomes-payable 1,948, ends 417, telehealth-listed 206, status-change 5; 915 anchored to an FR paragraph. Every fixture event in this issue is present: 99490 2015-01-01 (DE2VH9PD ¶1244), 99487/99489 2017-01-01, 99439 2021-01-01 (YBM4IZUS ¶686) + G2058 ends 2021-01-01, 99424 2022-01-01 + G2064 ends 2022-01-01, G2211 2024-01-01 (JJV3R692 ¶1735), G0556 2025-01-01 (JJ6AM5HJ ¶1526), 99441 ends 2025-01-01 (VXSUDWCR ¶489 deleted).

Tests: 18 unit (tests/pfs/test_exposure.py), 6 CLI, notebook structure + live run green; pre-commit suites (cli, pfs, notebooks) passed on the feature commit.

Known limits for #696 to weigh: 99487/99489's 2017 becomes-payable anchor is a bundled paragraph (no kind-matched event that year → any-kind fallback); revalued rows only exist from the ±10% lineage threshold; families for non-hand codes are the derived CPT-heading families, so control matching by family is coarse.

Ops note: while building I ran --write from a worktree that lacked a data/aco.duckdb link, which created an empty primary there and published it over the shared replica for about a minute; I republished from the real primary immediately (connect.publish_replica) and verified 1,088 tables / 209,267 rvu rows are back.

**Merged to main as 4bd86b0** (branch commits 79ab2eb feature, 4894acd + 57ed2c7 CLI docs). Live calendar built and published the same day. **What landed** - `pfs.code_exposure` (DDL + `ExposureRow`/`write_exposures`/`read_exposures` in `pfs.codetables`): one row per (code, effective date, kind) for `becomes-payable` / `revalued` / `status-change` / `ends` / `telehealth-listed`, with family key, the year's RVU status, prior status, decile band of `non_fac_total` among that year's payable codes, revaluation delta, and the FR anchor (`item_key`/`p_id`/`page`/`anchor_kind`) carried from `pfs.code_event`. - `pfs.exposure`: `rvu_series`/`rvu_bands`/`derive` (pure) + `build(con, store)` + `control_codes(con, code, year, window=2)` — never-treated codes with the same status + band and no exposure within ±window. - Rules: payable = A/R/T (`pfs.valuation.PAID_STATUSES`); left-censored at the 2015 file (a first-year payable code needs an FR created/adopted_cpt/replaces event that year); right-censored at the newest file; telehealth listed once per run of consecutive years; anchors prefer non-correction rules, then nearest year, then kind-matched, then lowest ¶. Effective date is 1 January of the rule year, or the correction notice's publication date when the event's own year is anchored only by a correction (32 rows, all CY2015 `6N8FPFHF`). - `stack pfs exposure [--code|--family] [--write] [--controls N --year Y --window W]`; notebook `code_families.py` section 7c lists a family's exposures with FR jump links and a control-set preview; provenance counts include the table. **Live numbers** (`stack pfs exposure --write`, 1.3 s): 6,314 rows / 4,796 codes — revalued 3,738, becomes-payable 1,948, ends 417, telehealth-listed 206, status-change 5; 915 anchored to an FR paragraph. Every fixture event in this issue is present: 99490 2015-01-01 (DE2VH9PD ¶1244), 99487/99489 2017-01-01, 99439 2021-01-01 (YBM4IZUS ¶686) + G2058 ends 2021-01-01, 99424 2022-01-01 + G2064 ends 2022-01-01, G2211 2024-01-01 (JJV3R692 ¶1735), G0556 2025-01-01 (JJ6AM5HJ ¶1526), 99441 ends 2025-01-01 (VXSUDWCR ¶489 deleted). Tests: 18 unit (`tests/pfs/test_exposure.py`), 6 CLI, notebook structure + live run green; pre-commit suites (cli, pfs, notebooks) passed on the feature commit. Known limits for #696 to weigh: 99487/99489's 2017 becomes-payable anchor is a `bundled` paragraph (no kind-matched event that year → any-kind fallback); revalued rows only exist from the ±10% lineage threshold; families for non-hand codes are the derived CPT-heading families, so control matching by family is coarse. Ops note: while building I ran `--write` from a worktree that lacked a `data/aco.duckdb` link, which created an empty primary there and published it over the shared replica for about a minute; I republished from the real primary immediately (`connect.publish_replica`) and verified 1,088 tables / 209,267 rvu rows are back.
kert closed this issue 2026-09-22 19:50:15 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: homelab/stack#693