Files
hq/02-DECISIONS/0073-the-installer-carries-a-builder.md
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

95 lines
5.6 KiB
Markdown

---
topic: the tiers
status: accepted
date: 2026-09-13
deciders: jochen
reconstructed: false
extends: 0070-the-catalogue-owns-the-module-graph.md
---
# 73. The installer carries a builder, and the registry stays where it is
## Context
[ADR 0070](0070-the-catalogue-owns-the-module-graph.md) decided that genesis builds rather than
carries, and [ADR 0071](0071-where-genesis-gets-its-source.md) 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](../04-ISSUES/044-the-runtime-every-module-builds-on-cannot-be-built-by-the-mesh/00-report.md)
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](0071-where-genesis-gets-its-source.md)),
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](0033-the-substrate-is-a-store-and-a-broker.md)'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](0033-the-substrate-is-a-store-and-a-broker.md) 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](0067-genesis-is-a-pivot.md) 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`](../03-DESIGN/01-to-be/17-raising-a-mesh.md) 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`](../03-DESIGN/01-to-be/12-a-module-repository.md) 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](../04-ISSUES/042-nothing-gives-a-node-an-account-for-a-registry/00-report.md)).