One Name, Two Spellings
The assistant that every sibling app talks to can run on several different model brains. Two parts of the system needed to name them, and they were written at different times by different concerns.
The settings side published the list a user picks from, and one of its values was the vendor's consumer brand name. The chat-routing side owned the endpoints, and it knew that same brain by the name of its command-line tool. Both spellings were correct inside their own half. Neither half was wrong. There was simply no place where the two halves met and had to agree.
So every sibling app had the same defect: pick that brain in Settings, and the assistant panel stops working. Not one app. Every app, at once, for the same reason, discovered independently — which is the specific shape that tells you the defect is not in any app.
Why No Existing Test Failed
This is the part worth sitting with. Each repository was internally consistent. The settings code stored what the settings endpoint published; the routing code routed what the routing table declared. A unit test in either half passes. An integration test inside one app passes too, as long as it uses a brain whose two spellings happen to coincide — and most of them did. The test that does fail is the one that walks every value the picker can produce through the routing table, and you can write it in any one app today; the sample below ends with it. Nobody had, because it tests neither half. It tests the crossing, and the crossing had no owner.
The defect lived in the space between two components that no existing test suite crossed. Duplication did not cause the naming split; the split would have been possible in a single application. What duplication did was multiply the blast radius and divide the ownership. Three apps had the bug. Zero apps had the responsibility for the boundary where it lived.
The Fix Names the Rule
The repair was not to rename either spelling. Both namespaces are legitimate: the picker shows what the settings owner publishes, and the routes accept what the route family declares. The fix was to give the boundary an owner — one translation function, in the shared layer, applied at exactly the moment a settings value crosses into a chat route, and never in reverse.
That is a much smaller change than "unify the vocabulary", and it is more honest. Two namespaces that exist for real reasons should be allowed to exist. What must not be allowed is for the crossing between them to be implicit, unwritten, and re-implemented in each caller. Track 6 comes back to this, because the same system later grew a second canonicalization running in the opposite direction, and the reason both must exist is the sharpest example in this quest of what shared code is really for.