Investigation

Cache-Read Coefficient: Methodology and Raw Data

Full method, instrument notes, phase table, arithmetic, error bars, and limitations for the cache-read coefficient measurement reported in the parent post.

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.

  1. One account, one model, one window, one day. No claim about other model tiers, other plan tiers, or stability over time.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. Cache lifetime was one hour, confirmed on every call. A five minute regime, which is what subagents get, was not tested.
  8. 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.

Ask About Projects
Hi! I can answer questions about Ashita's projects, the tech behind them, or how this blog was built. What would you like to know?