Plan: Complete Inbox Consumer Implementation (Spec-First)

Implement the inbox consumer by fixing specs and generators first, then regenerating/rewiring runtime code. Any file derived from manifests is generated and must be fixed upstream (specs/IR/generators) rather than patched directly.

Steps

  1. Update specs (ADR/PRD/SDS/SEA) — Extend PRD-022 and SDS-047 to cover the inbox schema fields, handler envelope contract, DLQ replay policy, and handler registry generation. Add/extend SEA model for messaging flows with required @cqrs tags. Regenerate manifests and code where applicable.

  2. Fix inbox schema with migration — Add apps/sea-mq-worker/migrations/002_inbox_messages.sql with inbox fields per SDS-047: message_id, subject, event_type, event_version, received_at, processed_at, correlation_id, causation_id, aggregate_type, aggregate_id, attempts, last_error, is_dlq, dlq_at, dlq_metadata. Update inbox_consumer.rs to extract message_id from Nats-Msg-Id (fallback to Message-Id), not random UUID, to satisfy INV-021.

  3. Generate static handler registry from manifests with sequential ports — Create tools/generate_handler_registry.py that reads all docs/specs/*/*.manifest.json, sorts contexts alphabetically, assigns sequential ports (8080, 8081, 8082, …), extracts model.events, and generates apps/sea-mq-worker/src/generated/handler_registry.rs with HashMap<event_type, handler_url> using pattern http://localhost:{port}/api/events/{event_type_kebab}. Wire the generator into build docs and ensure the worker uses the generated registry (static, no hot-reload).

  4. Complete DLQ with automated exponential backoff and jitter — Add SEA_DLQ and VIBESPRO_DLQ streams in infra/nats/streams.yaml with subjects {context}.dlq.> (30-day retention). Update move_to_dlq() to (1) publish to {context}.dlq.{event_type}.v{version} and (2) update inbox row is_dlq=true, dlq_at=NOW(), dlq_metadata={"replay_attempts": 0, "next_retry": "..."}. Create apps/sea-mq-worker/src/dlq_replayer.rs with pull consumer that re-publishes to the original subject after exponential delays (30s, 5m, 30m, 2h, 12h, 24h max) with ±20% jitter, updating dlq_metadata.replay_attempts and stopping after a max attempt cap.

  5. Enforce handler contract per SDS-047 — Update dispatch_to_handler() to send the full envelope body: {"message_id": "...", "subject": "...", "event_type": "...", "event_version": 1, "occurred_at": "...", "correlation_id": "...", "causation_id": "...", "aggregate_type": "...", "aggregate_id": "...", "payload": {...}}. Replace header-based metadata with body fields. Add structured tracing spans for correlation tracking. Update ACK logic: 200/409→mark_processed+ACK, 422→move_to_dlq+ACK, 5xx/timeout→NAK.

  6. Add observability and backlog queries — Create apps/sea-mq-worker/src/metrics.rs exposing HTTP endpoints: GET /metrics/outbox, GET /metrics/inbox, GET /metrics/dlq. Register Prometheus metrics: outbox_published_total, inbox_processed_total, inbox_dlq_total, inbox_dlq_replay_total, handler_latency_seconds histogram. Use metrics/logs for EVT-047-001/002 rather than inserting into outbox.

  7. Integration example + tests + docs — Add a minimal handler example in an existing FastAPI service using the SDS-047 envelope, add an E2E test in apps/sea-mq-worker/tests/, and document the registry regeneration workflow in apps/sea-mq-worker/README.md.