From d94f8a05a860cf1aee0ff3714f3fcf9e88ea7b18 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 25 Oct 2026 22:07:56 +0100 Subject: [PATCH 1/4] 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 --- .../47-delivery-from-commit-to-delivered.md | 233 ++++++++++-------- 1 file changed, 131 insertions(+), 102 deletions(-) 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 1d080815..8f442f3c 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] +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..` 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 @@ 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 - `..` 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,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..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). -- 2.54.0 From 5bdeb8db83803bfb60696b7b3d10be104ce10da1 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 25 Oct 2026 22:21:24 +0100 Subject: [PATCH 2/4] Design 47: take-over's test as ADR 0547's insight states it --- 03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 8f442f3c..3e4b934d 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 @@ -184,8 +184,9 @@ 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). + operator's `take-over` makes the grants part's list the one loaded; it is allowed only when the users of both + lists are equal but for users placement no longer names, so it waits until the enrolment users and the persons + have records on the bus, and the second milestone waits for it (ADR 0547 §8, §11). 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 -- 2.54.0 From d70791ddee2e74cda6dcf0f8f754671757d92eb2 Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 26 Oct 2026 02:58:12 +0100 Subject: [PATCH 3/4] Design 47: sentences that still named the controller as composer, issuer or reader of grants follow ADR 0547 as amended --- .../47-delivery-from-commit-to-delivered.md | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) 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 3e4b934d..ab400dee 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 @@ -160,9 +160,10 @@ source revision is derived from the keys: every **want** equals its module's **f 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. + bus's user list, and from ADR 0547's third milestone `grants..` (ADR 0547 §5, §6). It publishes + memberships from the first milestone; until the operator's `take-over` it keeps the bus's user list, the + assertions and the grants in shadow, composing and comparing them with what the bus loaded and writing nothing + of them 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 @@ -183,7 +184,11 @@ 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 + part publishes memberships (by the one grant the operator allowed in the controller's composer and its + mesh-sdk copy, publishing the assignment subjects and nothing more) and composes and compares the user list, + assertions and grants in shadow with its tools; the vault hashes the bus accounts it is handed into its key + `bus-accounts.` and adopts once the hashes of accounts it holds no value for, from the list the bus + loaded. The operator's `take-over` makes the grants part's list the one loaded; it is allowed only when the users of both lists are equal but for users placement no longer names, so it waits until the enrolment users and the persons have records on the bus, and the second milestone waits for it (ADR 0547 §8, §11). @@ -470,8 +475,8 @@ From its delivery, a check is this: - **The composition check is the assigner's.** Whether the machines still compose with a change is checked by the part that owns what each machine should run. The assigner reads the modules, fingerprints and manifests the indexer holds and the builds the builder holds; the machines, their roles, assignments and settings, and - the grants and credentials it reads from the controller's facts snapshot and from the controller's buckets it - names in its manifest's `reads` (ADR 0237 §1, ADR 0408 §3). It clones no repository but at most the change's + the grants and credentials it reads from the grants part's state and the vault's accounts, and the rest from the buckets it + names in its manifest's `reads` (ADR 0237 §1, ADR 0408 §3, ADR 0547 §4). It clones no repository but at most the change's 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 @@ -595,8 +600,9 @@ backup holder backs up nothing, and the have says so. 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). + when a new manifest digest is registered, with its limits; memberships are published from the first milestone + (the operator's one grant, 22:31 on 2026-10-25), while before `take-over` assertions are composed and compared + and nothing is asserted (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). @@ -988,7 +994,7 @@ release reports the controller's code lines against research 063's baseline (acc | R4e | The controller asks no build: a build is keyed by its fingerprint, the new form becomes the only one as one group, and a merge builds nothing its check built; builders fetch over SSH, so an SDK change ships with its users; the vendored copies leave mesh-controller and mesh-sdk; delivered only once the builder's artifact digests equal build-agent's (ADR 0453 clauses 2, 4, 5, 6) | 16, 2, 4 in part | mesh-controller (builds are no longer asked), mesh-delivery (builder), mesh-sdk | 979 (the installed toolchains; closed with the toolchain images in R4g), 1304, the controller asking no build (opened when it is prepared) | | R4f | A pull request carries one required status that says what it proved and how long each part took; the controller's composition check and its replays are deleted with the two old statuses; the controller's deletions R3e makes possible go; each level's times are measured, and a bound fails a repository from the first check that meets it (ADR 0447, ADR 0450 §8, ADR 0453 clauses 4, 9, 10) | 21, 22, 23, 24 (the status; the scripts' absence is proved in R4g) | mesh-delivery (checker, assigner), mesh-controller (composition check, replays, `delivery-plan`, `forget-checks`, the asker `mesh-delivery` deleted), mesh-catalog (gitea) | 1299 (the composition check deleted; closes issue 709, the replays' socket), 1300, 1301, 1302 (one status), 1305 (ADR 0482 §8), 1318 | | R4g | The last milestone of release 4 and release 5 as one, with one switch-over and no rehearsal (ADR 0524 §1): builds and checks are asks on streams that each build node pulls when it has a free slot, deliveries first, with nothing holding checks and no controller queue (ADR 0525); the assigner is made with its composition check, writes each node's wants compared with what the controller sends and every difference, and the view answers the asks that need no proof of who answered (ADR 0528, ADR 0437 §10); no module's fingerprint takes the builder (ADR 0530); the scripts of the repositories a module is built from, build-agent with its socket and Dockerfile code, the toolchain images and the controller's build code go, and the builder delivers its own module, the build modules and the controller from its keys (ADR 0453 clauses 5, 8, 10; ADR 0524 §5, §7); the ways to deliver without the builder are recorded (ADR 0526); hq's four checks are Go tests (ADR 0527); each repository's script goes (ADR 0529); the word for the composition check's predecessor is struck. Its pull requests are opened only after five readings, the revert path read, not shown on a test merge (ADR 0524 §3) | 4 (from R4g mesh-build-image, rootless, is the only part that builds an image: ADR 0487 §7), 17, 24 (no `merge-check.sh` in a repository a module is built from) | mesh-sdk, mesh-controller (build-agent removed), mesh-delivery, mesh-catalog, mesh-tools, mesh-tools-go, the node-engine (`mesh-host`), mesh-media-catalog, okioki, hq | 1887 (the flow), 1297 (the assigner), 1295 (`merge-check.sh` goes), 979 (closed with the toolchain images), 1296 and 1303 (hq's check, the old word struck), 1299, 1305, 1294, 1318 (the controller's deletions) | -| R6 | Each node applies from its wants the compositions the controller signs for it, a new version reaches the module's canary first and the rest once it is healthy there, a move a person must allow is asked before its want, the view says what is moving, settled, stuck and delivered, and the plans are deleted from the code; switched over by release 5's last plan (ADR 0539) | 18, 19, 20 | mesh-sdk, the node-engine (`mesh-host`: the node agent), mesh-controller (compositions, credentials on a done build; plans deleted), mesh-delivery (assigner, watchman, view), mesh-catalog (the gate, the messenger, the issue tracker, the backup holder), hq | 1942 (the planner puts the node-engine and the controller in one tier for the switch; delivered first), 1945's fix before the switch (the bus's user list grants what release 6 uses; delivered first), 1943 (mesh-sdk: the composition's layout and signature, the want's digest, `mesh-hand-compose`, the verb tables without the plan verbs), 1944 (the node agent), 1945 (the controller writes compositions and grants; the plans and the push deleted), 1946 (the gate keeps the merge's states; the messenger and the issue tracker hear the view), 1906 (the assigner's seventh rule and its asks, the watchman's pulses for wants, the view's wants and events), 1130 (hq) | +| R6 | Each node applies from its wants the compositions its own node agent composes (ADR 0547 §2; as released it applied the controller's signed ones), a new version reaches the module's canary first and the rest once it is healthy there, a move a person must allow is asked before its want, the view says what is moving, settled, stuck and delivered, and the plans are deleted from the code; switched over by release 5's last plan (ADR 0539) | 18, 19, 20 | mesh-sdk, the node-engine (`mesh-host`: the node agent), mesh-controller (plans deleted; as released also compositions and credentials, which ADR 0547 moves to the node agents, the grants part and the vault), mesh-delivery (assigner, watchman, view), mesh-catalog (the gate, the messenger, the issue tracker, the backup holder), hq | 1942 (the planner puts the node-engine and the controller in one tier for the switch; delivered first), 1945's fix before the switch (the bus's user list grants what release 6 uses; delivered first), 1943 (mesh-sdk: the composition's layout and signature, the want's digest, `mesh-hand-compose`, the verb tables without the plan verbs), 1944 (the node agent), 1945 (as released the controller writes compositions and grants, which ADR 0547 moves; the plans and the push deleted), 1946 (the gate keeps the merge's states; the messenger and the issue tracker hear the view), 1906 (the assigner's seventh rule and its asks, the watchman's pulses for wants, the view's wants and events), 1130 (hq) | Release 5 (the assigner's wants, compared only) is not a milestone of its own: ADR 0524 §1 folds it into R4g, whose row above holds it. Release 6 is milestone R6, prepared on 2026-10-24 with ADR 0539. Its prepare step found six repositories where its row first -- 2.54.0 From f1c50d3e018c1704e0188f5976420ea04b4c93aa Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 26 Oct 2026 02:59:58 +0100 Subject: [PATCH 4/4] =?UTF-8?q?Design=2047:=20the=20assigner's=20acceptanc?= =?UTF-8?q?e=20test=20names=20its=20six=20rules,=20as=20ADR=200547=20?= =?UTF-8?q?=C2=A74=20leaves=20them;=20the=20bus=20node=20follows=20the=20c?= =?UTF-8?q?ontroller's=20list=20until=20the=20third=20milestone,=20for=20h?= =?UTF-8?q?and-back;=20placement=20stays=20where=20it=20is=20for=20now=20(?= =?UTF-8?q?issue=201126)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 ab400dee..d3de3330 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 @@ -193,7 +193,7 @@ there is three milestones, one issuer of each key at every moment (ADR 0547 §11 lists are equal but for users placement no longer names, so it waits until the enrolment users and the persons have records on the bus, and the second milestone waits for it (ADR 0547 §8, §11). 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`. + elsewhere but the bus's user list, which the bus node keeps able to follow until the third milestone so `hand-back` has a list to return to. 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 @@ -826,7 +826,7 @@ What the build proves before this design is implemented (research 055's directio 1. A feature across the controller and the catalogue with a new seat verb is delivered as one group, with no `after:` line, one composed check and one Approve: its merges move one source revision, each module it changes - is built once, and every want naming one of those fingerprints is written by the assigner's seven rules, with + is built once, and every want naming one of those fingerprints is written by the assigner's six rules, with no order written by anyone. 2. An SDK change and a Go module using it are delivered as one group. 3. A data module is backed up by its node's backup seat before the node agent applies a new fingerprint of it, @@ -851,7 +851,7 @@ What the build proves before this design is implemented (research 055's directio newer fingerprint once its rules hold, a fingerprint nobody wants any more is never applied, and nothing is released by a person or held in the gate. 12. No table in the controller's store holds builds, deliveries or assignments: builds are the builder's keys, - wants the assigner's, haves the node agents', and placement the controller's assignments bucket. + wants the assigner's, haves the node agents', and placement, for now, the controller's assignments bucket (where it lives is the operator's choice, issue 1126). Tests 1 to 12 are stated as they hold from release 6. Tests 1, 3, 7, 8, 9, 10 and 11 were first proved by milestones 1 to 5 in the shape of their time, the controller's plans and what it sent (the milestones table keeps -- 2.54.0