fix(pfs): new_payment never flags a year whose year-1 is outside the supplied window (R84b)

This commit is contained in:
kert
2026-11-12 19:26:46 -05:00
parent 66f72b56a6
commit a006ae4a72
2 changed files with 38 additions and 4 deletions

View File

@@ -322,20 +322,37 @@ def new_codes_in(
"""The family's new payment events in *year* (R84): a code payable in
*year* (status A/R/T) that was not payable, or absent, in year-1 (judged
only when year-1 is in *payment*), and every curated link with
``since == year``. A link target is never judged by payability (R84a). Pass the full
payment history: a truncated window makes a code look absent in year-1."""
``since == year``. A link target is never judged by payability (R84a). A year-1 before the
first supplied year is unknown, and so is a code whose row count equals the
longest history (a ``valuation(years=N)`` window cut) while starting after
the family's first year: neither is flagged (R84b)."""
payable = {
(v.code, v.year)
for v in payment
if not v.proposed and v.status.strip().upper() in PAID_STATUSES
}
years = {v.year for v in payment if not v.proposed}
by_code: dict[str, set[int]] = {}
for v in payment:
if not v.proposed:
by_code.setdefault(v.code, set()).add(v.year)
first = min((min(ys) for ys in by_code.values()), default=year)
longest = max((len(ys) for ys in by_code.values()), default=0)
def truncated(code: str) -> bool:
# ``valuation(years=N)`` keeps the last N vintages per code, so a code
# with N rows that starts after the family's first year may have lost
# its earlier rows: its year-1 is unknown, never "absent" (R84b)
ys = by_code.get(code, set())
return bool(ys) and min(ys) > first and len(ys) == longest
targets = {getattr(link, "target", None) or link.code for link in links}
# R84a: payability counts only for the family's own member codes; a link
# target is new only in its link ``since`` year (G2211 became payable for
# office visits in 2024 but joins the home-visit family in 2026)
found = {
c for c, y in payable if y == year and year - 1 in years and c not in targets
c
for c, y in payable
if y == year and year - 1 >= first and c not in targets and not truncated(c)
}
found -= {c for c, y in payable if y == year - 1}
found |= {

View File

@@ -477,3 +477,20 @@ def test_link_target_flags_only_in_its_since_year_not_when_first_payable():
payment.append(val("G0318", 2024, 1.0))
(m,) = money_by_specialty(payment, psps, year=2024, links=links)
assert m.new_codes == ("G0318",)
def test_truncated_window_flags_nothing_in_its_first_year():
# valuation(years=7) shape: predecessors 2016-2022, current codes cut to
# 2021-2027 (their earlier rows fell out of the window), a real new code
payment = [val("99324", y, 50.0) for y in range(2016, 2023)]
payment += [val("99350", y, 100.0) for y in range(2021, 2028)]
payment += [val("G0318", y, 15.0) for y in range(2023, 2028)]
psps = [ps(2015, "99350", "Family Practice", 10.0)]
new = {
y: money_by_specialty(payment, psps, year=y)[0].new_codes
for y in range(2016, 2028)
}
assert new[2021] == () # 99350's year-1 is outside its window
assert new[2016] == () # before the first supplied year
assert new[2023] == ("G0318",)
assert [y for y, c in new.items() if c] == [2023]