ADR 0100 after review: found means unrecorded; assigning prepares, taking cuts over; openings through the found firewall on both paths; the mesh guards its own ports; ports kept as node settings; a converged genesis refuses a machine in use; designs 05, 07, 08, 09 and 17 in step
This commit is contained in:
@@ -133,16 +133,21 @@ is the component; that one is what happens to it.
|
||||
|
||||
## What it finds, on an adopted node
|
||||
|
||||
*2026-09-22, [ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md).* A declaration says whether the node is adopted. On an adopted node
|
||||
the host does not replace a file it finds at a declared path: it records what was there — its
|
||||
content, so the original is kept before anything is written — and holds the file as found. A
|
||||
module's files are converged when that module is assigned, because assigning a module is
|
||||
migrating it; the rest when the node is converged. The host's report says which files it is
|
||||
holding rather than converging, so an adopted node never reads as converged. This is the
|
||||
*2026-09-22, [ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md).* A declaration says whether the node is adopted, and which of its
|
||||
modules have been **taken**. *Found* is a file at a declared path, or a container at a declared
|
||||
name, that the host's store has no record of writing. On an adopted node the host keeps what it
|
||||
found for any module not yet taken: it records a found file's original content before anything
|
||||
else, and it reports the file or container as held — a report that says what it holds, so an
|
||||
adopted node never reads as converged. Once the module is taken, its resources converge like any
|
||||
other. A held file that changes while held is reported as changed by something else, not
|
||||
reverted; a held file is never removed, even when its module is unassigned. The host also
|
||||
converges a new resource, the **opening** — a port made reachable through the firewall it found
|
||||
([08-connectivity](08-connectivity.md)) — and reports which firewall it found. This is the
|
||||
companion the host's ownership rule needed: *never touch what you did not create, unless adoption
|
||||
made it yours — and while the node is adopted, keep it as you found it.* *How it is checked:*
|
||||
unit tests hold the host to keeping a found file on an adopted node and replacing it on a
|
||||
converged one, and the adoption bed asserts a found file byte for byte unchanged.
|
||||
made it yours — and while the node is adopted, not until its module is taken.* *How it is
|
||||
checked:* unit tests hold the host to keeping a found file and container, converging them once
|
||||
taken, never removing a held file and reporting one that changed; the adoption bed asserts a found
|
||||
file byte for byte unchanged until its module is taken.
|
||||
|
||||
## Where a declaration comes from
|
||||
|
||||
|
||||
@@ -11,8 +11,9 @@ code:
|
||||
- mesh-catalog modules/postgres
|
||||
- mesh-catalog modules/lavinmq
|
||||
- mesh-lab test/integration/mesh.test.ts (a bare machine becomes a mesh)
|
||||
updated: 2026-09-21
|
||||
updated: 2026-09-22
|
||||
decisions:
|
||||
- 02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md
|
||||
- 02-DECISIONS/0088-the-foundation-filters-before-anything-listens.md
|
||||
- 02-DECISIONS/0004-a-node-and-how-it-joins.md
|
||||
- 02-DECISIONS/0078-the-store-and-broker-are-modules.md
|
||||
@@ -172,6 +173,16 @@ ruleset the machine loaded. **Checked** by the installer's bundle test (order an
|
||||
the genesis bed, which probes the machine from outside for the length of the install: the store's
|
||||
port never answers, the bus's does.
|
||||
|
||||
**Except on a machine raised adopted**
|
||||
([ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md)). A
|
||||
machine already serving under a predecessor has a firewall of its own, and a second, stricter
|
||||
table would close everything it serves. There the base ruleset is not loaded and the filter module
|
||||
is not assigned until the node converges; the foundation's ports are opened through the found
|
||||
firewall from the private network and refused from anywhere else on the forwarded path, which
|
||||
keeps the same promise — the store's port never answers from outside — by other means. The
|
||||
foundation's ports themselves are the node's, given at genesis and kept as its settings. **Checked**
|
||||
by the adoption bed, which makes the same outside probe.
|
||||
|
||||
## Raising it
|
||||
|
||||
The order, from [research 011](../../01-RESEARCH/011-the-module-graph/worked-provider.md):
|
||||
|
||||
@@ -442,7 +442,8 @@ stopgap until the manifest layer can carry a label and a domain separately
|
||||
|
||||
**Derived from what is assigned here, and from the overlay's shape** — a node's open ports are a
|
||||
consequence of what runs on it and who must reach it, not an independent declaration to keep in
|
||||
step by hand.
|
||||
step by hand. That is true of a converged node; an adopted one keeps the firewall it was found
|
||||
with until it converges (below).
|
||||
|
||||
**A rule names its source** ([ADR 0007](../../02-DECISIONS/0007-connectivity.md)).
|
||||
A rule with no source is open, and must say so rather than appear to restrict something. `scope:`
|
||||
@@ -536,16 +537,24 @@ is why the check reads packets.*
|
||||
### On an adopted node
|
||||
|
||||
*2026-09-22, [ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md).* **The firewall found on the machine stays in force**, and the mesh
|
||||
loads no table of its own there — neither genesis's base ruleset nor the derived one. The kernel
|
||||
runs every table at a hook and a drop in any is final, so a second, stricter table would close
|
||||
every port the machine serves. What the mesh needs reachable — its foundation's ports and each
|
||||
migrated module's `listens` — it opens *through the found firewall*, as rules marked as the mesh's,
|
||||
and it removes only rules it marked. Converging the node replaces the found firewall with the
|
||||
derived filter in one step, after previewing which open ports will close. The mesh must speak the
|
||||
found firewall in its own terms; one kind is found on the machines measured, and a machine with
|
||||
another is not covered until someone writes for it. *How it is checked:* the adoption bed asserts
|
||||
the found firewall's rules differ only by the mesh's marked rules, that a second machine enrols
|
||||
through them, and that after the flip the declared port is open and the undeclared one closed.
|
||||
loads no table of its own there — neither genesis's base ruleset nor the derived one. Every base
|
||||
chain at a hook runs and a drop in any is final, whatever the other firewall is written in, so a
|
||||
second, stricter table would close every port the machine serves. What the mesh needs reachable
|
||||
it declares as **openings**: a port, from where, on the incoming path or the forwarded path — a
|
||||
published container port is forwarded, and a firewall that filters only incoming traffic never
|
||||
sees it. The host converges each opening through the found firewall in that firewall's own terms,
|
||||
marks it as the mesh's, removes only what it marked, and re-checks every opening on each reconcile
|
||||
so a reload or a reboot does not lose it. An opening is state, not a command, so it travels over
|
||||
the link like any other resource. **The mesh protects its own ports itself**: its foundation's ports
|
||||
are opened from the private network and refused from anywhere else on the forwarded path, so the
|
||||
store stays unreachable from outside whether or not the found firewall filters forwarded traffic.
|
||||
One kind of found firewall is spoken; a machine with another is refused adoption rather than
|
||||
adopted unprotected. Converging the node previews what is reachable now — listening sockets and
|
||||
published ports — and what will close, then loads the derived filter and disables the found
|
||||
firewall without flushing it. *How it is checked:* the adoption bed asserts the found firewall's
|
||||
rules differ only by the mesh's marked rules, that the store is unreachable from off the private
|
||||
network, that a second machine enrols through the openings before and after a reload and a reboot,
|
||||
and that after the flip the declared port is open and the undeclared one closed.
|
||||
|
||||
## 5 — Certificates
|
||||
|
||||
|
||||
@@ -292,14 +292,18 @@ until its migration is done and the operator converges it. A machine that was em
|
||||
converged, as before
|
||||
([research 012](../../01-RESEARCH/012-the-minimum-viable-node/00-overview.md)).
|
||||
|
||||
On an adopted node the firewall found there stays in force and the mesh opens what it needs
|
||||
through it ([08-connectivity](08-connectivity.md)); a file found at a path the mesh declares is
|
||||
kept until the module declaring it migrates ([05-the-node-host](05-the-node-host.md)).
|
||||
**Converging is one act per node, previewed**: it lists every port the found firewall allows and
|
||||
whether an assigned module declares it or it will close, then loads the mesh's own filter, retires
|
||||
the found one and converges what was kept. *How it is checked:* a lab bed prepares a machine the
|
||||
way a predecessor leaves one and asserts nothing on it changes until the flip, and that the flip
|
||||
closes exactly what the preview said.
|
||||
The operator says a node is adopted — at genesis for the control-node, in the enrolment token for
|
||||
the others — and the controller records it and says so in every declaration, with the modules
|
||||
**taken** on that node. On an adopted node what is found is held until its module is taken
|
||||
([05-the-node-host](05-the-node-host.md)): assigning a module prepares it, taking it is its
|
||||
cutover. The firewall found there stays in force and the mesh opens what it needs through it
|
||||
([08-connectivity](08-connectivity.md)). **Converging is one act per node, previewed**: it lists
|
||||
what is reachable on the machine now — listening sockets and published ports — and whether an
|
||||
assigned module declares each or it will close, then takes every module not yet taken, loads the
|
||||
mesh's own filter and disables the found one without flushing it. Returning a converged node to
|
||||
adopted enables the found firewall again. *How it is checked:* a lab bed prepares a machine the way
|
||||
a predecessor leaves one and asserts nothing that serves changes until a module is taken or the
|
||||
node is converged, and that the flip closes exactly what the preview said.
|
||||
|
||||
A candidate machine is not empty. It has a package manager, probably a container runtime,
|
||||
configuration somebody chose. [ADR 0005](../../02-DECISIONS/0005-the-node-host.md)
|
||||
@@ -316,11 +320,16 @@ an installation. This is a *never* rule, and it earns that from the worst loss i
|
||||
a tool acting on a path it did not own.
|
||||
|
||||
**On conflict, the machine's configuration wins.** Adoption always completes; the conflict is
|
||||
flagged and reconciled afterwards. A machine in use keeps working exactly as it did.
|
||||
flagged and reconciled afterwards. A machine in use keeps working exactly as it did. Two things are
|
||||
not conflicts in this sense ([ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md)):
|
||||
a module the operator has *taken* replaces what it found, because that is its cutover; and genesis
|
||||
refuses a port the foundation needs that something else holds, because a foundation that cannot
|
||||
bind is not adopted but broken.
|
||||
|
||||
**Adoption produces a briefing**, not just a result: what it found, what it took over, and what
|
||||
it could not resolve — with each line marked `ok`, `kept`, `unknown` or `failed`, and the overall
|
||||
outcome **derived** from the worst line rather than stated alongside it.
|
||||
outcome **derived** from the worst line rather than stated alongside it. A file or container the
|
||||
host is holding on an adopted node is a `kept` line for as long as it is held.
|
||||
|
||||
---
|
||||
|
||||
@@ -384,6 +393,11 @@ runtime because a declaration changed would stop every container on the node.
|
||||
|
||||
---
|
||||
|
||||
|
||||
*On an adopted node* ([ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md)),
|
||||
what the host is holding was found, not made, so nothing held is ever removed: a held file whose
|
||||
module is unassigned stays where it is.
|
||||
|
||||
## enrolled ⇄ disconnected
|
||||
|
||||
Not a failure. Not degraded. A situation
|
||||
|
||||
@@ -101,16 +101,23 @@ that runs it.
|
||||
### Genesis on a machine in use
|
||||
|
||||
*2026-09-22, [ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md).* A control-node that is already running a predecessor mesh is raised
|
||||
**adopted**. The predecessor's control on it is stopped first — the daemons that write its
|
||||
configuration — and its services keep running. **Every port the foundation binds is an input to
|
||||
genesis**, not a constant in the bundle or the catalogue, and genesis checks each is free before it
|
||||
raises anything, refusing with the name of what holds it. On such a machine the store's and the
|
||||
bus's usual ports were free and the registry's, the broker's management port and the private
|
||||
network's port were held. Genesis adopted **does not load the base ruleset**: the machine's own
|
||||
firewall already filters, and the mesh opens its foundation's ports through it
|
||||
([08-connectivity](08-connectivity.md)). *How it is checked:* the adoption bed raises genesis
|
||||
with the registry's port held and asserts the refusal names its holder, then with another port
|
||||
given asserts the foundation comes up and the machine's service is still reachable.
|
||||
**adopted**, said so by the operator. The operator stops the predecessor's control on it first —
|
||||
the daemons that write its configuration — and its services keep running. **Every port the
|
||||
foundation binds is an input to genesis**, checked free before anything is raised, refused with the
|
||||
name of what holds it; the ports given become the node's settings for the foundation's modules, so
|
||||
adopting the foundation as modules keeps them, and every reader of them — the filter, the base
|
||||
ruleset, the private network's endpoint, the addresses consumers are given — reads them there. On
|
||||
the control-node measured, the store's and the bus's usual ports were free and the registry's, the
|
||||
broker's management port and, as the private network's hub, its port were held. Genesis also
|
||||
checks the private network's range does not overlap a tunnel the predecessor runs. Genesis adopted
|
||||
**does not load the base ruleset**: the machine's own firewall already filters, and the mesh opens
|
||||
its foundation's ports through it and refuses them from outside itself
|
||||
([08-connectivity](08-connectivity.md)). **A converged genesis refuses a machine in use** — an
|
||||
active firewall or listeners that are not the mesh's — so a forgotten flag cannot close a working
|
||||
machine. *How it is checked:* the adoption bed raises genesis converged on a machine in use and
|
||||
asserts the refusal, then adopted with the registry's port held and asserts the refusal names its
|
||||
holder, then with another port given asserts the foundation comes up, stays on that port once
|
||||
adopted as modules, and the machine's service is still reachable.
|
||||
|
||||
## After the pivot, and still part of installing
|
||||
|
||||
@@ -157,7 +164,10 @@ What remains after *that* belongs to somebody else: adding machines, and decidin
|
||||
|
||||
A machine joins with the host binary and a token. It does not raise a foundation, does not install a
|
||||
registry, and is never enrolled twice. The mesh already knows how to tell a machine what to be;
|
||||
joining is the point at which a machine starts listening.
|
||||
joining is the point at which a machine starts listening. A machine in use joins **adopted**: the
|
||||
token says so, the operator has stopped the predecessor's control on it first, and from then on it
|
||||
keeps what it has until each module is taken
|
||||
([ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md)).
|
||||
|
||||
## Where the line falls
|
||||
|
||||
|
||||
Reference in New Issue
Block a user