fix: promote forwarded exchanges into the live replay index - #9
Merged
Conversation
JosiahBull
force-pushed
the
jo/fix-empty-file-dedup
branch
from
June 22, 2026 00:03
93bdc63 to
a28890d
Compare
The replay index was built once at `run()` from the snapshot file's initial contents and never updated. Starting from an empty (or partial) snapshot file, a freshly forwarded-and-recorded request never became a replayable snapshot, so a later identical request in the same run missed the index, was forwarded again, and recorded again — duplicating the entry instead of being served from the cache. `ReplaySource` is now interior-mutable (a `std::sync::RwLock` around the exchanges + index; critical sections are short and never `.await`), with an `insert()` that adds a freshly recorded `Response` exchange (errors are never replayed; first write wins, matching `build_index`). After a genuine upstream forward, the lifecycle promotes the recorded exchange into the index so the next identical request is a replay hit. Together with the skip-on-replay-hit fix this makes `Mode::Record` a true deduplicating cache (SPECIFICATION.md §8.3/§20.1) even within a single run that started from an empty file. Also updates custom_storage_via_per_upstream_snapshots to use distinct paths (three *identical* requests now correctly collapse to one record). Regression tests: record_mode_from_empty_file_dedupes_repeated_request record_mode_from_empty_file_still_records_new_request
JosiahBull
force-pushed
the
jo/fix-empty-file-dedup
branch
from
June 22, 2026 00:15
a28890d to
1e0597b
Compare
JosiahBull
marked this pull request as ready for review
June 22, 2026 02:55
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug
The replay index was built once at
run()from the snapshot file's initial contents and never updated. Starting from an empty (or partial) snapshot file, a freshly forwarded-and-recorded request never became a replayable snapshot, so a later identical request in the same run missed the index, was forwarded again, and recorded again — duplicating the entry instead of being served from the cache.Fix
ReplaySourceis now interior-mutable (astd::sync::RwLockaround the exchanges + index; critical sections are short and never.await), with aninsert()that adds a freshly recordedResponseexchange (errors are never replayed; first-write-wins, matchingbuild_index).custom_storage_via_per_upstream_snapshotsupdated to use distinct paths (three identical requests now correctly collapse to a single record).Together with the skip-on-replay-hit fix in the base PR, this makes
Mode::Recorda true deduplicating cache (SPECIFICATION.md§8.3/§20.1) even within a single run started from an empty file.