Skip to content

fix(ops): bound the stuck-orders and exception-inbox reads, report truncation (S-8) - #217

Merged
brownjuly2003-code merged 2 commits into
mainfrom
fix/s8-bounded-ops-reads
Jul 20, 2026
Merged

fix(ops): bound the stuck-orders and exception-inbox reads, report truncation (S-8)#217
brownjuly2003-code merged 2 commits into
mainfrom
fix/s8-bounded-ops-reads

Conversation

@brownjuly2003-code

Copy link
Copy Markdown
Owner

Closes security pre-audit S-8 (P3, unbounded reads): fetch_orders_by_status had no LIMIT and the exception inbox materialised every dead-letter row and dead webhook delivery in memory on a worker thread.

Semantics (per product decision): honest pagination, never a silent cut.

  • fetch_orders_by_status now requires a row cap (SQL LIMIT, deterministic ORDER BY primary key). The inbox's two store reads (list_dead_letter_events_for_inbox, list_dead_webhook_deliveries) accept an optional cap in both adapters (DuckDB + PostgreSQL), newest-N.
  • Every capped caller probes with cap+1 and reports scan_truncated in the response — /v1/ops/stuck-orders, /v1/ops/exceptions, /v1/ops/exceptions/stats (additive optional fields; OpenAPI snapshot regenerated).
  • Caps are env-tunable size safety nets in the journal_scan_limit mould: AGENTFLOW_OPS_ORDERS_SCAN_LIMIT, AGENTFLOW_OPS_INBOX_SCAN_LIMIT (default 20 000 — demo scale never gets near them).

Correctness guards under truncation:

  • A truncated webhook scan skips auto_resolve_missing_triage_findings: an incomplete seen-set cannot prove absence, and a wrongly resolved row whose updated_at never advances could not be reopened by the upsert.
  • R1 journal-vs-store keeps a false-negative-only failure mode: an order outside the bounded window falls into the existing "missing from the store — tolerated" branch, never a phantom finding.

Tests: engine LIMIT+determinism unit tests; newest-N store tests for both reads; integration tests pinning the truncation flag on all three surfaces and the auto-resolve guard. Locally: full unit suite 2026 passed, contract suite 17 passed (incl. live-vs-snapshot), ruff clean, bandit ratchet untouched (the reads stay parameterized/int-rendered — no new nosec).

🤖 Generated with Claude Code

…uncation (S-8)

fetch_orders_by_status now requires a row cap (SQL LIMIT, deterministic
ORDER BY primary key) and the exception inbox's two store reads
(dead-letter rows, dead webhook deliveries) accept one — before, a
large tenant's worklist read materialised its entire open-orders set
and every dead row in memory on a worker thread (security pre-audit
S-8).

Per product decision the bound is honest pagination, not a silent cut:
every capped caller probes with cap+1 and reports 'scan_truncated' in
the response (stuck-orders, exceptions list, exceptions stats) when the
window overflowed. Caps are env-tunable size safety nets in the
journal_scan_limit mould: AGENTFLOW_OPS_ORDERS_SCAN_LIMIT and
AGENTFLOW_OPS_INBOX_SCAN_LIMIT, both defaulting to 20000 — demo scale
never gets near them.

Two correctness guards that fall out of truncation:
- a truncated webhook scan skips auto_resolve_missing_triage_findings —
  an incomplete seen-set cannot prove absence, and a wrongly resolved
  row whose updated_at never advances could not be reopened by upsert;
- R1 journal-vs-store keeps its false-negative-only failure mode: an
  order outside the bounded window falls into the existing 'missing
  from the store - tolerated' branch, never a phantom finding.

OpenAPI snapshot regenerated (three additive optional fields). Tests:
engine LIMIT + determinism unit tests, newest-N store tests for both
reads, and integration tests pinning the truncation flag on all three
surfaces plus the auto-resolve guard.

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

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown

DORA Metrics

  • Window: last 30 days
  • Branch: main
  • Deployment frequency: 113 total / 26.37 per week
  • Lead time for changes: avg 0.61h / median 0.0h
  • Change failure rate: 77.88% (88/113)
  • MTTR: 20.13h across 5 incident(s)

@brownjuly2003-code
brownjuly2003-code merged commit c99eff1 into main Jul 20, 2026
27 checks passed
@brownjuly2003-code
brownjuly2003-code deleted the fix/s8-bounded-ops-reads branch July 20, 2026 14:50
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