Design 47 follows ADR 0547: node agents compose their own modules, a grants part composes who may say what, the bus node writes the user list alone, and the controller leaves build and delivery in three milestones

This commit is contained in:
2026-10-26 02:57:45 +01:00
parent fd0d712f7d
commit d94f8a05a8
@@ -1,9 +1,10 @@
---
layer: to-be
status: in-progress
code: [mesh-controller, mesh-catalog modules/mesh-delivery-gate, mesh-delivery, mesh-host, mesh-sdk, hq 00-META/checks]
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 0547"
- "ADR 0539"
- "ADR 0536"
- "ADR 0534"
@@ -136,26 +137,32 @@ source revision is derived from the keys: every **want** equals its module's **f
- **The gate** merges a group's pull requests once check, review and the operator's Approve agree on the same
heads, and then moves the mesh's source revision in one write.
- **The teller** carries conditions and asks to the operator's phone and is the only writer of an ask's answer.
- **The assigner** writes which fingerprint each node should run, by seven rules: the build is done, the
- **The assigner** writes which fingerprint each node should run, by six rules: the build is done, the
fingerprint is not held, the node is the module's **canary** or the canary runs it healthy, at most `step`
other nodes are ahead when `step` is above zero, every provider runs healthy, the module's credential for that
fingerprint exists, and the controller's **composition** of the module for that node at that fingerprint exists
(ADR 0429 §6, ADR 0539 §6). Each want `want.<node>.<module>` names the fingerprint and the digest of the one
composition it allows; the assigner also writes the node's own want `want.<node>.node` once the node's
composition exists, and never deletes a want (ADR 0539 §1, §6; ADR 0408 §4). A move a person must allow waits
for the operator's yes before its want is written (ADR 0539 §14).
other nodes are ahead when `step` is above zero, every provider runs healthy, and the module's grant
`grants.<module>.<fingerprint>` exists in the grants part's state (ADR 0429 §6, ADR 0547 §4). No rule waits on a
composition: the node composes its own (ADR 0547 §2). Each want `want.<node>.<module>` names the fingerprint,
the artifact's digest, the source revision and whether the module holds data; the assigner also writes the
node's own want `want.<node>.node`, and never deletes a want (ADR 0408 §4). A move a person must allow is judged
by the node agent, which waits; the assigner raises the ask and on a yes writes the want again naming it
(ADR 0547 §3).
It also runs the **composition check**: whether the machines a change touches still compose with it, read
from the keys the indexer and the builder hold and from what the controller keeps of machines, settings and
grants, with mesh-sdk's composition, the one the controller composes with (ADR 0446). Its module was made in
R4g with release 5, when its wants were only compared with what the controller sent; from release 6 it writes
no difference, and the controller writes `grants.<module>.<fingerprint>` when a module's build is done
(ADR 0524 §4, ADR 0528, ADR 0539 §7, §8).
- **The node agent**, the node-engine's own process, follows its node's wants and its own bucket of
compositions, applies one module at a time and only what differs from what runs, verifies each composition's
signature, backs up a data module first, and writes its haves with the fingerprint and the composition's
digest it runs (ADR 0539 §2, §3, §9, §16). A composition is not bounded by one bus message: a file over 64 KiB
travels by digest in the bus's object store, in a bucket of that node's own that no other node can read, and a
condition warns before the limit (ADR 0486, ADR 0488, ADR 0539 §4).
from the keys the indexer and the builder hold and from the machines, settings and grants it reads, with
mesh-sdk's composition, the one every node agent composes with (ADR 0446, ADR 0547 §2). Its module was made in
R4g with release 5; from release 6 it writes no difference (ADR 0524 §4, ADR 0528, ADR 0539 §8).
- **The node agent**, the node-engine's own process, follows its node's wants, **composes each wanted module for
its own node** with mesh-sdk's composition from the manifest by digest, the module's resolved values from
mesh-config, its secrets and bus credential asked of the vault sealed to the node's key, its licences and what
its providers contribute, applies one module at a time and only what differs from what runs, backs up a data
module first, and writes its haves with the fingerprint and the digest of the composition it runs (ADR 0547 §2,
§3; ADR 0539 §16). Nothing composed crosses the bus, so nothing is signed; of other nodes it reads only their
public records and the manifests wanted on them. On the node holding `mesh-broker` it also writes the bus's user
list, alone and with no want (*The bus's user list*, below).
- **The grants part** (module `mesh-grants`, holding the seat `mesh-grants`) composes who may say what on the bus
with mesh-sdk's bus composer: each module's membership, the buckets, logs and streams a manifest declares, the
bus's user list, and from ADR 0547's third milestone `grants.<module>.<fingerprint>` (ADR 0547 §5, §6). Until
the operator's `take-over` it runs in shadow, composing and comparing with what the bus loaded and writing
nothing that takes effect; its tools read all it holds and redo all it does.
- **The watchman** turns the bus's connections into presence and mirrors every key whose next move a machine
owes into a **pulse**, whose expiry is a stall.
- **The status view** is the operator's command `mesh-delivery-cli` and a web view, whose wants page sets each
@@ -164,9 +171,29 @@ source revision is derived from the keys: every **want** equals its module's **f
`moving`, `settled` and `stuck` once for a module on a node at one composition (ADR 0539 §17; *A delivery*
below).
Nine of these are modules of the repository `mesh-delivery`, prefixed `mesh-delivery-` (ADR 0429 §2); the
Ten of these are modules of the repository `mesh-delivery`, prefixed `mesh-delivery-` (ADR 0429 §2); the
repository is made by the forge module from its config (ADR 0428; issue 1128 makes the config value reach the
node at once). The reviewer stays the review agent's session.
node at once); the grants part is one of them. The reviewer stays the review agent's session.
**The controller leaves build and delivery** (ADR 0547, accepted 2026-10-25). The drawing above is the target, and
no act of build and delivery is the controller's in it: no part takes in done keys, composes centrally, signs a
composition, mints a bus account, writes a grant, publishes a membership, composes the user list or forwards a try
on the controller's behalf. Its code is not changed for this; it stops by losing its lease (ADR 0547 §1). The way
there is three milestones, one issuer of each key at every moment (ADR 0547 §11):
1. **The list follows, the grants part in shadow** (issue 1945): the bus node applies the user list alone, with
no want; mesh-sdk carries a copy of the bus composer, held byte for byte to the one release 6 runs; the grants
part composes and compares in shadow with its tools; the vault hashes the bus accounts it is handed. The
operator's `take-over` makes the grants part's list the one loaded, and is refused while any user differs, so
it waits until the enrolment users and the persons have records on the bus (ADR 0547 §8).
2. **Nodes compose** (issue 1126): each node agent composes its own modules; no node applies a composition made
elsewhere but the bus's user list until `take-over`.
3. **Nothing is left with the controller** (issues 1126, 774): the vault mints bus accounts, the grants part
writes grants, the try is the checker's own verb, placement and the signing key are where the operator's
answers put them, and the controller's lease is handed to a holder that is no controller once every other job
it keeps has a home by its own decision (research 072).
Until each milestone is delivered, release 6's text below holds for what that milestone replaces (ADR 0547 §11).
It lands in six releases, each leaving the mesh working, each one milestone below (ADR 0429 §7); releases 4 and 5 end in one milestone, R4g,
with one switch-over and no rehearsal (ADR 0524 §1). Until the
@@ -177,29 +204,32 @@ is delivered, so ADR 0539's clauses hold (ADR 0539 §20), and the as-is design d
## The parts
From release 6 (ADR 0539):
The target (ADR 0547):
```
forge ──forge messages──► forge bridge ──► the bus ◄── done keys ── builder, build modules (build seats)
│ ▲
gate: the merge, the source revision ◄┤ ├── indexer: each module's fingerprint
controller: signed compositions, ◄┤ ├── assigner: each node's wants, by seven rules
credentials and grants │ ├── watchman: presence, pulses, stuck keys
│ └── status view: delivered, moving, settled, stuck
gate: the merge, the source revision ◄┤ ├── indexer: each module's fingerprint and manifest
grants part: memberships, assertions,◄┤ ├── assigner: each node's wants, by six rules
the user list, grants │ ├── watchman: presence, pulses, stuck keys
vault: secrets, bus accounts ◄┤ └── status view: delivered, moving, settled, stuck
▼
node agent in the node-engine on every node
(reads its wants and its compositions; backs up first; writes its haves)
(reads its wants; composes its own modules; backs up first; applies; writes its haves;
on the bus node, writes the bus's user list)
```
- **The gate** (module `mesh-delivery-gate`, holding the seat `mesh-delivery`) owns hotfixes, features and
milestones up to the merge: it keeps one key per pull request, asks the operator's Approve, merges a group in
one pass and moves the source revision in one write. It asks the controller nothing, consumes no event of a
plan, never sends to a machine and writes no composition (ADR 0539 §17).
- **The controller** keeps registration, the inputs of every node (settings and given values, secrets,
identities and memberships, credentials, the facts), placement in its assignments bucket, and composing: it
writes each module's signed composition for each node, its digest and its judgement of the move, by
compare-and-set while it holds the lease, and issues a module's credential and grant when its build is done.
It plans nothing, orders nothing and sends nothing (ADR 0539 §1, §2, §5, §7, §12).
- **The controller** is no part of build and delivery (ADR 0547 §1). The jobs it still keeps outside them
(nodes and adoption, identities, secrets and given values, licences, config moves, conditions and facts, ADR
0429 §9) each move by a decision of their own under research 072 before it loses its lease; where placement and
the mesh's signing key live is the operator's choice, asked apart (issue 1126).
- **The vault** keeps every secret and, from ADR 0547's third milestone, mints each bus account a membership
names, seals it to its node and writes its bcrypt hash for the grants part alone; until then it hashes the
accounts it is handed (ADR 0547 §9).
- **The build modules** build and check with toolchains installed on their node, each as an account of its own, and pull
their asks from the bus's streams, deliveries first (ADR 0405, ADR 0525).
- **The forge module** (`gitea`) publishes every forge event on the bus through the forge's system webhook
@@ -304,7 +334,7 @@ module's progress on each node is its want against its have, shown by the view (
*ADR 0419 §1, §2, ADR 0429 §6, ADR 0539 §6, §7.*
A delivery group has no order among its members, and nobody writes one (ADR 0419 §1). From release 6 there are
no tiers: no plan orders modules into steps. What reaches a node, and when, is the assigner's seven rules, read
no tiers: no plan orders modules into steps. What reaches a node, and when, is the assigner's six rules, read
per module and node from the keys:
- **A build before its want.** No want names a fingerprint whose build is not done; a module whose build waits
@@ -444,10 +474,9 @@ From its delivery, a check is this:
own, and
composes only the machines that run or could run a module the change moves or adds, or whose grants or
providers it alters; for a group, once over every member's change, read from the indexer's candidates of the
group, and while the indexer holds none the group's check waits and says why. It composes with the function the
controller composes with, moved into mesh-sdk, so the two agree for one mesh-sdk version; its verdict names the
mesh-sdk version it composed with, and while the assigner and the controller run different versions the
controller's self-check raises a condition until they agree. No judge is built from a change: a change to the
group, and while the indexer holds none the group's check waits and says why. It composes with the function
every node agent composes with, mesh-sdk's composition, so the two agree for one mesh-sdk version; its verdict
names the mesh-sdk version it composed with. No judge is built from a change: a change to the
composition is proved by its own tests, a field only a newer composition reads goes out as optional first, and
the running composition refuses a manifest that uses a field it does not read, naming the field. What it fails on, and its warning past twelve rebuilt modules, are the composition check's, as they were the controller's composition check's (ADR 0446, ADR 0237 §2).
The assigner writes the verdict under the checker's hash of the heads it judged, in its own bucket, and the checker reads it into the
@@ -493,7 +522,7 @@ From its delivery, a check is this:
- **A merge moves the source revision, and nothing collects it.** The gate writes a group's merged heads as one
revision of `source.main` in one write (ADR 0429 §11). There is no merge window, no batch and no plan: the
indexer writes each module's fingerprint at the merge, the builder claims each new fingerprint once, and the
assigner writes each want when its seven rules hold. A merge is never refused, held or dropped once it is made.
assigner writes each want when its six rules hold. A merge is never refused, held or dropped once it is made.
- **Two merges close together are two revisions.** The second's fingerprints replace the first's in the
indexer's modules; a node gets the newer fingerprint's want once its rules hold, and a fingerprint nobody wants
any more is never applied. Nothing waits for a window to close.
@@ -536,57 +565,59 @@ 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 §1 to §7, §9, §14, §15.*
*ADR 0360 §8, §9, ADR 0377, ADR 0429 §4, §6, ADR 0539 §9, §14 to §16, ADR 0547 §2 to §9.*
- **A composition per module, node and fingerprint.** The controller composes one module's resources for one
node at one fingerprint with mesh-sdk's composition, the one the node-engine uses too, and writes it as
`<node>.<module>.<fingerprint>` in the bucket `composed-<node>`, which only that node's account reads, beside
the node's own composition `<node>.node` (adoption, firewall openings, accounts, the resolver, identities and
groups). Under the same key in `mesh-controller_composed`, which the assigner reads, it writes the
composition's digest and its judgement of the move from the composition the node runs now, as its have names
it: recreates a container, moves data, neither, or cannot be judged (ADR 0377 §3), rewritten when that have
changes. No composition's content is readable outside its node (ADR 0539 §1, §2).
- **Signed.** Each composition carries the signature of the controller's key or, made by hand, of the
operator's key; the node agent trusts exactly these two and applies nothing of a composition whose signature
fails or whose signer is neither. The operator's public key reaches a node in the switch's last declaration,
or at its adoption for a node adopted later (ADR 0539 §3).
- **Written on events, never on a timer.** A done build of an assigned module, an assignment written or ended,
a setting or given value, a secret rotated or moved, a credential issued, an outside acceptance, a node
adopted, taken or converged, a peer added to the hub and a change of the announced reads each make the
controller compose what they touch and write the compositions that differ. A change that keeps the
fingerprint is a new revision with a new digest, and reaches the node only when the assigner writes the want
again naming it, by the same rules as a new fingerprint (ADR 0539 §5).
- **Kept only while it can be wanted.** A composition and its digest are deleted when the fingerprint is no
longer among the module's five newest and no want names it; each bucket keeps five revisions of a key; a file
over 64 KiB travels by digest in `declaration-files-<node>`, removed a day after no composition of that node
names it. Neither bucket is a link of the chain: a composition is derived and can be composed again (ADR 0539 §4).
- **Credentials and grants on a done build.** When the builder's done key names a new fingerprint of an
assigned module, the controller issues the module's bus credential and writes `grants.<module>.<fingerprint>`
before any want can name it. The bus's user list is part of the bus module's composition: a revision that
changes only the user list is wanted at once, outside the person's hold, and the node agent applies it as a
file change and a reload (ADR 0539 §7).
- **The want names the composition.** A want `want.<node>.<module>` names a fingerprint and the digest of the
one composition the assigner allows for it; the node's own want `want.<node>.node` names the node's
composition (ADR 0539 §1, §6).
- **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
values read from mesh-config's resolved state filtered to its node, its secrets and bus credential asked of the
vault sealed to the node's key (ADR 0349 §11), its licences, and what its providers contribute; and the node's
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).
- **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).
- **Grants by the grants part.** A module's grant `grants.<module>.<fingerprint>`, which the assigner's sixth
rule reads, is written by the grants part from ADR 0547's third milestone; its account is minted by the vault
(ADR 0547 §4, §5, §9). Until that milestone the issuer ADR 0539 §7 names writes both, so a want never waits on a
key nobody writes.
- **The bus's user list.** The grants part composes the list with mesh-sdk's bus composer when an input changes,
writes it as an object sealed to the bus node's key and writes the key `user-list` with its digest, revision,
user count and the users left out; it says `user-list-changed`. The node agent of the bus node writes the bus
module's user-list file alone, mode 0600, only when its digest differs, and the bus reloads it in place; no want
is needed, no fingerprint moves and the bus is not moved. It says the list it wrote in the bus module's have:
where it was taken from, the digest wanted and the digest on the machine, the users and any refusal. A list
without the controller's own user, or one that drops more than half the users of the file on the machine, is
refused and the file kept. The watchman mirrors `user-list` as owed by the bus node, with a pulse of 60
seconds, so a list written and not loaded within a minute is stuck (ADR 0547 §7). Until the operator's
`take-over` the grants part runs in shadow, and the bus node takes the list from the bus module's composition
the running system writes for it, the user-list resource alone (ADR 0547 §8).
- **Memberships and assertions.** The grants part publishes each module's membership on the assignments stream
only when it differs from the one last published, and asserts every bucket, log and stream a manifest declares
when a new manifest digest is registered, with its limits; before `take-over` it composes and compares both and
publishes or asserts nothing (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).
- **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 or
digest differs from what runs, and only the composition whose digest the want names, removing only that
module's own resources: a shared path stays while any composition declares it. It writes the have with the
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,
removing only that module's own resources: a shared path stays while any composition declares it. It writes the have with the
fingerprint, the digest, the phase and the health after the module's start window. A failed apply is loud,
retried by the next change of the want or the composition, never by a clock, and fixed forward (ADR 0360 §8,
ADR 0539 §9).
- **Every want is owed.** The watchman mirrors every want as a pulse owed by that node's agent until its have
names the want's fingerprint, so a node that does not move is a stall (ADR 0539 §19).
- **A move a person must allow is asked before the want.** For a module of policy `record`, the assigner writes
no want naming a composition judged to recreate a container or move data, at a new fingerprint or a new
revision alike, until the operator answers its ask yes, on the phone or in the view; a move judged neither is
written as any want, and so is a module the node never ran; one that cannot be judged waits for the ask, which
says why. One exception, right after the switch: with no readable want, and a have from the old node-engine at
the module's newest fingerprint naming no composition, the want is written with no record hold, because the
node agent applies nothing when the composition equals the declaration it kept (ADR 0539 §9). Each judgement and the way it went are shown in the view and named in the ask (ADR 0539 §14).
- **The bus is never moved by the assigner.** The controller's `bus upgrade` checks as before and then asks the
operator to write the bus node's want with the operator's credential, recorded, until issue 1125 settles the
bus's replacement (ADR 0539 §15).
- **A move a person must allow is judged by the node and asked by the assigner.** The node agent applies ADR 0377
§3's tests to the composition it runs and the one it composed. For a module of policy `record`, a move judged to
recreate a container or move data, at a new fingerprint or a revision alike, is not applied: the node agent
writes its have with phase `waiting-yes` and the judgement, the assigner raises the ask, and on the operator's
yes, on the phone or in the view, writes the want again naming the yes, which the node agent reads from its own
want. A composition equal to what runs is no move and needs no ask. Each judgement and the way it went are shown
in the view and named in the ask (ADR 0547 §3).
- **The bus is never moved by the assigner.** A planned move of the bus is asked of the operator, who writes the
bus node's want with the operator's credential, recorded, until issue 1125 settles the bus's replacement (ADR
0539 §15). A new user list is no move of the bus (ADR 0547 §7).
- **The witness stays.** The node-engine's witness still puts back a controller or tool runner that does not
come up (ADR 0360 §9). A new node-engine runs on trial under its launcher until it writes its first have under
its own build (ADR 0539 §9).
@@ -660,8 +691,10 @@ history: no rollout is written after release 5's last plan (ADR 0539 §12).
| rollout | read-only from release 6: each plan of releases 1 to 5, its tiers, the builds it carried and the assignments it changed | nobody from release 6 | `mesh-controller_rollouts` |
Beside the chain, on the bus too: deliveries and groups (the gate's `deliveries` and `groups`, ADR 0239 §37), one
key per open pull request (the gate), and the compositions with their digests (`composed-<node>` and
`mesh-controller_composed`), which are derived state and no link of the chain (ADR 0539 §4). The buckets of plan
key per open pull request (the gate), and the grants part's state (`user-list`, the memberships it last
published, and from ADR 0547's third milestone the grants). A composition is no key of the bus once nodes compose
their own (ADR 0547 §2); until then the compositions with their digests are derived state and no link of the chain
(ADR 0539 §4). The buckets of plan
state, the merge window's keys, the silent sends' keys and a building plan's hold, are deleted by the controller
at its first start of release 6 (ADR 0539 §13).
@@ -727,20 +760,19 @@ the operator for the bus node's want (ADR 0539 §15).
*ADR 0526, ADR 0539 §9, §10, §11, §15.*
- **The controller, the node-engine, the tool runner and the gate are ordinary modules.** Each new fingerprint
gets its composition from the running controller, its credential and grant when its build is done, and its
want from the assigner; the control-node is the controller's only node and so its canary. The node-engine's
- **The node-engine, the tool runner, the grants part and the gate are ordinary modules.** Each new fingerprint
gets its grant from the grants part, its account from the vault and its want from the assigner, and its node
composes it (ADR 0547 §2, §4, §5, §9). The node-engine's
witness puts back a controller or tool runner that does not come up (ADR 0360 §9), and a new node-engine is
rolled back by its launcher unless it writes its first have under its own build (ADR 0539 §9). The bus stays
outside the assigner (ADR 0539 §15).
- **A replaced controller or part carries on from the bus**: the keys, the streams and the durable consumers hold
every step, so nothing is lost or repeated (ADR 0406 §6). A controller composes, at its start, every assigned
module and the fingerprint of the controller it replaced, so the way back to that controller is one want
(ADR 0539 §10).
- **A build before its want.** The controller takes every module, the builder's own and the build modules among
them, from the builder's done key whose artifacts all name a reference; a module whose key is not yet done
every step, so nothing is lost or repeated (ADR 0406 §6). The way back to a replaced version is one want
naming its fingerprint, which its node composes again (ADR 0547 §2).
- **A build before its want.** Every module, the builder's own and the build modules among them, is wanted only
from the builder's done key whose artifacts all name a reference; a module whose key is not yet done
waits under the assigner's first rule and fails nothing (ADR 0524 §7, ADR 0539 §18).
- **The switch to release 6 was one plan, release 5's last** (history: it is delivered). Release 5's controller ran
- **History: the switch to release 6 was one plan, release 5's last** (it is delivered; ADR 0547 takes the composing, signing and issuing it gave the controller away again). Release 5's controller ran
the group's plan with the new node-engine and the new controller in one tier (issue 1942), so every node's last
declaration named the new node-engine and carried the operator's public key, and the control-node's named the new
controller too. Each node applied it with the node-engine it ran; the new controller wrote every composition at
@@ -764,8 +796,8 @@ way is written down before the switch (ADR 0526, which ADR 0522 §6 asked of R4g
1. **A revert, with no build.** A broken builder or build module is undone by reverting its change: the earlier source's fingerprint has a done
key naming references, so the delivery of the revert builds nothing. It needs the earlier artifact in the artifact store, which keeps a
recorded build's artifact while it is among its module's five newest or a definition names it (ADR 0526 §1); from release 6 its
composition is kept while it is among the five newest too, so the assigner's want delivers it (ADR 0539 §4).
recorded build's artifact while it is among its module's five newest or a definition names it (ADR 0526 §1); the assigner's want
names it and its node composes it (ADR 0547 §2).
2. **A build by a session's call.** A session calls the build module's fetch and build tools on one named build node (for Go, a fetch and then
a build with publishing on); the build module pushes the artifact to the artifact store and answers its reference, as it does for the
builder (ADR 0526 §2, ADR 0525 §8). `mesh-pack`, in mesh-sdk, builds and packs a Go bundle with the Go build module's recipe, so a hand
@@ -773,13 +805,10 @@ way is written down before the switch (ADR 0526, which ADR 0522 §6 asked of R4g
3. **A registration by reference, at the controller's terminal only.** The operator names the module, its repository, its path and each
artifact's reference at the controller's terminal, and the controller registers it with no builder key, recording the act with its why;
no verb reaches it (ADR 0526 §3).
4. **A controller that cannot take its own fix** is put back by keys written at the terminal, never by a declaration sent by hand: the
operator's credential writes `want.<control-node>.mesh-controller` to a fingerprint whose composition is kept, the replaced
controller's among them, since a controller composes that one at its start. For a hand build never composed, `mesh-hand-compose`, a
command of mesh-sdk beside `mesh-pack`, composes the module for the node from the controller's kept inputs with mesh-sdk's
composition, signs it with the operator's key and, with the operator's credential, writes it into `composed-<node>` and its digest
into `mesh-controller_composed`; the operator then writes the want naming that digest. Each act is recorded in the hand-act log, and
the node-engine keeps no path that applies a whole declaration (ADR 0539 §10, which changes ADR 0526 §4).
4. **A part that cannot take its own fix** is put back by a want written at the terminal, never by a declaration sent by hand: the
operator's credential writes `want.<node>.<module>` to a fingerprint whose build is done, and the node agent composes it for its node
as any want (ADR 0547 §2). Each act is recorded in the hand-act log, and the node-engine keeps no path that applies a whole
declaration (ADR 0526 §4).
5. **Copies kept outside the store.** Before a switch that moves the controller, the builder or a build module, the artifacts of the
running versions are kept outside the artifact store on two nodes, each by digest with its module, artifact, commit, Go version and the
steps that put it back, because the store's nightly collection removes a blob the controller did not record (ADR 0526 §6).