--- status: resolved opened: 2026-09-29 located-in: [mesh-controller cmd/mesh-controller, mesh-controller internal/catalogue] fixed-by: mesh-controller PR 164 (module check) amended-design: 03-DESIGN/01-to-be/12-a-module-repository.md --- # 148 — a manifest outside this catalogue has no check ## What was observed A module's manifest is validated by a **test** — `internal/catalogue`'s suite parses every manifest in the catalogue checkout beside it and fails on one it cannot resolve. That works, and it is how several real faults were caught before a machine saw them. It is available to exactly one repository: this one. Somebody describing their own application in their own repository — the case [ADR 0037](../../02-DECISIONS/0037-where-a-module-lives.md) calls *the case that matters most* — has no check at all. They write a manifest, register it with a running mesh, and find out whether it is valid when the mesh refuses it, or later, when a machine applies something that resolved and should not have. The same record asks for the answer: **a `module check` command on the control plane's binary**, so a manifest is checked by the tool rather than by a test that imports the tool's internals. ## What would have prevented it Nothing prevents this; it was noticed and left. ADR 0037 named it on 2026-09-01 and the record sat `proposed` until 2026-09-29, so the missing half was never anybody's task. ## Evidence to carry into diagnosis - `mesh-controller/internal/catalogue` — `ParseManifest` and `CatalogueProblems` are the check, and both are internal. - The catalogue-wide test is `TestEveryCatalogueManifestDeclaresWhatItMounts` and its siblings; they take a path from `MESH_CATALOG`, so the mechanism is already path-driven and not repository-bound. - `mesh-controller module add` refuses a bad manifest at registration, which is the same check far too late: by then it is in a running mesh's records. ## Built, 2026-09-30 `mesh-controller module check …` runs what registration runs — the strict parse, the per-manifest problems, and the cross-manifest rules over every manifest given — with no store and no mesh, prints every problem in the manifest's words, and exits non-zero on any. What it cannot judge without a store it says: a claim on one of the mesh's own seats is judged fully only at registration ([ADR 0122](../../02-DECISIONS/0122-a-seat-is-data-a-rename-is-a-database-update.md)), and a seat declared by a module whose manifest was not passed reads as unknown. Written into [12 — A module repository](../../03-DESIGN/01-to-be/12-a-module-repository.md) as the section *a manifest is checked where it is written*. The console's own manifest was the first checked with it.