Files
hq/02-DECISIONS/0073-the-installer-carries-a-builder.md
T
jschoubben aabaaf2bb4 Rewrite 0073: the registry does not move, and the argument fails
Written an hour ago claiming a produced image must be published before anything
can fetch it, so the registry had to precede the control plane. The premise is
false: the machine that builds the image is the machine that runs it, and the
temporary control plane names a built image exactly as it names a carried one —
by the digest of its own configuration, which requires nothing to have served
it. Building changes where the bytes came from, not where they are.

Rewritten rather than superseded because nothing has been built on it and
nobody has read it: a record that contradicts itself is a draft, not a decision.
The argument is kept, because it was asked for and a negative answer is the
result.
2026-09-13 03:22:05 +02:00

5.6 KiB

topic, status, date, deciders, reconstructed, extends
topic status date deciders reconstructed extends
the tiers accepted 2026-09-13 jochen false 0070-the-catalogue-owns-the-module-graph.md

73. The installer carries a builder, and the registry stays where it is

Context

ADR 0070 decided that genesis builds rather than carries, and ADR 0071 settled where it clones from. Two questions were left open, and the design record names them as the one gap that stops a fresh mesh from being able to produce anything at all: how the builder arrives, and what it publishes into.

Today the installer carries the control plane's image inside itself. That works, and it is why genesis needs no registry: nothing is ever fetched, because the one image that matters is already present. The cost is that the mesh which results holds an artifact it did not make, cannot rebuild, and knows nothing about — no version, no source, no edges. That is the same shape as the fault issue 044 recorded for the shared runtime, and fixing it there while shipping it here on every new mesh would be a strange place to stop.

Decision

The installer carries a builder, and nothing else. One artifact, not a growing set. It clones the source at a named commit, checks what it got (ADR 0071), and produces the control plane from the same repository and path that any later rebuild of it would use. What raises the mesh is therefore the same thing that will maintain it, and there is no second mechanism kept in step with the first.

The registry does not move, and the argument for moving it does not survive being made.

It was put this way: a produced image has to be put somewhere before anything can fetch it, so the registry must now precede the control plane, and ADR 0033's answer to that question has to flip.

It does not, because the premise is false. The thing that builds the image and the machine that runs it are the same machine. A built image is already in that machine's container runtime, and the temporary control plane names it exactly as it names a carried one — by the digest of its own configuration, a local identity that requires nothing to have served it. Building changes where the bytes came from. It does not change where they are.

is it substrate? must it precede the control plane?
the store yes yes — there is nowhere else to put the control plane's state
the broker yes yes — the control plane reaches a machine only over it
the image registry yes — it cannot grant itself a repository still no — the first machine neither fetches the control plane nor needs to, whether the image was carried in or made here

So the registry stays where ADR 0033 put it: substrate by role, ordinary by delivery, installed by the temporary control plane as its first act. The bundle carries two services and a control plane, as it did. What publishes into the registry is unchanged too — the existing step that pushes the control plane's image into it, which is the moment that image first receives a digest assigned by something other than itself. It now pushes something this mesh built rather than something it was handed.

Consequences

Genesis gains one step and changes no others. A build happens before the image is loaded. The pivot described in ADR 0067 survives exactly as written, because the step it pivots on never cared where the image came from.

A fresh mesh can produce from the moment it exists. The builder is present before the control plane is, so the core modules, the catalogue and the builder's own module can be built in the ordinary way rather than waiting for somebody to carry them in. The paragraphs in 17-raising-a-mesh that describe this were describing something that could not start; they can start now.

Genesis needs more of the outside world. Carrying an image needed nothing but the installer. Building one needs the source, and whatever the build itself reaches for. This is a real cost and is not waved away: it makes genesis fail in more ways, all of them at a step that says what it was doing. It is accepted because the alternative is a mesh that cannot rebuild its own control plane, which fails in exactly one way, silently, later, and for ever.

A pre-built bundle remains possible and is not this. Nothing here forbids delivering artifacts rather than building them; it fixes where they may come from. A bundle of pre-built core modules is an export of a mesh that built them, carrying what the catalogue knows about each alongside the artifact itself — so that loading one leaves the graph in the state building would have left it. A bundle that carries images without that is the thing this decision rejects, whoever ships it.

What this does not decide

Whether the builder's own module is carried or built. It builds everything else; what installs it as an ordinary module afterwards, so that it too can be upgraded, is the same closed-list question 12-a-module-repository already holds, and is unchanged by this.

How a machine authenticates to a registry that asks it to. Genesis raises its own and reaches it over the loopback, so this remains a joining problem (issue 042).