ADR 0161: what deserves a seat — the vault's seat, the hub as a placement of capacity one, the uplink holder as the machine's dialect; design 26; issues 105, 106, 138

This commit is contained in:
2026-10-01 15:55:15 +02:00
parent 6b8fb562ce
commit f35f3757bb
6 changed files with 162 additions and 15 deletions
+102
View File
@@ -0,0 +1,102 @@
---
topic: the mesh
status: accepted
date: 2026-10-01
deciders: jochen
reconstructed: false
extends: 02-DECISIONS/0126-a-module-declares-its-own-seats.md
---
# 161. What deserves a seat: a role of a module is a seat, a singular fact about machines is a placement with a capacity of one, and a holder's software is the machine's
## Context
Three issues asked the same question from three sides. The vault provides `secret` to the whole
mesh and claims no seat, so nothing refuses a second vault by name
([issue 106](../04-ISSUES/106-the-vault-claims-no-seat/00-report.md)). The hub of the private
network is a placement, `overlay place <node> --hub`, and the issue asked whether "there is exactly
one hub" is a seat's shape ([issue 105](../04-ISSUES/105-the-hub-of-the-private-network-is-not-a-seat/00-report.md)).
Three modules claim the one uplink seat, one per network manager a machine might run, and nothing
checks that the holder names the manager the machine actually runs
([issue 138](../04-ISSUES/138-two-modules-claim-one-seat-and-are-not-interchangeable/00-report.md)).
Read against the code on the day of deciding:
- The mesh's own seats are five by [design 26](../03-DESIGN/01-to-be/26-the-seats.md)'s table and
four in the controller's seed: `mesh-vault` is in the table and not in the seed, and the vault's
definition claims nothing. The design also says `secret` is reserved; no parser or resolution rule
reserves it. A second provider of `secret` would be a second candidate, settled by a pin.
- The store already keeps one hub: a unique index since the overlay's first migration, and the
placing command refuses a second hub naming the first. What 105 observed as silent is not.
[ADR 0121](0121-a-system-seat-is-named-for-its-scope-and-modules-define-their-own.md) decided that
the private network becomes a mesh-scoped seat held by a server module, with client modules —
the overlay is the host's own today, so that seat has nothing to be held by yet.
- A machine's capabilities are its profile, detected by the host at enrolment and never since, and
resolution refuses a module on a machine lacking one it declares, naming the capability. The uplink
holders declare `package-manager` and `service-manager`, which every machine has.
[ADR 0126](0126-a-module-declares-its-own-seats.md) gave the reason the mesh's own seats exist:
**the mesh's own code looks them up by name.** `mesh-store` is an identifier the controller
dereferences, not a convention. That reason decides the first question; the other two are decided
by what a seat is — a role held by a module assignment — and by what the mesh can check.
## Decision
**1. A provision the mesh itself dereferences is delivered by a mesh seat its provider claims.**
The vault's `secret` is one: the controller seals every minted credential with it. `mesh-vault` is
the fifth seat of the mesh's own, mesh-scoped, delivering `secret`, under
[ADR 0079](0079-the-foundation-seats-are-named-after-their-servers.md)'s convention; the vault's
definition claims it; a second provider of `secret` is a second claimant and refused by name. The
word *reserved* leaves design 26: the effect it described is the seat's. Every other mesh-scoped
provision — `smtp`, `oidc-client`, `s3-bucket`, `route`, `acme-ca` and the rest — may have several
providers, and a consumer with several and none local is a person's choice, as the glossary says.
The test for "deserves a seat" is the question 0126 asked: does the mesh's own code find it by name?
**2. A singular fact about machines is a placement with a capacity of one; a singular role of a
module is a seat.** A seat is held by a module assignment and points at it; the hub is a machine,
and the private network is the host's own until 0121's server and client modules exist. So the hub
stays a placement, and what a seat would have given — refusal of a second by name, and the one
named when asked — a placement of capacity one gives: the store keeps one (the unique index), the
placing command refuses a second naming the one that stands, and the overlay listing names it.
0121's seat for the private network stands, deferred with the split it needs. The rule generalises:
a fact of the shape *exactly one machine is X* is a placement checked by the store and said by name,
never a seat with no module to hold it.
**3. A holder of a seat whose role is "speak to what this machine runs" must be the dialect the
machine runs, and the machine says which.** The host's profile gains one capability per network
manager found active — `uplink-networkmanager`, `uplink-systemd-networkd`, `uplink-dhcpcd`, each
`systemctl is-active` of the manager's unit — and each uplink holder declares its own. Assignment
then refuses the wrong holder with the refusal that already exists, naming the capability; nothing
new is judged. The profile is detected again by every apply and travels in the report, and the
controller keeps the latest, so a machine that switches managers is, at its next push, a machine
whose holder lacks a capability: the plan refuses and names it, which is the one thing the machine
is the only one to know. `node-uplink` stays one seat: its three holders are three dialects of one
role, and the capability picks the dialect. One module speaking all three is allowed by this and
built by nobody.
## Consequences
- The controller's seed gains `mesh-vault`; the seat table takes it additively at the next start,
as every seed row does. The vault's definition claims it, one release after the controller.
- The uplink definitions declare their capability one release after the host reports it, or they
are refused on every machine in between; the order is controller (the report carries a profile),
host, then catalogue.
- Design 26 loses the word *reserved* for `secret` and states rules 2 and 3; the uplink row of the
seat table names the capability its holders declare.
- Issue 106 is resolved by rule 1, 105 by rule 2 with nothing to build, 138 by rule 3.
## How this is checked
| Rule | Checked by |
|---|---|
| `mesh-vault` is in the mesh's own set, mesh-scoped, delivering `secret`, and the vault claims it | a catalogue test on the default seats; registration refuses a second claimant by name (`CanHold`'s existing test, with the vault's seat) |
| A second hub is refused naming the first, and the listing names the hub | the overlay command's test; the store's unique index |
| A machine's profile names the network manager it runs, and is renewed by every report | a host detector test per manager; a controller test that a report carrying a profile replaces the stored one |
| An uplink holder on a machine running another manager is refused, naming the capability | the existing capability refusal, exercised by a resolution test with a networkmanager machine and the systemd-networkd holder |
| Live | `mesh-controller.seats` lists `mesh-vault` held by the vault on the control node; `plan` of a machine refuses the wrong uplink holder naming `uplink-<manager>` |
## References
- [ADR 0079](0079-the-foundation-seats-are-named-after-their-servers.md), [ADR 0110](0110-a-seat-is-a-module-assignment-from-a-closed-set.md), [ADR 0117](0117-a-machines-uplink-is-a-seat.md), [ADR 0121](0121-a-system-seat-is-named-for-its-scope-and-modules-define-their-own.md), [ADR 0126](0126-a-module-declares-its-own-seats.md)
- [Design 26 — The seats](../03-DESIGN/01-to-be/26-the-seats.md)
- Issues [105](../04-ISSUES/105-the-hub-of-the-private-network-is-not-a-seat/00-report.md), [106](../04-ISSUES/106-the-vault-claims-no-seat/00-report.md), [138](../04-ISSUES/138-two-modules-claim-one-seat-and-are-not-interchangeable/00-report.md)
+1
View File
@@ -174,6 +174,7 @@ python3 00-META/checks/index.py fail if stale
- **0158** — [A provider with one credential shares it with every consumer, and the vault remakes it for all of them at once](0158-a-provider-with-one-credential-shares-it-with-every-consumer.md)
- **0159** — [A tool call names the machine it is for, every answer says which machine answered, and a holder's runtime serves its seat's verbs](0159-a-tool-call-names-the-machine-and-a-holder-serves-its-seats-verbs.md)
- **0160** — [The mesh issues an assignment's subjects, and a runtime serves what it is issued](0160-the-mesh-issues-an-assignments-subjects-and-a-runtime-serves-what-it-is-issued.md)
- **0161** — [What deserves a seat: a role of a module is a seat, a singular fact about machines is a placement with a capacity of one, and a holder's software is the machine's](0161-what-deserves-a-seat.md)
### Its tiers, from the bottom up