feat(sp31): integrate content-keys fallback into reconcile.run() with auto_matched_835 event

This commit is contained in:
Nora
2026-07-02 15:58:01 -06:00
parent 9bade2429c
commit ab91449e62
2 changed files with 151 additions and 4 deletions
+117
View File
@@ -653,3 +653,120 @@ def test_content_keys_npi_from_remit_raw_json(db_session, make_claim):
db_session.add(remit)
db_session.flush()
assert _content_keys_match(remit, claim) is True # charge + NPI = 2 of 3
# --- SP31: end-to-end integration via reconcile.run() -----------------------
def test_reconcile_run_emits_score_auto_match_when_pcn_misses(db_session, make_claim, make_remit):
"""A remit with no PCN match but matching charge+NPI triggers score-auto."""
from decimal import Decimal
from datetime import date
from sqlalchemy import select
from cyclone.db import Batch, ClaimState
from cyclone.reconcile import run as reconcile_run
claim = make_claim(patient_control_number="UNIQUE-CLM",
total_charge=Decimal("100.00"),
rendering_provider_npi="1111111111",
service_date_from=date(2026, 6, 1))
remit = make_remit(payer_claim_control_number="DIFFERENT-PCN",
total_charge_amount=Decimal("100.00"),
rendering_provider_npi="1111111111",
service_date=date(2026, 6, 5))
batch = Batch(id="batch-1", kind="835", input_filename="x.835", parsed_at=date(2026, 6, 5))
db_session.add(batch)
db_session.flush()
# Re-parent the remit to this batch (make_remit doesn't set batch_id).
remit.batch_id = batch.id
db_session.flush()
result = reconcile_run(db_session, batch.id)
db_session.flush() # autoflush=False on SessionLocal; force flush pending Match row
assert result.matched == 1
# Verify Match row was written with strategy="score-auto"
from cyclone.db import Match
matches = list(db_session.execute(
select(Match).where(Match.remittance_id == remit.id)
).scalars().all())
assert len(matches) == 1
assert matches[0].strategy == "score-auto"
assert matches[0].claim_id == claim.id
# Verify ActivityEvent was emitted with kind="auto_matched_835"
from cyclone.db import ActivityEvent
events = list(db_session.execute(
select(ActivityEvent).where(
ActivityEvent.remittance_id == remit.id,
ActivityEvent.kind == "auto_matched_835",
)
).scalars().all())
assert len(events) == 1
assert events[0].claim_id == claim.id
# Verify claim state was flipped
db_session.refresh(claim)
assert claim.state in {ClaimState.PAID, ClaimState.PARTIAL, ClaimState.RECEIVED}
def test_reconcile_run_pcn_path_unchanged(db_session, make_claim, make_remit):
"""Existing PCN-exact match still produces strategy='pcn-exact' (regression guard)."""
from decimal import Decimal
from datetime import date
from sqlalchemy import select
from cyclone.db import Batch, Match
from cyclone.reconcile import run as reconcile_run
claim = make_claim(patient_control_number="SAME-PCN",
total_charge=Decimal("100.00"),
rendering_provider_npi="1111111111",
service_date_from=date(2026, 6, 1))
remit = make_remit(payer_claim_control_number="SAME-PCN",
total_charge_amount=Decimal("100.00"),
rendering_provider_npi="1111111111",
service_date=date(2026, 6, 2))
batch = Batch(id="batch-1", kind="835", input_filename="x.835", parsed_at=date(2026, 6, 5))
db_session.add(batch)
db_session.flush()
remit.batch_id = batch.id
db_session.flush()
reconcile_run(db_session, batch.id)
db_session.flush() # autoflush=False on SessionLocal; force flush pending Match row
matches = list(db_session.execute(
select(Match).where(Match.remittance_id == remit.id)
).scalars().all())
assert len(matches) == 1
assert matches[0].strategy == "pcn-exact" # NOT "score-auto"
def test_reconcile_run_no_match_leaves_remit_unlinked(db_session, make_claim, make_remit):
"""No 2-of-3 match → no Match row, claim state unchanged."""
from decimal import Decimal
from datetime import date
from sqlalchemy import select
from cyclone.db import Batch, Match, ClaimState
from cyclone.reconcile import run as reconcile_run
claim = make_claim(patient_control_number="UNRELATED",
total_charge=Decimal("999.99"),
rendering_provider_npi="2222222222",
service_date_from=date(2026, 6, 1))
remit = make_remit(payer_claim_control_number="OTHER",
total_charge_amount=Decimal("100.00"),
rendering_provider_npi="1111111111",
service_date=date(2026, 6, 5))
batch = Batch(id="batch-1", kind="835", input_filename="x.835", parsed_at=date(2026, 6, 5))
db_session.add(batch)
db_session.flush()
remit.batch_id = batch.id
db_session.flush()
result = reconcile_run(db_session, batch.id)
assert result.matched == 0
matches = list(db_session.execute(
select(Match).where(Match.remittance_id == remit.id)
).scalars().all())
assert len(matches) == 0
db_session.refresh(claim)
assert claim.state == ClaimState.SUBMITTED # unchanged
db_session.refresh(remit)
assert remit.claim_id is None # unchanged