diff --git a/02-DECISIONS/0037-where-a-module-lives.md b/02-DECISIONS/0037-where-a-module-lives.md index a697d12..c01e6c6 100644 --- a/02-DECISIONS/0037-where-a-module-lives.md +++ b/02-DECISIONS/0037-where-a-module-lives.md @@ -1,6 +1,6 @@ --- topic: building it -status: proposed +status: accepted date: 2026-09-01 deciders: jochen reconstructed: false @@ -101,3 +101,19 @@ the digest down after building. **Whether kind 4 deserves a module at all.** Thirty-five descriptions that say *install this and write these files* may be better as one module with settings than as thirty-five modules. Left open deliberately; it is a question about the shape of the catalogue, not about whether to have one. + +## Accepted, 2026-09-29, against what was built + +*Marked in a grooming pass: the mesh was built to this record and the record still said `proposed`.* + +The proposal is the arrangement that exists. `mesh-catalog` holds descriptions of software we did +not write and the programs that provision it, and holds neither the mesh's own components nor an +application's own module. The mesh's list of modules is a table in the control plane, filled by +`module add`, and every module records the source it came from with the commit it was read at. + +**One half is not built: `module check` as a command on the control plane's binary.** A manifest is +still validated by a test that reaches into the control plane's internals — which works for this +catalogue and gives nothing at all to somebody describing their own application in their own +repository, which this record says is the case that matters most. That is +[issue 148](../04-ISSUES/148-a-manifest-outside-this-catalogue-has-no-check/00-report.md). + diff --git a/02-DECISIONS/0113-the-vault-makes-every-secret.md b/02-DECISIONS/0113-the-vault-makes-every-secret.md index a8ae287..b4b61fa 100644 --- a/02-DECISIONS/0113-the-vault-makes-every-secret.md +++ b/02-DECISIONS/0113-the-vault-makes-every-secret.md @@ -1,6 +1,6 @@ --- topic: what runs on it -status: proposed +status: accepted date: 2026-09-25 deciders: jochen reconstructed: false @@ -275,3 +275,11 @@ On acceptance, each of these is superseded or amended by this record, not edited everything a module needs is a requirement - [Issue 095](../04-ISSUES/095-a-module-assigned-after-genesis-has-no-broker-account/00-report.md), [issue 103](../04-ISSUES/103-a-container-is-not-recreated-when-a-file-it-reads-changes/00-report.md): what fails today + +## Accepted, 2026-09-29, against what was built + +*Marked in a grooming pass.* The vault is a module providing `secret` at mesh scope, and six +modules in the catalogue require it — so a shared secret is a requirement answered by the vault, +which is what this record asks for. Private keys are still made where they are used and never +travel, which is the other half and was never in question. + diff --git a/02-DECISIONS/0115-one-assignment-of-a-module-per-node.md b/02-DECISIONS/0115-one-assignment-of-a-module-per-node.md index 341a3ff..5936529 100644 --- a/02-DECISIONS/0115-one-assignment-of-a-module-per-node.md +++ b/02-DECISIONS/0115-one-assignment-of-a-module-per-node.md @@ -1,6 +1,6 @@ --- topic: what runs on it -status: proposed +status: accepted date: 2026-09-26 deciders: jochen extends: 0112-a-module-definition-names-no-node-mesh-or-path.md @@ -47,3 +47,10 @@ other boundary already is: the module name. node runs one of each (ADR 0115)" — instead of failing on whichever name collides first. - Multi-tenant asks are answered in the catalogue (a second module definition), not in the control plane. + +## Accepted, 2026-09-29, against what was built + +*Marked in a grooming pass.* The rule is enforced where it cannot be forgotten: `assignment`'s +primary key is `(node, module)`, so a second assignment of one module to one machine is not a thing +the mesh can hold. The record read `proposed` while the schema had already settled it. + diff --git a/02-DECISIONS/README.md b/02-DECISIONS/README.md index 3e1cf39..cbf086a 100644 --- a/02-DECISIONS/README.md +++ b/02-DECISIONS/README.md @@ -207,9 +207,9 @@ python3 00-META/checks/index.py fail if stale - **0099** — [A step that runs once names what it reads, and runs again when it changed](0099-a-step-that-runs-once-names-what-it-reads.md) - **0110** — [A seat is held by one assignment, from a closed set, and it may deliver a provision](0110-a-seat-is-a-module-assignment-from-a-closed-set.md) - **0112** — [A module definition names no node, no mesh and no path: everything it needs is a requirement the mesh resolves](0112-a-module-definition-names-no-node-mesh-or-path.md) -- **0113** — [The vault makes every shared secret, a provider makes resources and data, and the mesh carries both](0113-the-vault-makes-every-secret.md) *(proposed)* +- **0113** — [The vault makes every shared secret, a provider makes resources and data, and the mesh carries both](0113-the-vault-makes-every-secret.md) - **0114** — [A credential two parties hold rotates over two credentials; one a single party holds rotates in place, staged; and retiring a credential never removes what it reached](0114-a-shared-credential-rotates-over-two-credentials.md) *(proposed)* -- **0115** — [One assignment of a module per node: the module's name is the assignment's identity](0115-one-assignment-of-a-module-per-node.md) *(proposed)* +- **0115** — [One assignment of a module per node: the module's name is the assignment's identity](0115-one-assignment-of-a-module-per-node.md) - **0117** — [A machine's uplink is a seat: the mesh configures the manager, never the link](0117-a-machines-uplink-is-a-seat.md) - **0118** — [Undeclaring removes what the mesh made, and gives a unit back the state it was found in](0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md) - **0120** — [A roster fact carries its format as a template: the mesh owns the data, the module owns the format](0120-a-roster-fact-carries-its-format-as-a-template.md) @@ -237,7 +237,7 @@ python3 00-META/checks/index.py fail if stale - **0014** — [No workspace — each module is a standalone package consuming published dependencies](0014-no-npm-workspace.md) - **0015** — [Applications live in their own repository; the monorepo is for the mesh](0015-applications-live-in-their-own-repository.md) - **0016** — [The lab](0016-the-lab.md) -- **0037** — [Where a module lives](0037-where-a-module-lives.md) *(proposed)* +- **0037** — [Where a module lives](0037-where-a-module-lives.md) - **0039** — [What the SDK holds, and what it refuses](0039-what-the-sdk-holds-and-refuses.md) - **0068** — [The lab takes requests, one at a time, and runs each from its own copy](0068-the-lab-takes-requests.md) *(proposed)* - **0069** — [A module is a repository and a path within it](0069-a-module-is-a-repository-and-a-path.md) diff --git a/04-ISSUES/148-a-manifest-outside-this-catalogue-has-no-check/00-report.md b/04-ISSUES/148-a-manifest-outside-this-catalogue-has-no-check/00-report.md new file mode 100644 index 0000000..1bd3f00 --- /dev/null +++ b/04-ISSUES/148-a-manifest-outside-this-catalogue-has-no-check/00-report.md @@ -0,0 +1,37 @@ +--- +status: open +opened: 2026-09-29 +located-in: [mesh-controller cmd/mesh-controller] +--- + +# 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.