Files
hq/02-DECISIONS/0036-a-node-is-a-managed-machine.md
T
jschoubben 72b22830f3 ADRs 0036, 0037, 0038 — what a node is, what the host does, how one joins
0036 (accepted): a node is a managed machine, and disconnection is a situation.
The open question posed a class distinction — full nodes and lesser presences.
There is none. Reachability is state, not kind, which promotes the host's local
store from a component to a requirement: it is what makes disconnection ordinary
rather than exceptional. The reduced contract the question reached for is real
but it is capability, and that belongs in the profile.

0037 (accepted): the host applies, it does not decide. Measured rather than
argued — the absorption is smaller than the machinery that already applies
state, and eight of ten adapters carry no dependency to move. The two that do
open a Postgres connection to the control plane, which inside tier 0 is the one
thing the tier rule exists to forbid. So each concern splits: deciding needs
every other node and stays in tier 2; applying needs root and locality and goes
to tier 0. The host carries ONE concern, of which the six are instances.

0038 (proposed): a node joins by linking first. The operator's two-modes
proposal, adopted as intent and corrected as structure. Two modes is two code
paths where the first runs once per mesh and rots — and the mesh already has
that fault in its worst form, as three hand-run shell scripts. Instead: one
behaviour, two sources of declaration. The first node is not a different kind of
node, it is a node whose mesh is not up yet, and its specialness is temporary
and self-erasing.

0038 also shrinks the migration 0037 called expensive: a joining node never
needs mesh-wide state, because the hard part of the overlay is only needed to
compute the WHOLE mesh. It needs one peer. The rest arrives.

Left open and said so: what may be pushed over the link and how a joining node
proves it is entitled to join, and whether one host can raise the substrate
alone.
2026-08-25 10:34:45 +02:00

76 lines
3.7 KiB
Markdown

---
status: accepted
date: 2026-08-25
deciders: jochen
reconstructed: false
---
# 36. A node is a managed machine, and disconnection is a situation
## Context
[Research 006](../01-RESEARCH/006-mesh-from-scratch/00-overview.md) left open: *"does an
unprivileged node earn a place in the inventory, or only a presence? Decides whether 'node'
means one thing or two."*
The question came from requirement 6 — *Arch Linux only for now; ideally any device, including
phones, on lighter terms* — and from the observation that some machines cannot be fully
managed. A phone will not run the host. A laptop is absent for days.
The question assumed the answer was a **class**: full nodes and lesser ones, with the
inventory recording the first and merely acknowledging the second.
## Considered options
1. **Two classes — nodes and presences.** An unprivileged device gets a lighter record and a
reduced contract. Rejected: it makes "node" mean two things, so every context that reasons
about nodes acquires a branch, and the branch is invisible in the type. The mesh already has
one instance of this shape and it is the one this repository keeps writing issues about —
a declared thing that is only sometimes honoured.
2. **One class, membership by capability.** Everything is a node; what it can do is a property.
Chosen.
## Decision
**A node is a managed machine inside the mesh.** Not a device that is merely known about, not
an unprivileged something. If the mesh does not manage it, it is not a node — it is a client, a
peer, or a thing on the network, and those want their own names rather than a weakened version
of this one.
**A disconnected node is still a node, in a different situation.** Reachability is state, not
class. A node that is switched off, roaming, or behind a connection that has dropped has not
become a lesser kind of thing; it has a last-known state and a pending set of declarations.
The distinction the original question reached for is real, but it is **capability**, not kind —
what this machine can be asked to do — and that belongs in the host's profile, not in the
definition of a node.
## Consequences
- **The inventory has one shape.** No branch, no second record type, no context that must ask
which kind it is holding.
- **Local state is structural, not a convenience.** If disconnection is an ordinary situation
rather than an exception, the host's store is authoritative while disconnected by design —
it is what makes the situation ordinary. This promotes `store/` from a component to a
requirement.
- **Absence is not failure.** A node that has not been seen is in a state, and the mesh must be
able to say which. Anything that treats unreachable as broken will be wrong most of the time
about a laptop.
- **Devices that cannot be managed do not become nodes by being lenient about the word.** A
phone that cannot run the host is not a node under this record. Whether the mesh should reach
such devices at all, and as what, is not decided here and needs its own record if it is
wanted.
- **The reduced-contract idea is not lost, it is relocated.** What a given node can be asked to
do is its profile — the host's capability detection — and varies per machine without varying
what a node is.
## References
- [Research 006](../01-RESEARCH/006-mesh-from-scratch/00-overview.md) — the open question, and
requirement 6 that raised it.
- [ADR 0015](0015-mesh-brokers-nodes-host-agents-think.md) — *nodes host*; this says what a
node is.
- [Issue 007](../04-ISSUES/007-an-installed-package-is-not-a-capability/00-report.md) —
capability as something detected rather than assumed, which is where the reduced contract
now lives.