Skip to content

offload: the replay depth-gate bypass is justified per-message but keyed per-content, so a replay can splice at depth into uncompacted content #199

Description

@amiddavid

The mismatch

extract_llm's same-session replay bypasses the cache-tail depth gate — the lookup is at extract_llm.go:890 and the gate at :932 — and the bypass is justified in the block's own comment:

SAME-SESSION replay first. This session already sent these compacted bytes on an earlier turn, so the provider's cached prefix holds the COMPACTED form and replaying it is byte-identical — which is why it is safe at any depth, cached prefix included.

That justification is about this message. The lookup is keyed on content (extract.ContentKey), not on position. So the same content appearing at a different position also takes the bypass — and at a position that was never compacted, the provider holds the original, so splicing the compaction there changes bytes inside the cached prefix and forces a cache-write of the suffix. That is the cost the gate exists to prevent, at ~11.5x a cache read.

extract_llm_sweep's replay path has the same shape.

Why the window is narrow, and what widens it

Mostly self-limiting, which is why this is filed as a question rather than a defect:

  • The common case is not affected. The client re-sends the original transcript every turn (see collapse.go, failed_run.go, agentdiet.go — "the agent re-sends the original each turn"), so a message compacted last turn arrives unmarked again at the same position, and the replay re-derives the same bytes. The provider holds the compacted form there. Nothing flips. This is the case the bypass is for.
  • A genuinely new occurrence arrives in the tail. It is appended, so its index exceeds MaxCachedIdx, and TailOnly (components/component.go:414-419) already permits acting there — the bypass buys nothing. By the time that position is at depth it was compacted on its arrival turn.

So reaching "content at a position that is already at depth and was never compacted there" needs one of:

  1. the boundary moved — an agent self-compaction resets the cached-prefix boundary (compaction_resets counts these);
  2. the component did not act on the arrival turnllm_every_n_requests throttle, llm_max_per_request cap, below min_tokens, a model decline, or (after fix(store): give rewind payloads their own reserve, and refuse a removal whose original cannot be stored #188) a refused reserve slot;
  3. a different component wrote the record — see offload: extract_llm and extract_llm_sweep share the cg:res: namespace with no component tag, so a depth-gate bypass can rest on another component's decision #197; the reuse is content-addressed and cross-turn, so extract_llm can encounter an id the sweep ruled on at a position extract_llm never touched.

Evidence available, and what it does not show

Iteration 024 measured 364 extract_llm replays in arm B (0 fresh calls, 99.2% cache hit rate, 0 in arm A) — see docs/experiments/loca/iter024/results.md §2. That is the total replay count, not a count of fresh-position replays, and the run cannot separate them:

  • an argument that all 364 were fresh-position, on the grounds that the marker skip precedes the lookup so replays land on unmarked content, does not hold — unmarked is the normal steady state at every position on every turn, because the client re-sends originals;
  • cache_read_tokens, cache_write_tokens and fresh_input_tokens read 0 in every arm-seed of that build — unpopulated rather than measured — so the direct signal is missing.

So the size of the affected subpopulation is unknown, and could be zero. Filed to get it measured rather than argued.

What would settle it

Possible fixes, if it turns out to be non-empty

  1. Key the replay decision on (content, position) rather than content alone — most faithful to the justification, and it gives up cross-position reuse, which is much of what the channel buys.
  2. Record, per content id, the positions at which it has been sent compacted, and bypass the gate only for those. Preserves legitimate reuse; costs a small set per id.
  3. Let the bypass apply only when compaction_resets has not moved and the component acted on the arrival turn — cheap, and it targets routes 1 and 2 without touching the common case.

How it was found

Reviewing #188. Raised as the residual after the byte-flip concern in #197 was closed by execution — a cross-component replay writes byte-identical text to what the writing component would have written, so sharing is not the hazard; this positional mismatch is what remains, and it belongs to extract_llm's own replay independently of any sharing.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions