2eeb16a240
Completes async event coupling infrastructure for downstream consumers: Migrations: 1. 0009_CreateInboxTable.sql - Deduplication: UNIQUE (outbox_id, consumer_id) - Status: Pending, Processed, Failed - Idempotent processing (each consumer once per event) - Constraint: If status=Processed, processed_at must be set - Indexes: status, created_at, consumer_id 2. 0010_CreateApprovalQueueTable.sql - Workflow: Pending → Approved/Rejected - References: run_id (FK shadow_run), model_id - Audit: requested_at, approved_at, rejected_at - Triggers: Enforce timestamp/reason consistency - Indexes: status, model_id, requested_at Design Principles: ✅ Append-only: Records immutable (status transitions, not updates) ✅ PIT Safety: All records timestamped, no forward lookups ✅ Data Integrity: Check constraints enforce workflow rules ✅ Idempotency: UNIQUE constraint prevents duplicate processing ✅ Traceability: Full audit trail (requested_by, approved_by, timestamps) Workflow: ShadowRunJob ├─ Phase 6: Emit ShadowRunCompletedEvent to Outbox └─ Hangfire OutboxPoller (30s) ├─ Inbox fanout (INSERT inbox for each consumer) └─ InboxConsumers (fanout) └─ ApprovalQueueConsumer ├─ If AllGatesPassed: INSERT approval_queue (status='Pending') └─ Notify: approval_queue subscribers Ready for: 1. ShadowRunJob event emission (Phase 6) 2. OutboxPollerJob + InboxProcessorJob Hangfire integration 3. Human approval workflow (Maker-Checker) Test Status: 84/84 PASSING (no changes to app code) AGENTS.md v16.0: ✅ Safety: Constraints enforce workflow invariants ✅ Audit: Complete audit trail (timestamps, user IDs) ✅ Simplicity: Clear schema, obvious workflow Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>