A module is a repository and a path within it
The design said a module's manifest sits at a repository's root, full stop, which means one repository per module. Nothing that exists is shaped that way: the catalogue holds sixty-seven modules one to a directory, no code repository has a manifest at its root, and the system being replaced has always built a module from a repository and a path. So the builder could be asked to build nothing that exists — pointed at the catalogue it finds no manifest, pointed at a module's source it finds none either. Recorded as a decision because it moves the core modules' manifests beside their source, and corrects the design that said otherwise. Also corrects, in the same document, how the three things the build loop cannot produce actually arrive. They were written as though all three were carried in. Only the control plane is: the registry is pulled from the public internet, and the builder has no route at all — which is now stated as the open one rather than implied to be solved. Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
@@ -2,12 +2,14 @@
|
||||
layer: to-be
|
||||
status: in-progress
|
||||
code:
|
||||
- mesh-catalog modules/builder
|
||||
- mesh-control internal/builder
|
||||
- mesh-control internal/catalogue/build.go
|
||||
- mesh-control internal/inventory/secrets.go
|
||||
- mesh-control cmd/mesh-builder
|
||||
updated: 2026-08-31
|
||||
updated: 2026-09-12
|
||||
decisions:
|
||||
- 02-DECISIONS/0069-a-module-is-a-repository-and-a-path.md
|
||||
- 02-DECISIONS/0009-modules-and-the-graph.md
|
||||
- 02-DECISIONS/0010-delivery.md
|
||||
- 02-DECISIONS/0005-the-node-host.md
|
||||
@@ -39,13 +41,25 @@ resolution, and assigning it brings both. So the module count does not return, b
|
||||
that made it return — *a module is expensive, so put several things in one* — is gone. A module
|
||||
here is cheap: a manifest and, usually, nothing else.
|
||||
|
||||
## One file at the root
|
||||
## One file, at the module's own path
|
||||
|
||||
`module.json`, and a convention somebody can look for beats a setting somebody has to find. It
|
||||
says what the module is, what it provides and requires, what it claims, what capabilities it
|
||||
needs, what it puts on a machine — and, if anything must be produced from the source, what to
|
||||
build.
|
||||
|
||||
**A module is a repository and a path within it** ([ADR 0069](../../02-DECISIONS/0069-a-module-is-a-repository-and-a-path.md)).
|
||||
The manifest sits at that path, beside the source it describes, and everything it declares is
|
||||
produced from there. A module whose path is the repository root is the ordinary case of this and
|
||||
not a separate shape.
|
||||
|
||||
*Corrected 2026-09-12. This section previously said the manifest was at the root, full stop, which
|
||||
made a repository hold exactly one module. Nothing that exists is shaped that way: the catalogue
|
||||
holds sixty-seven modules in their own directories, the system being replaced has always built a
|
||||
module from a repository and a path, and the root-only reading left every existing module
|
||||
unbuildable — pointed at the catalogue the builder finds no manifest, pointed at a module's source
|
||||
it finds no manifest either.*
|
||||
|
||||
## The manifest in the repository is not the manifest the mesh holds
|
||||
|
||||
A resource names an artifact:
|
||||
@@ -345,3 +359,42 @@ first copy comes from outside, exactly once, and every copy after it is the mesh
|
||||
machine across the private network, because a mesh-scoped provision that only answers locally is
|
||||
not one. A container that is running is not a registry that replies, and this project has paid for
|
||||
that distinction once already.*
|
||||
|
||||
## The three the loop cannot build, and there are only three
|
||||
|
||||
*2026-09-12. Written down because it keeps being rediscovered as if it were new, once per
|
||||
component. It is one rule, it has three instances, and the list is closed.*
|
||||
|
||||
**Anything the build loop needs in order to run cannot be delivered by the build loop.** It arrives
|
||||
from outside exactly once, and from then on it is an ordinary module, upgraded like one. What
|
||||
"from outside" means is *not* the same for all three, and saying so matters, because two of them
|
||||
have a route and one does not:
|
||||
|
||||
| What | Why it cannot come through the loop | How it arrives |
|
||||
|---|---|---|
|
||||
| The control plane | It is what installs modules. Nothing can install it before it runs. | **Carried inside the installer** and published once there is a registry ([ADR 0067](../../02-DECISIONS/0067-genesis-is-a-pivot.md)) |
|
||||
| The registry | It *is* where artifacts are delivered from. A store cannot be delivered through itself. | **Pulled from the public internet** — its image is an ordinary public one, never built ([`04-ISSUES/029`](../../04-ISSUES/029-the-artifact-store-cannot-be-delivered-by-the-artifact-store/00-report.md)) |
|
||||
| The builder | It is what builds. Nothing builds it before it runs. | **Nothing yet.** Not carried, not public. See below. |
|
||||
|
||||
**The builder has no route, and this is the open one.** It is built from the control plane's
|
||||
repository, so it cannot be pulled from the public internet like the registry; and the installer
|
||||
carries one image only, the control plane's. So a mesh raised by the installer today has no builder
|
||||
and no way to obtain one, which means it cannot build the catalogue, which means every module
|
||||
waiting on a digest keeps waiting. Whatever answers this — the installer carrying a second image,
|
||||
the control plane's own build producing both, or the first builder being fetched some other way —
|
||||
is the last thing between a raised mesh and a self-upgrading one.
|
||||
|
||||
**There is no fourth.** Everything else the mesh runs is either upstream — a third-party image
|
||||
pulled by digest — or built by the builder from a repository and published to the registry. So the
|
||||
question "how does *this* one get here first?" has an answer for every module without asking it
|
||||
again: if it is not one of the three above, it comes through the loop.
|
||||
|
||||
**A carried artifact is not a differently-pinned artifact.** Once published it is named by a digest
|
||||
the mesh's registry assigned, exactly like everything the builder produces. A reader cannot tell
|
||||
from a running mesh which of its images were carried, and that is the point: carrying is how the
|
||||
first copy arrives, not what it permanently is.
|
||||
|
||||
*Checked by the thing already checked at genesis: after installing, the running control plane is
|
||||
pinned to a digest the mesh's own registry assigned, and not to the id of the image the installer
|
||||
carried. The same check applies to the builder and to the registry, and it is the same check —
|
||||
an image id where a registry digest belongs means the pivot did not finish.*
|
||||
|
||||
Reference in New Issue
Block a user