October 26, 2026·5 min read

Let the server be the truth

Two hours after a clean reprice, one laptop posted ten sessions at the old rates, and the server stored them as given.

By Andrew Pyle

A number that many machines compute is only as current as the oldest copy of the code computing it.

01A clean apply

At 12:44 the table agreed with itself

At 12:44 PM Central on October 12 I ran a repricing apply over my record of Claude Code sessions. These are estimated costs, priced from token counts at API rates, not invoices. That morning I had fixed the rates for newer models, which had been resolving to their older family's rate. A dry run right after the apply showed a delta of zero dollars across the whole table. Five minutes later a second fix landed that keeps the split between one hour and five minute cache writes.

Every Mac I work on runs a small ingester. It reads the local session transcripts, prices them with its own copy of the pricing code, and posts the result to a central server. The server stored the cost and its breakdown exactly as each machine sent them. If the same session arrived twice, the last write won.

That design works only while every machine runs the same pricing code. When one machine falls behind, its old prices win the moment it posts.

023:29 and 3:44

One laptop posted the old prices

At 3:29 and 3:44 that afternoon, one laptop posted ten sessions. It had not pulled the day's code. Its slots had no split between the cache tiers, and its rates were the old family rates. The server stored them as given, over rows that had been correct since 12:44.

A read only dry run then showed those ten sessions off by 181.69 dollars, with the largest model priced about 1.9 times too high. The other 2,201 sessions showed a delta of zero. The drift appeared about two hours and forty five minutes after a clean apply, and I opened the fix three minutes after the last stale post.

The absolute totals in that table had a separate problem, duplicate usage lines in the transcripts, which inflated them, so I do not read them as real spend. The 181.69 is a different kind of number. It is the gap between two pricings of the same tokens, so it measures the drift itself.

03Not the first time

The same stale client, earlier the same day

This was the second time that day the pattern showed up. While checking the cache split, a dry run showed one model family's cost jump. In six sessions, twelve slots for that model had been stored at zero. Its rates had not changed. The reprice was pricing those slots for the first time. A model that read as free was an artifact of a stale client.

Behind that sat a bigger group. After a repricing in July, 54 sessions had been posted again by Macs still on older code, 53 of them from that same laptop. They had stored one model at an old rate and another at zero, and they ran a median of 2.96 times too high.

The rate logic is not something I can ship to every client and then trust. Rates differ by model version, and they change. A one hour cache write costs twice the input rate and a five minute write costs 1.25 times. The main thread writes one kind and subagents write the other, so each session's cache tokens are apportioned by lane, main slots first. On production that rule matches the session's own one hour total for 2,153 of 2,202 sessions. A Mac that has not pulled the latest code carries an old version of all of it.

04Tokens in, price out

The server prices from tokens and ignores the dollars

The fix was to stop storing the client's arithmetic. The ingest endpoint now recomputes the cost and the breakdown from the posted token counts and ignores the posted dollars. The repricing math moved out of the history command into one shared module, so the command that reprices old rows and the endpoint that prices new ones call the same code and cannot disagree. The command lost 128 lines in the move.

An unknown model keeps its price

If the server cannot price a model at all, that slot keeps the client's posted cost instead of dropping to zero. Without that guard, a model the server has never heard of would read as free, the same artifact the stale client produced earlier that day.

Drift gets a count

When a posted total differs from the server's by more than a cent, the server logs a warning and counts it. The warning is one line in the ingest view.

logger.warning('claude_code_usage ingest: repriced %s/%s $%s -> $%s', ...)

The response now includes a repriced count, and the ingester prints how many sessions the server repriced in each batch. The comment beside that print says what the number means.

A nonzero count means this Mac's pricing.py disagrees with the server's.

To check the change mattered, I stubbed out the server price, and four of the six new tests failed. Disabling the unpriced guard failed the test for an unknown model. A read only production dry run after the refactor showed zero delta on 2,201 sessions, with the ten stale sessions as the only movers.

It is not finished. The ten drifted sessions stay wrong until each one is posted again or repriced directly. I have not yet seen a live ingest from that laptop go through the new path. A machine on very old code can still post usage. What it can no longer do is store a wrong price, as long as it sends token counts the server can parse. When a number has to agree across many clients, the clients now send what they observed and the server does the math once.

Have something you need built or fixed?

I build production Django / Next.js platforms and human-supervised AI-agent systems. Solo, senior, and fast. Tell me what you are building.

Start a project