The question
Anthropic's prompt caching distinguishes cache creation from cache reads, and the API prices them
differently. Subscription plans expose a five hour session meter as an integer percentage rather
than a dollar figure, and no published document states how heavily a cached read is weighted
against that meter. Three hypotheses were pre-declared, expressed as r, the weight of a read
token relative to a creation token:
| Hypothesis | r | Predicted read-arm meter movement |
|---|---|---|
| Excluded, the way a throughput limiter excludes reads | 0.0 | 0.50 pp |
| Weighted as API dollar billing discounts reads | 0.1 | 7.02 pp |
| Weighted at full input weight | 1.0 | 56.84 pp |
Observed read-arm movement was 1 pp, which is consistent with the first and refutes the other two.
Design
Two serial arms in a single five hour window on one subscription account, back to back, same model and reasoning effort throughout, run with an empty tool configuration so per-request overhead stayed fixed and lean.
Shared payload. 300,000 bytes, built deterministically from a sorted concatenation of markdown documents and then truncated to an exact byte count, reused byte for byte across every request in both arms. Measured token density on this corpus was 2.46 bytes per token.
Sizing deviation, recorded. The original brief specified roughly 600 KB. At the measured density that would have been about 244,000 tokens, pushing total input past the 200,000 band and risking a long context pricing regime as a confound. The 300 KB half was used instead, giving 182,350 total input tokens per write-arm request, comfortably inside the standard band.
Write arm. 18 independent single-turn sessions, each with a unique random nonce prefixed to the payload so no cache hit was possible across sessions. Per request: roughly 163,944 creation, 18,404 read, 2 input, 4 output. Creation across the 17 full-payload requests ranged 163,897 to 163,946.
Read arm. One seeded session, then 120 continuations resumed on the returned session id, each a trivial instruction to reply with a single word. Per resume: roughly 16 creation and 182,300 to 185,900 read tokens.
Cache verification, a pre-declared gate. Before committing budget, the pilot session was resumed and confirmed at 16 creation against 182,344 read. The runner then checked all 120 resumes individually and was set to abort if any read fell below 100,000 tokens. None did.
Budget discipline. Stop-loss was 35% of the session; the run finished at 12%. The second read batch was sized so that even under the worst case of r = 1.0 it would stop short of the cap.
The instrument, and an incident worth recording
The meter is the OAuth usage endpoint. Its raw body exposes session utilisation as a float, but the value is integer valued in practice, so resolution is one percentage point and the error bars below come from propagating half a point of quantisation per boundary reading.
Polling the endpoint on demand every 5 to 25 seconds from two loops at once tripped a 429 rate limit on that endpoint, which a monitoring cron on this machine shares. The monitor's readings went stale for about ten minutes. Its fail-safe behaved correctly, preserving the last good value and setting an error field, and nothing was lost. Self-polling stopped entirely and the rest of the run read the monitor's own output file instead of the API, at zero additional API calls.
Two lessons generalise. The usage endpoint tolerates roughly three calls per five minutes and not much more. And an experiment's instrumentation can degrade shared production monitoring when the two share a quota, which is a failure mode worth checking for before any measurement run that polls anything.
A second bug cost one aborted block. The runner used jq -r '.is_error // true', and jq's //
operator treats false as empty, so every successful request was read as an error. Fixed with an
explicit null check.
Phase table
Cumulative token sums rebuilt from session transcripts rather than from runner logs, so the ledger captures every API call that actually happened. All 140 calls were the same model; no hidden calls.
| Observed (UTC) | Session % | Cumulative creation | Cumulative reads | Phase |
|---|---|---|---|---|
| 19:59:41 | 3 | 0 | 0 | baseline |
| 20:00:49 | 4 | 60,496 | 0 | mechanics test |
| 20:01:35 | 4 | 224,436 | 18,404 | pilot |
| 20:04:32 | 5 | 552,326 | 55,212 | write arm |
| 20:15:02 | 9 | 1,863,896 | 384,788 | write arm |
| 20:20:03 | 11 | 2,683,614 | 476,808 | write end / read start |
| 20:25:02 | 12 | 2,848,090 | 4,145,563 | read batch 1 done |
| 20:35:03 | 12 | 2,848,972 | 9,826,513 | read batch 2 |
| 20:45:03 | 12 | 2,851,106 | 22,763,264 | read batch 2 done |
| 20:50:02 | 12 | 2,851,106 | 22,763,264 | settled |
The meter climbs from 3 to 11 while creation accumulates, then holds at 12 while 18.6 million further read tokens pass through it. The weekly meter moved one point during the write arm and stayed flat through the whole read arm, giving the same conclusion on a second instrument.
Arithmetic
Model: meter_pp = b0 + k_w · creation + k_r · reads, with r ≡ k_r / k_w.
Two segment closed form. With k = ΔP_read / ΔP_write = 1/8 = 0.125, eliminating the unknown
budget scale gives r = (C_read − k·C_write) / (k·R_write − R_read):
r = (167,492 − 0.125 × 2,683,614) / (0.125 × 476,808 − 22,286,456)
= −170,976 / −22,226,855
= 0.0076
Calibration falls out as 335,902 creation tokens per percentage point, or roughly 33.6 million creation tokens per full window on this plan.
Joint regression over all 22 meter observations, using cumulative tokens at each observation
instant, gives b0 = 3.305 pp, k_w = 3.0017e-06 pp per creation token (333,145 creation tokens
per point), and k_r = 7.6397e-09 pp per read token, for r = 0.0025, 95% CI [−0.006, 0.011].
Error bars. Bootstrap over half a point of quantisation noise on each boundary reading, n = 6,000: 95% CI on r is [−0.004, 0.021], median 0.008; P(r ≥ 0.1) = 0.000 and P(r ≥ 1.0) = 0.000.
Negative values inside the interval are a quantisation artefact and not a claim that reads earn credit. In working units, a percentage point costs about 44 million read tokens at the point estimate and about 16 million at the 95% upper bound, against about 336,000 creation tokens.
Limitations
State these alongside any use of the number.
- One account, one model, one window, one day. No claim about other model tiers, other plan tiers, or stability over time.
- The read arm's 1 pp of movement is fully explained by that arm's own 167,000 tokens of creation. No residual demands a nonzero r. Any true r in 0 to 0.02 fits equally well; 0 cannot be separated from 0.01.
- r is measured relative to creation, not to plain uncached input. Uncached input was 2 tokens on every request, because the harness writes essentially the whole prompt into the cache. In this harness creation is the fresh input path, so r is the quantity the three hypotheses are about, but a separate weight for genuinely uncached input is unmeasurable here.
- The absolute write coefficient is not identified. 336,000 creation tokens per point is measured, but whether that reflects a 1.0x or 2.0x weighting of creation cannot be determined without knowing the plan's true token budget.
- Output tokens are a bounded, negligible confound: 645 output tokens across all 140 calls, about 4 per request in both arms, worth about 0.01 pp even at a 5x weight.
- Meter resolution is one point and it lags actual consumption by well under a minute; readings settled and stayed settled across five minutes after each arm. Both are folded into the bootstrap.
- Cache lifetime was one hour, confirmed on every call. A five minute regime, which is what subagents get, was not tested.
- One working directory, one fixed system prefix of 60,496 tokens. A different prefix size changes the per-request ratios but not r.
Confound log. The account was otherwise idle for the whole run, with no scheduled traffic routed to it after 19:50Z and the last such routing at 17:45Z, before baseline. All 18 transcripts in the experiment's project directory are the experiment's own.
Inherited comparisons, re-verified at publication
The internal research note that motivated this run compared three external sources: the 0.1x figure
in wide circulation, a local usage tracker summing cache reads at full weight against plan limits,
and a proxy study reporting reads draining quota far faster than measured here. The latter two were
first verified in July 2026 and re-fetched on 2026-08-07, the day of publication, so the parent
post names them. The ccusage blocks --token-limit view
sums input, output, cache creation and cache reads raw and equal weighted, confirmed in its current
documentation, whose own sample table totals the four columns at face value. The ArkNill proxy
study records 1.5 to 2.1 million cache read
tokens per 1% of quota, cross validated over three datasets totalling roughly 362,000 calls, and
its entire capture window sits inside the March to April 2026 run of client cache bugs the vendor
later acknowledged, so its full weight conclusion plausibly measured cache misses as reads. The
0.1x figure needs no fetch, being the API price sheet's discount applied to the wrong meter.
Artifacts
Scripts and data live with the experiment: a deterministic payload builder; a runner covering both arms with stop-loss and per-request cache verification; a ledger builder that rebuilds authoritative token counts from transcripts; an analysis script performing the two segment solve, the joint regression, and the bootstrap; the byte-identical payload with its checksum; a JSONL ledger of all 140 API calls with per-call token counts; and the full meter timeline. The analysis reproduces with two commands, the ledger build followed by the analysis.