diff --git a/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md b/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md index c23482c3..44dd2f01 100644 --- a/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md +++ b/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md @@ -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] -updated: 2026-10-24 +code: [mesh-controller, mesh-catalog modules/mesh-delivery-gate, mesh-delivery, mesh-host, mesh-sdk, mesh-vault, hq 00-META/checks] +updated: 2026-10-25 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..` names the fingerprint and the digest of the one - composition it allows; the assigner also writes the node's own want `want..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..` 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..` 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`, 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..` 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..` (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 @@ design says, and ADR 0539's clauses hold from that delivery (ADR 0539 §20). ## 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 - `..` in the bucket `composed-`, which only that node's account reads, beside - the node's own composition `.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-`, 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..` - 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..` names a fingerprint and the digest of the - one composition the assigner allows for it; the node's own want `want..node` names the node's - composition (ADR 0539 §1, §6). +- **Each node composes its own.** For each want `want..` 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..`, 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..` names the fingerprint, the artifact's digest, the + source revision and whether the module holds data; the node's own want `want..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-` 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,20 @@ 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 is one plan, release 5's last.** Release 5's controller runs the group's plan with +- **History: the switch to release 6 was one plan, release 5's last.** Kept as it was decided (ADR 0539 §11); + ADR 0547 takes the composing, signing and issuing it gave the controller away again. Release 5's controller runs the group's plan with the new node-engine and the new controller in one tier (issue 1942), so every node's last declaration names the new node-engine and carries the operator's public key, and the control-node's names the new controller too. Each node applies it with the node-engine it runs; the new controller writes every composition at its @@ -765,8 +798,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 @@ -774,13 +807,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..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-` 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..` 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).