On 4 September 2026 we were looking at the Git server for another reason and queried its own list of SSH keys. One of them was a key we had retired in August. It was registered to the administrator account: full control of the server that holds the estate’s code and the record of every change ever made to it. The key had been declared gone for two weeks.
Every statement about the retirement was true about the places it had been checked.
What “retired” meant
The retirement was careful. On 19 August the key came off every virtual machine, and all five refused it. On 20 August it came off the remaining hosts, and each refused it at a real login attempt. The code declared it as a key that must never appear anywhere again, and an audit read every account’s key files across the estate and reported clean.
The orientation file, which every working session reads first, said the key was retired and refused by every host.
Every word of that was true, and all of it was about machines. The Git server does not keep its keys in a file on a machine. It keeps them in its own database, where the audit never looked. So the audit covered four kinds of place and said nothing about the fifth. Worse than saying nothing, it reported clean. We had positive evidence for a claim that was false.
This was not the key’s first escape. By 30 August it had already come back three times, by three different paths. A retired credential is not a state you reach once. It is a claim you keep checking everywhere the credential could live.
Why this belongs to working with an agent
The sentence that did the damage was in the file an agent reads at the start of every session. An agent brings no memory to that file, so it has nothing to doubt it with. A person who did the retirement might remember that only the machines were checked. The agent inherits “retired and refused” as a fact, fresh, every morning, and plans on top of it.
Our method for working with an agent keeps what matters in documents and adds detail only when it is needed. It fails in one particular way: not when information is missing, but when there is no placeholder pointing at the place nobody has looked. Nothing in the documents pointed at the Git server’s key list, so no session ever went looking.
The corrected line in that file now says what the retirement covered, and what it did not.
The fix that did not run
The same night, the audit gained the Git server’s key list as a fifth place to look, and matched on the key itself rather than on its label. The registry entry had been titled with the old key’s name, and a renamed entry would have slipped past a label check. Then the backlog row that asked for the fix stayed open, because nobody wrote back that it had landed.
On 14 September, closing that row, we did not take the fix’s word for it. We ran it and measured what it could actually report.
- From the machine its own header said to run it on, it could not reach the machines it audits, so none of its later checks ran, and its summary showed no failed task.
- From the operator’s laptop, it stopped at an earlier check that had had a known finding since 7 September. The Git server check came after it, and it never executed on any run.
- And the Git server check skipped itself when its read came back empty. A broken query would have looked exactly like a clean registry.
So now every check runs and reports, and one final task fails and names each check that did not pass. The Git server check refuses an empty read. It must find at least one key the code declares before its silence counts, so “no retired key” can only be said about a live read. Its verdict on 14 September: no retired key among the 2 keys the server accepts, with 2 declared keys found, so the read was live.
A check that cannot see a place says nothing about it. A check that reports clean anyway says something false.
What it cost
- Two weeks in which the administrator key to the estate’s most irreplaceable server was one we had stopped vouching for, while everything that checked said it was gone.
- Revoking it cut the operator’s own access to the repository. The replacement key had never been registered in the Git server either, for the same reason. Access came back when it was added, the same day.
- Ten days in which the fix existed and the backlog said it did not, and from 7 September on, the fix could not reach its verdict on any run.
The rule it bought
Declared is not verified. A claim that something is gone has to name where it was checked, and it is only as wide as that list. A check has to prove its read was live before its silence means anything. And a fix is not a fix until it has run somewhere and reported.
None of this is new
In 1975 Jerome Saltzer and Michael Schroeder set out the design principles for protecting information in computer systems. One is complete mediation: “Every access to every object must be checked for authority.” They warned about shortcuts that remember the result of an earlier check: “If a change in authority occurs, such remembered results must be systematically updated.”
A revoked key is a change in authority. The remembered result here was not a cache in an operating system. It was a sentence in a document, remembered by nobody and read by an agent every morning. The principle is half a century old. What changed is where the remembered results live, and how faithfully they get believed.