ADR 0220: resolver config needs the uplink; retired resolver pieces go
The rule that keeps resolv.conf the mesh's was checked by nothing, and a retired seat and an unused module still read as live options. Amends to-be 26 and 08 to match.
This commit is contained in:
+157
@@ -0,0 +1,157 @@
|
||||
---
|
||||
topic: what runs on it
|
||||
status: accepted
|
||||
date: 2026-10-05
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
extends: 02-DECISIONS/0207-a-module-depends-on-the-node-seats-that-apply-its-resources.md
|
||||
---
|
||||
|
||||
# 220. What a machine asks needs its uplink held, and the retired resolver pieces go
|
||||
|
||||
## Context
|
||||
|
||||
**Three things about a machine's resolver were left half done when the mesh moved to one resolver.**
|
||||
On the production mesh on 2026-10-05, read from the controller's `seats` verb:
|
||||
|
||||
- **`node-dns-resolver` has no holder on any node, and no module in the catalogue claims it.**
|
||||
[ADR 0194](0194-the-mesh-has-one-resolver-and-every-node-asks-it-for-the-meshs-names.md) retired it
|
||||
and the controller kept its row deliberately, *"deleted once nothing claims it"*, because removing a
|
||||
seat a machine still holds makes that machine unresolvable. That condition now holds. The row still
|
||||
stands in the controller's compiled set and in the store's seat table, and the overview still lists
|
||||
it, unheld, beside the seats a mesh actually has.
|
||||
- **The rule that keeps `/etc/resolv.conf` the mesh's is checked by nothing.**
|
||||
[ADR 0117](0117-a-machines-uplink-is-a-seat.md) found that a network manager rewrites the resolver
|
||||
file on every connectivity change unless it is told not to, and gave that telling to the module
|
||||
holding `node-uplink`. It said the condition *"only if NetworkManager runs"* is expressed by
|
||||
assigning the manager's module. Nothing makes anybody do so: `resolv-conf` can be assigned to a
|
||||
machine with no uplink holder, and the file is then replaced the first time a laptop changes
|
||||
network while every surface of the mesh reads green. Today every node holding
|
||||
`node-resolver-config` also holds `node-uplink` — NetworkManager on the home server, the
|
||||
workstation and the laptop, systemd-networkd on the anchor — by care, not by check.
|
||||
- **The catalogue still carries a systemd-resolved split-DNS module**, `resolved-split-dns`, claiming
|
||||
`node-resolver-config`. [ADR 0196](0196-a-node-asks-the-meshs-resolver-first-and-a-public-one-only-when-it-is-silent.md)
|
||||
chose against a stub on every node and says *"There is no `systemd-resolved` module."* It is
|
||||
assigned nowhere. `resolv-conf`'s own resolver file still tells its reader that systemd-resolved or
|
||||
NetworkManager may be assigned *instead* — the opposite of how the roles now divide.
|
||||
|
||||
**A dependency mechanism already exists.** [ADR 0207](0207-a-module-depends-on-the-node-seats-that-apply-its-resources.md)
|
||||
made a module depend on the node seats that apply its resources, derived rather than stated, judged
|
||||
over the node's whole set of assignments, refused at `assign` naming the seat and its possible holders,
|
||||
and refused at composition. [ADR 0210](0210-a-tools-configuration-is-its-seat-holders-and-every-other-module-extends-it-through-the-seat.md)
|
||||
derived a second kind from contributions. What is missing is a dependency that belongs to a *role*
|
||||
rather than to what a module declares.
|
||||
|
||||
## Considered Options
|
||||
|
||||
**For the retired seat:**
|
||||
|
||||
1. **Keep the row until the build seat's retired row goes too, and delete both together.** Rejected:
|
||||
the two have nothing in common but having been retired; one is unclaimed now and the other is not
|
||||
yet known to be.
|
||||
2. **Remove it from the compiled set only.** Rejected: seeding adds a seat a release ships and never
|
||||
removes one ([ADR 0122](0122-a-seat-is-data-a-rename-is-a-database-update.md)), so the store's
|
||||
row, which is the live set, would stay.
|
||||
3. **Remove it from the compiled set and delete the store's row in a numbered migration**, as the
|
||||
artifact store's rename did for its old row. Chosen.
|
||||
|
||||
**For the resolver file and the uplink:**
|
||||
|
||||
1. **Leave it to the operator.** Rejected: it is the failure ADR 0117 describes — the file silently
|
||||
replaced — with the one difference that the operator was told.
|
||||
2. **`resolv-conf` declares the manager's settings itself.** Rejected by ADR 0117 already: which
|
||||
setting depends on which manager runs, and a resolver module that knew about network managers would
|
||||
be the wrong module knowing the wrong thing.
|
||||
3. **A manifest field in `resolv-conf` naming `node-uplink`.** Rejected for the reason ADR 0207
|
||||
rejected its own option 2: a second module claiming the same seat would have to restate it, and
|
||||
one that forgot would pass.
|
||||
4. **The seat carries what its holder needs beside it.** `node-resolver-config` names `node-uplink`;
|
||||
any module claiming the former depends on the latter, derived from the claim and judged exactly as
|
||||
ADR 0207 judges a resource's dependency. Chosen.
|
||||
|
||||
**For the split-DNS module:** keep it for a machine that wants systemd-resolved in charge, or remove it.
|
||||
Kept, it is a second answer to a question ADR 0196 settled, and a claimant the catalogue offers
|
||||
without a record allowing it. Removed.
|
||||
|
||||
## Decision
|
||||
|
||||
**1. `node-dns-resolver` is deleted from the mesh's set.** The controller's compiled set no longer
|
||||
carries it, and a numbered migration of the controller's store deletes its row and any alias naming
|
||||
it. No alias is kept: nothing was renamed, and a manifest still claiming it should be refused at
|
||||
registration, naming the seat. This completes ADR 0194's retirement; nothing it decided changes.
|
||||
|
||||
**2. A seat may name the node seats its holder needs held on the same node.** A module claiming such a
|
||||
seat depends on each of them. The dependency is a third source beside ADR 0207's resources and ADR
|
||||
0210's contributions, and everything ADR 0207 §3 and §4 say of those applies unchanged: met by any
|
||||
module assigned to the node, the claimant included; judged over the node's whole set; refused at
|
||||
`assign` naming the seat and the catalogue's possible holders; refused at composition; and only said,
|
||||
never refused, when no module in the catalogue could hold the needed seat. Unassigning the needed
|
||||
seat's last holder beneath a dependent is refused, naming the dependent. What a seat needs is part of
|
||||
the mesh's definition of the role: compiled with the set, never stored, as ADR 0212 keeps what a seat
|
||||
receives. Adding a need to a seat is a decision, recorded.
|
||||
|
||||
**3. `node-resolver-config` needs `node-uplink`.** The holder that writes the resolver file is right
|
||||
only while the network manager is told to leave it alone, and that telling is the uplink holder's
|
||||
(ADR 0117). Every manager the catalogue knows — NetworkManager, systemd-networkd, dhcpcd — holds
|
||||
`node-uplink`, so the refusal always has a remedy to name.
|
||||
|
||||
**4. `resolved-split-dns` leaves the catalogue.** `resolv-conf` is the only module claiming
|
||||
`node-resolver-config`. Its resolver file's comment says the uplink's holder is required beside it,
|
||||
rather than naming alternatives to assign instead.
|
||||
|
||||
## Consequences
|
||||
|
||||
- **The set reads as the mesh is.** Thirty-seven seats in the compiled set; the overview no longer
|
||||
lists a role nothing can fill.
|
||||
- **A machine cannot be given the mesh's resolver file without its network manager being told to keep
|
||||
off it.** A machine with no manager at all — a static configuration — needs the smallest holder,
|
||||
`dhcpcd`, or a new module holding `node-uplink` for its way of configuring the link. That is the
|
||||
point: such a machine has to say what manages its link before the mesh writes a file the manager
|
||||
could overwrite.
|
||||
- **Order of assignment on a new machine**: the uplink holder before or with `resolv-conf`, in one
|
||||
`assign` when together. On the production mesh nothing changes: every node already holds both.
|
||||
- **The uplink becomes harder to take away.** Unassigning a machine's manager module while
|
||||
`resolv-conf` stays is refused; replacing one manager with another is one act assigning the new and
|
||||
unassigning the old, or the dependent goes first.
|
||||
- **A machine wanting systemd-resolved has no module for it.** A future need for one is a new record,
|
||||
not a revival of the removed module.
|
||||
- **Changing `resolv-conf`'s comment rewrites `/etc/resolv.conf` on every node once**, with the same two
|
||||
nameserver lines and options; only the comment differs.
|
||||
- **The merge order matters.** The controller's tests read the catalogue beside them, and the two
|
||||
changes are judged together: the controller's change and the catalogue's removal merge together,
|
||||
the catalogue's first or in the same window, and the controller rolls out only once its test suite
|
||||
passes against the merged catalogue.
|
||||
|
||||
## How it is checked
|
||||
|
||||
| Rule | Checked by |
|
||||
|---|---|
|
||||
| `node-dns-resolver` is not in the set, and the set has thirty-seven seats | mesh-controller's closed-set unit test on the compiled seats |
|
||||
| The store's row goes with it | the migration, and after rollout the controller's `seats` verb listing no `node-dns-resolver` |
|
||||
| `node-resolver-config` needs `node-uplink`, and a module claiming it depends on the uplink with nothing in its manifest | mesh-controller's seat-dependency tests on the seat definition and on a synthetic claimant |
|
||||
| What a seat needs survives loading the set from the store | a unit test loading the store's rows, which carry no such column |
|
||||
| `resolv-conf` without an uplink holder is refused at `assign`, naming `node-uplink` and its possible holders; beside one, or with one in the same act, it passes; a composition without one is refused | the same tests, and `assign` live |
|
||||
| Unassigning the uplink's last holder beneath `resolv-conf` is refused | an unassign test |
|
||||
| In the catalogue, `resolv-conf` depends on the uplink, dhcpcd, NetworkManager and systemd-networkd each hold it, and `resolv-conf` is the only claimant of `node-resolver-config` | a mesh-controller test reading the catalogue beside it |
|
||||
| Two modules deciding what a machine asks are still refused on one node | the resolver test, now with a synthetic second claimant |
|
||||
| Every node of the live mesh holding `node-resolver-config` also holds `node-uplink` | the controller's `seats` verb, read before this was decided and after it rolls out; `status` reports no unheld dependency |
|
||||
|
||||
## References
|
||||
|
||||
- [ADR 0194](0194-the-mesh-has-one-resolver-and-every-node-asks-it-for-the-meshs-names.md) — retired
|
||||
`node-dns-resolver`; this record deletes it.
|
||||
- [ADR 0196](0196-a-node-asks-the-meshs-resolver-first-and-a-public-one-only-when-it-is-silent.md) — no
|
||||
stub, and so no systemd-resolved module.
|
||||
- [ADR 0117](0117-a-machines-uplink-is-a-seat.md) — the uplink's holder keeps the manager off the
|
||||
resolver file; this record makes that a checked dependency.
|
||||
- [ADR 0121](0121-a-system-seat-is-named-for-its-scope-and-modules-define-their-own.md) — serving and
|
||||
asking as two seats.
|
||||
- [ADR 0207](0207-a-module-depends-on-the-node-seats-that-apply-its-resources.md),
|
||||
[ADR 0210](0210-a-tools-configuration-is-its-seat-holders-and-every-other-module-extends-it-through-the-seat.md) — the dependency mechanism
|
||||
this extends.
|
||||
- [ADR 0122](0122-a-seat-is-data-a-rename-is-a-database-update.md) — the set as data, which is why a
|
||||
deletion is a migration.
|
||||
- [The seats](../03-DESIGN/01-to-be/26-the-seats.md) and
|
||||
[connectivity §2](../03-DESIGN/01-to-be/08-connectivity.md), amended alongside.
|
||||
- mesh-controller `internal/catalogue/seats.go`, `internal/catalogue/seat_dependencies.go`, and the
|
||||
store migration deleting the row; mesh-catalog `modules/resolv-conf`.
|
||||
@@ -318,6 +318,7 @@ python3 00-META/checks/index.py fail if stale
|
||||
- **0214** — [Backups guard against mistakes, stay on the machine, and are declared by the module that owns the data](0214-backups-guard-against-mistakes-and-stay-on-the-machine.md)
|
||||
- **0215** — [The machine's message bus is a node seat, and it is never restarted live](0215-the-machines-message-bus-is-a-node-seat-and-is-never-restarted-live.md)
|
||||
- **0216** — [The agent's configuration is registered through its module, at three scopes, and served as one plugin](0216-the-agents-configuration-is-registered-through-its-module-at-three-scopes-and-served-as-one-plugin.md)
|
||||
- **0220** — [What a machine asks needs its uplink held, and the retired resolver pieces go](0220-what-a-machine-asks-needs-its-uplink-held-and-the-retired-resolver-pieces-go.md)
|
||||
|
||||
### How it is built
|
||||
|
||||
|
||||
@@ -7,14 +7,16 @@ code:
|
||||
- mesh-controller internal/identity/authority.go
|
||||
- mesh-controller cmd/mesh-controller/plan.go (the names the roster publishes)
|
||||
- mesh-controller internal/catalogue/zones.go (the zones a module answers, ADR 0199)
|
||||
- mesh-controller internal/catalogue/seats.go (mesh-dns-resolver, node-hosts-file)
|
||||
- mesh-controller internal/catalogue/seats.go (mesh-dns-resolver, node-hosts-file, node-resolver-config needing node-uplink)
|
||||
- mesh-controller internal/catalogue/seat_dependencies.go (a seat's need checked at assignment, ADR 0220)
|
||||
- mesh-catalog modules/dnsmasq (the mesh's one resolver)
|
||||
- mesh-catalog modules/resolv-conf (what a node asks)
|
||||
- mesh-catalog modules/hosts (a node's /etc/hosts)
|
||||
- mesh-host internal/identity/serving.go
|
||||
- mesh-host internal/apply (the service that reflects a rule set)
|
||||
updated: 2026-10-03
|
||||
updated: 2026-10-05
|
||||
decisions:
|
||||
- 02-DECISIONS/0220-what-a-machine-asks-needs-its-uplink-held-and-the-retired-resolver-pieces-go.md
|
||||
- 02-DECISIONS/0199-a-module-that-answers-names-declares-its-zone-and-a-nodes-hosts-file-is-one-modules.md
|
||||
- 02-DECISIONS/0196-a-node-asks-the-meshs-resolver-first-and-a-public-one-only-when-it-is-silent.md
|
||||
- 02-DECISIONS/0194-the-mesh-has-one-resolver-and-every-node-asks-it-for-the-meshs-names.md
|
||||
@@ -374,10 +376,21 @@ public names keep resolving then, and `.internal` is never asked of a public res
|
||||
answers. Containers take the same two from their machine, the runtime copying non-loopback resolvers
|
||||
into every container, so the runtime is given no `dns` of its own
|
||||
([ADR 0196](../../02-DECISIONS/0196-a-node-asks-the-meshs-resolver-first-and-a-public-one-only-when-it-is-silent.md),
|
||||
replacing ADR 0194's per-node `systemd-resolved` stub).
|
||||
replacing ADR 0194's per-node `systemd-resolved` stub). `resolv-conf` is the one module the catalogue
|
||||
offers for it; the systemd-resolved split-DNS module that once claimed the same seat is gone
|
||||
([ADR 0220](../../02-DECISIONS/0220-what-a-machine-asks-needs-its-uplink-held-and-the-retired-resolver-pieces-go.md)).
|
||||
|
||||
**That file stays the mesh's only beside the uplink.** A network manager rewrites `/etc/resolv.conf`
|
||||
on every connectivity change unless it is told not to, and the module holding `node-uplink` is what
|
||||
tells it ([ADR 0117](../../02-DECISIONS/0117-a-machines-uplink-is-a-seat.md)). So
|
||||
`node-resolver-config` needs `node-uplink` held on the same node: assigning the resolver file to a
|
||||
machine with no uplink holder is refused, naming the managers' modules that could hold it, and taking
|
||||
the last uplink holder from beneath it is refused too
|
||||
([ADR 0220](../../02-DECISIONS/0220-what-a-machine-asks-needs-its-uplink-held-and-the-retired-resolver-pieces-go.md)). *Checked by the controller's seat-dependency tests and by `assign` live.*
|
||||
|
||||
**No node holds a copy.** The per-node resolver, its zones file and the mesh's region of `/etc/hosts`
|
||||
go: every resolution fault found on 2026-10-03 was a copy disagreeing with the truth — a hosts file
|
||||
go, and the per-node resolver's seat with them, deleted from the set once nothing claimed it
|
||||
([ADR 0220](../../02-DECISIONS/0220-what-a-machine-asks-needs-its-uplink-held-and-the-retired-resolver-pieces-go.md)): every resolution fault found on 2026-10-03 was a copy disagreeing with the truth — a hosts file
|
||||
read once at start, an operator's old line beside the mesh's, a node's resolver lent to a LAN. No
|
||||
member's resolver answers a LAN; a router pointing at one is moved first. *Checked by each node's
|
||||
`/etc/resolv.conf` naming `mesh-resolver` then a public resolver, by no node but the holder answering
|
||||
@@ -1035,10 +1048,14 @@ The list is worth having in one place, because it is most of the argument:
|
||||
|
||||
## Open
|
||||
|
||||
- **One resolver ([ADR 0194](../../02-DECISIONS/0194-the-mesh-has-one-resolver-and-every-node-asks-it-for-the-meshs-names.md)).** Not built: every node still runs
|
||||
`node-dns-resolver`. The migration's four steps are in the record, in order.
|
||||
Nor are zones or the hosts file's holder ([ADR 0199](../../02-DECISIONS/0199-a-module-that-answers-names-declares-its-zone-and-a-nodes-hosts-file-is-one-modules.md)): the
|
||||
workstation moves to the one resolver only once both exist, its lab and operator names depending on them.
|
||||
- **One resolver ([ADR 0194](../../02-DECISIONS/0194-the-mesh-has-one-resolver-and-every-node-asks-it-for-the-meshs-names.md)).** *Correction of fact,
|
||||
2026-10-05:* no node holds `node-dns-resolver` any more, and
|
||||
[ADR 0220](../../02-DECISIONS/0220-what-a-machine-asks-needs-its-uplink-held-and-the-retired-resolver-pieces-go.md) deletes the seat. What stood here before: *"Not built: every node still runs
|
||||
`node-dns-resolver`. The migration's four steps are in the record, in order."* Nor did it
|
||||
stay true that *"the workstation moves to the one resolver only once"* zones and the hosts file's
|
||||
holder ([ADR 0199](../../02-DECISIONS/0199-a-module-that-answers-names-declares-its-zone-and-a-nodes-hosts-file-is-one-modules.md))
|
||||
exist: every node, the workstation included, asks the one resolver, and every node holds
|
||||
`node-hosts-file`.
|
||||
|
||||
- ~~**What happens when the hub is down.**~~ **Resolved** by
|
||||
[ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md), together with `06`'s
|
||||
|
||||
@@ -4,14 +4,16 @@ status: in-progress
|
||||
code:
|
||||
- mesh-controller internal/catalogue/seats.go
|
||||
- mesh-controller internal/catalogue/resolve.go
|
||||
- mesh-controller internal/catalogue/seat_dependencies.go
|
||||
- mesh-controller internal/inventory/seats.go
|
||||
- mesh-controller internal/inventory/migrations/0039-a-seat-is-held-by-one-assignment-on-record.sql
|
||||
- mesh-controller cmd/mesh-controller/seats.go
|
||||
- mesh-controller cmd/mesh-controller/source.go
|
||||
- mesh-controller internal/inventory/migrations/0032-a-source-may-live-on-a-seat.sql
|
||||
- mesh-catalog modules/gitea/module.json
|
||||
updated: 2026-10-03
|
||||
updated: 2026-10-05
|
||||
decisions:
|
||||
- 02-DECISIONS/0220-what-a-machine-asks-needs-its-uplink-held-and-the-retired-resolver-pieces-go.md
|
||||
- 02-DECISIONS/0199-a-module-that-answers-names-declares-its-zone-and-a-nodes-hosts-file-is-one-modules.md
|
||||
- 02-DECISIONS/0194-the-mesh-has-one-resolver-and-every-node-asks-it-for-the-meshs-names.md
|
||||
- 02-DECISIONS/0161-what-deserves-a-seat.md
|
||||
@@ -129,12 +131,12 @@ convention, which later seats departed from.
|
||||
| `mesh-git` | `git` | mesh | `git` | the forge |
|
||||
| `mesh-build-machine` | `the-build-machine` | node | — | a builder |
|
||||
| `mesh-resolver` | — | mesh | — | the mesh's one resolver, holding every node's internal domain ([ADR 0194](../../02-DECISIONS/0194-the-mesh-has-one-resolver-and-every-node-asks-it-for-the-meshs-names.md)) |
|
||||
| ~~`mesh-dns-port`~~ | `the-dns-port` | node | — | retired by [ADR 0194](../../02-DECISIONS/0194-the-mesh-has-one-resolver-and-every-node-asks-it-for-the-meshs-names.md): the local resolver became the mesh's one |
|
||||
| ~~`mesh-dns-port`~~ | `the-dns-port` | node | — | retired by [ADR 0194](../../02-DECISIONS/0194-the-mesh-has-one-resolver-and-every-node-asks-it-for-the-meshs-names.md): the local resolver became the mesh's one; deleted from the set, and from the store's table, once nothing claimed it ([ADR 0220](../../02-DECISIONS/0220-what-a-machine-asks-needs-its-uplink-held-and-the-retired-resolver-pieces-go.md)) |
|
||||
| `node-hosts-file` | — | node | — | owns `/etc/hosts`: the machine's own lines and the operator's kept region, changed through its verbs `entries`, `add`, `remove` ([ADR 0199](../../02-DECISIONS/0199-a-module-that-answers-names-declares-its-zone-and-a-nodes-hosts-file-is-one-modules.md)) |
|
||||
| `mesh-intrusion-prevention` | `the-intrusion-prevention` | node | — | an intrusion-prevention service |
|
||||
| `mesh-packet-filter` | `the-packet-filter` | node | — | the packet filter |
|
||||
| `mesh-private-network` | `the-private-network` | node | — | the private network the mesh runs over |
|
||||
| `mesh-resolver-configuration` | `the-resolver-configuration` | node | — | whichever of the alternative resolver configurations is chosen |
|
||||
| `mesh-resolver-configuration` | `the-resolver-configuration` | node | — | the module writing `/etc/resolv.conf`; its holder needs the uplink's held on the same node ([ADR 0220](../../02-DECISIONS/0220-what-a-machine-asks-needs-its-uplink-held-and-the-retired-resolver-pieces-go.md)) |
|
||||
| `mesh-showcase` | `the-showcase` | node | — | the showcase module |
|
||||
|
||||
The controller holds **the mesh's own** entries in code, and a test asserts their size and that
|
||||
@@ -202,10 +204,28 @@ Nothing reaches that state by accident: an unknown manifest field is refused out
|
||||
protocol was written as one. Checked by a registration test accepting a node seat with no protocol
|
||||
and by the showcase manifest, which declares one.
|
||||
|
||||
Most node seats deliver nothing. They say which module is this machine's packet filter, or which of
|
||||
two alternative resolver configurations it runs, and a second holder is refused. That is the whole of
|
||||
Most node seats deliver nothing. They say which module is this machine's packet filter, or which
|
||||
module writes its resolver file, and a second holder is refused. That is the whole of
|
||||
their job, and it is a real one: it is the mesh saying what a machine is, in words a person can read.
|
||||
|
||||
## A seat that needs another beside it
|
||||
|
||||
*2026-10-05* ([ADR 0220](../../02-DECISIONS/0220-what-a-machine-asks-needs-its-uplink-held-and-the-retired-resolver-pieces-go.md)). **A seat may name the node seats its holder needs held on the
|
||||
same node**, because some roles are right only while another is filled beside them. The holder of the
|
||||
resolver configuration writes `/etc/resolv.conf`, and that file stays the mesh's only while the
|
||||
machine's network manager is told to leave it alone — which is what the uplink's holder does
|
||||
([ADR 0117](../../02-DECISIONS/0117-a-machines-uplink-is-a-seat.md)). So the resolver configuration
|
||||
needs the uplink.
|
||||
|
||||
**A module claiming such a seat depends on each seat it needs**, exactly as a module declaring a
|
||||
service depends on the service manager
|
||||
([ADR 0207](../../02-DECISIONS/0207-a-module-depends-on-the-node-seats-that-apply-its-resources.md)):
|
||||
derived from the claim and never written in a manifest, met by any module assigned to the node, judged
|
||||
over the node's whole set, refused at assignment naming the seat and the modules that could hold it,
|
||||
and refused at composition. Taking the needed seat's last holder from beneath a dependent is refused
|
||||
too. What a seat needs is the mesh's definition of the role, compiled with the set and never stored,
|
||||
and adding a need is a decision.
|
||||
|
||||
## The overview
|
||||
|
||||
The controller lists every seat in the set with its scope, what it delivers, and its holder as a node
|
||||
@@ -259,5 +279,7 @@ checked as their tables say:
|
||||
| `secret` has one provider, the holder of `mesh-vault` | 0161: a second claimant of the seat is refused by name (`CanHold`); *correction of fact, 2026-10-01: no parser rule ever reserved the word, the seat does the work*. |
|
||||
| A singular fact about machines is a placement of capacity one, refused by name | 0161: the overlay command's test for a second hub; the store's unique index. |
|
||||
| A holder of `node-uplink` is the dialect the machine runs | 0161: the host reports `uplink-<manager>` in its profile with every report; a resolution test refuses the other holder naming the capability. |
|
||||
| A seat's holder has the seats it needs beside it: the resolver configuration is refused at `assign` without the uplink held on its node, and the uplink's last holder cannot be taken from beneath it | 0220: seat-dependency tests on the definition, on a synthetic claimant, at assign, at unassign and at composition, and one reading the catalogue for the uplink's possible holders. |
|
||||
| A retired seat leaves the set once nothing claims it, from the compiled set and the store's table both | 0220: the closed-set test's count, and the store migration that deletes the row. |
|
||||
| Holdings are derived, and the overview lists every seat | 0118: the `seats` command test, including an unheld seat. |
|
||||
| A build source on the seat records no address; an unheld seat refuses only self-hosted builds | 0111's tests. |
|
||||
|
||||
Reference in New Issue
Block a user