test(opps): lock down OPPS conversion factors with two guards
Some checks failed
CI / lint (push) Successful in 38s
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
Deploy / report (push) Successful in 17s
CI / test (push) Failing after 13m16s

Make the CY2014-CY2026 conversion factors regression-proof:

- TestGoldenConversionFactors pins every year's CF to its Federal-
  Register / Addendum-B-verified value (runs in CI, no data needed), so
  any accidental edit fails and forces a cited, deliberate change.
- TestAddendumBSelfConsistency (skipped when the aco DuckDB is absent)
  reconciles OppsPricer against the loaded Addendum B and asserts every
  APC row matches weight × CF to the cent — the independent proof the
  golden values are correct, not merely unchanged. Verified: all six
  loaded years (2021-2026) reconcile 100% exact.
This commit is contained in:
kert
2026-07-08 11:47:23 -04:00
parent 3760541b08
commit b21b1ae453

113
tests/opps/test_rules.py Normal file
View File

@@ -0,0 +1,113 @@
"""Golden + self-consistency guards for opps.rules conversion factors.
The OPPS conversion factor per year is correctness-critical reference
data: OppsPricer computes national APC rates as ``weight × CF`` and
reconciles them against CMS's published Addendum B. Two guards keep it
bulletproof:
1. ``TestGoldenConversionFactors`` pins every year's CF to the value
taken from that year's Federal Register OPPS Final Rule (CY2014-
CY2020) and cross-checked against the empirical
``payment_rate / relative_weight`` ratio in Addendum B (CY2021-
CY2026). Runs everywhere (no data needed), so any accidental edit
fails CI. Changing a value requires updating the citation below too.
2. ``TestAddendumBSelfConsistency`` (skipped when the aco DuckDB is
absent, e.g. headless CI) proves the CFs actually reproduce CMS's
published Addendum B rate to the cent — the independent check that
the golden values above are *correct*, not merely *unchanged*.
"""
from __future__ import annotations
import pytest
from conf import path
from opps.rules import RULES
# Full OPPS conversion factor — the rate for hospitals that MEET quality
# reporting (not the reduced/OQR-penalty CF).
#
# Sources:
# CY2014-CY2020 — each year's Federal Register OPPS/ASC Final Rule
# preamble ("we are using a conversion factor of $X").
# CY2021-CY2026 — empirical payment_rate / relative_weight in
# opps.addendum_b (5,000+ APC-priced rows/year), which
# reproduces the published national rate to the cent.
# CY2020 = 80.793 is the corrected value; the final rule as published
# stated 80.784 and CMS later corrected it (the CY2021 rule
# builds off 80.793).
# CY2016 is genuinely below CY2015 — a one-time -2.0pp packaged-lab
# ("two-times") adjustment more than offset the market basket.
_EXPECTED_CF: dict[int, float] = {
2014: 72.672,
2015: 74.144,
2016: 73.725,
2017: 75.001,
2018: 78.636,
2019: 79.490,
2020: 80.793,
2021: 82.797,
2022: 84.177,
2023: 85.585,
2024: 87.382,
2025: 89.169,
2026: 91.415,
}
_HAS_ACO_DB = path("db.aco").exists()
class TestGoldenConversionFactors:
"""CI-runnable pin — guards against accidental CF edits."""
def test_all_years_present(self) -> None:
assert set(RULES) == set(_EXPECTED_CF)
@pytest.mark.parametrize("year", sorted(_EXPECTED_CF))
def test_cf_matches_published_value(self, year: int) -> None:
assert RULES[year].conversion_factor == _EXPECTED_CF[year], (
f"CY{year} OPPS conversion factor changed. If this is a real "
f"correction, update _EXPECTED_CF with a Federal Register / "
f"Addendum B citation — do not silently override it."
)
def test_monotonic_except_2016(self) -> None:
"""CFs rise year over year, except the deliberate CY2016 dip."""
years = sorted(_EXPECTED_CF)
for prev, cur in zip(years, years[1:]):
prev_cf = RULES[prev].conversion_factor
cur_cf = RULES[cur].conversion_factor
if cur == 2016:
assert cur_cf < prev_cf
else:
assert cur_cf > prev_cf
@pytest.mark.skipif(not _HAS_ACO_DB, reason="data/aco.duckdb not present")
class TestAddendumBSelfConsistency:
"""Prove weight × CF reproduces CMS's published Addendum B rate.
Runs only where the aco DuckDB (with ``opps.addendum_b``) is present.
This is the independent check that the golden CFs are *correct*: if a
CF is wrong, the calculated national rate diverges from the published
``payment_rate`` and this fails.
"""
def test_reconciles_to_the_cent_for_all_loaded_years(self) -> None:
from conf import connect
from rec.engine import reconcile
from rec.pricers.opps import OppsPricer
con = connect.duckdb()
pricer = OppsPricer()
years = pricer.years_available(con)
assert years, "opps.addendum_b has no years overlapping RULES"
for year in years:
r = reconcile(pricer, con, year)
assert r.matched_rows > 0, f"CY{year}: no APC rows to reconcile"
assert r.exact_matches == r.matched_rows, (
f"CY{year}: {r.matched_rows - r.exact_matches} of "
f"{r.matched_rows} APC rows do not match weight × CF to the "
f"cent — the CY{year} conversion factor is wrong."
)