Merge pull request 'Design 47 says what a node composes from: placement, its config layers, and the node record (issue 1126)' (#482) from feat/1126-nodes-compose into main
This commit was merged in pull request #482.
This commit is contained in:
@@ -4,6 +4,7 @@ status: in-progress
|
||||
code: [mesh-controller, mesh-catalog modules/mesh-delivery-gate, mesh-delivery, mesh-host, mesh-sdk, mesh-vault, hq 00-META/checks]
|
||||
updated: 2026-10-26
|
||||
decisions:
|
||||
- "ADR 0555"
|
||||
- "ADR 0551"
|
||||
- "ADR 0550"
|
||||
- "ADR 0549"
|
||||
@@ -663,7 +664,7 @@ backup holder backs up nothing, and the have says so.
|
||||
|
||||
## Compositions, wants and the apply
|
||||
|
||||
*ADR 0360 §8, §9, ADR 0377, ADR 0429 §4, §6, ADR 0539 §9, §14 to §16, ADR 0547 §2 to §9.*
|
||||
*ADR 0360 §8, §9, ADR 0377, ADR 0429 §4, §6, ADR 0539 §9, §14 to §16, ADR 0547 §2 to §9, ADR 0549, ADR 0555.*
|
||||
|
||||
- **Each node composes its own.** For each want `want.<node>.<module>` the node agent composes that module for
|
||||
its own node with mesh-sdk's composition from the manifest by digest the indexer wrote, the module's resolved
|
||||
@@ -672,6 +673,74 @@ backup holder backs up nothing, and the have says so.
|
||||
own composition (adoption, firewall openings, accounts, the resolver, identities and groups) from the same
|
||||
inputs. Of other nodes it reads only their public records and the manifests wanted on them, which its firewall
|
||||
and resolver need. Nothing composed crosses the bus, so nothing composed is signed (ADR 0547 §2).
|
||||
- **What a node composes from, and who writes it.** One composer, mesh-sdk's, has three callers: the node agent for
|
||||
its own node, the assigner's composition check for every node, and the grants part. Each fills the composition's
|
||||
input from the bus with its own credential and nothing else (ADR 0547 §2, ADR 0549 §3):
|
||||
- **placement**, the indexer's state `placement`, one key `placement.<node>` read at each catalogue merge from
|
||||
the node's placement file and said by `placement-changed` (ADR 0549 §2);
|
||||
- **the node records**, each in its node's own have key `<node>.node`, written by that node alone and heard as
|
||||
the key's change (ADR 0555 §3);
|
||||
- **the manifests**, the indexer's `modules.<module>` and its manifests by digest, or the digest the composing
|
||||
node's want names where it runs another build; the private network's manifest comes with mesh-sdk;
|
||||
- **the config values**, mesh-config's resolved state, the composing node's slice alone for a node agent; a module
|
||||
in the settings form (its manifest declares no config, so mesh-config holds none for it) has its values in the
|
||||
placement file instead;
|
||||
- **its own secrets and credentials**, from the vault's verb `own`, sealed to the asking node's key and answered to
|
||||
that node's engine alone, and composed again when the vault says `secret-changed` (ADR 0550 §5).
|
||||
While both sources stand (ADR 0549 §5), mesh-config resolves values for a module either the placement or the
|
||||
controller's assignments name on a node, and the grants part composes both, holding a seat held once for the mesh
|
||||
where the placement says.
|
||||
- **The placement file.** One file per node in the catalogue, changed only by a pull request and checked before
|
||||
it merges (ADR 0549 §1, ADR 0555). It holds what a person decides of the node and nothing a machine observes:
|
||||
- the node's decided facts: its endpoint and site, whether it is the private network's hub, its address on the
|
||||
private network (a decision written once at enrolment; nothing allocates one at run time), the domain its
|
||||
routed names are composed under, its operator and agent logins by name with their homes, whether it is
|
||||
adopted with the modules taken on it, the tunnel found on it at adoption (no longer there to observe once taken
|
||||
over), and on the hub the names given to that tunnel's peers. No secret, and keys only as public halves;
|
||||
- its modules in the order the composition reads them, each with its host ports by the port the software
|
||||
listens on, its bindings by provision, and its config placement (`places`, `accesses`, `networks`,
|
||||
`endpoints`, `expose`, `reach`, `ports`) as two layers: the mesh-wide one, repeated in every node's file so a
|
||||
node reads its own key alone, and the node's own, with a mark when the node has a layer that holds no placement,
|
||||
since an empty layer still carries the module's config values; and, for a module in the settings form only,
|
||||
the config values a person set in each of those layers (on the day of the seed the media modules of one node);
|
||||
- its pins by provision, and the seats its modules hold.
|
||||
The catalogue's check refuses a placement naming a module it does not hold or a node not enrolled, two modules
|
||||
of one node on one host port, a pin, binding or holding naming a provider not placed where it says, a seat held
|
||||
once for the mesh held twice, two nodes with one address and more than one hub, each named in one answer.
|
||||
- **The node record.** What the machine observes of itself: its tunnel's public key, its capabilities, the
|
||||
public halves of its sealing and serving keys, the certificate issued for its internal name, its outward links
|
||||
and networks, and its node-engine's contract. Written at start and when an observed fact changes, only when it
|
||||
differs (ADR 0555 §3). Whether the hub took its found tunnel over, and which node enrolled under a carried
|
||||
peer's key, are read from the placement and the records together, never written.
|
||||
- **What a node's account reads to compose.** The grants part's composer gives every node's account these reads,
|
||||
each read only, and the controller's frozen copy none of them (ADR 0555):
|
||||
- every node's `<node>.node` of the node-engine's have bucket: the other nodes' records;
|
||||
- every key of the indexer's `placement`: where modules run and what a person decided of each node;
|
||||
- every key of the indexer's `modules` and `manifests`: the manifests it composes from;
|
||||
- every key of the builder's `builds`: the manifest of a build its want names when that is not the trunk's;
|
||||
- mesh-config's `resolved` values of its own node alone, `<node>.>`.
|
||||
Since the take-over the grants part's list is the one the bus loads; after a `hand-back` the controller's list
|
||||
holds, without these reads, and nodes keep applying while composing their own fails loudly until the next
|
||||
`take-over`. mesh-sdk's composer test holds the copy, user for user, to every grant of the controller's golden
|
||||
plus exactly these reads and the bucket-creation advisories of issue 1790.
|
||||
- **A node composes its own once the catalogue places it.** Its agent reads its key `placement.<node>` at start:
|
||||
with one it composes its own, without one it applies the controller's compositions as before, so nothing changes
|
||||
on a node before the seeded placement file reaches it; it follows the key, and when it appears the agent begins
|
||||
again composing its own, with no restart. A node never applies a stand-in: a composition that stands
|
||||
in for a value its input lacks (an own secret, a credential, a vault box, the certificate) is refused whole, said,
|
||||
and the node keeps running what it runs; the bus's user list alone is held out of the apply, since the bus node
|
||||
follows it apart. A secret or credential the vault does not hold is such a gap: the vault names it missing, and
|
||||
the node composing it keeps what runs until the vault holds it. Likewise a consumer of `model-access` answered by a
|
||||
licence record, placed before the vault serves licences (ADR 0550 §3, issue 569), is refused by the same guard and
|
||||
its node keeps what runs; none is placed today.
|
||||
- **The order a node takes to composing its own.** One delivery group carries every part: the controller's verb
|
||||
`placement-export`, the node-engine (its record and its own composer), the vault's `own`, the grants part's reads,
|
||||
mesh-config's and the assigner's reading of placement, and the indexer writing it. Nothing changes on a node by
|
||||
that delivery alone, since no placement file exists yet: the node records appear, and the grants part's list gives
|
||||
the nodes their reads. Then the seed: one catalogue pull request writes each node's placement file from the
|
||||
controller's export, and its composition check composes every node from it with no difference to what the node
|
||||
runs; only then is it merged. The indexer writes `placement`, each node begins composing its own, and the assigner
|
||||
writes its wants as the build alone.
|
||||
- **Composed again on events, never on a timer.** A changed input at the same fingerprint (a setting or given
|
||||
value, a secret rotated or moved, a credential issued, a provider's contribution, a peer added to the hub) is
|
||||
composed again when its event is heard, and applied as a revision of what runs (ADR 0547 §2).
|
||||
@@ -697,7 +766,10 @@ backup holder backs up nothing, and the have says so.
|
||||
and nothing is asserted (ADR 0547 §5).
|
||||
- **The want names the build.** A want `want.<node>.<module>` names the fingerprint, the artifact's digest, the
|
||||
source revision and whether the module holds data; the node's own want `want.<node>.node` names the node
|
||||
(ADR 0547 §2).
|
||||
(ADR 0547 §2). A want to a node the catalogue places says so: it carries `self` and names no composition,
|
||||
since the node composes it; every other want still names the one composition it allows, so nothing written
|
||||
before (the controller's bus upgrade among it) reads a want differently. A person's yes to a move the node
|
||||
judged is written into the want as `yes`, the digest of the composition allowed (ADR 0547 §3).
|
||||
- **The apply, one module at a time.** At its first start the node agent takes the declaration it kept last as
|
||||
what each module runs and writes each have. Then it applies a module only when its want's fingerprint
|
||||
differs from what runs or the composition it composed differs from the one it runs, and only that module,
|
||||
|
||||
Reference in New Issue
Block a user