Files
stack/tests/rec/conftest.py
kert f6e418e400
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
fix(rec): include status-R (Restricted Coverage) in PFS pricer (#340)
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>
2026-04-23 18:26:04 -04:00

194 lines
6.4 KiB
Python

"""Shared fixtures for rec tests.
Provides:
* ``con`` — an in-memory DuckDB with a ``pfs`` schema seeded with
tiny rvu/gpci/carrier_locality rows designed to exercise the full
match/miss matrix:
row A — exact match (calc round == carrier)
row B — 1¢ near-miss (calc rounds to $X.Y1, carrier $X.Y0)
row C — ground-truth only (carrier row with status_code = 'C'
so calc side skips it)
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
frames so engine tests don't need DuckDB.
"""
from __future__ import annotations
from typing import ClassVar
import duckdb
import polars as pl
import pytest
from pfs.rules import RULES
# Pick a year that exists in pfs.rules.RULES
_TEST_YEAR = 2025
assert _TEST_YEAR in RULES, f"test seed year {_TEST_YEAR} missing from RULES"
_CF = RULES[_TEST_YEAR].conversion_factor
# ── In-memory DuckDB seeded for PfsPricer tests ──────────────────
@pytest.fixture
def con() -> duckdb.DuckDBPyConnection:
"""DuckDB in-memory with seeded pfs.* tables."""
c = duckdb.connect(":memory:")
c.execute("CREATE SCHEMA pfs")
# RVU values engineered so:
# 99213 (A): work=0.97, nfpe=1.04, mp=0.07
# 99214 (A): work=1.50, nfpe=1.56, mp=0.11
# 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
# 66666 (R): work=0.80, nfpe=0.90, mp=0.06 -- restricted coverage,
# algorithm-priced like A
c.execute(
"""
CREATE TABLE pfs.rvu (
year INTEGER,
hcpcs VARCHAR,
mod VARCHAR,
status_code VARCHAR,
work_rvu DOUBLE,
non_fac_pe_rvu DOUBLE,
fac_pe_rvu DOUBLE,
mp_rvu DOUBLE,
conv_factor DOUBLE
)
"""
)
c.execute(
f"""
INSERT INTO pfs.rvu VALUES
({_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}, '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}, '66666', NULL, 'R', 0.80, 0.90, 0.30, 0.06, NULL)
"""
)
# Single locality seeded so expected payments are deterministic.
c.execute(
"""
CREATE TABLE pfs.gpci (
year INTEGER,
mac VARCHAR,
locality VARCHAR,
locality_name VARCHAR,
work_gpci DOUBLE,
pe_gpci DOUBLE,
mp_gpci DOUBLE
)
"""
)
c.execute(
f"""
INSERT INTO pfs.gpci VALUES
({_TEST_YEAR}, '10212', '01', 'ALABAMA', 1.000, 0.880, 0.550)
"""
)
# Carrier-locality rows.
# Row A (99213): calculate exact expected payment and seed it.
# nf = (0.97*1.0 + 1.04*0.88 + 0.07*0.55) * CF
# fac = (0.97*1.0 + 0.41*0.88 + 0.07*0.55) * CF
nf_99213 = round((0.97 * 1.0 + 1.04 * 0.88 + 0.07 * 0.55) * _CF, 2)
fac_99213 = round((0.97 * 1.0 + 0.41 * 0.88 + 0.07 * 0.55) * _CF, 2)
# Row B (99214): seed a value 1¢ off the calc to exercise near_matches.
nf_99214_calc = round((1.50 * 1.0 + 1.56 * 0.88 + 0.11 * 0.55) * _CF, 2)
fac_99214_calc = round((1.50 * 1.0 + 0.63 * 0.88 + 0.11 * 0.55) * _CF, 2)
nf_99214_seeded = round(nf_99214_calc - 0.01, 2)
fac_99214_seeded = fac_99214_calc # only nf is the near miss
# Row C (99999): status C, so calc side skips — only GT.
nf_99999 = 55.55
fac_99999 = 44.44
# 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(
"""
CREATE TABLE pfs.carrier_locality (
year INTEGER,
mac VARCHAR,
locality VARCHAR,
hcpcs VARCHAR,
mod VARCHAR,
non_fac_fee DOUBLE,
fac_fee DOUBLE,
non_fac_limiting_charge DOUBLE,
fac_limiting_charge DOUBLE
)
"""
)
c.execute(
f"""
INSERT INTO pfs.carrier_locality VALUES
({_TEST_YEAR}, '10212', '01', '99213', NULL,
{nf_99213}, {fac_99213}, NULL, NULL),
({_TEST_YEAR}, '10212', '01', '99214', NULL,
{nf_99214_seeded}, {fac_99214_seeded}, NULL, NULL),
({_TEST_YEAR}, '10212', '01', '99999', NULL,
{nf_99999}, {fac_99999}, NULL, NULL),
({_TEST_YEAR}, '10212', '01', '66666', NULL,
{nf_66666}, {fac_66666}, NULL, NULL)
"""
)
return c
@pytest.fixture
def test_year() -> int:
return _TEST_YEAR
# ── Fake pricer for engine tests ─────────────────────────────────
class _FakePricer:
"""Hand-rolled pricer that returns hard-coded polars frames."""
system: ClassVar[str] = "fake"
description: ClassVar[str] = "Test pricer — returns fixture frames"
join_keys: ClassVar[list[str]] = ["hcpcs", "mod"]
compare_cols: ClassVar[list[str]] = ["fee"]
def ground_truth(self, con, year: int) -> pl.DataFrame:
return pl.DataFrame(
{
"hcpcs": ["A001", "A002", "A003"], # exact, 1¢ near, gt-only
"mod": ["", "", ""],
"fee": [10.00, 20.00, 30.00],
}
)
def calculated(self, con, year: int) -> pl.DataFrame:
return pl.DataFrame(
{
"hcpcs": ["A001", "A002", "A004"], # exact, 1¢ near, calc-only
"mod": ["", "", ""],
"fee": [10.00, 20.01, 40.00],
}
)
def years_available(self, con) -> list[int]:
return [2025]
@pytest.fixture
def fake_pricer() -> _FakePricer:
return _FakePricer()