Adds the second pricer to the reconciliation engine (rec was open/closed
with only PfsPricer). OppsPricer validates that our OPPS conversion
factor reproduces CMS's published Addendum B national unadjusted rate:
ground truth = opps.addendum_b.payment_rate (published, rate > 0)
calculated = relative_weight × RULES[year].conversion_factor
(APC-priced rows, weight > 0)
Rows with a weight but no published rate (packaged, SI N) surface as
calculated_only; a published rate with no weight (non-APC method) as
ground_truth_only — mirroring how PfsPricer treats carrier-priced codes.
Wage-index adjustment is intentionally out of scope: Addendum B is the
national unadjusted rate, so the check is weight × CF only.
Also:
- stack rec opps CLI subcommand (mirrors rec pfs).
- Pricer-aware "no years available" hint (was hardcoded to PFS tables).
100% coverage on the new module, CLI paths, and registry.
Note: running this against loaded Addendum B data surfaces a systematic
CF drift in opps.rules for CY2021-CY2026 (stored CFs differ from the
empirical payment_rate/weight, which matches the real published CMS
values). Tracked for a follow-up fix — the pricer is doing its job.
165 lines
5.9 KiB
Python
165 lines
5.9 KiB
Python
"""Tests for rec.pricers.opps.OppsPricer with a seeded in-memory DuckDB."""
|
||
|
||
from __future__ import annotations
|
||
|
||
import duckdb
|
||
import polars as pl
|
||
import pytest
|
||
|
||
from opps.rules import RULES
|
||
from rec.base import Pricer
|
||
from rec.engine import reconcile
|
||
from rec.pricers import PRICERS
|
||
from rec.pricers.opps import OppsPricer
|
||
|
||
# Pick a year present in opps.rules.RULES.
|
||
_TEST_YEAR = 2026
|
||
assert _TEST_YEAR in RULES, f"test seed year {_TEST_YEAR} missing from RULES"
|
||
_CF = RULES[_TEST_YEAR].conversion_factor
|
||
|
||
|
||
@pytest.fixture
|
||
def con() -> duckdb.DuckDBPyConnection:
|
||
"""DuckDB in-memory seeded with ``opps.addendum_b`` exercising the
|
||
full match/miss matrix:
|
||
|
||
10060 (T): exact match — payment_rate == weight × CF
|
||
10061 (S): 1¢ near-miss — published rate 1¢ below weight × CF
|
||
10062 (A): ground-truth only — published rate, NULL weight
|
||
(priced by a non-APC method → nothing to compute)
|
||
10063 (N): calculated only — positive weight, NULL rate
|
||
(packaged → computable but CMS publishes no rate)
|
||
"""
|
||
c = duckdb.connect(":memory:")
|
||
c.execute("CREATE SCHEMA opps")
|
||
c.execute(
|
||
"""
|
||
CREATE TABLE opps.addendum_b (
|
||
hcpcs VARCHAR,
|
||
short_description VARCHAR,
|
||
status_indicator VARCHAR,
|
||
apc VARCHAR,
|
||
apc_title VARCHAR,
|
||
relative_weight DOUBLE,
|
||
payment_rate DOUBLE,
|
||
minimum_unadjusted_copayment DOUBLE,
|
||
year INTEGER
|
||
)
|
||
"""
|
||
)
|
||
exact_rate = round(2.0 * _CF, 2)
|
||
near_rate = round(round(3.0 * _CF, 2) - 0.01, 2)
|
||
c.execute(
|
||
f"""
|
||
INSERT INTO opps.addendum_b
|
||
(hcpcs, status_indicator, apc, relative_weight, payment_rate, year)
|
||
VALUES
|
||
('10060', 'T', '5051', 2.0, {exact_rate}, {_TEST_YEAR}),
|
||
('10061', 'S', '5052', 3.0, {near_rate}, {_TEST_YEAR}),
|
||
('10062', 'A', NULL, NULL, 150.00, {_TEST_YEAR}),
|
||
('10063', 'N', '5053', 1.5, NULL, {_TEST_YEAR})
|
||
"""
|
||
)
|
||
return c
|
||
|
||
|
||
@pytest.fixture
|
||
def test_year() -> int:
|
||
return _TEST_YEAR
|
||
|
||
|
||
class TestRegistration:
|
||
def test_in_PRICERS(self) -> None:
|
||
assert "opps" in PRICERS
|
||
assert PRICERS["opps"] is OppsPricer
|
||
|
||
def test_conforms_to_protocol(self) -> None:
|
||
assert isinstance(OppsPricer(), Pricer)
|
||
|
||
def test_class_attributes(self) -> None:
|
||
assert OppsPricer.system == "opps"
|
||
assert OppsPricer.join_keys == ["year", "hcpcs"]
|
||
assert OppsPricer.compare_cols == ["payment_rate"]
|
||
|
||
|
||
class TestGroundTruth:
|
||
def test_row_count(self, con, test_year) -> None:
|
||
# Published rate > 0: 10060, 10061, 10062 = 3 (10063 has NULL rate).
|
||
gt = OppsPricer().ground_truth(con, test_year)
|
||
assert gt.height == 3
|
||
|
||
def test_columns(self, con, test_year) -> None:
|
||
gt = OppsPricer().ground_truth(con, test_year)
|
||
for col in ["year", "hcpcs", "payment_rate"]:
|
||
assert col in gt.columns
|
||
|
||
def test_excludes_null_rate(self, con, test_year) -> None:
|
||
"""10063 is packaged (NULL published rate) — not ground truth."""
|
||
gt = OppsPricer().ground_truth(con, test_year)
|
||
assert "10063" not in gt["hcpcs"].to_list()
|
||
|
||
|
||
class TestCalculated:
|
||
def test_row_count(self, con, test_year) -> None:
|
||
# weight > 0: 10060, 10061, 10063 = 3 (10062 has NULL weight).
|
||
calc = OppsPricer().calculated(con, test_year)
|
||
assert calc.height == 3
|
||
|
||
def test_excludes_null_weight(self, con, test_year) -> None:
|
||
"""10062 has no relative weight → nothing to compute."""
|
||
calc = OppsPricer().calculated(con, test_year)
|
||
assert "10062" not in calc["hcpcs"].to_list()
|
||
|
||
def test_weight_times_cf(self, con, test_year) -> None:
|
||
calc = OppsPricer().calculated(con, test_year)
|
||
rate = calc.filter(pl.col("hcpcs") == "10060")["payment_rate"][0]
|
||
assert rate == round(2.0 * _CF, 2)
|
||
|
||
def test_returns_cents_rounded(self, con, test_year) -> None:
|
||
calc = OppsPricer().calculated(con, test_year)
|
||
for rate in calc["payment_rate"].to_list():
|
||
assert rate == round(rate, 2)
|
||
|
||
|
||
class TestReconcileOpps:
|
||
def test_summary_counts(self, con, test_year) -> None:
|
||
r = reconcile(OppsPricer(), con, test_year)
|
||
assert r.ground_truth_rows == 3 # 10060, 10061, 10062
|
||
assert r.calculated_rows == 3 # 10060, 10061, 10063
|
||
assert r.matched_rows == 2 # 10060, 10061
|
||
assert r.ground_truth_only == 1 # 10062 (published, no weight)
|
||
assert r.calculated_only == 1 # 10063 (packaged, no rate)
|
||
|
||
def test_exact_and_near(self, con, test_year) -> None:
|
||
r = reconcile(OppsPricer(), con, test_year)
|
||
assert r.exact_matches == 1 # 10060
|
||
assert r.near_matches == 2 # 10060 + 10061 (1¢)
|
||
|
||
def test_tolerance_promotes(self, con, test_year) -> None:
|
||
r = reconcile(OppsPricer(), con, test_year, tolerance_cents=1)
|
||
assert r.exact_matches == 2
|
||
|
||
def test_delta_table_contains_all_hcpcs(self, con, test_year) -> None:
|
||
r = reconcile(OppsPricer(), con, test_year)
|
||
assert set(r.deltas["hcpcs"].to_list()) == {
|
||
"10060",
|
||
"10061",
|
||
"10062",
|
||
"10063",
|
||
}
|
||
|
||
def test_years_available(self, con, test_year) -> None:
|
||
assert OppsPricer().years_available(con) == [test_year]
|
||
|
||
def test_years_available_excludes_non_rule_years(self, con) -> None:
|
||
"""A year absent from opps.rules.RULES can't be priced."""
|
||
con.execute(
|
||
"INSERT INTO opps.addendum_b (hcpcs, relative_weight, payment_rate, year) "
|
||
"VALUES ('20000', 1.0, 10.0, 1999)"
|
||
)
|
||
assert 1999 not in OppsPricer().years_available(con)
|
||
|
||
def test_missing_year_raises(self, con) -> None:
|
||
with pytest.raises(KeyError, match="RuleYear missing"):
|
||
OppsPricer().calculated(con, 1999)
|