Five parallel passes read every page under /docs and checked each concrete claim against the code that implements it. A third of the load-bearing ones were wrong, and every error ran in the same direction.
Documentation rots in one direction. It drifts toward the product you meant to build, never toward the one that shipped. Nobody writes a doc page claiming less than what exists, so every gap between the words and the code opens the same way, and it opens quietly.
So we audited ours. Five parallel passes read every page under /docs and checked each concrete claim — endpoint paths, auth headers, request and response field names, limits, plan gating, environment variables — against the code that implements it. Not a proofread. A diff between the documentation and the source.
The worst finding was on the docs index, in the sentence the whole site rests on: every surface reports into the same evidence log, and every record is sealed with a content hash you can re-verify. That is true for four of six surfaces. CanaryShield block records and CanaryRAG trigger records live in their own tables and carry no content hash at all, which means a buyer exporting evidence of blocked prompts would have received an empty file. That is precisely the claim this product gets bought for.
Second: the CanaryVaults page described a decoy as an identity that exists in exactly one file, giving per-file leak attribution. No file association exists anywhere in the product. A decoy binds to a protected email address, three per email, across three tiers. The page carried exactly one code example, and it did not work — it authenticated with a header that endpoint does not accept, and printed a JSON shape that endpoint does not return.
Third, and the most expensive if you had acted on it: the enterprise page said pending invitations reserve a seat, and that the 25-seat floor counts joined members plus outstanding invites. The code does the opposite. Invitations are uncapped and the seat check runs at the moment an invite is accepted. An admin sizing a rollout on our text would have under-invited by however many invitations were still outstanding.
Every single error ran the same direction. Not one page understated what the code does. That is the tell, and it is why proofreading does not catch these — a page that reads confidently and describes a coherent product will pass any review that does not have the source open beside it.
The pages are fixed. Where the code is a scaffold, the page now says scaffold and tells you not to build on it yet. Where a capability is gated by plan, the gate is stated. And the findings still outstanding are written down in the open rather than quietly queued, because a documented gap is a much smaller liability than a confident sentence.
If you ship a product with docs, this exercise is cheap and it will not flatter you. Take the ten claims your customers act on most often, open the implementing code beside each one, and read them together.
This article is about a shipped surface: All product surfaces. Integration details live in the docs.
Continue reading
More notes from the CanaryVaults team.
What a paste-site canary sees: the anatomy of a credential-stuffing hit
A walkthrough of the seeding pipeline end to end: how a decoy credential ends up on a paste site, what happens in the moments after someone tries to use it, and what lands in your alert channel.
PostmortemEvery page on our site was shipping an empty body
One call to useSearchParams() sat inside the root layout's only Suspense boundary, and deopted the entire application to client-side rendering. Twelve words of markup left our server. Nothing in the build said so.
EngineeringIt worked, it said so, and nothing happened
A contact form returned 201 and showed a green confirmation every time. Nobody was ever notified. We went looking for more of these and found about thirty, all with the same shape.