Skip to content

fix: do not re-record requests served from the replay snapshot - #8

Merged
JosiahBull merged 3 commits into
mainfrom
jo/fix-rerecord-replay-hits
Jun 22, 2026
Merged

fix: do not re-record requests served from the replay snapshot#8
JosiahBull merged 3 commits into
mainfrom
jo/fix-rerecord-replay-hits

Conversation

@JosiahBull

Copy link
Copy Markdown
Collaborator

Bug

In Mode::Record, the request lifecycle recorded every served exchange unconditionally — including responses served from the replay snapshot. Since each upstream's storage backend is both the replay source and the recording sink, replaying an already-recorded request appended a duplicate on every hit, so re-runs (and any request already present in the snapshot) multiplied records for existing requests.

This contradicts SPECIFICATION.md §8.3/§20.1, which require the snapshot to act as a deduplicating cache: an already-seen request is replayed "rather than re-recording it".

Fix

  • Thread the terminal's ResponseSource into the recording decision and skip recording when the response came from the replay snapshot (ResponseSource::Snapshot). Stub and forwarded responses are unaffected.
  • Reconcile the §6 spec wording ("every served exchange is appended back"), which contradicted the §8.3/§20.1 dedup rule.
  • Update the replay test that previously asserted the old (buggy) behaviour.

Test

New regression test record_mode_does_not_re_record_request_already_in_snapshot: a request pre-seeded into the snapshot is served from it (proved via an unreachable upstream — a forward would 502) and the file stays at one line instead of growing to two. Full lib suite + clippy + rustfmt clean.

Note

This is part 1 of 2. The empty-file / within-run duplication (jo/fix-empty-file-dedup) builds on this branch — fully resolving that symptom needs both the skip-on-hit logic here and index promotion there.

In `Mode::Record`, the request lifecycle recorded every served exchange
unconditionally — including responses served from the replay snapshot.
Because the per-upstream storage backend is both the replay source and
the recording sink, replaying an already-recorded request appended a
duplicate entry on every hit, so re-runs multiplied records for requests
already in the file.

`SPECIFICATION.md` §8.3/§20.1 require the snapshot to act as a
deduplicating cache: an already-seen request is replayed "rather than
re-recording it". This threads the terminal's `ResponseSource` into the
recording decision and skips recording when the response came from the
replay snapshot (`ResponseSource::Snapshot`). Stub and forwarded
responses are unaffected.

Also reconciles the §6 wording that said "every served exchange is
appended back", which contradicted the §8.3/§20.1 dedup rule, and
updates the replay test that encoded the old behaviour.

Regression test: record_mode_does_not_re_record_request_already_in_snapshot
Comment thread crates/partly-proxy-lib/tests/record.rs Outdated
Comment thread crates/partly-proxy-lib/tests/record.rs Outdated
Comment thread crates/partly-proxy-lib/tests/record.rs Outdated
Comment thread crates/partly-proxy-lib/tests/record.rs Outdated
@JosiahBull
JosiahBull marked this pull request as ready for review June 21, 2026 23:29
- Move ndjson_line_count / seed_snapshot / unreachable_addr into a shared
  tests/common/mod.rs so they can be reused across integration test files.
- ndjson_line_count now streams line-by-line instead of reading the whole
  file, so it stays cheap on large snapshot files.
- Reuse unreachable_addr in unreachable_upstream_records_error_outcome.
- Drop the low-value banner comment and the doc-comment lead-in.
@JosiahBull
JosiahBull marked this pull request as draft June 22, 2026 00:04
spawn_echo, http_client and cfg(url) were copy-pasted across nearly every
integration test file; unreachable_addr existed in two forms. Move the
shared versions into tests/common/mod.rs and have each test binary import
them, dropping the local copies (and now-unused imports).

- spawn_echo / http_client: identical across assertions, control_plane_tcp,
  forward, middleware, record, replay, stubs.
- cfg(url): identical across assertions, replay, stubs; middleware's
  byte-identical `upstream_cfg` folded into it; forward::spawn_proxy now
  uses it too.
- unreachable_addr: unified on the sync form; forward's inline block and
  record's two call sites now use it.

File-specific helpers (rt, make_recorded, in_memory_store, TrackingStorage,
shutdown/tls fixtures) are left in place. No behaviour change.
@JosiahBull
JosiahBull marked this pull request as ready for review June 22, 2026 00:18
@JosiahBull
JosiahBull merged commit 6017da4 into main Jun 22, 2026
3 checks passed
@JosiahBull
JosiahBull deleted the jo/fix-rerecord-replay-hits branch June 22, 2026 00:18
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