The Same Pair, Twice, Backwards
Track 1's second lesson ended with a translation function: settings vocabulary in, routing vocabulary out, applied at the crossing and never stored back. That closed the bug that broke every app.
Later, the workshops needed to record which brain performed a piece of work. They needed one spelling so that provenance records are queryable, and the spelling they needed was the other one — the picker vocabulary, the one a person recognizes. So a second canonicalization exists, and it maps the routing name back to the picker name.
Two functions. Same pair of names. Opposite directions. And the family's rule about them is blunt: never merge them.
Why This Looks Exactly Like a Cleanup Opportunity
Imagine finding both for the first time. Two functions, both mapping between the same two strings, in the same family, both called canonical-something. Every instinct says this is duplication with a typo in it, and the fix is to pick a direction.
It is not duplication. They answer different questions:
- Which endpoint should this request go to? The answer is in the routing vocabulary, because that is what the routes are named.
- What should this record say the work was done by? The answer is in the picker vocabulary, because that is what a person reading the record will recognize, and it is what the settings owner publishes.
Merging them would not remove a function; it would change what one of them means. And because both directions have already written identifiers into stored records — one into request logs, the other into provenance rows — the merge would silently reinterpret history. That is data corruption arriving under the banner of a cleanup.
How to Make the Distinction Survive
The defense is naming and location, not a comment — and in the live kit only part of it is taken. The two functions live in different modules, matching the concern that owns each vocabulary, and the provenance module's own docstring carries the sentence that they run in opposite directions on purpose and must never be merged. But both are still named canonical-brain, so a call site does not say which way it runs. Naming each after its destination vocabulary, as the sample below does, is the stronger form of the same defense: the routing one and the picker one become distinguishable at every call site without opening either.
That last part is the load-bearing one, because the person who eventually finds both will not be reading the architecture document. They will be reading one of the two functions, at the moment they think they have found a bug.