--- status: resolved opened: 2026-09-14 located-in: [mesh-controller (the catalogue), mesh-catalog] fixed-by: mesh-controller 3ae7b88, 2b82872; mesh-catalog d2dce34; proven by one-node-mesh.test.ts (the catalogue holds every module the control plane built) amended-design: --- # 050 — The catalogue knows nothing that was built before it ## Symptom A mesh raised from bare metal built six modules in order: the shared base, a store, the catalogue, the control plane, a module, and a broker. Asked afterwards what it holds, the catalogue answered with three — exactly the three built *after* it started running: ``` amqp-ping built from lavinmq built from mesh-control built from ``` Missing: the shared base, the store, and the catalogue itself. The catalogue learns what exists by consuming the builder's announcement over the broker. Anything built before it was running was announced to nobody, and nothing goes back for it. ## Why this matters **The modules it cannot see are the ones a mesh is made of.** On a fresh mesh the things built before the catalogue are, necessarily, the things the catalogue needed in order to exist: the base it was compiled against and the store it keeps its records in. So the hole is not random — it is always the foundation, on every mesh, at exactly the moment the graph is first populated. **It breaks the question the catalogue exists to answer.** Build edges are derived facts between versions, and the base is the node nearly every other module hangs off. A catalogue with no record of the base cannot know that moving it makes everything standing on it stale, so `catalog_stale` answers confidently and wrongly — the worst shape for a question about what to rebuild. **Nothing reports the gap.** The catalogue does not know what it was not told, so it does not say "three of six" — it says three, and a reader with no independent count believes it. This was found by asking it a question and comparing the answer against what the mesh had just been watched doing. **The record is not lost, only the catalogue's copy.** The control plane holds every build it ordered, with commit, repository, path and resolved artifacts. So this is a gap between two stores that should agree, rather than information nobody has. ## Open questions - **Should the catalogue backfill on start** — ask the control plane for the builds it already recorded and take them in? That fixes the fresh-mesh case and every case where the catalogue was down while something was built, which is the same fault with a different cause. - **Or should announcements be durable**, so a build announced while nothing was listening is delivered when something is? That treats the catalogue as one consumer among several, which it already is. - **Or should the control plane be the record and the catalogue a projection of it?** Two stores that must agree, kept in step by events, is the arrangement that produced this. - **How would anyone notice next time?** The catalogue cannot compare itself to a source of truth it does not have. Whatever is chosen, something has to be able to say "these disagree". ## How this would be checked | Rule | Checked by | |---|---| | The catalogue holds every module the mesh built | A mesh is raised from bare metal and the catalogue is asked; its list is compared against the control plane's build records, and a module in one and not the other is a failure. | | A change to the base makes what stands on it stale | The base is rebuilt on a fresh mesh and the catalogue names the modules that must follow — which requires it to know the base exists. |