This sentence is from one of our decision records, and every word of it is true:
the server computes the authoritative value
It was written during a rewrite of how cookd syncs usage. Before the rewrite, a CLI on your laptop computed a percentage and pushed it, and the server stored it in a column. After, the CLI pushed raw observations and the server derived the percentage itself, in SQL, at read time.
To a reader who was not in the room, "the server computes the authoritative value" says the number has been checked. It has not. It cannot be. And the next engineer to read that sentence is the one who might build something that assumes it was.
Why nothing can be checked
cookd grants access to a phone app in proportion to how much of your Claude usage window you have used. A program on your laptop reads Claude Code's transcript files, counts tokens, and sends what it saw. The server stores it, derives a rolling window, gates access on it, and shows a version of it to people who follow you.
The input is a set of files on the user's disk, read by a program the user controls, on a machine the user owns. There is no integrity boundary available between that program and the server, and no version of this design creates one. The same is true of any CLI, desktop agent, browser extension or companion app that reports what it observed locally.
A note that reviews no code
During the security review of that rewrite, a section was added to the decision record that fixes no bug. Its title:
Standing note: every usage number is client-ASSERTED, not server-verified
The rewrite had made that neither more nor less true. The note exists because, in its own words, "this branch changes what the words mean". Before, "authoritative" plainly meant the server's copy of what the client said. Now buckets were the source of truth, the server derived the window, and the language "reads like verification and is not".
So the note pins down what the phrase does mean:
the server is authoritative over the client for values that other people see or that gate access, so a modified app cannot claim a number its companion never reported. It is not attestation. Between the companion and the server there is no integrity boundary at all, and there cannot be one while the input is a local file read by code the user controls.
That is a useful property. A patched phone app cannot invent a number, so the social feed shows what some companion actually reported. It is a much narrower property than the sentence suggested.
Call it word drift: a refactor that moves data closer to the server makes words like "authoritative", "verified", "validated" and "source of truth" sound stronger, whether or not anything was verified. It is a change to the system, and it gets no schema migration and no failing test. The only fix is another sentence, placed where the next reader will find it.
Ask what forging it buys
Once you accept that the numbers cannot be checked, "can this be faked?" stops being useful. The answer is always yes. The useful question is what faking it gets you.
Here: more access to your own account, in an app you already signed up for. The note says it directly: inflating the number "grants you more of a product you already signed up for." Nobody else's data is exposed and nobody else loses anything.
So the design accepts it, and writes down where the acceptance ends:
Do not build anything adversarial on these numbers without a different source. Leaderboards, paid tiers, rewards, or anything where beating someone else has value would be trivially gamed […] The social rail is safe today only because ranking your friends by burn rate has no prize attached.
That paragraph is what turns an accepted weakness into a rule about future products. It also names the exact thing that changes the answer. Not scale, not user count: a prize. The moment beating someone else is worth something, the same weakness becomes an incentive.
The one number the server owns
The note ends with a rule:
The one number the server does own is
received_at. If a future feature needs a value a user cannot forge, it has to be derived from something the server observes, not something the companion sends.
Every bucket carries two timestamps. captured_at is the laptop's clock: useful for debugging,
worthless as evidence. received_at is written by the server when the request arrives.
Most of what you might ever want to prove (that someone was active, that pushes arrived at a plausible cadence, that two devices report concurrently) can be built from arrival times, which are observed, rather than payload contents, which are asserted. One server-observed column costs almost nothing, and it is the only material you will have if you ever need a feature that does not trust the client.
The same instinct had already shaped the merge. Buckets merge with greatest() per component and
ignore both timestamps, so a client-supplied clock never influences what gets stored.
The same shape on a different object
Reviewing this turned up a related, real finding. The new bucket tables had been given the old table's row-level security shape: readable by you and by anyone following you. That was correct for a single current-window percentage. It was wrong for a 15-minute-resolution timeline 48 hours deep, because following someone needs no approval and can be undone afterwards, so one unapproved insert would have exposed a named person's working hours and sleep schedule. Nothing read that arm of the policy yet. It shipped self-only. (Ship the shape, not the answer covers it in full.)
What gave it away was an inconsistency: a third, related table had been written self-scoped. The one place that did not match was the one place that was right.
Where "clients never write authoritative state" stops being true
The rule holds for usage and not everywhere. User-authored values also reach the database through direct client writes under row-level security, with no server in the path, among them post headlines and bodies, comment bodies, the byline handle, and a JSON blob of per-post statistics.
The last one matters because a value derived from it is rendered as a visual award on the post, a stamp. So a client-authored number feeds a derived surface. The decision record for stamps lists it as an accepted residual risk: the stamp is, in effect, self-reported. That is tolerable for the same reason as before. It describes only its owner's own post and affects nobody else. It is written down because the next person to derive something from that blob needs to know it came from a client, and the field name will not tell them.
What we would do differently
- Search the design doc for trust words on every data-flow change. "Authoritative", "verified", "trusted", "source of truth". Each one should say who verified what, or be replaced.
- Put the "no prize" rule where product decisions are made, not only in an ADR. A security-review note is read by engineers. The person proposing a leaderboard may never open it.
- Name the provenance in the field. A column called
statsdoes not say "client-supplied". Provenance belongs in the name or the column comment, where the next reader sees it without opening a decision record.
Write down what the word means
No code changed the trust model here. A sentence did, by sounding stronger than it was. The fix was another sentence.
When you cannot verify a number, the decision that matters is not whether it can be faked. It is what faking it would buy, and what you promise never to build on it.