Transactional idempotency claims — inbox + HTTP ingress
## Summary Reliability redesign of both idempotency ingress boundaries (child of &74): the MQ inbox becomes a **single-transaction savepoint-accounted attempt machine** (claim + handler effects + completion commit together; hard cap over counted attempts; mandatory deterministic DLX; collision ledger) and HTTP mutations get **in-domain-transaction claims** (`request_claims` + per-endpoint IntentV1; the unused lease-based middleware is deleted, not fenced). Uploads/exports move to a generation-fenced, digest-verified attempt state machine (§U); the 27 audited stale-replay-hazard routes are fixed in-program (§G). Doctrine: atomic effects + bounded-horizon dedup + convergent external effects — ADR-062. Plan (authoritative, with the full per-route ledger): [transactional-idempotency-claims](https://gadhs.gitlab.io/application/ccwis/craig/craig/plans/transactional-idempotency-claims.html) *(lands with U0 — #1239)*. Anchors #1178 (Track A) / #1182 (Track B) ride `Relates to` on unit MRs and close manually at track completion. #1053 is repurposed as A1's issue; #1194 as B2's; #1209 closes with A1. ## Children ### Phase 0 — docs first - [x] #1239 docs: ADR-062 transactional idempotency claims + program plan page (weight: 3) ### Track A — transactional inbox (stop-then-start deploys) - [x] #1053 fix(mq): subscriber dead-letters on 2nd delivery - inbox 5-retry/backoff path unreachable, failed_at never stamped (weight: 8) - [x] #1240 fix(placement,exchange): convert inbox handlers to the transactional substrate (weight: 3) - [x] #1241 fix(security): convert inbox handlers — audit + ledger writes atomic (weight: 3) - [x] #1242 fix(financial): convert inbox handlers — money path on the substrate tx (weight: 5) - [x] #1243 fix(rules): thread the substrate tx through engine evaluate audit (weight: 3) - [x] #1244 fix(reporting): one tx per envelope + delete the legacy inbox API (weight: 3) ### Track B core — claims substrate - [x] #1245 feat(api): request_claims module + IntentV1 envelope + migrations x8 (weight: 5) - [x] #1246 test(api): claims battery — proptests, collect-all helper, synthetic endpoint (weight: 5) - [x] #1194 fix(api): idempotency claim 500s in the expired-but-not-cleaned window (weight: 5) ### §U — generation-fenced upload/export attempts - [x] #1247 feat(store): upload_attempts state machine + reconciler (weight: 8) - [x] #1248 feat: upload_attempts migrations x4 + target columns (weight: 2) - [x] #1249 fix(cases): attachments + court-order document on generation-fenced attempts (weight: 5) - [x] #1250 fix(exchange): icpc attachments on attempts (weight: 3) - [x] #1251 fix(placement): home documents reserve-first + first reconciler worker (weight: 3) - [x] #1252 fix(reporting): deterministic exports on attempts (weight: 3) - [x] #1253 test(store): upload-attempt race matrix (weight: 5) - [x] #1254 chore(store): retire AttachmentScanner entity targets (weight: 2) ### Conversion slices - [x] #1255 feat(cases): claims — persons/referrals/allegations/investigations/safety (weight: 5) - [x] #1256 feat(cases): claims — case/household/plans/tasks/contacts/court-orders (weight: 5) - [x] #1257 feat(cases): claims — reports family + create_report intent hash (weight: 5) - [x] #1258 feat(intake): client-held request id protocol + SDK submit fields (weight: 5) - [x] #1259 feat(placement): claims — six creates (weight: 3) - [x] #1260 feat(exchange): claims — five converts + home-study UNIQUE (weight: 5) - [x] #1261 feat(security): claims — six creates + app-minted id refactor (weight: 5) - [x] #1262 feat(security): one-time-secret pair columns for issue/rotate key (weight: 3) - [x] #1263 feat(financial): claims — four creates + sweep-preview claim (weight: 3) - [x] #1264 feat(reporting): claims — AFCARS/NCANDS generates (weight: 2) - [x] #1265 feat(rules): claims — rule-set create + import wrapper (weight: 3) ### §G — replay-guard hardening - [x] #1266 fix(cases): replay guards — SSN lifecycle + update CAS/IDF/SUP sweep (weight: 5) - [x] #1267 fix(placement,exchange): replay guards — license CAS, partner resurrection, approved_at FWW (weight: 3) - [x] #1268 fix(security,reporting,rules,financial): replay guards — status CAS + gated events (weight: 5) - [x] #1269 fix(cases): convert_report auto-link resumable via outbox consumer (weight: 3) ### Close-out - [x] #1270 chore: drop idempotency_responses x8 + program close-out gates (weight: 2) - [x] #1271 docs: program aggregation — CLAUDE.md, scorecard, known-issues (weight: 2) --- ## Completion record (2026-08-02) All **35 units delivered and merged** (!1122–!1159 + UF !1160); both anchors closed with track-completion comments (#1178 Track A — the craig-mq single-transaction attempt machine + fleet conversion; #1182 Track B — request_claims/IntentV1, all 40 convert-class routes, §U generation-fenced attempts, §G guard hardening, BF drop ×8). ADR-062 **Accepted**; plan archived (`docs/modules/ROOT/pages/plans/archive/transactional-idempotency-claims.adoc`). Honest per-class guarantees: ADR-062 §H. Final battery: 5319 tests green on the BF push — the entire suite running against post-drop databases. Follow-ups (open, outside this epic): #1272 (typed rejection mapper), #1273 (`payload_hash` NOT NULL post-horizon), #1274 (orphan-blob janitor). **Plan Completion Audit (2026-08-02)**: 8/8 items PASS, zero defects (fresh-context auditor, 2026-08-02, repo HEAD + GitLab API): the archived plan's 35-row Status table is uniformly `Done`; 16 unit issues spot-checked plus both anchors closed with track-completion comments (the #1182 comment carries its own 30-not-27 hazard-count correction note); 35/35 epic checkboxes ticked; docs consistent (nav clean of the pre-archive path, ADR-062 Accepted in both nav and §Status, CHANGELOG #1270 Removed entry present); zero `feature/1178-*`/`feature/1182-*` branches locally or on origin; follow-ups #1272/#1273/#1274/#1304 open; `idempotency_responses` survives only in historical migrations and documentation.
epic