Preflight — relationship to existing issues
I ran a 3-week forensic audit of my local transcripts (2026-06-26 → 07-17: 200 main-session files / 11,889 requests + 513 subagent transcripts / 25,971 requests) classifying every prompt-cache rebuild by what happened between the two requests. Several rebuild classes are already tracked, so this report files only the two classes I could not find issues for, plus one reliability observation — with corroborating numbers for the known ones rather than duplicates: #75142 (mid-session tool loading invalidates cache — confirmed, 82 front-load events / 4.3M tokens even when done as early as possible), #64901 (async subagent completion rebuilds warm cache — confirmed still live on 2.1.2xx: 10 events / 2.35M tokens, median ~230K, collapse to the ~17–25K tool-defs/first-message floor), #63930 (collapse to system+tools floor), #76606 (old system-reminder blocks rewritten in long sessions — Finding 1 below appears to be a named, deterministic trigger for exactly that class), #74318 (subagent 5-minute cache tier — corroborated from the child side: 13 events where the child's own >5-minute tool call, e.g. a remote test suite, expired the child's cache, 91K–554K per event, 3.6M total; survival in my data is binary: 0/256 losses under 300s gaps, 35% at 300–420s, 100% at 600s+), #74149 (TTL docs).
Finding 1 — the "task tools haven't been used recently" nudge, fired mid-tool-loop, mutates cached history
What's wrong?
When the task-reminder nudge (transcript attachment entry, type: "task_reminder") fires while the assistant is mid-tool-loop, the next request's cache_read_input_tokens collapses to the byte offset of the last human text message, and cache_creation rewrites everything after it. Everything is visible in the local transcript's usage fields.
Evidence from the window:
- 1,597 task_reminder firings total; the ones that fired between a tool_result and the next request of the same turn are the ones followed by rebuilds (22 of 24 rebuild-adjacent firings were mid-loop). Firings at ordinary turn boundaries are benign (tail-append).
- The collapse offset is byte-identical across consecutive occurrences. Worst case (a single-prompt scheduled session on 2026-07-10): three consecutive requests collapsed to exactly
cache_read=24,997 while rewriting 217K → 231K → 238K, within 90 seconds — ~650K tokens re-written, one full rebuild per nudge firing during an Edit loop. A second session (2026-07-16) shows the identical pattern at cache_read=26,366 with a 311K rewrite.
- The blast radius scales with how far back the last human text message is: in interactive sessions it is recent (small rebuild); in single-prompt autonomous/scheduled sessions it is the first message, so every firing is a near-total rebuild.
- Cost in my window: 1.77M excess cache-write tokens attributed directly, plus a ~1.8M residual family with the same collapse-to-last-human-turn signature at other turn-entry paths (queued-message delivery, return-from-away).
This looks like a deterministic trigger for the class reported in #76606 (old <system-reminder> blocks changing shape/position in long sessions): the injection appears to be anchored to the most recent human message rather than appended after the pending tool_result, so it edits a message deep inside the cached prefix.
What should happen
Reminder/nudge injections must be append-only relative to the cached prefix — attached to the newest message, never to an earlier one. (And arguably the nudge should be suppressed entirely during autonomous stretches with no human present to see it.)
Steps to reproduce
- Start a session with a single prompt that triggers a long autonomous tool loop (many Edit/Bash calls, no TaskCreate/TaskWrite usage so the nudge fires).
- Watch the session JSONL: when an
attachment entry with type: "task_reminder" lands between a tool_result and the next assistant request, compare that request's usage.cache_read_input_tokens with the previous request's cache_read + cache_creation.
- Observed:
cache_read collapses to the offset of the last human text message and cache_creation rewrites the rest; repeat firings collapse to the byte-identical offset.
Finding 2 — 29% of sessions double-write the opening context (two fully cold requests at session start)
What's wrong?
In 49 of 169 sessions, request #1 cold-writes the opening context (cache_read=0, e.g. cache_creation=66K) and request #2, issued seconds later, is also fully cold (cache_read=0, cache_creation=93K — a superset of request #1's content). The opening 60–90K is paid twice; 2.71M wasted cache-write tokens in my 3-week window. The rate is similar for CLI-local and web-bridged sessions (27/131 vs 22/69).
Likely either request #2 is issued before request #1's cache entry is reusable, or session-start initialization (SessionStart hook additionalContext, deferred-tool listing, skill listing) lands between the two requests and changes the prompt head so nothing before the first breakpoint matches.
What should happen
Request #2 should read request #1's write (or the harness should defer the first request until the head is settled). Expected loss at session start is one cold write, not two.
Steps to reproduce
Scan any transcript corpus: take the first two distinct requestIds per session file and count sessions where both have cache_read_input_tokens == 0 with cache_creation_input_tokens > 10K. My data: 49/169 sessions (29%).
Finding 3 (reliability observation) — total cache miss seconds after a healthy 300K+ hit
Roughly once a day under parallel-subagent load, a subagent request reads 300K+ from cache and the next request 6–11 seconds later gets cache_read=0 — not even the system prompt matches — rewrites the full prompt (up to 395K), and subsequent requests then hit normally. Context sizes are scattered (100K–395K), so it does not look like a threshold crossing (e.g. into a long-context pool); it looks like server-side eviction or routing on the 5-minute tier. 8 clean occurrences / ~2.1M tokens in the window. Mentioning it here since it surfaces in the same audit; happy to move it to a separate report if that's more useful.
Impact summary (one user, 3 weeks, subscription)
| Population |
Requests |
Cache writes |
Excess rewrite tokens |
| Main sessions (169) |
11,889 |
60.7M |
10.56M (17% of writes) |
| Subagents (513 transcripts) |
25,971 |
102.0M |
10.09M (10% of writes) |
| Session-start double cold write |
49 sessions |
— |
2.71M |
≈ 23.4M excess cache-write tokens in 3 weeks (~1.1M/day) — roughly $300 API-equivalent, i.e. material subscription quota burn. Overall caching is otherwise healthy (2.8B main-chain cache-read tokens vs 60.7M writes).
Method (reproducible from local transcripts)
Every assistant record in ~/.claude/projects/**/*.jsonl carries message.usage. Dedupe streamed chunks by requestId; a rebuild is cur.cache_read < prev.cache_read + prev.cache_creation − ε. One accounting note that matters: input_tokens is the uncached tail after the final cache breakpoint and was never written to cache — including it in the baseline (prev.cache_read + prev.cache_creation + prev.input) fabricates hundreds of phantom "tail rebuilds" (~18K each, matching the injected-reminder tail). Attribution comes from transcript entries between the two requests: attachment entries (incl. type: task_reminder), ToolSearch tool_use, queue-operation, compact boundaries, human turns, and file boundaries. I'm happy to share the analysis script and redacted per-event data.
Environment
- Claude Code 2.1.162 → 2.1.212 across the window (current: 2.1.212); macOS (darwin 25.5); CLI, plus a minority of web-bridged sessions (both affected)
- Subscription (Max); main loop on the 1h cache tier, subagents on the 5m tier
- Models: claude-fable-5 (main), claude-opus-4-8 (subagents); API provider: Anthropic
Preflight — relationship to existing issues
I ran a 3-week forensic audit of my local transcripts (2026-06-26 → 07-17: 200 main-session files / 11,889 requests + 513 subagent transcripts / 25,971 requests) classifying every prompt-cache rebuild by what happened between the two requests. Several rebuild classes are already tracked, so this report files only the two classes I could not find issues for, plus one reliability observation — with corroborating numbers for the known ones rather than duplicates: #75142 (mid-session tool loading invalidates cache — confirmed, 82 front-load events / 4.3M tokens even when done as early as possible), #64901 (async subagent completion rebuilds warm cache — confirmed still live on 2.1.2xx: 10 events / 2.35M tokens, median ~230K, collapse to the ~17–25K tool-defs/first-message floor), #63930 (collapse to system+tools floor), #76606 (old system-reminder blocks rewritten in long sessions — Finding 1 below appears to be a named, deterministic trigger for exactly that class), #74318 (subagent 5-minute cache tier — corroborated from the child side: 13 events where the child's own >5-minute tool call, e.g. a remote test suite, expired the child's cache, 91K–554K per event, 3.6M total; survival in my data is binary: 0/256 losses under 300s gaps, 35% at 300–420s, 100% at 600s+), #74149 (TTL docs).
Finding 1 — the "task tools haven't been used recently" nudge, fired mid-tool-loop, mutates cached history
What's wrong?
When the task-reminder nudge (transcript
attachmententry,type: "task_reminder") fires while the assistant is mid-tool-loop, the next request'scache_read_input_tokenscollapses to the byte offset of the last human text message, andcache_creationrewrites everything after it. Everything is visible in the local transcript'susagefields.Evidence from the window:
cache_read=24,997while rewriting 217K → 231K → 238K, within 90 seconds — ~650K tokens re-written, one full rebuild per nudge firing during an Edit loop. A second session (2026-07-16) shows the identical pattern atcache_read=26,366with a 311K rewrite.This looks like a deterministic trigger for the class reported in #76606 (old
<system-reminder>blocks changing shape/position in long sessions): the injection appears to be anchored to the most recent human message rather than appended after the pending tool_result, so it edits a message deep inside the cached prefix.What should happen
Reminder/nudge injections must be append-only relative to the cached prefix — attached to the newest message, never to an earlier one. (And arguably the nudge should be suppressed entirely during autonomous stretches with no human present to see it.)
Steps to reproduce
attachmententry withtype: "task_reminder"lands between a tool_result and the next assistant request, compare that request'susage.cache_read_input_tokenswith the previous request'scache_read + cache_creation.cache_readcollapses to the offset of the last human text message andcache_creationrewrites the rest; repeat firings collapse to the byte-identical offset.Finding 2 — 29% of sessions double-write the opening context (two fully cold requests at session start)
What's wrong?
In 49 of 169 sessions, request #1 cold-writes the opening context (
cache_read=0, e.g.cache_creation=66K) and request #2, issued seconds later, is also fully cold (cache_read=0,cache_creation=93K— a superset of request #1's content). The opening 60–90K is paid twice; 2.71M wasted cache-write tokens in my 3-week window. The rate is similar for CLI-local and web-bridged sessions (27/131 vs 22/69).Likely either request #2 is issued before request #1's cache entry is reusable, or session-start initialization (SessionStart hook additionalContext, deferred-tool listing, skill listing) lands between the two requests and changes the prompt head so nothing before the first breakpoint matches.
What should happen
Request #2 should read request #1's write (or the harness should defer the first request until the head is settled). Expected loss at session start is one cold write, not two.
Steps to reproduce
Scan any transcript corpus: take the first two distinct
requestIds per session file and count sessions where both havecache_read_input_tokens == 0withcache_creation_input_tokens > 10K. My data: 49/169 sessions (29%).Finding 3 (reliability observation) — total cache miss seconds after a healthy 300K+ hit
Roughly once a day under parallel-subagent load, a subagent request reads 300K+ from cache and the next request 6–11 seconds later gets
cache_read=0— not even the system prompt matches — rewrites the full prompt (up to 395K), and subsequent requests then hit normally. Context sizes are scattered (100K–395K), so it does not look like a threshold crossing (e.g. into a long-context pool); it looks like server-side eviction or routing on the 5-minute tier. 8 clean occurrences / ~2.1M tokens in the window. Mentioning it here since it surfaces in the same audit; happy to move it to a separate report if that's more useful.Impact summary (one user, 3 weeks, subscription)
≈ 23.4M excess cache-write tokens in 3 weeks (~1.1M/day) — roughly $300 API-equivalent, i.e. material subscription quota burn. Overall caching is otherwise healthy (2.8B main-chain cache-read tokens vs 60.7M writes).
Method (reproducible from local transcripts)
Every assistant record in
~/.claude/projects/**/*.jsonlcarriesmessage.usage. Dedupe streamed chunks byrequestId; a rebuild iscur.cache_read < prev.cache_read + prev.cache_creation − ε. One accounting note that matters:input_tokensis the uncached tail after the final cache breakpoint and was never written to cache — including it in the baseline (prev.cache_read + prev.cache_creation + prev.input) fabricates hundreds of phantom "tail rebuilds" (~18K each, matching the injected-reminder tail). Attribution comes from transcript entries between the two requests:attachmententries (incl.type: task_reminder),ToolSearchtool_use,queue-operation, compact boundaries, human turns, and file boundaries. I'm happy to share the analysis script and redacted per-event data.Environment