Every sentence was true. The system was still unsafe.
The short version: every sentence in the security section was true, and the system was still unsafe. Accuracy and safety are different properties. Reviews must attack the text, not read it.
The Airtable skill I build my practice on has a section on multi-tenant portals: how to give one client a view of their own records without exposing anyone else's. Before release, that section passed every check I knew how to run. Every sentence in it was factually true. I read it three times. A careful engineer could have followed it and felt responsible doing so.
It still described a system that leaked.
That gap, between text that is true and text that is safe to follow, is the most useful thing I learned building the skill. It is also the reason my client work goes through a gate that most delivery work never sees.
Two different properties
We tend to treat "accurate" and "safe" as the same virtue. In documentation, and in system design, they are not. A sentence is accurate if it corresponds to reality. A procedure is safe to follow if, when a competent person executes it exactly as written, the result cannot be quietly wrong.
You can write a paragraph where every claim is true and every reader who follows it builds a hole. The truth of the individual sentences does nothing to close the hole, because the danger lives in what the sentences leave unstated: the default behavior, the error path, the scope of a token. Proofreading finds false sentences. It does not find true sentences that add up to an unsafe instruction.
So I stopped reading the security section and started attacking it. The rule was strict. The text does not ship until a reviewer who is trying to break it can no longer construct a concrete leak from following it word for word. The reviewer found three.
Attack one: the cache that forgot who was asking
The section recommended caching query results to stay under rate limits. True and sensible. Airtable's API is capped, and I had live-tested the real batch limit at 25 records per request in July 2026, where the public docs still said 10, so I know exactly how much caching matters in practice.
But the text described the cache without requiring the cache key to include the client. Follow it as written and you build a store where the second client to request "my open orders" is served the first client's open orders, because the key was the query, not the query plus the tenant. Nothing in the paragraph was false. The paragraph was still an instruction to leak. The fix was one non-negotiable sentence: the tenant identifier is part of every cache key, always, and a cache that cannot express that is the wrong cache.
Attack two: the filter that failed open
The portal pattern filtered records to the signed-in client with a formula. Correct as far as it went. The reviewer asked the question the text did not. What happens when the filter throws? An empty client id, a malformed value, a transient error in the expression?
The unstated default was fail-open. On error, the query returned the unfiltered set, which is every client's records. The safe default is the opposite: on any failure to positively identify the tenant, return nothing and raise. "Fails closed" is not a nicer way to say "fails open." It is the difference between a blank screen and a breach. The corrected text made fail-closed the rule, and treated a filter that can silently degrade to all-records as a defect rather than an edge case.
Attack three: the agent with the master key
The most modern hole was the newest pattern. The section covered giving a Claude-powered agent access to the data so it could answer questions and take actions. What it did not pin down was the scope of the token behind that agent.
Handed a base-wide access token, the agent can reach every client in the base. It does not need to be attacked with a clever prompt. A reasonable question, asked by the wrong user, is enough, because the token draws no boundary the model is obligated to respect. True sentence in the original: the agent needs access to the data. Missing and load-bearing: the agent's credential must be scoped to exactly one tenant's slice, so that the worst a confused or coaxed agent can do is stay inside walls the token already draws. The fix moved the boundary out of the prompt, where it is a wish, and into the token, where it is enforced.
Reviews must attack, not read
None of the three fixes made a false sentence true. They made a true section safe, by naming the default, the error path, and the scope that the accurate prose had left to chance. A proofreader would have signed off on the original. Three adversarial passes constructed three working leaks and blocked release until each attack failed against the corrected text.
That is the whole lesson, and it reaches well past Airtable and past security. In the AI era, generating text that is fluent and factually clean is cheap, and systems will produce a great deal of it. What stays scarce is the review that assumes the text is trying to hurt you and goes looking for how. Accuracy is a claim about sentences. Safety is a claim about consequences. Only the second one keeps a client off a disclosure call.
The same gate on client work
Every engagement I take runs through this discipline, not only the skill. Facts get verified against the live platform and dated, because documentation drifts and my own memory is a stale document too. The volatile ones get re-checked on a monthly automated schedule rather than trusted indefinitely. And anything that touches more than one client's data gets the adversarial pass: not "does this read correctly" but "if I were trying to serve the wrong person's records, where would I start."
It is slower than shipping the first version that reads well. That is the point. I take a small number of clients at a time precisely so the systems I hand over have survived someone trying to break them, and not merely someone trying to like them.
If your systems are older than your AI ambitions, the method explains where I would start, and a conversation is how engagements begin.