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:
@@ -4,17 +4,17 @@ status: in-progress
|
||||
code: [mesh-host]
|
||||
updated: 2026-08-27
|
||||
decisions:
|
||||
- 02-DECISIONS/0011-how-this-repository-works.md
|
||||
- 02-DECISIONS/0015-a-node-and-how-it-joins.md
|
||||
- 02-DECISIONS/0016-the-node-host.md
|
||||
- 02-DECISIONS/0015-a-node-and-how-it-joins.md
|
||||
- 02-DECISIONS/0015-a-node-and-how-it-joins.md
|
||||
- 02-DECISIONS/0023-delivery.md
|
||||
- 02-DECISIONS/0016-the-node-host.md
|
||||
- 02-DECISIONS/0016-the-node-host.md
|
||||
- 02-DECISIONS/0016-the-node-host.md
|
||||
- 02-DECISIONS/0016-the-node-host.md
|
||||
- 02-DECISIONS/0016-the-node-host.md
|
||||
- 02-DECISIONS/0019-how-this-repository-works.md
|
||||
- 02-DECISIONS/0004-a-node-and-how-it-joins.md
|
||||
- 02-DECISIONS/0005-the-node-host.md
|
||||
- 02-DECISIONS/0004-a-node-and-how-it-joins.md
|
||||
- 02-DECISIONS/0004-a-node-and-how-it-joins.md
|
||||
- 02-DECISIONS/0010-delivery.md
|
||||
- 02-DECISIONS/0005-the-node-host.md
|
||||
- 02-DECISIONS/0005-the-node-host.md
|
||||
- 02-DECISIONS/0005-the-node-host.md
|
||||
- 02-DECISIONS/0005-the-node-host.md
|
||||
- 02-DECISIONS/0005-the-node-host.md
|
||||
---
|
||||
|
||||
# The node host
|
||||
@@ -25,11 +25,11 @@ Tier 0. The one thing ever installed by hand, and the only thing that changes a
|
||||
|
||||
A **statically linked binary that requires nothing to be present** — copy it onto a machine and
|
||||
run it, and that is the whole installation
|
||||
([ADR 0016](../../02-DECISIONS/0016-the-node-host.md)). Written in Go, because the
|
||||
([ADR 0005](../../02-DECISIONS/0005-the-node-host.md)). Written in Go, because the
|
||||
job is system-level and because the host shares no code with any other tier.
|
||||
|
||||
A single binary with one job: **apply declared state on this machine**
|
||||
([ADR 0016](../../02-DECISIONS/0016-the-node-host.md)). Overlay
|
||||
([ADR 0005](../../02-DECISIONS/0005-the-node-host.md)). Overlay
|
||||
membership, packet filtering, packages, services, containers and filesystems are not six
|
||||
concerns it carries; they are six instances of the one.
|
||||
|
||||
@@ -61,7 +61,7 @@ returns it.
|
||||
Three properties, each following a recorded decision:
|
||||
|
||||
**A failed step fails the apply.** Not "logs and continues"
|
||||
([ADR 0023](../../02-DECISIONS/0023-delivery.md)). A partial apply that
|
||||
([ADR 0010](../../02-DECISIONS/0010-delivery.md)). A partial apply that
|
||||
reports success is the mesh's most expensive shape.
|
||||
|
||||
**Each applier reads back.** Setting a value is not evidence the value took. The firewall is
|
||||
@@ -69,7 +69,7 @@ asked whether the rule loaded; conntrack is asked what timeout it holds. This is
|
||||
§5 as a component requirement rather than a review habit.
|
||||
|
||||
**What was applied is recorded after it works, never before**
|
||||
([ADR 0014](../../02-DECISIONS/0014-a-picture-is-read-from-what-runs.md)). A failed apply leaves
|
||||
([ADR 0018](../../02-DECISIONS/0018-a-picture-is-read-from-what-runs.md)). A failed apply leaves
|
||||
the machine in whatever state it reached, and nothing must claim otherwise.
|
||||
|
||||
### store
|
||||
@@ -78,17 +78,17 @@ Local, and **authoritative while disconnected**. Not a cache of the control plan
|
||||
of what this node has applied and what it currently holds.
|
||||
|
||||
This is structural rather than convenient: if disconnection is an ordinary situation rather
|
||||
than an exception ([ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md)), the
|
||||
than an exception ([ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md)), the
|
||||
store is what makes it ordinary. A laptop shut for a week comes back and reconciles; it does
|
||||
not come back and ask what it is.
|
||||
|
||||
### link
|
||||
|
||||
The node's one connection to the control plane, and its security boundary
|
||||
([ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md)).
|
||||
([ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md)).
|
||||
|
||||
It is the broker connection that already exists
|
||||
([ADR 0001](../../02-DECISIONS/0001-nodes-communicate-over-a-broker.md)) — outbound,
|
||||
([ADR 0002](../../02-DECISIONS/0002-nodes-communicate-over-a-broker.md)) — outbound,
|
||||
node-initiated, per-node addressed — carrying **per-node identity instead of a shared
|
||||
credential**. The node owns no password. It owns an identity, and that identity is what it
|
||||
presents.
|
||||
@@ -108,7 +108,7 @@ architecture, a network position.
|
||||
capability is real when it is present, running and working, and the difference is the whole
|
||||
point of detecting it.
|
||||
|
||||
The profile is what makes [ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md)
|
||||
The profile is what makes [ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md)
|
||||
work: a node is a node, and what varies between them is here rather than in the definition.
|
||||
|
||||
### inventory
|
||||
@@ -133,7 +133,7 @@ is the component; that one is what happens to it.
|
||||
## Where a declaration comes from
|
||||
|
||||
One behaviour, two sources
|
||||
([ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md)):
|
||||
([ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md)):
|
||||
|
||||
| Situation | Source |
|
||||
|---|---|
|
||||
@@ -150,7 +150,7 @@ the mesh, and the full peer set arrives derived.
|
||||
|
||||
## What a declaration is
|
||||
|
||||
Settled by [ADR 0016](../../02-DECISIONS/0016-the-node-host.md).
|
||||
Settled by [ADR 0005](../../02-DECISIONS/0005-the-node-host.md).
|
||||
|
||||
**JSON**, because the host has no dependencies to spend and the standard library carries no
|
||||
YAML. **An ordered list of typed resources**, each with a stable identity — the order is stated
|
||||
@@ -187,8 +187,8 @@ Raising the substrate needs six shapes in the host's vocabulary, and **all six a
|
||||
| `directory`, `file` | **built** | no machine dependency at all |
|
||||
| `service` | **built** | running/stopped **and** enabled/disabled at boot — a unit started but not enabled stops being true at the next reboot |
|
||||
| `package` | **built** | present, never upgraded, and **never uninstalled** — the host cannot know what else needs it, so dropping one is *forgotten*, not *removed* |
|
||||
| `container` | **built** | pinned by digest ([ADR 0021](../../02-DECISIONS/0021-the-substrate-and-the-control-plane.md)); identified by a label carrying a digest of the declaration that made it, because a runtime normalises what it is given and that is indistinguishable from drift |
|
||||
| `action` | **built** | bundle-only ([ADR 0016](../../02-DECISIONS/0016-the-node-host.md)); verify is mandatory and is the idempotency check as well as the read-back |
|
||||
| `container` | **built** | pinned by digest ([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)); identified by a label carrying a digest of the declaration that made it, because a runtime normalises what it is given and that is indistinguishable from drift |
|
||||
| `action` | **built** | bundle-only ([ADR 0005](../../02-DECISIONS/0005-the-node-host.md)); verify is mandatory and is the idempotency check as well as the read-back |
|
||||
|
||||
**The parser enforces the boundary rather than the caller remembering it.** `Parse` refuses an
|
||||
action and is what the link uses; `ParseTrusted` permits one and is what the bundle uses. The
|
||||
@@ -205,7 +205,7 @@ until it is done the substrate bootstrap has no end-to-end test.
|
||||
**3 — link and store.** The node connects, receives declarations, and holds what it applied.
|
||||
|
||||
**4 — enrolment.** The one genuinely new mechanism in
|
||||
[ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md); everything else there
|
||||
[ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md); everything else there
|
||||
is configuration of what already runs.
|
||||
|
||||
Stage 1 is deliberately the smallest useful thing. The lab currently raises **empty machines**
|
||||
@@ -216,7 +216,7 @@ that, and every later stage is tested by a lab that already works.
|
||||
|
||||
**The lab is the harness.** A scenario places a host on a machine and asserts what it did —
|
||||
against a real hypervisor, with the boundary never mocked
|
||||
([ADR 0013](../../02-DECISIONS/0013-a-test-defends-a-decision.md)).
|
||||
([ADR 0017](../../02-DECISIONS/0017-a-test-defends-a-decision.md)).
|
||||
|
||||
Each decision above owes a test:
|
||||
|
||||
@@ -239,7 +239,7 @@ Each decision above owes a test:
|
||||
package, a unit, a container and a dataset *are*. Nothing has measured that surface, and it is
|
||||
the residue of the question [`host-size.md`](../../01-RESEARCH/006-mesh-from-scratch/host-size.md)
|
||||
answered.
|
||||
- **Rescue.** [ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md) suggests it is
|
||||
- **Rescue.** [ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md) suggests it is
|
||||
a node whose local state is discarded so the mesh re-derives it, and does not decide it.
|
||||
- **What may expire.** An identity needing refresh to stay valid would make a laptop fail for
|
||||
being a laptop ([ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md)).
|
||||
being a laptop ([ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md)).
|
||||
|
||||
Reference in New Issue
Block a user