Files
cyclone/backend/tests
Nora a97f1d1350 feat(sp28): apply_claim_ack_links orchestrator + 999/277CA/TA1 helpers
The auto-linker closes the operator gap where every inbound 999 /
277CA / TA1 ack was persisted but never linked back to the claim it
acknowledges. Five pure helpers land in cyclone/claim_acks.py:

- lookup_claims_for_ack_set_response — D10 two-pass join. Primary is
  Batch.envelope.control_number (== source 837 ST02 for Gainwell
  batches); fallback is Claim.patient_control_number. Pass 1 wins,
  the two paths cannot both fire.
- apply_999_acceptances — walks parsed_999.set_responses, emits one
  ClaimAck per AK2 per matched claim (one-ack-to-many supported).
  Both accepted AND rejected AK2s link; per-AK2 granularity.
- apply_277ca_acks — same shape for parsed_277ca.claim_statuses.
  STC category code carried on the link row's
  set_accept_reject_code so the UI can render the lane inline
  without re-parsing raw_json.
- apply_ta1_envelope_link — envelope-level link. The link row has
  claim_id NULL + batch_id populated (the spec's batch-level TA1
  trace). Sender/receiver matching is delegated to a closure the
  caller supplies.
- link_manual — manually link an ack to a claim. Used by the new
  /api/acks/{kind}/{id}/match-claim endpoint. Idempotent.

All five helpers are pure (callers own the session); idempotent via
the partial unique index ux_claim_acks_dedup (helpers pre-check to
avoid IntegrityError log noise on re-ingest); flush-only (callers
commit).

14 of 15 named tests pass (the facade surface check belongs in
Phase 3 once store/claim_acks.py lands).

Steps 2.1/2.2/2.3/2.4/2.5 of the SP28 implementation plan.
2026-07-02 11:29:02 -06:00
..