Repository navigation
Pin the compaction summary at the request's cache lifetime - #381
Conversation
On a bot set to the hour-long Anthropic cache, the pinned compaction summary and carry-forward note kept a breakpoint with no lifetime, which the API reads as five minutes. Instructions (1h), then the summary (5m), then the request's own breakpoint (1h) breaks the rule that a longer lifetime may not follow a shorter one, so every call after a bot's first summary was refused with a 400. Every breakpoint in a request now takes one lifetime, as other harnesses compute one cache marker per request and use it everywhere. The turn picks it once: the bot's setting, unless the turn's model, its summarizer (which copies the turn's calls) or its fallback (which answers them) must keep five minutes, in which case they all do. The pinned blocks are rendered from the stored summary on every request, so a bot already stuck this way recovers on its next turn with no repair. The Anthropic test fixture now refuses misordered lifetimes as the API does; the new compaction tests fail without the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEPbASx5sbXvPAfKHw
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
The advisory I think it's timing or isolation in that test, not this change. The check gets a 5 s timeout on a shared runner. Also, Generated by Claude Code |
Requested by George · project thread
Daemon change (bug fix). On a bot set to the hour-long Anthropic cache (
cache_ttl = "1h", Sonny's default for Claude bots since #318), every call after the bot's first compaction was refused with a 400.Cause
The request's own breakpoints (instructions, and the top-level one) took
ttl: "1h", but the pinned compaction summary and carry-forward note kept{"type":"ephemeral"}, which the API reads as five minutes (src/store/context.rs). That makes 1h → 5m → 1h, and Anthropic refuses a longer lifetime after a shorter one ("a 1-hour cache entry must appear before any 5-minute cache entries").Fix
Every breakpoint in a request now takes the same lifetime, as pi computes one cache marker per request and uses it at every breakpoint (opencode never sets a TTL, so it never mixes them either).
codec::cache_control(hour)is the one marker; the provider's markers andpinned_itemboth use it.Provider::takes_cache_hourexposes that rule.Bots already stuck recover on their next turn. The pinned blocks are rendered from the stored summary on every request, so nothing on disk holds the bad marker. The one exception is a paced summary copy parked with its prefix: its retry fails once, is reported as
compaction_failed, and the turn goes on. Their next call also replays older thinking without it once, since the prefix bytes change.No retry on a
cache_control400: no harness we checked has one, the error would have to be matched by its text, and requests are now correct by construction.Tests
test_an_hour_long_cache_pins_the_summary_for_an_hour_too: a 1h bot compacts and keeps completing turns, and every pinned summary is marked 1h. It fails when the summary's marker is forced back to five minutes.test_a_bot_moved_to_an_hour_after_its_summary_keeps_working: compacts at 5m, moves to 1h, and the next turn completes with the summary at 1h.one_model_that_keeps_five_minutes_keeps_every_request_at_fiveandpinned_blocks_cache_only_with_their_provider_format(both lifetimes).cargo fmt --checkandcargo clippy --workspace --all-targets -D warningsare clean.Generated by Claude Code