Skip to content

feat(server): opt-in IO capture for replay (--capture-io-path)#148

Merged
Pama-Lee merged 2 commits into
mainfrom
feat/server-capture-io
Jul 5, 2026
Merged

feat(server): opt-in IO capture for replay (--capture-io-path)#148
Pama-Lee merged 2 commits into
mainfrom
feat/server-capture-io

Conversation

@Pama-Lee

@Pama-Lee Pama-Lee commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

The production-traffic source for ordo replay (#147). ordo-server can now record each execution's full input + output to a JSONL file — the exact shape ordo replay consumes — turning production traffic into a replayable regression corpus.

What

  • --capture-io-path <dir> (ORDO_CAPTURE_IO_PATH) — enable capture; each execution appends a line to capture-YYYY-MM-DD.jsonl (daily rotation). --capture-io-sample-rate (ORDO_CAPTURE_IO_SAMPLE_RATE, default 100) bounds volume.
  • capture.rsCaptureLogger mirroring AuditLogger (Arc, Mutex<BufWriter>, atomic sample rate, sync flush). Record: {ts, rule_name, tenant, input, code, output, duration_us, source_ip}.
  • api.rs execute_rulesetshould_capture() is checked before the input clone, so a disabled or unsampled request never clones the Value on the hot path; the record is written in the success arm beside the existing audit call.
  • Threaded through AppState (+ the RPC-state + the 3 test constructions).
  • docs — en/zh "Traffic Capture & Replay" page (capture → replay → --write-tests loop, PII/sampling caveats) + sidebar.

Design / scope

  • Off by default; zero hot-path cost when off. Opt-in because captured inputs are full payloads that may contain PII (documented; sample-rate bounded).
  • v1 = HTTP single execute. Batch + gRPC capture are documented follow-ups — their service state (OrdoGrpcService, the batch per-item loop) doesn't carry the config/handle yet, so wiring them is a separate change.

Verified end-to-end

Ran the server with --capture-io-path, executed two rules over HTTP, confirmed two JSONL lines with full input/output/code, then ordo replay'd them against a local project — and watched a rule change (limit 10000 → 30000) flip a captured decision REJECTED → APPROVED. cargo test -p ordo-server green (175); clippy clean; docs build clean.

Part 2 of 2 — pairs with #147 (ordo replay).

ordo-server can now record each execution's full input + output to a JSONL file
— the exact shape 'ordo replay' consumes — turning production traffic into a
replayable regression corpus. Disabled by default; when off, no input is ever
cloned on the hot path.

- config: --capture-io-path (ORDO_CAPTURE_IO_PATH) + --capture-io-sample-rate
  (ORDO_CAPTURE_IO_SAMPLE_RATE, default 100)
- capture.rs: CaptureLogger mirroring AuditLogger (Arc, daily-rotated
  capture-YYYY-MM-DD.jsonl, atomic sample rate, sync flush); should_capture()
  is checked BEFORE the input clone so a disabled/unsampled request pays nothing
- api.rs execute_ruleset: snapshot input only when should_capture(); write the
  {ts, rule_name, tenant, input, code, output, duration_us, source_ip} record in
  the success arm beside the existing audit call
- threaded through AppState (+ the RPC-state + test constructions)
- docs: en/zh 'Traffic Capture & Replay' page (the capture -> replay ->
  write-tests loop, PII/sampling caveats) + sidebar

Scope v1: HTTP single execute. Batch + gRPC capture are documented follow-ups
(their service state doesn't carry the config/handles yet). Verified end-to-end:
ran the server with --capture-io-path, executed two rules, confirmed the JSONL
lines, replayed them locally, and saw a rule change flip a captured decision.
@vercel

vercel Bot commented Jul 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ordo_docs Ready Ready Preview, Comment Jul 5, 2026 11:31am
ordo-app Error Error Jul 5, 2026 11:31am

An isolated, reproducible perf harness for CaptureLogger (excluded from CI via
#[ignore]). Measures single-threaded per-call cost and the multi-threaded
throughput ceiling of the write path, for small and ~4KB payloads. Confirms the
mutex only guards the write (serialization happens outside the lock), so capture
throughput scales with cores rather than serializing on the lock.

Run: cargo test -p ordo-server --bin ordo-server capture_throughput -- --ignored --nocapture
@Pama-Lee Pama-Lee merged commit bba8e5e into main Jul 5, 2026
14 of 16 checks passed
@Pama-Lee Pama-Lee deleted the feat/server-capture-io branch July 6, 2026 09:53
Pama-Lee added a commit that referenced this pull request Jul 6, 2026
* feat(server): opt-in IO capture for replay (--capture-io-path)

ordo-server can now record each execution's full input + output to a JSONL file
— the exact shape 'ordo replay' consumes — turning production traffic into a
replayable regression corpus. Disabled by default; when off, no input is ever
cloned on the hot path.

- config: --capture-io-path (ORDO_CAPTURE_IO_PATH) + --capture-io-sample-rate
  (ORDO_CAPTURE_IO_SAMPLE_RATE, default 100)
- capture.rs: CaptureLogger mirroring AuditLogger (Arc, daily-rotated
  capture-YYYY-MM-DD.jsonl, atomic sample rate, sync flush); should_capture()
  is checked BEFORE the input clone so a disabled/unsampled request pays nothing
- api.rs execute_ruleset: snapshot input only when should_capture(); write the
  {ts, rule_name, tenant, input, code, output, duration_us, source_ip} record in
  the success arm beside the existing audit call
- threaded through AppState (+ the RPC-state + test constructions)
- docs: en/zh 'Traffic Capture & Replay' page (the capture -> replay ->
  write-tests loop, PII/sampling caveats) + sidebar

Scope v1: HTTP single execute. Batch + gRPC capture are documented follow-ups
(their service state doesn't carry the config/handles yet). Verified end-to-end:
ran the server with --capture-io-path, executed two rules, confirmed the JSONL
lines, replayed them locally, and saw a rule change flip a captured decision.

* test(server): add ignored capture throughput micro-benchmark

An isolated, reproducible perf harness for CaptureLogger (excluded from CI via
#[ignore]). Measures single-threaded per-call cost and the multi-threaded
throughput ceiling of the write path, for small and ~4KB payloads. Confirms the
mutex only guards the write (serialization happens outside the lock), so capture
throughput scales with cores rather than serializing on the lock.

Run: cargo test -p ordo-server --bin ordo-server capture_throughput -- --ignored --nocapture
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.

1 participant