Consolidate: 65 decision records to 23
Every remaining cluster merged. Each was one design that had been split across
several records because it was worked out over days rather than at once.
the node host 8 -> 1 applies not decides, depends on nothing,
per operating system, root service, the
launcher, episodic, what a declaration is,
actions from the bundle only
a node and how it joins 4 -> 1 what a node is, joining, the link as
security boundary, the enrolment token
modules and the graph 7 -> 1 everything is a module, no domain modules,
three edges, provisioning, the core library
substrate and control 6 -> 1 the test, seven contexts, one control plane,
plane the authority is not a database, the named
products, the pinned bundle
connectivity 3 -> 1 a route is a grant, reachability declared,
filter rules
delivery 5 -> 1 reconciliation not a pipeline, artifacts,
the three silos, a failed step, the verdict
the lab 5 -> 1 (earlier)
how this repository 10 -> 1 (earlier)
works
Nothing was dropped. Each consolidated record carries the reasoning of the ones
it absorbs -- the measurements, the incidents, the alternatives rejected --
because that reasoning is the only reason to keep a record at all. What is gone
is the fragmentation: eight files to read to understand tier 0, when tier 0 is
one component.
The four superseded records went too. They existed to point at their
successors, and the successors now contain what they said.
The checker made this safe. Each merge left dangling links -- 38 files after
the host merge alone -- and it named every one. Nothing was found by reading,
and a manual pass would certainly have missed some, including references inside
AGENTS.md which every session loads.
This commit is contained in:
@@ -5,16 +5,16 @@ code: [mesh-host]
|
||||
updated: 2026-08-27
|
||||
decisions:
|
||||
- 02-DECISIONS/0019-how-this-repository-works.md
|
||||
- 02-DECISIONS/0036-a-node-is-a-managed-machine.md
|
||||
- 02-DECISIONS/0037-the-host-applies-it-does-not-decide.md
|
||||
- 02-DECISIONS/0038-a-node-joins-by-linking-first.md
|
||||
- 02-DECISIONS/0039-the-link-is-the-security-boundary.md
|
||||
- 02-DECISIONS/0008-a-failed-step-fails-the-job.md
|
||||
- 02-DECISIONS/0041-the-host-depends-on-nothing.md
|
||||
- 02-DECISIONS/0043-a-declaration-is-an-ordered-list-of-owned-resources.md
|
||||
- 02-DECISIONS/0057-the-host-is-a-root-service-installed-as-a-package.md
|
||||
- 02-DECISIONS/0060-the-host-is-built-per-operating-system.md
|
||||
- 02-DECISIONS/0061-the-host-asks-an-init-for-start-and-restart.md
|
||||
- 02-DECISIONS/0036-a-node-and-how-it-joins.md
|
||||
- 02-DECISIONS/0037-the-node-host.md
|
||||
- 02-DECISIONS/0036-a-node-and-how-it-joins.md
|
||||
- 02-DECISIONS/0036-a-node-and-how-it-joins.md
|
||||
- 02-DECISIONS/0058-delivery.md
|
||||
- 02-DECISIONS/0037-the-node-host.md
|
||||
- 02-DECISIONS/0037-the-node-host.md
|
||||
- 02-DECISIONS/0037-the-node-host.md
|
||||
- 02-DECISIONS/0037-the-node-host.md
|
||||
- 02-DECISIONS/0037-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 0041](../../02-DECISIONS/0041-the-host-depends-on-nothing.md)). Written in Go, because the
|
||||
([ADR 0037](../../02-DECISIONS/0037-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 0037](../../02-DECISIONS/0037-the-host-applies-it-does-not-decide.md)). Overlay
|
||||
([ADR 0037](../../02-DECISIONS/0037-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 0008](../../02-DECISIONS/0008-a-failed-step-fails-the-job.md)). A partial apply that
|
||||
([ADR 0058](../../02-DECISIONS/0058-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
|
||||
@@ -78,14 +78,14 @@ 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 0036](../../02-DECISIONS/0036-a-node-is-a-managed-machine.md)), the
|
||||
than an exception ([ADR 0036](../../02-DECISIONS/0036-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 0039](../../02-DECISIONS/0039-the-link-is-the-security-boundary.md)).
|
||||
([ADR 0036](../../02-DECISIONS/0036-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,
|
||||
@@ -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 0036](../../02-DECISIONS/0036-a-node-is-a-managed-machine.md)
|
||||
The profile is what makes [ADR 0036](../../02-DECISIONS/0036-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 0038](../../02-DECISIONS/0038-a-node-joins-by-linking-first.md)):
|
||||
([ADR 0036](../../02-DECISIONS/0036-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 0043](../../02-DECISIONS/0043-a-declaration-is-an-ordered-list-of-owned-resources.md).
|
||||
Settled by [ADR 0037](../../02-DECISIONS/0037-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 0046](../../02-DECISIONS/0046-the-installer-fetches-what-it-pins.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 0047](../../02-DECISIONS/0047-the-bundle-may-carry-actions-the-link-may-not.md)); verify is mandatory and is the idempotency check as well as the read-back |
|
||||
| `container` | **built** | pinned by digest ([ADR 0048](../../02-DECISIONS/0048-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 0037](../../02-DECISIONS/0037-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 0039](../../02-DECISIONS/0039-the-link-is-the-security-boundary.md); everything else there
|
||||
[ADR 0036](../../02-DECISIONS/0036-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**
|
||||
@@ -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 0038](../../02-DECISIONS/0038-a-node-joins-by-linking-first.md) suggests it is
|
||||
- **Rescue.** [ADR 0036](../../02-DECISIONS/0036-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 0036](../../02-DECISIONS/0036-a-node-is-a-managed-machine.md)).
|
||||
being a laptop ([ADR 0036](../../02-DECISIONS/0036-a-node-and-how-it-joins.md)).
|
||||
|
||||
Reference in New Issue
Block a user