There is a scripts directory in your repo with eleven files in it. You wrote four. Nobody has opened the other seven this year, and last month somebody wrote a ninth thing that does what the third one already did, slightly differently, because looking took longer than writing.
The hour is not the loss. The loss is that the rule now has two implementations, they disagree in one edge case, and the disagreement will surface as a bug report eight months from now that nobody can reproduce.
Encoding is half the job
A rule you have written down and encoded is not yet a rule your team follows. It is a rule you follow, and a file the next person has to stumble over.
Everything in this series so far has been about the first half: reason once, encode, replay. Turning a runbook into a command only pays if the second person knows the command exists, and that turns out to be a separate problem with a separate fix.
Three things make an encoded rule survive contact with a second person, and only the third one is usually missing:
| what it means | fails when | |
|---|---|---|
| a name | says what it does, not how it does it | it is called utils
|
| a location | the first place someone would look | it lives where its author happened to be |
| an index | one file that names everything | it is a wiki page from 2023 |
The second reader changed the economics
This used to be a politeness problem. A colleague who cannot find your script loses an afternoon, once, and you feel vaguely bad about it.
An assistant that cannot find your script rediscovers the repository from scratch, on every task, forever. It gets there, you paid for it, and you will pay again next session, because nothing it worked out was written down anywhere.
That is the shift worth internalising. Discoverability stopped being courtesy and became a per-task cost with a recurring bill.
Four registries, four questions
Deskspace, a Spring Boot and React service I keep as a reference implementation, answers each of them with a file and a lookup tool rather than with a document somebody is supposed to read:
toolbox/tool_mapping.py list # what tools exist, by key
toolbox/arch_map.py get booking # where the code lives, and what may depend on it
toolbox/lexicon.py search "checkstyle" # how we solved this before
toolbox/check_readmes.py # does every directory explain itself
The architecture map is the clearest case. A package structure is a fact about the repository, so it belongs in a file rather than in a model’s reasoning. Ask an assistant to add a validation rule with no map and it opens half a dozen files to infer a layout that has not changed since the repo was created, then does it again next session. Ask with a map and it is told.
The lexicon is the only one of the four that makes the repository better over
time rather than merely keeping it green. Gates stop bad things escaping; a
record of how a recurring problem was solved stops the same afternoon being spent
twice. Every entry in that one cost somebody real time: that a bare
checkstyle:check silently runs Sun’s ruleset, that one code generator breaks
against the current TypeScript, that two adapters onto the same upstream collide
on a bean name at context startup rather than at compile time.
An index is load-bearing, so it drifts
The index is the piece that keeps working after everyone who built the thing has moved on, which is exactly why it decays unnoticed. Nothing breaks when an index goes stale. The build passes. The tests pass. The only symptom is somebody rebuilding something, months later, in another directory.
So the registry is checked rather than trusted. That repository fails its own build when a tool exists on disk without being registered, and when the architecture map disagrees with the actual package tree:
$ toolbox/tool_mapping.py check
FAIL coverage_gaps.py exists but is not registered in mapping.json:
an unregistered tool is an undiscoverable tool
$ toolbox/arch_map.py check
FAIL map lists slice 'billing', no such package in src/main/java
Both directions fail differently. Something on disk missing from the index gets rebuilt. Something in the index missing from disk is worse: it sends the next reader, or the next agent, confidently to a place that does not exist, which is more expensive than having no map at all.
The way this check fails is the point
Moving those scripts into one directory broke the checker in the most instructive way available. It kept globbing the old path, and globbing a directory that no longer exists yields nothing, so nothing was ever unregistered, so the check reported ok.
Forever. The build was green and the index was unenforced, and there is no symptom for that.
What caught it was not the check. It was a test asserting that the check fails when a tool is unregistered. The happy-path test still passed and told us nothing, which is the general shape: a gate with only a happy-path test proves that it runs, not that it gates.
Write the index for both readers
There is no version of this that serves a person onboarding and not an assistant starting a task. Both arrive with no context, both need to know what already exists before building anything, and both give up in the same way when the answer is buried.
That is convenient rather than profound, but it settles an argument that used to take a while: there is no separate machine-readable index to maintain. There is the index, and it is checked, and the human-facing README is generated from it so the two cannot disagree.
The test
Delete the person who wrote it. Can the next one find it in under a minute, without asking anybody, starting from the file they were already going to open?
If the answer is no, the thing is not encoded yet. It is stored, which is not the same, and storage without retrieval is how a team ends up paying to keep a decision it no longer benefits from.
If your team keeps solving the same problem in two directories because nobody could find the first solution, that’s the work I do.