Commit Graph

2 Commits

Author SHA1 Message Date
Nora fba594baf4 fix(sp28): align Batch.kind filter with prod ('837p' not '837')
The SP28 helpers (batch_envelope_index + lookup_claims_for_ack_set_response
+ two _batch_lookup closures in handle_ta1 + api.py) all filter
Batch.kind == "837", but prod Batch rows are persisted with
kind="837p" (lowercase p — see api.py:443 / store/records.py:58).
Result: the D10 batch-envelope index was empty on prod and zero 999 /
277CA / TA1 acks auto-linked to their claims via Pass 1 (ST02 via
batch.envelope.control_number). Pass 2 (PCN) was the only path firing,
which on this codebase matches 0 acks (Gainwell's 999 echoes the 837's
ST02, not its CLM01 — see spec §D10).

Fix: 4 production sites swapped to Batch.kind == "837p". 3 test
files updated to use the prod value (test_apply_claim_ack_links.py +
test_api_claim_acks.py + test_e2e_999_to_claim_drawer.py). All 25 SP28
tests + 20 handler tests pass. Expected prod effect: claim
t991102989o1c120d's 143 incoming 999 AK2 acks now auto-link via the
batch with envelope.control_number=991102989 (Pass 1), plus 727/1,398
total acks across all batches.
2026-07-02 12:22:29 -06:00
Nora 21a5485faa feat(sp28): api_routers/claim_acks (7 endpoints) + claim_acks surface on claims/acks
Phase 5 of SP28 (Ack↔Claim Auto-Link). Adds the public HTTP
surface for the claim_acks join table and wires it into the
existing claims + acks list endpoints.

New router (registered with matrix_gate auth, any-logged-in-user):

* GET    /api/claims/{id}/acks           — per-claim links
* GET    /api/claims/{id}/acks/stream    — NDJSON live-tail
* GET    /api/acks/{kind}/{id}/claims    — per-ack links
* GET    /api/acks/{kind}/{id}/claims/stream — NDJSON live-tail
* POST   /api/acks/{kind}/{id}/match-claim   — manual link (D5)
* DELETE /api/acks/{kind}/{id}/match-claim/{claim_id} — unlink
* GET    /api/inbox/ack-orphans          — orphan reconciliation

Manual match is any-logged-in-user (D5/D9), idempotent on the
(claim_id, ack_kind, ack_id) dedup key, rejects with 409 when the
claim is in a terminal state (REVERSED), and publishes
claim_ack_written / claim_ack_dropped on the bus so live-tail
subscribers refresh.

Existing list endpoints extended:
* /api/acks           — each item gains linked_claim_ids
* /api/ta1-acks       — each item gains linked_claim_ids
* /api/277ca-acks     — each item gains linked_claim_ids
* /api/claims/{id}    — body gains ack_links (compact form)

All three list extensions use a single batched SELECT against
claim_acks to avoid N+1.

Tests:
* tests/test_api_claim_acks.py — 8 tests covering all 7
  endpoints + the spec §6 named tests for the extended
  surfaces (claim_detail_includes_ack_links,
  acks_list_includes_linked_claim_ids,
  claim_acks_stream_emits_claim_ack_written). The stream test
  uses the established direct-endpoint-invocation pattern
  from test_api_stream_live.py so it gets true byte-streaming
  + clean async cancellation.
2026-07-02 11:55:15 -06:00