feat(sp41): 120-day timely-filing gate with per-batch override

This commit is contained in:
Nora
2026-07-07 20:24:40 -06:00
parent ea7acd2e66
commit 30d13876cd
2 changed files with 76 additions and 0 deletions
@@ -0,0 +1,37 @@
"""120-day timely-filing gate for Colorado Medicaid.
Per HCPF's Colorado Medical Assistance Program provider manual, claims must
be filed within 120 days from the date of service. The gate is HARD by
default — past-window visits are surfaced as EXCLUDED_TIMELY_FILING in the
summary CSV and not emitted by Pipeline B.
The operator may pass override=True per batch to relax the gate (e.g. for
good-cause appeal visits). The decision is recorded in the summary CSV
either way so the audit trail shows the override.
"""
from dataclasses import dataclass
from datetime import date
FILING_WINDOW_DAYS = 120
@dataclass(frozen=True)
class TimelyFilingDecision:
dos: date
as_of: date
days_old: int
within_window: bool
override: bool
rebillable: bool
def timely_filing_decision(
dos: date, as_of: date, override: bool
) -> TimelyFilingDecision:
days_old = (as_of - dos).days
within_window = days_old <= FILING_WINDOW_DAYS
return TimelyFilingDecision(
dos=dos, as_of=as_of, days_old=days_old,
within_window=within_window, override=override,
rebillable=within_window or override,
)
@@ -0,0 +1,39 @@
"""120-day DOS-age gate. CO Medicaid's timely-filing window is 120 days from DOS."""
from datetime import date
from decimal import Decimal
from cyclone.rebill.timely_filing import timely_filing_decision, FILING_WINDOW_DAYS
def test_visit_within_window_is_rebillable():
decision = timely_filing_decision(
dos=date(2026, 6, 1), as_of=date(2026, 7, 7), override=False
)
assert decision.rebillable is True
def test_visit_past_window_excluded_by_default():
decision = timely_filing_decision(
dos=date(2026, 1, 1), as_of=date(2026, 7, 7), override=False
)
assert decision.rebillable is False
assert decision.days_old == 187
def test_visit_at_exact_120_days_inclusive():
decision = timely_filing_decision(
dos=date(2026, 3, 9), as_of=date(2026, 7, 7), override=False
)
# 2026-03-09 → 2026-07-07 = 120 days
assert decision.days_old == 120
assert decision.rebillable is True
def test_override_flag_relaxes_the_gate():
decision = timely_filing_decision(
dos=date(2026, 1, 1), as_of=date(2026, 7, 7), override=True
)
assert decision.rebillable is True
def test_window_constant_is_120():
assert FILING_WINDOW_DAYS == 120