Order the records the way the system is learned

Jochen asked whether the order made sense. It did not -- it followed when
things happened to be decided, which after consolidation is fictional anyway
since record 5 alone folds decisions taken across a week.

Concretely wrong before: the domain statement sat at 8, after five engineering
rules; the constitution was scattered across 5, 12 and 17; the tiers landed at
15, 16, 21 and 22 with process records in between.

Now it walks: what the mesh is (1-3), its tiers from the bottom up (4-8), what
runs on them and how it gets there (9-10), how it is built (11-16), how it is
checked (17-18), how we work (19-23).

Two things made this safe rather than free. It is a permutation, not a
compaction, so the renames go through temporary names -- otherwise two files
want one slot and one is lost. And the reference rewrite is a single
simultaneous pass, because almost every number moved into a slot another number
was vacating; replacing one at a time would have cascaded and pointed things at
the wrong record while still resolving.

Verified: 284 [ADR NNNN](path) links across the repository, all with matching
text and target.

The ordering principle is now stated in 19 rather than left implicit -- the
repository already said "the numbering is the flow" about its folders, and
there was no reason for the records to be the exception.
This commit is contained in:
2026-08-28 23:30:42 +02:00
parent e1febe8e0f
commit 333356cff3
85 changed files with 471 additions and 465 deletions
+19 -19
View File
@@ -4,14 +4,14 @@ status: designed
code: []
updated: 2026-08-27
decisions:
- 02-DECISIONS/0011-how-this-repository-works.md
- 02-DECISIONS/0016-the-node-host.md
- 02-DECISIONS/0015-a-node-and-how-it-joins.md
- 02-DECISIONS/0021-the-substrate-and-the-control-plane.md
- 02-DECISIONS/0016-the-node-host.md
- 02-DECISIONS/0021-the-substrate-and-the-control-plane.md
- 02-DECISIONS/0022-connectivity.md
- 02-DECISIONS/0016-the-node-host.md
- 02-DECISIONS/0019-how-this-repository-works.md
- 02-DECISIONS/0005-the-node-host.md
- 02-DECISIONS/0004-a-node-and-how-it-joins.md
- 02-DECISIONS/0006-the-substrate-and-the-control-plane.md
- 02-DECISIONS/0005-the-node-host.md
- 02-DECISIONS/0006-the-substrate-and-the-control-plane.md
- 02-DECISIONS/0007-connectivity.md
- 02-DECISIONS/0005-the-node-host.md
---
# The substrate
@@ -27,22 +27,22 @@ Every module that needs a database asks the control plane's provisioning for one
plane needs a database too — and it cannot ask itself, because it is not running yet. That
circularity is not an awkwardness to work around; it *is* the definition. Anything on the wrong
side of it must be raised some other way, and the other way is the bundle the host carries
([ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md)).
([ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md)).
The test, applied:
| | control plane needs it | can it grant itself one? | |
|---|---|---|---|
| a relational store — **PostgreSQL** | its own state lives there | no — provisioning needs the store | **substrate** |
| a message bus — **LavinMQ** | it reaches nodes over it ([ADR 0001](../../02-DECISIONS/0001-nodes-communicate-over-a-broker.md)) | no — it cannot grant itself a virtual host | **substrate** |
| a message bus — **LavinMQ** | it reaches nodes over it ([ADR 0002](../../02-DECISIONS/0002-nodes-communicate-over-a-broker.md)) | no — it cannot grant itself a virtual host | **substrate** |
| an object store — **MinIO** | artifacts and blobs it delivers | no — it needs a bucket to hold them | **substrate** |
| an image registry — **the OCI registry** | images it delivers to nodes | no — it needs a repository | **substrate** |
| an identity provider | only if it delegates authentication | — | **conditional, below** |
| ingress — **Traefik** | not to start; only to be reached by name | — it grants itself one afterwards | **not substrate** ([ADR 0022](../../02-DECISIONS/0022-connectivity.md)) |
| ingress — **Traefik** | not to start; only to be reached by name | — it grants itself one afterwards | **not substrate** ([ADR 0007](../../02-DECISIONS/0007-connectivity.md)) |
| anything else the mesh hosts | no | — | not substrate |
**The role and the product are both written**, here and everywhere
([ADR 0021](../../02-DECISIONS/0021-the-substrate-and-the-control-plane.md)). The role is what the argument
([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)). The role is what the argument
turns on — the test above works on roles, and would give the same answers for a different store.
The product is what actually gets installed and pinned, and a design that names only the role
does not record that the choice was ever made.
@@ -96,19 +96,19 @@ Being substrate and being in the bundle are two different questions:
| PostgreSQL | yes — the control plane's own state lives in it | **yes** — there is nowhere to put that state otherwise |
| LavinMQ | yes — it cannot grant itself a virtual host | **not established** — see below |
| MinIO | yes — it cannot grant itself a bucket | no — nothing is delivered before the mesh exists |
| the OCI registry | yes — it cannot grant itself a repository | no — the first node fetches upstream ([ADR 0021](../../02-DECISIONS/0021-the-substrate-and-the-control-plane.md)) |
| the OCI registry | yes — it cannot grant itself a repository | no — the first node fetches upstream ([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)) |
The three on the bottom rows are **substrate by role and ordinary by delivery**: by the time
they are wanted there is a control plane, and it provisions them the way it provisions anything.
That keeps the bundle to roughly one image rather than four, which is what makes it small enough
for the review [ADR 0016](../../02-DECISIONS/0016-the-node-host.md)
for the review [ADR 0005](../../02-DECISIONS/0005-the-node-host.md)
requires.
**Why pinned:** the bundle is applied when no mesh exists, so nothing can resolve a version, ask
a registry, or check a constraint. What the host carries must already be exact.
**Why references and not payload:** the bundle names images by **digest** and the host fetches
them ([ADR 0021](../../02-DECISIONS/0021-the-substrate-and-the-control-plane.md)). A first node is
them ([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)). A first node is
a real machine with a network; the sealed case is the lab, and the lab places images itself.
Reproducibility comes from pinning the identity of a thing rather than carrying its bytes, which
@@ -136,7 +136,7 @@ container, so a container runtime must be working before anything else happens
is a *package*, not a container.
**Which runtime is detected, not chosen**
([ADR 0016](../../02-DECISIONS/0016-the-node-host.md)): a machine that
([ADR 0005](../../02-DECISIONS/0005-the-node-host.md)): a machine that
already has one keeps it. On a machine with none, the control plane names the package, because
what it is called differs per system. It is:
@@ -145,7 +145,7 @@ what it is called differs per system. It is:
- **adopted rather than installed** when the machine already has one with configuration somebody
chose ([research 012](../../01-RESEARCH/012-the-minimum-viable-node/00-overview.md));
- a package, which needs the machine's own package manager and a network — both permitted by
[ADR 0021](../../02-DECISIONS/0021-the-substrate-and-the-control-plane.md).
[ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md).
So the host's bootstrap vocabulary is six shapes: **package**, **container**, **file**,
**directory**, **service**, and **action**. **All six are built**
@@ -155,7 +155,7 @@ blocked on the host any longer.
**Steps 2 and 3 happen before there is a mesh to do them**, which is why provisioning is part of
the bootstrap rather than a service consumers use later. They are **actions** the bundle
declares and the host runs
([ADR 0016](../../02-DECISIONS/0016-the-node-host.md)) — so the
([ADR 0005](../../02-DECISIONS/0005-the-node-host.md)) — so the
host's vocabulary grows by one shape rather than by one resource type per substrate service.
## Open
@@ -170,7 +170,7 @@ host's vocabulary grows by one shape rather than by one resource type per substr
question about the control plane's internal shape, not about the substrate**, which is why it is
not answered here.
- ~~**Whether the host can do step 2.**~~ **Resolved** by
[ADR 0016](../../02-DECISIONS/0016-the-node-host.md). A service
[ADR 0005](../../02-DECISIONS/0005-the-node-host.md). A service
running on this machine is part of this machine, so the scope was never in question — the real
question was whether the host must learn what a database is, and it must not. The bundle
declares an **action**; the host runs it and verifies it, and what a database means stays with