Skip to content

D4: exception inbox (dead-letter + webhook overlay + R1/R2 reconciliation) - #146

Merged
brownjuly2003-code merged 1 commit into
mainfrom
feat/d4-exception-inbox
Jul 4, 2026
Merged

D4: exception inbox (dead-letter + webhook overlay + R1/R2 reconciliation)#146
brownjuly2003-code merged 1 commit into
mainfrom
feat/d4-exception-inbox

Conversation

@brownjuly2003-code

Copy link
Copy Markdown
Owner

Summary

  • Implements D4 of plan_endgame_02_07_26.md: the exception inbox per docs/ops-surfaces-spec.md §4 — GET /v1/ops/exceptions, GET /v1/ops/exceptions/stats, POST /v1/ops/exceptions/{id}/acknowledge, POST /v1/ops/exceptions/{id}/resolve.
  • One triage feed over three sources: dead-letter events (native, read-only), dead webhook deliveries and R1 (journal_vs_store)/R2 (stuck_replay) reconciliation findings — the latter two backed by a new ops_exception_triage overlay table (control-plane state class 7, both the embedded DuckDB and PostgreSQL adapters).
  • Demo seed gets dead_letter_events store counterparts for the already-seeded evt-004/evt-009 journal rows, so the inbox is non-empty out of the box (I7).
  • manual_resolutions (§4.5) counts only operator acknowledge/resolve actions, not system auto-resolves.

Test plan

  • Unit: pytest tests/unit — 1620 passed
  • Integration: pytest tests/integration/ — 240 passed, 52 skipped (Docker-gated Kafka/Iceberg tests, unavailable on this Windows host — pre-existing, unrelated to this change)
  • ruff check / ruff format --check — clean
  • mypy src/ --ignore-missing-imports — clean
  • python scripts/export_openapi.py --check — clean after regeneration

🤖 Generated with Claude Code

…nciliation (D4)

GET /v1/ops/exceptions, GET /v1/ops/exceptions/stats, POST .../acknowledge,
POST .../resolve (ops-surfaces-spec.md §4): one triage feed aggregating
dead-letter events (native, read-only mirror of the existing store), dead
webhook deliveries and R1 journal_vs_store / R2 stuck_replay reconciliation
findings (both overlay-backed via the new ops_exception_triage table, control-
plane state class 7, both adapters).

- store.py: TriageState + ensure/list/upsert/auto-resolve/set-state/count
  port methods, plus dead-letter/webhook reads for the inbox and
  stuck_replay_threshold_seconds() (reuses AGENTFLOW_CONTROLPLANE_LEASE_SECONDS).
- embedded.py/postgres.py: ops_exception_triage schema + full method set;
  the resolved-row reopen decision runs in SQL (not Python) so DuckDB's
  naive-local timestamp coercion and PostgreSQL's TIMESTAMPTZ both compare
  consistently regardless of whether the caller's seen_at is aware or naive.
- reconciliation.py: pure R1 (serving store behind its journal stage) / R2
  (dead-letter stuck in replay_pending) checks, read-only over the
  QueryEngine/ControlPlaneStore ports (I10).
- duckdb_backend.py: dead_letter_events store counterparts for the two
  already-seeded evt-004/evt-009 journal rows, so the demo inbox is
  non-empty (I7) — control-plane state on the shared connection, seeded
  once regardless of SERVING_BACKEND.
- manual_resolutions (§4.5) counts only operator acknowledge/resolve
  actions, not system auto-resolves (AUTO_RESOLVE_NOTE sentinel).

Tests: 16 new unit cases for the store/overlay methods, a new
test_exceptions_inbox.py integration suite (demo pins I7, stable ids I5,
dl: 409 guard I6, R1/R2 detection, idempotent reads I10, auto-resolve,
ack/resolve lifecycle, manual_resolutions re-pin I9), plus a tenant-scoping
case in test_tenant_isolation.py (I8). Full unit 1620 passed, integration
240 passed/52 skipped (docker unavailable on this host, pre-existing),
ruff+mypy strict clean, openapi/agent-tools regenerated.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown

DORA Metrics

  • Window: last 30 days
  • Branch: main
  • Deployment frequency: 122 total / 28.47 per week
  • Lead time for changes: avg 0.43h / median 0.0h
  • Change failure rate: 77.05% (94/122)
  • MTTR: 0.29h across 2 incident(s)

@brownjuly2003-code
brownjuly2003-code merged commit 3e74489 into main Jul 4, 2026
23 checks passed
@brownjuly2003-code
brownjuly2003-code deleted the feat/d4-exception-inbox branch July 4, 2026 02:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants