9e16b8d9bd
Phase 4 of SP28 (Ack↔Claim Auto-Link). Refactors the per-AK2 helpers in cyclone.claim_acks to return ClaimAckLinkRow dataclasses instead of mutating the session directly — the orchestrator (the 999 / 277CA / TA1 handlers + the matching parse-* API endpoints) now persists each row via cycl_store.add_claim_ack so the publish-from-store contract owns the live-tail event emission. * handle_999 / handle_277ca / handle_ta1 — build batch envelope index outside the work session (SQLite + concurrent sessions causes 'database is locked'), call apply_X to get ClaimAckLinkRow dataclasses, snapshot the rows before committing the work session, then call cycl_store.add_claim_ack per row in fresh sessions. * /api/parse-999 / /api/parse-277ca / /api/parse-ta1 — mirror the handler chain with event_bus passed through so live-tail subscribers on the claim and ack sides see the new rows the moment they land. Adds a 'claim_ack_links_count' field to each ack response (spec §4). * lookup_claims_for_ack_set_response — now accepts either a callable OR a plain dict as batch_envelope_index (the store returns a dict; tests pass callables). * test_apply_claim_ack_links.py — 15 tests updated to assert on the dataclass shape and exercise the full helper→add_claim_ack cycle (so idempotency is verified at the store layer). * test_e2e_999_to_claim_drawer.py — 2 new tests covering the D10 two-pass join end-to-end via FastAPI TestClient (Pass 1 via ST02 + Pass 2 via PCN fallback).