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:
@@ -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)
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user