Expand description
Replay time-travel debugging (DW-102): a PURE decision replayer.
The gateway’s request path (dataplane::proxy) weaves together route
matching, authorization, rate limiting, transforms, and endpoint
selection with live I/O (upstream dials, live GCRA counters, breaker
state). Replay inverts that: given a captured request and a
Snapshot (a compiled config generation), it re-runs the SAME
decision logic with NO side effects — no network, no live counters,
no breaker state — so an operator can ask “what would this recorded
request do under THIS config?” and diff the answer across two
generations.
§Sandbox isolation
decide is pure: it reads only its inputs (&Snapshot,
&ReplayRequest) and a caller-supplied SimulatedCounter for the
rate-limit simulation. It never touches the network, the filesystem,
the live rate limiter, or any shared mutable gateway state. The
rate-limit check uses a SIMULATED counter (not the live GCRA store),
the breaker is reported from config alone (no live failure counts),
and the endpoint pick is deterministic (the first healthy-by-config
endpoint, no live health tracking). This is the contract that makes
replay safe to run in CI and against candidate configs that have
never served traffic.
§Capture source
The request detail (method, path, redacted headers, auth identity)
is captured by the analytics raw table (DW-043, extended in DW-102
with optional request_headers_redacted and auth_identity
columns). The capture is opt-in and redacted via the existing PII
redaction patterns (ai::redaction); the replay CLI reads those
rows (or an exported recording) and feeds them to decide.
§Diffing
DecisionDiff compares two ReplayDecisions (the same request
under an old and a new snapshot) and reports which decision stages
changed — the unit the dwara replay CLI emits per request, and the
signal a CI gate exits non-zero on.
Structs§
- Decision
Diff - A per-stage diff between two
ReplayDecisions (the same request under an old and a new snapshot). Each field istruewhen that stage’s decision changed;DecisionDiff::anyis the CI-gate signal (exit 1 when any stage differs). - Replay
Decision - The outcome of one stage of the replayed decision path. Each stage reports what the LIVE proxy would have decided at that point, with no side effects applied.
- Replay
Request - One captured request fed to
decide. The fields mirror what the analytics raw table stores (DW-043 + DW-102): the request shape and the redacted auth identity. Headers are ALREADY redacted at capture time (the existing PII patterns); replay never sees raw secrets. - Simulated
Counter - A simulated rate-limit counter (DW-102). Replay does NOT touch the
live GCRA store; instead the caller threads a counter that tracks
per-key usage within a fixed window, and
decideadvances it the way the live limiter would. The simulation is deliberately simple (fixed-window, not GCRA): replay answers “would this request be admitted under this config’s budget?” not “what is the exact GCRA TAT?” — the decision boundary is what a diff cares about. - Transform
Summary - A summary of the transforms that would apply to a matched route (DW-028). Counts (not full op lists) keep the diff output stable across unrelated key-order changes while still surfacing a change in which transforms apply.
- Upstream
Pick - The upstream endpoint a matched proxy route would dispatch to. The pick is deterministic for replay (the first endpoint of the resolved upstream, or the first split target’s first endpoint) — replay has no live health state, so load-balancer selection is reported as the resolved upstream name plus its first endpoint.
Functions§
- decide
- The pure decision function (DW-102). Re-runs the gateway’s decision
path — route match, authz, simulated rate limit, transform
resolution, upstream pick — against
snapshotforrequest, with NO I/O and NO side effects on live gateway state. Therate_counteris the ONLY mutable state touched, and it is a simulated counter the caller owns (not the live limiter).