The catalogue owns the module graph, and genesis builds rather than carries
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
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
---
|
||||
topic: the tiers
|
||||
status: accepted
|
||||
date: 2026-09-12
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
extends: 0067-genesis-is-a-pivot.md
|
||||
---
|
||||
|
||||
# 70. The catalogue owns the module graph, and genesis builds rather than carries
|
||||
|
||||
## Context
|
||||
|
||||
**The module graph has no owner.** What modules exist, what each requires and provides, what each
|
||||
claims, what each is made of — all of it lives inside the control plane because that is where it
|
||||
was first written, not because anything decided it belonged there.
|
||||
|
||||
**The control plane's own test says it does not belong there.**
|
||||
[`06-the-control-plane`](../03-DESIGN/01-to-be/06-the-control-plane.md) defines the tier as
|
||||
*everything that needs to know about more than one node*, and states the corollary plainly:
|
||||
anything a single machine could answer alone is not the control plane's. What a module is, and
|
||||
what it needs, requires no knowledge of any node whatsoever.
|
||||
|
||||
**And nothing can query it.** The graph is the thing that answers *what must be rebuilt when this
|
||||
changes*, *what would break if this were removed*, and *what can be installed here* — and today it
|
||||
is reachable only as control-plane internals. [ADR 0009](0009-modules-and-the-graph.md) already
|
||||
decided that a build edge is derived, that an artifact is stale when anything it was built against
|
||||
moved, and that the rebuild set is therefore computable. None of that has anywhere to live.
|
||||
|
||||
**Genesis currently carries an image, and cannot produce a builder at all.**
|
||||
[ADR 0067](0067-genesis-is-a-pivot.md) has the installer carry the control plane's image. That
|
||||
works, but it leaves the builder with no route onto a fresh mesh — it cannot be fetched from the
|
||||
public internet, because the mesh builds it, and the installer carries one image only. So a raised
|
||||
mesh cannot build anything, including the modules it is made of.
|
||||
|
||||
## Decision
|
||||
|
||||
**The catalogue is a core module, beside the control plane and the builder, and it owns the module
|
||||
graph.** Modules, what they require and provide, what they claim, their dependencies and their
|
||||
build edges, assignments and configuration — the catalogue holds them and serves tools over them:
|
||||
install a module, query what is available and what it needs, query the graph, query and update
|
||||
settings.
|
||||
|
||||
**It is one per mesh**, expressed the way the control plane already expresses it — a claim scoped
|
||||
to the mesh, not a new mechanism.
|
||||
|
||||
**The control plane consumes it.** Resolving what a module requires into an actual binding, and
|
||||
composing what a machine should be, both need to know what modules are. So the dependency runs
|
||||
from the control plane to the catalogue, which is the opposite of what the tiers suggest and is
|
||||
therefore written down here rather than left to be inferred.
|
||||
|
||||
**Genesis builds the core modules rather than carrying them.** The installer ships an *init
|
||||
builder* — the one thing carried — which is started, clones the source, and builds the control
|
||||
plane, the catalogue and the builder. The installer then raises a temporary control plane, which
|
||||
installs the catalogue, registers the permanent control plane and the builder, and assigns all
|
||||
three to the first machine. The temporary control plane stops; the installer verifies that the
|
||||
permanent one answers and can query the graph. The builder then sees a catalogue in its initial
|
||||
state and builds the core modules into it.
|
||||
|
||||
**So exactly one thing is carried, and it is a builder rather than a result.** That is the
|
||||
difference from [ADR 0067](0067-genesis-is-a-pivot.md), which carried the control plane's image:
|
||||
carrying a builder produces every core module on the machine, including the builder itself, so
|
||||
there is no component left without a route.
|
||||
|
||||
## Consequences
|
||||
|
||||
The catalogue joins the small set of things that cannot arrive through the ordinary path, because
|
||||
it cannot be installed by something that needs it in order to install anything. It arrives the same
|
||||
way everything else does under this record — built by the init builder before the mesh can install
|
||||
anything — so the set is answered by one mechanism rather than three special cases.
|
||||
|
||||
The rebuild fan-out gains a home. *What was this built against* and *what must rebuild now* are
|
||||
questions about the graph, and the graph now has an owner to hold the edges and answer them.
|
||||
|
||||
The catalogue holds state, so it owns a store in the substrate's database, the same way the control
|
||||
plane's contexts do. That is the mesh's own store and not the `postgres` module, which is a
|
||||
provider other modules consume.
|
||||
|
||||
A mesh without a catalogue cannot resolve anything, where previously it merely lacked an interface.
|
||||
That is the cost of ownership over surfacing, and it is deliberate: one owner beats two copies.
|
||||
|
||||
## Open, and to be settled before this is built
|
||||
|
||||
**Where the init builder clones from.** [ADR 0067](0067-genesis-is-a-pivot.md) rejected building
|
||||
from source at genesis partly because the source lives in a forge that runs on the mesh, so a
|
||||
total rebuild would need the mesh it is rebuilding. Carrying a builder answers the toolchain half
|
||||
of that objection and not this half. Genesis must therefore name a source that exists before the
|
||||
mesh does.
|
||||
|
||||
**What the init builder publishes into.** Building produces artifacts that must be pinned by a
|
||||
digest a registry assigned, and today the registry is installed after the machine has joined. If
|
||||
the core modules are built first, the registry has to exist first, so the substrate's order needs
|
||||
restating rather than assumed.
|
||||
|
||||
**Where the line falls between the catalogue and the control plane.** Claims and assignments need
|
||||
to know about every node, which by the control plane's own test is its work. Whether the catalogue
|
||||
holds them and asks, or the control plane holds them and the catalogue surfaces them, is not
|
||||
settled here.
|
||||
|
||||
## How this is checked
|
||||
|
||||
| Rule | Checked by |
|
||||
|---|---|
|
||||
| The catalogue owns the graph | The control plane answers *what does this module require* by asking the catalogue, and a mesh whose catalogue is stopped cannot resolve — observed, not assumed. |
|
||||
| One per mesh | A second catalogue assigned anywhere in the mesh is refused by the claim, and the refusal is exercised. |
|
||||
| Genesis builds rather than carries | The installer carries exactly one artifact, and after installing, every core module is pinned to a digest the mesh's own registry assigned. |
|
||||
| The builder has a route | A mesh raised by the installer, with no hand-placed image, can build a module. |
|
||||
@@ -102,6 +102,7 @@ python3 00-META/checks/index.py fail if stale
|
||||
- **0067** — [Genesis is a pivot: a temporary control plane installs the registry that makes it permanent](0067-genesis-is-a-pivot.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)
|
||||
- **0070** — [The catalogue owns the module graph, and genesis builds rather than carries](0070-the-catalogue-owns-the-module-graph.md)
|
||||
|
||||
### What runs on them, and how it gets there
|
||||
|
||||
|
||||
Reference in New Issue
Block a user