fix(rec): include status-R (Restricted Coverage) in PFS pricer (#340)
Some checks failed
CI / lint (push) Failing after 28s
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 / mc (push) Has been skipped
Infra CI / notebooks (push) Failing after 13s
Infra CI / zotero (push) Successful in 12s
Infra CI / docs (push) Successful in 14s
Infra CI / api (push) Successful in 21s
Infra CI / mc (push) Successful in 12s
Deploy / report (push) Successful in 11s
CI / test (push) Has been cancelled

Investigation: characterized the consistent ~11K-12K ground-truth-only
rows per year (2016-2026) by joining against pfs.rvu. Result: 100% of
the gap is status_code='R'. Zero are A/T (no real calc bugs hidden in
the noise), zero are missing from pfs.rvu entirely.

Status R = Restricted Coverage. CMS applies special coverage rules
(certain settings, modifier requirements, NCD-driven) but the price
formula is identical to A: RVU × GPCI × CF. The pricer was filtering
status_code IN ('A', 'T'), treating R as if it were carrier-priced.

Fix: add 'R' to _ALGORITHMIC_STATUS. One-character change in the
SQL filter, plus updated docstrings.

Verified: live `stack rec pfs` for every year 2016-2026 now reports:
  Ground-truth only: 0   (was 9,990 - 12,650)
  Status: 100.00% exact

Residual deltas are single-digit ≤1¢ float-rounding noise across
~11M rows. Closes the framework's empirical concordance gap → #340
acceptance criteria fully satisfied.

Test: added 66666 (status R) to the in-memory fixture; updated count
assertions across the existing test class to reflect the new
4-row/3-match baseline; added test_includes_restricted_coverage
regression guard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
kert
2026-04-23 18:26:04 -04:00
parent 7445d097fd
commit f6e418e400
3 changed files with 50 additions and 24 deletions

View File

@@ -9,12 +9,13 @@ Calculated: join ``pfs.rvu`` × ``pfs.gpci`` for the year, override
non-facility. non-facility.
Status-code filter: Status-code filter:
Only status ``A`` (algorithm-priced) and ``T`` (paid under Algorithm-priced statuses ``A``, ``R``, and ``T`` reconcile to the
algorithm when more than one service on same day) are expected cent. ``A`` is active, ``R`` is restricted-coverage (special
to reconcile to the cent. Carrier-priced codes (``C``), bundled coverage rules apply but the price formula is identical to A),
(``B``), and other status indicators are excluded from the and ``T`` is paid-under-algorithm-when-multiple-services. Carrier-
calculated side so they show up as ``ground_truth_only`` rather priced codes (``C``), bundled (``B``), and other status indicators
than being flagged as computation bugs. are excluded from the calculated side so they show up as
``ground_truth_only`` rather than being flagged as computation bugs.
Gaps tracked: Gaps tracked:
- Limiting charge columns are stack-synthesized in pipe.py - Limiting charge columns are stack-synthesized in pipe.py
@@ -37,7 +38,10 @@ from pfs.rules import RULES
# Status codes whose payment is computed algorithmically and should # Status codes whose payment is computed algorithmically and should
# reconcile to the cent. Everything else is ground-truth only. # reconcile to the cent. Everything else is ground-truth only.
_ALGORITHMIC_STATUS: tuple[str, ...] = ("A", "T") # R = Restricted Coverage — coverage rules differ but pricing formula is
# identical to A. Including R closes the entire ~11K/year GT-only gap
# observed across CY2016-CY2026 (verified empirically).
_ALGORITHMIC_STATUS: tuple[str, ...] = ("A", "R", "T")
class PfsPricer: class PfsPricer:

View File

@@ -11,6 +11,9 @@ Provides:
row C — ground-truth only (carrier row with status_code = 'C' row C — ground-truth only (carrier row with status_code = 'C'
so calc side skips it) so calc side skips it)
row D — calculated only (RVU row with no carrier file entry) row D — calculated only (RVU row with no carrier file entry)
row R — exact match for status_code = 'R' (Restricted Coverage):
R is algorithm-priced same as A/T, just with coverage
restrictions that don't affect the price formula.
* ``fake_pricer`` — a hand-rolled Pricer that takes hard-coded polars * ``fake_pricer`` — a hand-rolled Pricer that takes hard-coded polars
frames so engine tests don't need DuckDB. frames so engine tests don't need DuckDB.
@@ -46,6 +49,8 @@ def con() -> duckdb.DuckDBPyConnection:
# 99214 (A): work=1.50, nfpe=1.56, mp=0.11 # 99214 (A): work=1.50, nfpe=1.56, mp=0.11
# 99999 (C): work=1.00, nfpe=1.00, mp=0.00 -- carrier-priced # 99999 (C): work=1.00, nfpe=1.00, mp=0.00 -- carrier-priced
# 88888 (A): work=0.50, nfpe=0.40, mp=0.05 -- no carrier row # 88888 (A): work=0.50, nfpe=0.40, mp=0.05 -- no carrier row
# 66666 (R): work=0.80, nfpe=0.90, mp=0.06 -- restricted coverage,
# algorithm-priced like A
c.execute( c.execute(
""" """
CREATE TABLE pfs.rvu ( CREATE TABLE pfs.rvu (
@@ -67,7 +72,8 @@ def con() -> duckdb.DuckDBPyConnection:
({_TEST_YEAR}, '99213', NULL, 'A', 0.97, 1.04, 0.41, 0.07, NULL), ({_TEST_YEAR}, '99213', NULL, 'A', 0.97, 1.04, 0.41, 0.07, NULL),
({_TEST_YEAR}, '99214', NULL, 'A', 1.50, 1.56, 0.63, 0.11, NULL), ({_TEST_YEAR}, '99214', NULL, 'A', 1.50, 1.56, 0.63, 0.11, NULL),
({_TEST_YEAR}, '99999', NULL, 'C', 1.00, 1.00, 1.00, 0.00, NULL), ({_TEST_YEAR}, '99999', NULL, 'C', 1.00, 1.00, 1.00, 0.00, NULL),
({_TEST_YEAR}, '88888', NULL, 'A', 0.50, 0.40, 0.20, 0.05, NULL) ({_TEST_YEAR}, '88888', NULL, 'A', 0.50, 0.40, 0.20, 0.05, NULL),
({_TEST_YEAR}, '66666', NULL, 'R', 0.80, 0.90, 0.30, 0.06, NULL)
""" """
) )
@@ -107,6 +113,10 @@ def con() -> duckdb.DuckDBPyConnection:
nf_99999 = 55.55 nf_99999 = 55.55
fac_99999 = 44.44 fac_99999 = 44.44
# Row D (88888): calc side only — no carrier row. # Row D (88888): calc side only — no carrier row.
# Row R (66666): status R, must reconcile exactly with the same formula
# as A/T after the fix. Seed the carrier value to the calculated value.
nf_66666 = round((0.80 * 1.0 + 0.90 * 0.88 + 0.06 * 0.55) * _CF, 2)
fac_66666 = round((0.80 * 1.0 + 0.30 * 0.88 + 0.06 * 0.55) * _CF, 2)
c.execute( c.execute(
""" """
@@ -131,7 +141,9 @@ def con() -> duckdb.DuckDBPyConnection:
({_TEST_YEAR}, '10212', '01', '99214', NULL, ({_TEST_YEAR}, '10212', '01', '99214', NULL,
{nf_99214_seeded}, {fac_99214_seeded}, NULL, NULL), {nf_99214_seeded}, {fac_99214_seeded}, NULL, NULL),
({_TEST_YEAR}, '10212', '01', '99999', NULL, ({_TEST_YEAR}, '10212', '01', '99999', NULL,
{nf_99999}, {fac_99999}, NULL, NULL) {nf_99999}, {fac_99999}, NULL, NULL),
({_TEST_YEAR}, '10212', '01', '66666', NULL,
{nf_66666}, {fac_66666}, NULL, NULL)
""" """
) )

View File

@@ -26,8 +26,8 @@ class TestGroundTruth:
def test_row_count(self, con, test_year) -> None: def test_row_count(self, con, test_year) -> None:
p = PfsPricer() p = PfsPricer()
gt = p.ground_truth(con, test_year) gt = p.ground_truth(con, test_year)
# Seeded 3 carrier rows (99213, 99214, 99999) # Seeded 4 carrier rows (99213, 99214, 99999, 66666)
assert gt.height == 3 assert gt.height == 4
def test_columns(self, con, test_year) -> None: def test_columns(self, con, test_year) -> None:
p = PfsPricer() p = PfsPricer()
@@ -59,6 +59,16 @@ class TestCalculated:
hcpcs = set(calc["hcpcs"].to_list()) hcpcs = set(calc["hcpcs"].to_list())
assert {"99213", "99214", "88888"}.issubset(hcpcs) assert {"99213", "99214", "88888"}.issubset(hcpcs)
def test_includes_restricted_coverage(self, con, test_year) -> None:
"""66666 has status_code='R' (Restricted Coverage). R is
algorithm-priced same as A/T — coverage restrictions don't
affect the price formula. Was previously excluded; this test
guards against regression."""
p = PfsPricer()
calc = p.calculated(con, test_year)
hcpcs = set(calc["hcpcs"].to_list())
assert "66666" in hcpcs
def test_returns_cents_rounded(self, con, test_year) -> None: def test_returns_cents_rounded(self, con, test_year) -> None:
p = PfsPricer() p = PfsPricer()
calc = p.calculated(con, test_year) calc = p.calculated(con, test_year)
@@ -70,12 +80,12 @@ class TestCalculated:
class TestReconcilePfs: class TestReconcilePfs:
def test_summary_counts(self, con, test_year) -> None: def test_summary_counts(self, con, test_year) -> None:
r = reconcile(PfsPricer(), con, test_year) r = reconcile(PfsPricer(), con, test_year)
# Ground-truth rows: 99213, 99214, 99999 = 3 # Ground-truth rows: 99213, 99214, 99999, 66666 = 4
assert r.ground_truth_rows == 3 assert r.ground_truth_rows == 4
# Calculated rows: 99213, 99214, 88888 = 3 (99999 skipped) # Calculated rows: 99213, 99214, 88888, 66666 = 4 (99999 skipped)
assert r.calculated_rows == 3 assert r.calculated_rows == 4
# Matched: 99213, 99214 = 2 # Matched: 99213, 99214, 66666 = 3
assert r.matched_rows == 2 assert r.matched_rows == 3
# gt_only: 99999 # gt_only: 99999
assert r.ground_truth_only == 1 assert r.ground_truth_only == 1
# calc_only: 88888 # calc_only: 88888
@@ -83,19 +93,19 @@ class TestReconcilePfs:
def test_exact_and_near(self, con, test_year) -> None: def test_exact_and_near(self, con, test_year) -> None:
r = reconcile(PfsPricer(), con, test_year) r = reconcile(PfsPricer(), con, test_year)
# 99213 seeded to match exactly; 99214 is 1¢ off on non_fac_fee. # 99213 + 66666 seeded exact; 99214 is 1¢ off on non_fac_fee.
assert r.exact_matches == 1 assert r.exact_matches == 2
assert r.near_matches == 2 assert r.near_matches == 3
def test_tolerance_promotes(self, con, test_year) -> None: def test_tolerance_promotes(self, con, test_year) -> None:
r = reconcile(PfsPricer(), con, test_year, tolerance_cents=1) r = reconcile(PfsPricer(), con, test_year, tolerance_cents=1)
assert r.exact_matches == 2 assert r.exact_matches == 3
def test_delta_table_contains_hcpcs(self, con, test_year) -> None: def test_delta_table_contains_hcpcs(self, con, test_year) -> None:
r = reconcile(PfsPricer(), con, test_year) r = reconcile(PfsPricer(), con, test_year)
hcpcs = set(r.deltas["hcpcs"].to_list()) hcpcs = set(r.deltas["hcpcs"].to_list())
# All four distinct hcpcs from outer join # All five distinct hcpcs from outer join
assert hcpcs == {"99213", "99214", "99999", "88888"} assert hcpcs == {"99213", "99214", "99999", "88888", "66666"}
def test_years_available(self, con, test_year) -> None: def test_years_available(self, con, test_year) -> None:
p = PfsPricer() p = PfsPricer()