The graph had no owner: what modules are, what they require, what they claim and what they are built against all sat in the control plane because that is where it was written first. The control plane's own test says otherwise — anything a single machine could answer alone is not its work, and what a module needs requires no knowledge of any node. So the catalogue becomes a core module beside the control plane and the builder, owning the graph and serving tools over it. The control plane consumes it, which is the opposite of what the tiers suggest and is therefore stated rather than inferred. That makes the catalogue a fourth thing that cannot arrive through the ordinary path, so the claim written this morning that the list was closed at three is corrected. All four are answered by one mechanism instead: the installer carries an init builder and the core modules are built on the machine, so what is carried is a builder rather than a result and nothing is left without a route. Two things are open and named rather than assumed: where the init builder clones from, given the forge normally runs on the mesh it would be rebuilding, and what it publishes into, given the registry is installed later in the order today. Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
9.9 KiB
layer, status, code, updated, decisions
| layer | status | code | updated | decisions | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| to-be | in-progress |
|
2026-09-12 |
|
Raising a mesh
How a mesh comes into existence on machines that have none, and how a machine joins one that already exists. This is the procedure an operator runs. It is not a description of the lab, and the lab does not have one of its own.
Two moments, and only two
A mesh is raised once and joined many times, and the two are not variations of each other.
Genesis happens on one machine, when there is no mesh. Nothing can be asked, nothing can be granted, and nothing has been published anywhere. It is the only moment at which the ordinary rules cannot all hold at once, and it is resolved by a pivot (ADR 0067).
Joining happens on every machine after the first, and it is ordinary. A mesh exists, so it can be asked for a token and told what the machine should be. Joining installs the host and nothing else: no temporary anything, no substrate raised by hand, no registry.
Confusing the two is what produced a procedure that only ever worked in a fixture. A bed that raises four machines the same way has not tested genesis at all — it has tested joining, four times, with the first one hand-fed.
Genesis is decided to change, and has not yet
2026-09-12. ADR 0070 settles that the installer carries an init builder rather than the control plane's image, and that the core modules — control plane, catalogue, builder — are built on the machine before a mesh exists to install anything. One thing is carried, and it is a builder rather than a result, which is what gives the builder and the catalogue a route they did not have.
The section below describes what the installer does today, which is to carry the control plane's image and publish it once there is a registry. It is kept as written because it is true of the program that exists, and replacing it with the intention would leave nothing describing the thing anybody actually runs. The order changes when the init builder is built; the pivot does not.
Genesis
The installer is a single program carrying the control plane's image inside it. That is what makes genesis possible without a network to fetch from and without a registry to name: the image is present because the installer is present.
It proceeds in one direction, and every step is safe to run again.
First it refuses to start if the machine is not ready. A container runtime, the ability to write where it must write, the host binary where it expects it. A machine that is not ready is told what is missing rather than half-changed.
Then it loads the carried image and describes what the machine will become. The image is named by the digest of its own configuration — content-addressed and unforgeable, and requiring nothing to have served it. This is legal precisely where nothing could have served one, and nowhere else.
Then it raises the substrate and a temporary control plane, and waits for that control plane to answer. At this point the machine is a mesh of one node with nothing joined to it.
Then the machine joins the mesh it is itself running. It enrols, and an agent runs on it. Being heard from once is not the same as an agent running, and the installer checks both, because enrolling is itself the thing that makes a mesh hear from a machine.
Then it installs a registry, so the mesh has somewhere to keep its own images.
Then it publishes the control plane's image to that registry, which is the moment the image
first receives a digest assigned by something other than itself. This is the carrying step, and it
is the same step for all three things the build loop cannot produce for itself — the control plane,
the registry, and the builder. The rule and its closed list are in
12-a-module-repository.
Then it installs the control plane again, as an ordinary module pinned to that digest, and drops the temporary one. The pivot is complete: what raised the mesh is gone, and what runs is a module like any other. From here the mesh can build and roll out its own upgrades, including to the thing that runs it.
After the pivot, and still part of installing
Genesis ends with a mesh of one that runs, and that is not the same as a mesh that works. What it has is a control plane, a store, a queue and a registry. What it cannot yet do is produce anything — and almost every module in the catalogue is waiting to be produced, because a manifest names what its artifacts are and nothing has made them.
So installing continues:
The builder arrives. It is a module like any other and is assigned to a machine like any other,
but it cannot be built by the thing it is — see
12-a-module-repository.
How it arrives is unsettled, and it is the one gap that stops everything after this paragraph
from being possible on a machine nobody is sitting at.
The core modules are built. Each is named by a repository and a path (ADR 0069), and the builder is asked for each in turn: it clones, reads the manifest at that path, produces what it declares, publishes each artifact into the mesh's own registry, and hands back the module with its artifacts pinned and the commit recorded. The mesh records that, and from then on the module is described by something it made rather than by a placeholder.
The control plane is built like the rest. It was carried in and published once, which got the mesh running; building it from its own repository and path is what makes it upgradeable. The first time that happens is the moment the mesh stops depending on the installer for anything.
And then the catalogue. Every module with source of its own is built the same way. Until this has happened a mesh can install only what is public or carried, which is the substrate and little else.
Only after all of that is the ordinary loop available: change a module's source, the mesh notices its own copy is older than the source, rebuilds it, and rolls it out. That loop is what makes moving services across one at a time possible, so it is part of installing rather than something that comes later.
What remains after that belongs to somebody else: adding machines, and deciding what they run.
Joining
A machine joins with the host binary and a token. It does not raise a substrate, does not install a registry, and is never enrolled twice. The mesh already knows how to tell a machine what to be; joining is the point at which a machine starts listening.
Where the line falls
The installer owns everything that is the mesh's own. The lab owns only what is the lab's: raising virtual machines, giving them addresses that resolve nowhere, and injecting faults.
The lab runs the installer. It does not describe installation. This is the whole point. A second description kept in step with the first is the arrangement that already failed — the fixture invented a registry that exists in no production, and hid two separate faults for as long as it existed. Anything the lab must do that the installer does not is either a lab concern or a hole in the installer, and saying which is a decision, not a convenience.
What is not yet true
Stated plainly, because a document that implies otherwise is worse than none.
The installer is not packaged. It builds from source. An operator raising a first machine still needs a toolchain and a working tree, which is most of the burden the installer exists to remove.
A mesh cannot say how it was raised. Nothing afterwards can contradict a claim that a machine was brought up the supported way, so the rule that it must be is, today, unenforced.
The init builder is not built. Until it is, the installer carries the control plane's image and nothing gives a fresh mesh a builder or a catalogue, so the paragraphs above describing the core modules being built describe something that cannot yet start.
A machine has no account for a registry that asks for one. The mesh grants a consumer a credential for a database; it does not yet do so for the store its own images live in. Genesis avoids the question by carrying the image it needs, which makes this a joining problem and a pulling problem, not a genesis one.
How these rules are checked
| Rule | Checked by |
|---|---|
| Genesis works on a machine that is not the lab | The bed raises its first machine by running the installer, not around it. A bed that stops doing so fails its own acceptance check. |
| The other machines join, and are not re-raised | The bed gives them the host binary and a token only. A second enrolment of the first machine is a failure, not a no-op. |
| Every step may be run again | The installer is re-run against a raised machine and must change nothing and report why. |
| An image is named exactly | A machine refuses a bundle naming an image by tag. The refusal is exercised, not assumed. |
| The installer is what installed this | Nothing. See above. |
| The builder can arrive on a fresh mesh | Nothing. There is no route for it yet. |
| A core module is built rather than only carried | The control plane is rebuilt from its own repository and path, and the running mesh is upgraded to the result — the same path any module takes. |
| Installing produced a mesh that can produce | After installing, a module with source of its own is asked for and comes back pinned to a digest this mesh's registry assigned, not to a placeholder. |