feat(canopy-mq): durable consumer-side inbox + DLQ + replay endpoint
External review (2026-05-09) flagged that canopy has the producer half of the durable-events story (event_outbox per ADR-018, #388 (closed)) but lacks the consumer half. CRAIG has the matching pieces:
crates/craig-mq/src/inbox.rs— durable inbox table with idempotent-event recordingcrates/craig-mq/src/subscriber.rs:250— retry/backoff + DLQ wiringcrates/craig-api/src/admin_replay.rs— admin endpoint for replaying DLQ'd events
Scope
- Per-subscriber
event_inboxtable (event_id PK, payload, processed_at, attempts, last_error). Inserted in the same transaction as the consumer's domain write so events are processed exactly-once at the database level. - Subscriber retry policy: exponential backoff up to N attempts before DLQ.
- Dead-letter queue (separate RabbitMQ exchange + per-service queue).
POST /v1/admin/events/replayendpoint per consumer service to re-process DLQ'd events after operator triage.
Refs
External review (2026-05-09 IdP/architecture audit). Companion to #388 (closed) (outbox).