Skip to main content

Each registry file is named after the type it holds

@nubbin/core exports createRegistry(blocks): Registry, the compile-side registry that compile validates against. @nubbin/react exports defineRegistry(map): BlockRegistry, the render-side map of lazy importers. Two registries exist on purpose — it is the catalog/registry split as a consumer meets it, and the render path imports only the second.

A consumer's registry.ts holds the Registry. A consumer's blockRegistry.ts holds the BlockRegistry. Two plans crossed these, so blockRegistry.ts held a Registry and registry.ts held a BlockRegistry, and the catch-all went on importing @/nubbin/registry and receiving the wrong kind of object — a mismatch no gate can see, because both files exist and both typecheck in isolation.

The alternative was letting whichever plan shipped first fix the names by convention. It was rejected because the names had already diverged across two phases and five dependent tasks, and a convention nobody can check is how they diverged.

The earlier phase owns the artifact; the later phase consumes it. Phase 2 needs the demo's blocks, catalog, both registries, the publish script and the catch-all to demonstrate its own thesis, so ownership cannot move to Phase 3 without blocking the earlier phase on the later one.