Records say what the build does: 0101 names only measured daemons; 0102 adds to lists and keeps what it writes over; 0103 names every held kind, the found-service rule, conflicting found rules, guards, and what of 0100 it replaces; designs 05, 09 and 17 in step; issue 084's diagnosis in its own file

This commit is contained in:
2026-09-22 19:38:16 +02:00
parent ca1f648973
commit c74ea2a4a8
8 changed files with 74 additions and 38 deletions
@@ -42,9 +42,8 @@ habit.
## Decision
**A listener held by one of the operating system's own network daemons does not make a machine
in use.** The daemons are the name resolver, the network manager, the address-configuration
client and the time client, named in the installer's code beside the measurement that found
them. Everything else in ADR 0100's definition stands: a running container, or any other
in use.** The daemons are the ones the measurement found: the name resolver and the network
manager, named in the installer's code beside that measurement. Everything else in ADR 0100's definition stands: a running container, or any other
listener on an address other than loopback that is not ssh's, makes the machine in use, and
genesis still names every one it counted.
@@ -42,10 +42,18 @@ the runtime.
**A file the mesh shares with software it did not install is written into, never over.** A
file resource may say it is written *into* a structured file. The host then reads what is there,
sets only the keys the mesh declares, keeps every other key as it found it, and records what each
of its keys held before. Undeclared later, each key goes back to what it held, and a file the
mesh created is removed only if nothing but its own keys is left. A file written into replaces
nothing, so on an adopted node it is never held: it is written whether or not its module has
been taken.
of its keys held before. **A list is added to, never replaced**: where the machine already has a
list under a key the mesh declares, the mesh's members are added to it and the host records
exactly which members it added — setting the key would replace the operator's own list, the harm
this record exists to prevent. Undeclared later, each key goes back to what it held and each
added member is taken out again, and a file the mesh created is removed only if nothing but its
own keys is left. A file written into replaces nothing, so on an adopted node it is never held:
it is written whether or not its module has been taken.
**Whatever the host writes over without a record of it, it keeps first.** On any node, adopted
or converged, before the host writes a file over one it has no record of making, it keeps the
original once and says where; if it cannot keep it, it does not write. A file the mesh takes over
is then never lost, whatever put it there.
**A service that re-reads its configuration on a reload is reloaded, not restarted.** A service
resource may name what it must be *reloaded* on, beside what it must be restarted on. The
@@ -70,8 +78,9 @@ and stays held until networking is taken; a converge preview names it among the
## How it is checked
Unit tests hold the host to setting only the declared keys and keeping the rest, restoring each
key and removing only a file it created when the resource is undeclared, refusing a file that is
not a JSON object rather than overwriting it, never holding a file written into on an adopted
key and removing only a file it created when the resource is undeclared, adding to a list and
removing only the members it added, keeping the original of a file it writes over without a
record, refusing a file that is not a JSON object rather than overwriting it, never holding a file written into on an adopted
node, and reloading rather than restarting a service whose reload-on resource changed. A test in
the controller holds the networking module to declaring the runtime's file written into and the
runtime reloaded. The adoption lab bed gives the machine a runtime file with a setting of its own
@@ -40,9 +40,14 @@ for a module not yet taken:
- a **directory** present with no record is held: its mode and owner are left, and nothing in it
is touched;
- a **service** whose unit is present with no record is held: its state and whether it starts at
boot are left. A reload named by the module still happens, since a reload stops nothing
([ADR 0102](0102-the-mesh-writes-into-a-shared-file-never-over-it.md));
- a **service** the machine runs — a unit running or enabled at boot — with no record is held: its
state and whether it starts at boot are left. A reload named by the module still happens, since
a reload stops nothing ([ADR 0102](0102-the-mesh-writes-into-a-shared-file-never-over-it.md)).
A unit file a package merely ships, which nothing runs, is not found: the private network's own
tunnel unit is one;
- an **archive** whose target is present with no record is not unpacked or re-owned; a
**process** whose unit file is present with no record is not written over or restarted; a
**user** that exists with no record keeps its shell and groups;
- a **container** not found by its name is still held if it would mount a path or a volume that
is present with no record, because it would share the predecessor's data;
- an **action** or one-off step run *in* a held container is held until the module is taken.
@@ -51,23 +56,34 @@ What is held is reported as held and is never removed, as ADR 0100 decides for f
containers.
**The guard refuses what the found firewall may miss, for taken modules only.** Its ports are
derived, not listed. They are every machine port a *taken* module publishes that the filter
would admit from the private network only, together with the store's port and the broker's
management port. A port of a module that is assigned but not taken is not guarded: it may still
derived from each *taken* module: every machine port it publishes that the filter would admit
from the private network only, and the ports its manifest names under `guards` — which is how
the store's port and the broker's management port are included. Only TCP is guarded. A port of a module that is assigned but not taken is not guarded: it may still
be the predecessor's. The guard matches only packets addressed to this machine. Traffic the
machine routes for others is never its business.
**An opening already answered by a found rule is not added.** If the found firewall already
admits what an opening says, the opening is reported as satisfied by the found rule, and the
mesh adds nothing and later removes nothing. The found firewall treats two rules differing only
in their comment as one rule, so adding the mesh's would take over the operator's.
in their action, log setting or comment as one rule, so adding the mesh's would take over the
operator's. Where the found rule is such a twin but is not a plain allow — a deny, a limit, a
logged allow — the opening is refused, naming that rule, and nothing is added.
**A machine raised adopted stays adopted if genesis is run again.** The installer reads the
node's mode from what the machine records, not only from the operator's flag. A run without
the flag on an adopted machine is refused.
**What of ADR 0100 this replaces.** ADR 0100's guard refused two ports, the foundation's own,
checked free at genesis, and could therefore close nothing the machine served. That guard is
replaced by the one above: a guarded port of a taken module may be one the predecessor served
more widely, and taking the module narrows it to the private network. Everything else in ADR 0100
stands, and its rules for files and containers now cover the other kinds listed here.
## Consequences
- Taking a module can narrow a port the predecessor served to anyone: the guard then refuses it
from outside the private network, as the module declares. Nothing says so yet
([issue 086](../04-ISSUES/086-taking-a-module-narrows-a-port-without-saying-so/00-report.md)).
- An untaken module on an adopted node can come up only beside what was found, never on top of
it: whatever would share the predecessor's data waits for the cutover.
- The guard grows with the modules taken, and a module's published private-network port is
@@ -78,14 +94,15 @@ the flag on an adopted machine is refused.
## How it is checked
Unit tests hold the host to holding a found directory, a found service and a container that
would mount found data, to deferring an action run in a held container, and to adding no
opening a found rule answers. They hold the controller to deriving the guard from taken modules'
Unit tests hold the host to holding a found directory, a found service, a found archive, process
and user, and a container that would mount found data; to not holding a unit nothing runs; to
deferring an action run in a held container; to adding no opening a found rule answers, and to
refusing one a conflicting found rule would absorb. They hold the controller to deriving the guard from taken modules'
private-network published ports, and the guard's text to matching only this machine's
addresses. The installer's tests hold a re-run without the flag on an adopted machine to a
refusal. The adoption lab bed asserts that the broker's plaintext port is unreachable from
outside the private network, and that an operator's own rule for a port the mesh opens
survives the opening being removed.
outside the private network even with the found firewall admitting it, and that an operator's
own rule for a port the mesh opens survives the opening being removed.
## References