Strip the billing header wherever it appears, not just line 1 - #180
Merged
Conversation
Claude Code sends x-anthropic-billing-header as its own system block, so after extractSystemText joins the blocks it is never line 1 and the old first-line-only test never fired. The line fell through to splitStaticDynamic, which has no XML wrapper to key on, classified it static, and rendered it into the slab PNG. On CLI 2.1.220 the value was session-stable (11/11 captured bodies share cch=07295), so the PNG stayed byte-identical and nothing showed. 2.1.222 added cc_prev_req=<previous request id>, making the line per-turn by construction: the slab re-renders and the whole cached prefix is void on every request. Match the line wherever it appears, so it re-enters the system tail beside dynamicText/envMarkdown, outside the image.
teamchong
force-pushed
the
fix/billing-header-out-of-slab
branch
from
August 5, 2026 18:43
28be574 to
50b80fa
Compare
teamchong
added a commit
that referenced
this pull request
Aug 6, 2026
Cache-correctness release. The per-turn billing header no longer lands in the cached prefix (#180, #161), plus tag-scanning, history-collapse and supply-chain hardening. Relabel the stale 'Unreleased' heading to 0.11.0: its contents (#146, 08ec156) shipped in v0.11.0 and v0.11.1 without a changelog entry.
teamchong
added a commit
that referenced
this pull request
Aug 9, 2026
The #206 fix appended x-anthropic-billing-header after the final user message's cache markers. Cache-safe, but the block renders as user-attributed conversation text, so the line leaked into the transcript every turn. There is no body position that is both cache-safe and invisible: req.system precedes the last cache_control marker (#180/#161), and anything after the markers reads as the user's words. So the line now leaves the body entirely: transform exports info.billingLine and the proxy sets it as an actual HTTP header on the upstream request. Tests now assert the line appears nowhere in the outgoing body, from any source position, instead of pinning a body placement.
teamchong
added a commit
to SiNaPsEr0x/pxpipe
that referenced
this pull request
Aug 9, 2026
The CLI now emits per-request cch/cc_prev_req values in x-anthropic-billing-header. Re-emitting the line in system placed it before the last cache_control marker, so every turn produced a distinct cached prefix: 0 cache reads, full input price (teamchong#180). Re-emit it instead as the final un-cached block of the last user message, past all markers. Cached span is now byte-identical across turns.
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.
Fixes #177.
Claude Code 2.1.222 injects a per-turn header into the system text:
cc_prev_reqnames the previous request, so the line changes every turn. It has to be relocated out of the cached slab and re-appended as volatile tail text, which is whatstripBillingLineis for.The old matcher only tested the first line. The header is not always first, it lands after other system content depending on what else the CLI prepends. When it isn't first it stays in the slab, the rendered prefix differs by a few bytes every turn, and the prompt cache misses on essentially every request.
Before:
After:
The header then joins
sysTailalongside the other per-turn churn, and the slab goes back to being byte-identical across consecutive turns.Note this changes slab bytes, so it invalidates existing warm caches once on deploy.