The Other Way a Root Gets Bent
Freezing the root stops one kind of erosion: editing the base class to suit a child. There is a second kind that never touches the root at all. A caller somewhere writes if vault.backend == "delta": ..., or isinstance(vault, DeltaVault), to reach a feature only that child has. From that line on, the caller knows which child it holds, and the root is no longer the contract; it is a suggestion. Add a second such caller and the next implementation has to imitate the first one's quirks to keep them working.
Soul Vault's architecture document states the rule plainly as invariant 2: outside backends/ and select.py, nothing imports a child, calls isinstance on one, or branches on .backend. And, as with the frozen hash, it is a test rather than a hope.
Three Tests Beside the Hash
- T-NO-OVERRIDE. For every child the selector knows, the test walks the class and checks that each template method is still the root's own function object. A child that redefines
write_batchfails, even if its version does exactly the same thing today. The same test checks the other direction: a child that leaves any primitive unimplemented fails too, and a child'sbackendname must equal the pointer value that selects it. - T-NO-ISINSTANCE. The test parses every Python file of the package outside
backends/andselect.pyinto an abstract syntax tree and looks for two things: anisinstanceorissubclasscall that mentions a child's class name, and an import from the backends package. Either is an offence, reported with file and line. Parsing the code instead of grepping it means a comment or a string that mentions a child does not trip it, and a real call cannot hide behind formatting. - T-NO-LITERALS. No vault path literal anywhere in the package. Where the store lives is data in the pointer record (track 3), never a string in code.
The One Place That Knows
Something has to turn the pointer's word into a class. That place is soulvault/select.py, and it is tiny. It holds one dictionary, BACKENDS, mapping a pointer value to a "module:Class" string; today it has a single entry, "delta". The module is imported only when the pointer selects it. A pointer naming anything else raises backend_not_available with a cause that says which implementations this Mac has, and the comment above it is a quote from Dad: no default entry, no fallback chain.
Everything else receives a SoulVault from open_vault() and uses only the root's methods. That includes cwkPippa building a prompt, Vestige reading memory, the canary, every harness bootstrap. None of them could tell you which child they hold, and none of them needs to.
When a Caller Really Needs Something Special
The honest objection: what if one store really can do something the others cannot, like returning old revisions? The answer is the capability flags from lesson 1. The caller asks vault.capabilities().durable_history, or simply calls history() and handles unsupported_capability. Either way it is asking the contract a question, not identifying the child. If a third store gains history tomorrow, every such caller benefits with no edit. If a caller had written isinstance(vault, DeltaVault), it would ignore the new store forever.