diff --git a/.claude/agents/mesh-watcher.md b/.claude/agents/mesh-watcher.md index 1ecffb34..9d85fab2 100644 --- a/.claude/agents/mesh-watcher.md +++ b/.claude/agents/mesh-watcher.md @@ -23,8 +23,13 @@ without that read on each machine the module is wanted on. Loop: wait with `mesh_wait` on the event family (its answer only wakes you), then read the state from the verb the handover names; never report a state you did not read in that round. Report and end at the first of: the thing reached its end (passed, merged, delivered, accepted, chosen, declined), it failed (quote every failure -line word for word), five minutes passed with no change while something should be moving (say what you last -read and when), the bound passed, or a call failed twice (quote it). +line word for word), the bound passed (say what you last read, when, and since when nothing moved), or a call failed +twice (quote it). + +**Never end on a quiet five minutes.** Your final report is your only channel to the lead: once you end, nothing +watches the thing. Five minutes with no change while something should be moving is no end: note it, keep waiting, +and put it in your final report (what stood still, from when to when, what you last read). A lead that wants to hear +of stillness sooner gives a shorter bound. You only read: no verb that writes, never ssh, never a shell helper. Report in a few lines, with times in UTC as the tools give them; the lead says them to the operator in local time. diff --git a/00-META/glossary.md b/00-META/glossary.md index 31c8ffc5..b5313a59 100644 --- a/00-META/glossary.md +++ b/00-META/glossary.md @@ -291,11 +291,17 @@ every other domain has something to run on. **Recorded by** the controller and t **Purpose.** To decide, send and apply what each node runs, and to say why. **Recorded by** the controller's `inventory` database; from ADR 0567, by the seat `mesh-module-assigner`, in its states on the bus. **Upstream of** Provisioning, Connectivity, Data -and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 0252, 0261, 0411, 0539, 0549, 0559, 0565, 0567, 0571, 0634. +and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 0252, 0261, 0411, 0539, 0549, 0559, 0565, 0567, 0571, 0634, 0645. **Uses:** node, machine, module, seat, manifest (Module), config value (Config), proposal (Operator and conversation). - **assignment** — a module put on a node. Its config values on that node (module-assignment config, Config) are `mesh-config`'s, never part of what the controller records (ADR 0348 §9). +- **assignment graph** — the module versions placed on nodes at one revision, with the edges between versions that + its inputs give: provisioning, contribution, and the acting parts' versions that are to act on each entry. The + assigner computes it from the catalog graph, the placements and the nodes' capabilities and from nothing else, keeps + each revision as objects of the seat `mesh-wants` naming the revisions of its inputs, and writes the wants from a + trunk revision's alone (ADR 0645 §2, §3, §7). Not the **catalog graph** (Delivery), whose entries are modules, not + versions on nodes; not an **assignment**, one module put on one node. - **placement** — which module runs on which node, with its pins, host ports and bindings, and what a person decided of the node, as one key per node in the state `placement` of the seat `mesh-module-assigner`. It changes only by a placement proposal the operator approves, and no repository holds it or names a node (ADR 0567). Until ADR @@ -515,7 +521,7 @@ and the operator act. **Recorded by** the controller's `identity` and `licences` back when it fails. The domain is continuous integration and delivery, named **delivery**, and its parts live in the repository `mesh-delivery` (ADR 0429 §2). **Recorded by** the `mesh-delivery` module (deliveries) and the controller (the planner, the rollout) until release 6 of ADR 0429; from each release on, by the parts it builds. **Downstream of** Module, Core, Health and repair and Data. -**Decided by** ADR 0162, 0218, 0236, 0237, 0238, 0239, 0250, 0267, 0270, 0276, 0323, 0401–0408, 0428, 0429, 0444–0447, 0524–0530, 0539, 0548, 0551, 0571, 0578, 0579, 0593, 0601. +**Decided by** ADR 0162, 0218, 0236, 0237, 0238, 0239, 0250, 0267, 0270, 0276, 0323, 0401–0408, 0428, 0429, 0444–0447, 0524–0530, 0539, 0548, 0551, 0571, 0578, 0579, 0593, 0601, 0644–0651. **Uses:** module, node, declaration and send (Placement), health (Health and repair), person. - **merge check** — what a pull request carries before it may merge, judging the merge of its head into a @@ -524,11 +530,35 @@ controller (the planner, the rollout) until release 6 of ADR 0429; from each rel **composition check**; for a delivery group, one verdict on every member's head (ADR 0445, ADR 0447). Before release 4 of ADR 0429 a pull request carried two statuses, one for the modules the change touches and one for the repository's own script (ADR 0238). -- **module graph** — the edges the indexer keeps between modules, from which each delivery part orders a source - revision by its own rule: provisions, bus state, a served verb and a reader's capability are waited on; a package - and a build module's change are triggers that rebuild, never waits; a verb edge on a cycle is left out (ADR 0603 - §1, §2, ADR 0614). Nothing stores the order. +- **catalog graph** — the modules as their manifests declare them at one revision (bases, packages, provides and + requires, invokes and serves), with the acting rules the seats declare; the indexer keeps it per source revision it + takes in, as objects of its own (ADR 0645 §1, §3). Its other name is **module graph**, the word for it before + ADR 0645, from which each delivery part orders a source revision by its own rule: provisions, bus state, a served + verb and a reader's capability are waited on; a package, and until research 085's milestone a build module's + change, are triggers that rebuild, never waits; a verb edge on a cycle is left out (ADR 0603 §1, §2, ADR 0614); from research 085's milestone an acting part's edge is a wait within + its step (ADR 0646 §3). Nothing stores the order. Not the **assignment graph** (Placement), computed from it. *Not:* ~~build graph~~ +- **acting part** — the holder of a seat whose definition says, in its field `acts`, the step its holder acts in + (taking in, validating, checking, building, composing, granting or placing) and the modules it acts on (every + module, or those of a language): the indexer, the checker, the build modules, the node-engine, the grants part, the + assigner (ADR 0646 §1). Within a revision its new version acts first in its step, a wait with a bound; when it fails, + the modules it was to act on stay on their running builds and a condition names it (ADR 0646 §3). Not every + **part**: an acting part may be any module that holds such a seat, a build module among them. +- **graph difference** — a change's assignment graph against the current one: the new versions, the moved edges, + the touched nodes and the order read off the edges. It is the change's delivery, and nothing stores a plan beside + it; the assigner serves it by the seat `mesh-wants`'s verb `difference` (ADR 0647 §1). Not a **delivery plan**, + which was stored and handed out. +- **revision view** — what every part acts on: the catalog graph with its heads, seat definitions, verdicts and + fingerprints, served by the seat `mesh-catalog`'s verb `revision`, and the assignment graph computed from it, + served by the seat `mesh-wants`'s verb `revision`, for a trunk revision or a candidate's heads; a pair, each half + served by its one owner (ADR 0649 §1). A part with none for the current revision says it waits (§3). +- **delivery record** — the gate's record of one milestone's delivery, a ledger instance it alone writes: the group's + state (heads, verdicts, checks, asks), the trace (milestone, issues, pull requests, commits, the assignment graph + revisions it moved between) and each entry's outcome on each node (ADR 0650 §1). It holds no tiers and nothing + else orders by it. Not a **delivery**, one commit on its way. +- **checking program** — the rules that judge a check, built from the change's heads and run in a build seat's + sandbox with the revision view as its input and no bus account; the running checker only asks for it, reads its + verdict, records and publishes it (ADR 0648 §2, ADR 0644 §3). Not the **checker**, the part that asks for it. - **composition check** — whether the machines a change touches still compose with it, run by the assigner from the modules the indexer and the builder hold, with the composition of `mesh-delivery-sdk`, the one the controller composes with 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 afe743bd..2be2c0ba 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,17 @@ --- layer: to-be status: in-progress -code: [mesh-controller, mesh-catalog modules/mesh-delivery-gate, mesh-delivery, mesh-host, mesh-sdk, mesh-vault, hq 00-META/checks] -updated: 2026-11-05 +code: [mesh-controller, mesh-catalog modules/mesh-delivery-gate, mesh-delivery, mesh-host, mesh-sdk, mesh-vault, mesh-contracts, hq 00-META/checks] +updated: 2026-11-06 decisions: + - "ADR 0651" + - "ADR 0650" + - "ADR 0649" + - "ADR 0648" + - "ADR 0647" + - "ADR 0646" + - "ADR 0645" + - "ADR 0644" - "ADR 0639" - "ADR 0638" - "ADR 0637" @@ -12,10 +20,13 @@ decisions: - "ADR 0634" - "ADR 0633" - "ADR 0632" + - "ADR 0618" - "ADR 0615" - "ADR 0614" + - "ADR 0612" - "ADR 0603" - "ADR 0601" + - "ADR 0597" - "ADR 0596" - "ADR 0595" - "ADR 0594" @@ -45,6 +56,7 @@ decisions: - "ADR 0526" - "ADR 0525" - "ADR 0524" + - "ADR 0496" - "ADR 0494" - "ADR 0493" - "ADR 0491" @@ -69,6 +81,7 @@ decisions: - "ADR 0452" - "ADR 0450" - "ADR 0449" + - "ADR 0448" - "ADR 0447" - "ADR 0446" - "ADR 0445" @@ -96,9 +109,11 @@ decisions: - "ADR 0401" - "ADR 0398" - "ADR 0395" + - "ADR 0391" - "ADR 0382" - "ADR 0377" - "ADR 0364" + - "ADR 0363" - "ADR 0362" - "ADR 0360" - "ADR 0350" @@ -137,6 +152,18 @@ nodes once it runs healthy there (ADR 0429 §6, ADR 0539); and one chain, from m to want to have, is kept in the bus's key-value store as its only source (ADR 0406, ADR 0408, ADR 0429 §17). A running delivery never touches merging: a merge moves the source revision, and the wants follow it. +**From research 085's milestone, two graphs order a change, and every part reads one revision view.** The +indexer keeps the **catalog graph** (the modules as their manifests declare them) and the assigner computes the +**assignment graph** (module versions placed on nodes, with the edges between versions), both kept per revision +(ADR 0645 §1 to §3). A change's **graph difference** against the current assignment graph is its delivery, and +nothing stores a plan (ADR 0647 §1). A part that acts on every other module's change in one step, an **acting +part**, says so in its seat's definition, and its new version acts first in that step, a wait with a bound +(ADR 0646 §1, §3). The check builds the change's own acting parts first and fails when it cannot (ADR 0648 §1, +§3); every part acts on one **revision view**, served as a pair by the indexer and the assigner (ADR 0649 §1); and +the gate keeps one **delivery record** per milestone's delivery (ADR 0650 §1). One bootstrap delivery goes before +that milestone, the only delivery ever made ahead of a change (ADR 0644 §1, §2). Each section below says what +changes; *Two graphs, one source of truth* and *The check on the change's own acting parts* hold the whole of it. + This is the delivery of [to-be 10](10-delivery.md) carried out. To-be 10 says what is built: the comparison of source and artifacts decides, and nothing here changes that. This design says who answers for one commit's journey, in what order the steps are allowed, and where each fact of it is kept. It was rewritten on @@ -155,7 +182,9 @@ source revision is derived from the keys: every **want** equals its module's **f forge. - **The indexer** computes each module's fingerprint at the merge preview and writes the candidates of each group and the modules of the trunk. It reads no placement: placement is not in any repository, and the forge - bridge carries nothing of placement (ADR 0567). + bridge carries nothing of placement (ADR 0567). From research 085's milestone it keeps the catalog graph per + revision and serves its half of the revision view by a verb of its seat `mesh-catalog` (ADR 0645 §1, §3, + ADR 0649 §1). - **The builder** claims a build by creating its key, once per fingerprint, and orders it as an ask on the stream of the artifact's language; it makes no artifact's bytes since R4e and chooses no node, because the build modules pull the asks (ADR 0498 §1, ADR 0525 §1, §4). From R4g it delivers its own module, the build modules and the controller from its keys, and nothing falls back to build-agent, which is removed @@ -170,11 +199,16 @@ source revision is derived from the keys: every **want** equals its module's **f taking the kept verdict of the rest; it writes the change's one status (ADR 0444, ADR 0445, ADR 0447); it runs dark in R4c-5 (ADR 0484). It judges a delivery once per set of heads, and carries a verdict to a newer trunk commit by its package digests instead of judging it again (ADR 0548 §1, §5; *A move of the trunk carries every verdict*, below). + From research 085's milestone its judging rules are a **checking program** built from the change's heads and run + in a build seat's sandbox; the running checker only asks, records and publishes (ADR 0648 §2; *The check on the + change's own acting parts*, below). - **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. While the check gates merges, it holds an approved merge for another delivery's running check of the repositories the merge goes into, and keeps the merge's **merge turn** there (ADR 0548 §2, §3, as ADR 0551 §1 bounds them; *Nothing merges into a repository - under check*, below). + under check*, below). From research 085's milestone it keeps one delivery record per milestone's delivery as a + ledger instance, its `merges` and `turns` carried into the records (ADR 0650 §1, §3; *The delivery record*, + below). - **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 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` @@ -193,7 +227,10 @@ source revision is derived from the keys: every **want** equals its module's **f R4g with release 5; from release 6 it writes no difference (ADR 0524 §4, ADR 0528, ADR 0539 §8). The check composes no placement and waits for no node's answer: a pull request changes no placement, since placement is bus state changed by a proposal (ADR 0567; ADR 0446 §3 read as written). Its own composition stands in for every sealed value, so only a node's answer to a proposal can say that - what the node would run is the same. + what the node would run is the same. From research 085's milestone it computes the assignment graph from the + catalog graph, the placements and the nodes' capabilities, keeps each revision as objects of its seat + `mesh-wants`, works out a change's graph difference and writes the wants from a trunk revision's assignment graph + alone (ADR 0645 §2, §3, §7, ADR 0647 §1, §3). - **The node agent**, the node-engine's own process, follows its node's wants, **composes each wanted module for its own node** with the composition of `mesh-delivery-sdk` 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 @@ -370,6 +407,63 @@ compare-and-set (ADR 0406 §4). It writes a new head when the forge says one, an pull request's verdict is carried to it or a whole check is asked against it (ADR 0548 §5, §7). A running check watches that key and stops only when the head in it moves; a trunk move never ends it (ADR 0548 §1). +### The delivery record + +*ADR 0650; ADR 0595, ADR 0597, ADR 0596, ADR 0603 §7, ADR 0493 §3, ADR 0633 §4, §5.* + +From research 085's milestone the gate, holder of the seat `mesh-delivery`, keeps its state per milestone's +delivery as one **delivery record**, a ledger instance (ADR 0595's template `ledger`, ADR 0597) the gate alone writes +(ADR 0650 §1). It holds: + +- **the group's state**: the heads, the verdicts, the checks and the asks, which `merges` and `turns` hold today; +- **the trace**: the milestone, its issues, its pull requests, their commits, and the assignment graph revisions the + delivery moved between (ADR 0645); +- **each entry's outcome on each node**: for every entry of the graph difference (ADR 0647), taken in, built, + checked, composed, wanted, running healthy, or away. + +It holds no tiers, and no part but the gate orders work by it, so it is no second copy of the keys (ADR 0650 §1). + +- **The outcomes arrive as events, through a durable consumer of the gate's own.** The gate's manifest `consumes` + each step event of *What each step says* (below); its consumer resumes from the last event applied, an event + applied twice changes nothing, an event is applied only when it comes from its owner's account, and running + healthy is taken from the node-engine seat's event, never from a have read across the seam (ADR 0650 §2, + ADR 0596). +- **It ends when every present node runs its entries.** It says the nodes away with since when, and takes a node + away's outcomes when it wakes (ADR 0650 §5, ADR 0603 §7). A small fix is a milestone of one issue and has a + record of its own (ADR 0650 §5, ADR 0493 §3). +- **It pins the graph revisions it points at.** The gate says, as events of the seat `mesh-delivery`, which catalog + and assignment graph revisions a record pins and when it frees them, and when a candidate's heads were replaced + or its pull request closed; the indexer and the assigner remove a revision or drop a candidate's graphs only on + those events (ADR 0645 §5, ADR 0647 §3). Records are kept for good unless configured, and the revisions they pin + with them (ADR 0650, Consequences). +- **The switch carries today's state in.** At the new gate's start, `merges`, `turns` and every group in flight + become records, so no approved group is asked again; a gate rolled back reads them back (ADR 0650 §3). Which of + the two the gate does after the switch, keep `merges` and `turns` current beside the records or write them back at + the rollback, the record leaves open (*What is not decided here*). +- **The forge bridge asks the seat for a group.** It reads a group's members from the seat `mesh-delivery`'s verb + `groups`, never the gate's `merges` state, both to set the group on each merged message and to publish a group's + end again (ADR 0650 §4, which changes ADR 0633 §4 and §5; ADR 0596). +- **Its size.** One record of 30 modules on four nodes is about 30 KiB, against the bus's 256 KiB value limit + (ADR 0650, Context; §7). +- **Its tools**, against the four lines a module's tools answer: + + | Line | The gate | + |---|---| + | read everything it holds | `gate_record` (one record whole: the group's state, the trace, each entry's outcome per node, the nodes away), `gate_records` (every record with its fill against the value limit), `gate_consumer` (its durable consumer: the last event applied per family, the events waiting, the age of the oldest) | + | do by hand what it does itself | `gate_record_repair` (ask each part for its outcome again and apply the answers) | + | recover without help | `gate_record_end` (end a record left open, a node gone for good or an entry that never runs, with the reason, recorded in the hand-act log of the seat `mesh-hand-acts`) | + | one seat, many tools | the seat `mesh-delivery`'s verbs, with `groups` answering a group's members | + + `gate_record`, `gate_records` and `gate_record_repair` are ADR 0650 §6's; `gate_consumer` and `gate_record_end` + answer the seams review of 2026-11-06 on the records, and no record names them yet. +- **How it is checked.** The gate's whole-module test stops and restarts the gate in the middle of a delivery, and + the record is complete with no outcome counted twice; a group approved before the switch is not asked again + after it, nor after a rollback; the forge bridge's whole-module test reads a group's members from `groups` and + publishes a group's end from it. Live: one call of `gate_record` traces an issue of the registry milestone to + each node's running build, also after six later merges; a record of 30 modules on four nodes stays under + 256 KiB; a group checked again at old heads after a main move is not asked of the operator again (issue 1972) + (ADR 0650 §7). + ## The state table *ADR 0539 §17.* @@ -403,9 +497,190 @@ verdict that names the trunk's head (*A move of the trunk carries every verdict* backup hold, superseded, covered, stopped, retired and failed) and the machine steps went at release 6: a module's progress on each node is its want against its have, shown by the view (ADR 0539 §17). +## Two graphs, one source of truth + +*ADR 0645, ADR 0647, ADR 0649; ADR 0595, ADR 0596, ADR 0603 §2, §6, §7, ADR 0567 §5, ADR 0571 §8, ADR 0614 §4, +ADR 0618 §2, ADR 0636 §1, §4, §7, ADR 0639 §7.* + +From research 085's milestone. One graph answered two questions, which modules exist and which version runs where, +with one writer per key it could not keep; two graphs answer them, the second computed from the first, so there is +one source of truth (ADR 0645, Context and Option 1). + +``` + manifests ──► indexer (mesh-catalog) ──► catalog graph revision ──┐ + ├──► assigner (mesh-wants) ──► assignment graph revision + placements (mesh-module-assigner) ───────────────────────────────┤ │ │ + node capabilities (node records) ────────────────────────────────┘ │ └─► wants, from a trunk revision only + ▼ + a change's assignment graph − the current one = its graph difference = its delivery +``` + +- **The catalog graph is the indexer's.** The indexer, holder of the seat `mesh-catalog`, keeps at each revision one + entry per module as its manifest declares it (bases, packages, provides and requires, invokes and serves), with the + acting rules the seats declare (ADR 0645 §1, ADR 0646 §1). It is today's module graph, and *module graph* stays its + other name. Each revision is kept as objects of its own (ADR 0595's template `objects`, its cap in the indexer's + manifest), so the graph leaves its key-value state as ADR 0595 §11 moves a module when next touched (ADR 0645 §3), + in this milestone; the five past values of ADR 0603 §2 go with it (*What is not decided here* says the interim). +- **The assignment graph is the assigner's, computed and never written by hand.** The assigner, holder of the seats + `mesh-module-assigner` and `mesh-wants`, computes it from the catalog graph, the placements and the nodes' + capabilities and from nothing else: one entry per module version on a node, with the edges between versions those + inputs give, provisioning, contribution, and the acting parts' versions that are to act on each entry (ADR 0645 + §2). Each revision is kept as objects of the seat `mesh-wants`, announced by that seat's event and served by its + verbs, and names the revisions of its inputs: the catalog graph revision, the placements and the capability + readings (ADR 0645 §3). It is kept, but it is no stored plan: any revision is computed again from the inputs it + names and compared with the one kept, by a tool (below), so a kept revision is a checked derivation, never a + second source. +- **A revision is made by a merge, and also with no merge.** The indexer makes a catalog graph revision when it + takes a source revision in; the assigner makes an assignment graph revision on each new catalog graph revision, + on the seat `mesh-module-assigner`'s `placement-changed` (ADR 0567 §5), and on a change of the capabilities a + node-engine states in its node record (ADR 0614 §4) (ADR 0645 §4). +- **A revision is kept while a delivery record points at it.** The indexer and the assigner remove a revision, and + the input revisions it names, only on the gate's event that frees it, never on a timer and never by reading the + gate's state (ADR 0645 §5; *The delivery record*, above). +- **What happened is not in the graph.** An entry says what is to run and what it waits on; whether it was built, + wanted or runs healthy is said by the parts as their events and kept in the delivery record (ADR 0645 §6). +- **The want stays the one record a node reads.** The assigner writes `want..` from a trunk + revision's assignment graph only, and the have stays what the node runs (ADR 0645 §7, which changes ADR 0571 §8). + +### A change's graph difference is its delivery + +- **The difference names everything a plan named.** For a change (a pull request's heads, a delivery group's + heads, or a merge), the indexer gives its catalog graph and the assigner its assignment graph; against the current + assignment graph, the difference names the new versions, the moved edges, the touched nodes and the order, which + is read off the edges (ADR 0647 §1). ADR 0603 §6's tiers, as ADR 0633 §5 changes it, are a view worked out from + that difference through the seat `mesh-wants`'s verb `difference`, the waits and holds through their owners' + tools, and the pending revisions through `indexer_pending` (ADR 0647 §1, which changes ADR 0603 §6). Issue 1874's + plan preview is a group's difference, read by one call (ADR 0647 §8). +- **A changed fingerprint with no difference is refused by name.** When a module's fingerprint in the change + differs from the running one while the difference is empty, the assigner refuses it, naming the module, and the + check fails naming it (ADR 0647 §2). +- **A candidate's graphs are kept apart, and only trunk writes wants.** A candidate's two graphs are computed per + check, kept apart from trunk's, and dropped on the gate's event that its heads were replaced or its pull request + closed; wants come only from a trunk revision, a merge's or a placement or capability change's (ADR 0647 §3, + ADR 0645 §4). +- **Each part acts on its own entries.** The builder, the build modules, the grants part and the node-engine each act + when their own entries in the new revision differ from what they run, read through the seat `mesh-wants`'s verbs + and events, never its bus state, and naming no other module (ADR 0647 §4, ADR 0596). +- **A node asleep catches up when it wakes**, by its wants (ADR 0647 §6, ADR 0603 §7); a want's new form reaches only + a node-engine that says it reads it (ADR 0614 §4, ADR 0618 §2). +- **No delivery goes ahead of a change.** A change is delivered as its own difference, its acting parts first in + their own steps (ADR 0647 §7, ADR 0646); the one exception is the bootstrap delivery (*The bootstrap delivery, and the one milestone + after it*, under *Milestones*; ADR 0644 §1, §2). + +### The revision view + +- **A pair, each half served by its one owner.** For a trunk revision, or for a candidate's heads before any merge, + the indexer serves the catalog half by the seat `mesh-catalog`'s verb `revision`: the catalog graph, the heads, the + seat definitions, the manifests' verdicts and the fingerprints. The assigner serves the assignment half by the seat + `mesh-wants`'s verb `revision`: the assignment graph it computed from that catalog half, naming the catalog + revision it read. `seat-definitions` stays the seat list's verb, and the catalog half carries the same definitions + at its revision (ADR 0649 §1, ADR 0636 §4). +- **Every part takes a first view, then follows the events.** The checker, the builder, the grants part, the + node-engine and the indexer's own later passes take a first view from both verbs and then follow both seats' + events, never a list compiled into their build nor another module's bus state; the assigner reads only the + catalog half, never its own output back. A running part acts only on a trunk revision's view; a candidate's view is + read only by the check and the indexer's candidate pass (ADR 0649 §2, ADR 0596, ADR 0636 §4). +- **A part with no view says it waits.** It names the revision it has no view for, acts on nothing new, and keeps + running what it runs (ADR 0649 §3, which changes ADR 0636 §1 to the checker, the builder and the grants part, and to + the view). +- **Each process knows its own build from its start.** The node-engine hands every process it starts the + fingerprint of the build it is started with, and the process takes its own build from that, never learning it + later (ADR 0649 §4, widening ADR 0639 §7 from the indexer to every process). *The fingerprint handover*, below, + says its form. + +### What the records leave to this design + +Each of these the records name and leave here, under issue 1921 (ADR 0646 §1, ADR 0649 §4, ADR 0648, +Consequences). + +- **An acting rule's fields.** A seat's definition gains one optional field `acts`, with two fields of its own: + `step`, one of `take-in`, `validate`, `check`, `build`, `compose`, `grant` and `place`; and `on`, either `every` + (every module) or a `language` naming the language of the modules it acts on, matched against what the manifest + says its language is, as the indexer's language map matches today. The definition format's own schema + (design 26) gains the field; the indexer reads it into the catalog graph, the assigner into + edges, and the checking program from the revision view. **Its cost in mesh-sdk:** the runtime in every module reads + a definition only at the seat list's grain (name, scope, verbs, provision) and reads no `acts`; if the runtime's + decoder refuses a field it does not read, it gains a pass-over of unread fields, which is a change of mesh-sdk's + runtime and rebuilds every module once. That rebuild is the same one the fingerprint handover makes, so the + milestone rebuilds every module once in all, and no other module's code changes (ADR 0646 §1). Which of the two the + runtime's decoder does today was not read for this amendment (*What is not decided here*). +- **The fingerprint handover.** The node-engine starts each process, a service or a container alike, with the + environment value `MESH_FINGERPRINT`, the fingerprint of the want it applies; mesh-sdk's runtime reads it once at the + process's start and holds it as the process's own build. A process started with no value says `own build unknown` + in its runtime tool and its journal, and the indexer acts on it as ADR 0639 §8 has it. **Its cost:** one change of + mesh-sdk's runtime, which rebuilds every module once, and one of the node-engine; the order between them is the + composing step's wait of the node-engine (*Order without a person*, below), so a module whose runtime reads the + value is composed only by a node-engine that hands it (ADR 0649 §4). +- **The build seat's ask that runs a program in the sandbox.** The checker asks the seat `node-build-go` for an ask + `run` on the build seats' `check` stream: one whole job on one node (ADR 0525 §3), which fetches the named heads, + builds the named program at them, runs it in the run step (ADR 0448 §2) with the input the ask carries as a file, + and writes the program's output and its exit on the build module's step key named by the ask's id (ADR 0525 §6). It + is an accepted ask of the seat, not a request verb, because it is a long job pulled where there is capacity, never + a call to a named node. The seat definition of `node-build-go` in `mesh-delivery-contracts` names it; the checking + program, the manifest validator and the composer a check builds from a change all run through it (ADR 0644 §3, + ADR 0648 §2). +- **The first tier's own bound.** A check's first tier has 20 minutes for all its builds together, inside the check's + one-hour bound of the state table; an acting part not built within it is one the first tier cannot build, and the + check fails naming it (ADR 0648 §3; ADR 0648, Consequences). The value is this amendment's (*What is not decided + here*). + +### What each step says + +Each step says what it did as its own event, carrying the source revision, the assignment graph revision, the +fingerprint and the node (ADR 0647 §5). The seat's event comes first where the parts follow it through a seat (ADR +0649 §2); a holder's own event stays under its own subject, declared in its own manifest's `streams` and published +on `mesh.stream..event.` (ADR 0363 §1, §2). A seat's event is declared in its definition and its +holder's manifest claims the seat. + +| Step | Event | Owner: the seat, then the module | Subject | Declared in | +|---|---|---|---|---| +| a catalog graph revision kept | `catalog-revision` | `mesh-catalog`, the indexer | `mesh.seat.mesh-catalog.event.catalog-revision` | the seat's definition in `mesh-delivery-contracts` | +| an assignment graph revision kept | `assignment-revision` | `mesh-wants`, the assigner | `mesh.seat.mesh-wants.event.assignment-revision` | the seat's definition in `mesh-placement-contracts` | +| a difference worked out | `difference` | `mesh-wants`, the assigner | `mesh.seat.mesh-wants.event.difference` | the same | +| an entry taken in | `take-in.taken`, which gains the entries | the indexer's own | `mesh.stream.mesh-delivery-indexer.event.take-in.taken` | the indexer's manifest | +| an entry built | `build.ended` | the builder's own | `mesh.stream.mesh-delivery-builder.event.build.ended` | the builder's manifest | +| an entry checked | `checked` | `mesh-delivery-checker`, the checker | `mesh.seat.mesh-delivery-checker.event.checked` | the seat's definition in `mesh-delivery-contracts` | +| an entry wanted | `wanted` | `mesh-wants`, the assigner | `mesh.seat.mesh-wants.event.wanted` | the seat's definition in `mesh-placement-contracts` | +| an entry composed, and running healthy | `composed`, `running` | `node-engine`, the node-engine on each node | `mesh.seat.node-engine.event.composed`, `.running` | the seat's definition in `mesh-contracts` | +| a record pins or frees a revision; a candidate's heads replaced | `pinned`, `freed`, `heads-replaced` | `mesh-delivery`, the gate | `mesh.seat.mesh-delivery.event.` | the seat's definition in `mesh-delivery-contracts` | + +The subjects, the event names and which are a seat's are this amendment's; the records say only that each is the +event of the part that did it (*What is not decided here*). How it is checked: each seat definition's conformance +fixtures name the subject of every event it gains, and a case of the holder's whole-module test matches an event it +publishes against them, as for every seat (design 26); the gate's whole-module test hears each row through its +durable consumer. + +### Their tools + +| Line | The assigner | The indexer | +|---|---|---| +| read everything it holds | `assigner_revision` (one assignment graph revision whole, with the revisions of its inputs), `assigner_entry` (one entry, with the seat rule that gave each edge), `assigner_difference` (a change's difference), `assigner_waits` (*Order without a person*), `assigner_candidate_graphs` (every candidate's graphs: its heads, its revisions, since when) | `indexer_catalog_revision` (one catalog graph revision), `indexer_candidate_graphs` (every candidate's catalog half) | +| do by hand what it does itself | `assigner_recompute` (compute a revision again from its named inputs and compare it with the one kept) | — | +| recover without help | `assigner_drop_candidate_graph` (drop a candidate's graphs whose gate event never came) | `indexer_drop_candidate_graph` (the same for its half) | +| one seat, many tools | `mesh-wants`: `revision`, `entry`, `difference` | `mesh-catalog`: `revision`, beside `seat-definitions` | + +ADR 0645 §8 names the reads and the recompute; the candidates' list and drop answer the seams review of 2026-11-06, +and no record names them yet. ADR 0636 §7's two tools in mesh-sdk's runtime bundle read which view revision a part +holds and what it waits for, and make it read the view again now; a tool of the node-engine, `node_process_builds`, +reads the build each process was started with (ADR 0649 §5, which changes ADR 0636 §7). + +**How it is checked.** Unit (assigner): a revision computed again from its named inputs equals the one kept; one +revision of about 120 modules on four nodes stays under the bus's value limit; a fixture change with a new +fingerprint and an empty difference is refused, naming its module. Whole (assigner): a placement change with no merge +gives a new revision whose difference moves only that module; a revision a record points at is removed only on the +gate's event freeing it; a pull request's graph leaves every node's want unchanged; a placement-only revision moves +the want of the module it places (ADR 0645 §9, ADR 0647 §8). Whole (indexer, assigner): for a candidate's heads both +`revision` verbs answer, the assigner's naming the catalog revision it read; a pull request that adds a seat and a +module using it is validated by the indexer's candidate pass and checked by the checker with the same definitions; +with the indexer stopped, a part asking the view for a new revision says it waits, naming it, and acts once the +indexer is back. Whole (node-engine): a part started while its node's want differs from what runs reports the build it +was started with (ADR 0649 §6). Live: a group's plan preview is its difference, read by one call; an old node-engine +that wakes takes its new build in a form it reads (ADR 0647 §8). + ## Order without a person -*ADR 0419 §1, §2, ADR 0429 §6, ADR 0539 §6, §7.* +*ADR 0419 §1, §2, ADR 0429 §6, ADR 0539 §6, §7; from research 085's milestone ADR 0646, which changes ADR 0603 §1, +§2, §3 and ADR 0614 §1, §6.* 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 six rules, read @@ -425,6 +700,56 @@ per module and node from the keys: - **No `after:` line is read.** The gate reads no `after:` line, no refusal asks for one, and a description that holds one is told once on its pull request that the line is not read (ADR 0419 §2). +### An acting part's new version acts first, a wait with a bound + +From research 085's milestone. An **acting part** is the holder of a seat whose definition says what it acts on and +in which step (*What the records leave to this design*, above, gives the fields): the indexer taking in and +validating, the checker checking, the build modules building, the node-engine composing, the grants part granting, +the assigner placing (ADR 0646 §1). Adding one needs its manifest and its seat's rule, and no code elsewhere: the +indexer's map from language to build module and the checker's own cases for a change to the validator or the Go +build module go (ADR 0646 §1). + +- **The rule becomes edges between versions.** In the assignment graph, at one revision, the assigner gives an edge + from the acting part's version to each version its rule says it acts on; no part names another module in its code + to order by (ADR 0646 §2). +- **Within a revision the edge is a wait, with a bound.** An entry waits in a step for the new version of that + step's acting part. When that new version fails, or does not run within its bound, the modules it was to act on + stay on their running builds and the watchman raises a condition naming the acting part (ADR 0646 §3, ADR 0603 + §8). A build module's edge, a trigger no want waited on, becomes this wait: the extra build per recipe change of + ADR 0603 §3 goes, and a module whose build module changes is built once, by the new one (ADR 0646 §3, which changes + ADR 0603 §1, §3 and ADR 0614 §1, §6). +- **A wait holds only within its step, and skips the holder's own inputs.** An entry waits only for its own step's + holders, so two acting parts that act on each other in different steps (the indexer taking in the checker, the + checker checking the indexer) form no cycle. Within a step a holder's own change is its first act, and what its new + version is built from or needs (a base, a package, a provider) is acted on by its running version, never waited + for: the running build module builds the shared contracts and the registry holder, then the new build module + builds the rest, so ADR 0614 §6's cycle stays allowed for that reason now (ADR 0646 §4). +- **The check refuses a cycle among the waits within one step**, beside the edges ADR 0614 §6 lists; a cycle across + two steps, or through a holder's own inputs, is none (ADR 0646 §5, which changes ADR 0603 §2's last sentence). +- **The indexer's own steps have no wait.** Taking in and validating stay as *Taken in by the indexer it names* + has them: a revision is taken in only by the indexer it names, and no build waits on which indexer judged it + (ADR 0646 §6, ADR 0603 §4, ADR 0633 §1). +- **A rule with no holder is no silent pass.** An entry a rule matches with no holder for its step is held by the + assigner, naming the missing holder, and the check fails naming it (ADR 0646 §7). +- **An acting rule grants nothing.** A holder's bus grants come from the grants part as today, and the operator's + Approve ask of a change names any acting rule it adds (ADR 0646 §8, ADR 0539 §7). +- **Each step's wait is its own part's.** Building: the builder's build-key wait; placing and wanting: the assigner's + hold; granting: the grants part's; composing: the node-engine's; checking: the check's first tier (*The check on + the change's own acting parts*, below). A wait ends when the acting part's new version runs healthy, as the + node-engine seat's `running` event says (ADR 0646 §9). +- **Read and steered by the parts' own tools.** The assigner's `assigner_waits` reads each wait: its entry, its step, + the seat rule that gave it, the acting part's version it waits for and since when; `assigner_release` and + `builder_build_again` steer them (ADR 0646 §10, ADR 0603 §11). +- **How it is checked.** Whole (assigner, builder): a fixture seat declaring a rule, with a fixture holder, gets its + edges with no code change elsewhere; a fixture build module whose new build fails leaves its modules on their + running builds and raises the condition naming it; a module with no holder for its step is held by name; a group + changing shared contracts and the build module that builds them is delivered, the contracts built by the running + build module first; a group changing the indexer and a module is taken in by the new indexer with no build waiting + on it. Unit (graph): an acting part acting on itself, two acting parts acting on each other in different steps, + and a cycle through a build module's edge each pass the cycle check, each new version first in its own step; a + cycle among waits within one step is refused. Live: a search of the delivery parts' code finds no other module's + name (ADR 0646 §11). + The planner's edges (*built by*, *SDK before its users*, *verb before caller*, *version skew*) and its one default, the node-engine before the controller, ordered the tiers of a plan until release 6 (ADR 0419 §3 to §5). For release 6's own switch, the last plan of release 5's controller, the version-skew edge and that @@ -610,11 +935,60 @@ From its delivery, a check is this: 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 every node agent composes with, the composition of `mesh-delivery-sdk`, so the two agree for one version of that - package; its verdict names the version it composed with (ADR 0635 §4). No composing program is built from a change: a change to the + package; its verdict names the version it composed with (ADR 0635 §4). Until research 085's milestone no composing program is built from a change but at a node-engine member's head (ADR 0636 §4): 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 - composition of its verdict, which says "not run" until the assigner's module exists (ADR 0528 §5). + composition of its verdict, which says "not run" until the assigner's module exists (ADR 0528 §5). From research + 085's milestone the composer is an acting part of the step `compose`: a change to it is built from the change's + heads in the check's first tier and composes with its own code (*The check on the change's own acting parts*, + below; ADR 0648 §1). + +### The check on the change's own acting parts + +*ADR 0648, ADR 0644; ADR 0448 §2, ADR 0391 §1, ADR 0603 §10, ADR 0614 §7, ADR 0633 §6, ADR 0636 §4.* + +From research 085's milestone. A change was checked by the running versions of the parts that build and judge it, +so a check could pass while the part that would build or judge the change never ran: 7 of 24 failures since +2026-11-01 (ADR 0648, Context). + +- **Two tiers on the change's assignment graph.** The first tier builds, at the change's heads, only the acting parts + whose fingerprint in the change's assignment graph differs from the running one and which are to act on a module + the check acts on; a change to an ordinary module asks no first-tier build. The second tier runs the check's levels + with those programs and the revision view of the change's heads (ADR 0648 §1). This keeps ADR 0603 §10's building of + changed build modules first and widens it to every acting part. +- **The judging rules are a checking program built from the change.** Every check builds its checking program from + the change's heads; every program built from a change runs only in the build seat's sandbox, through the seat + `node-build-go`'s ask `run` (*What the records leave to this design*), with the revision view as its input and no + bus account. The running checker alone asks, reads the program's verdict, records it and publishes it (ADR 0648 §2, + ADR 0644 §3, ADR 0448 §2). +- **A first tier that cannot build an acting part fails the check, naming it.** The verdict never passes on the + running version's word: a module whose changed build module the check cannot run is no longer composed from its + manifest, and a build module invoking a verb no running holder serves fails the check naming the build module and + the verb (ADR 0648 §3, which replaces that part of ADR 0603 §10 and ADR 0614 §7). An acting part not built within + the first tier's bound of 20 minutes is one it cannot build. +- **A change that alters or removes a rule of the checking program is named**, in its verdict and in the operator's + Approve ask (ADR 0648 §4). +- **ADR 0633 §6 stays.** Whether the running parts can take the change in is still checked with the trunk's manifest + validator (ADR 0648 §5; *Taken in by the indexer it names*). +- **The asking and recording are covered by the checker's whole-module test**, which starts the changed checker on a + real bus and asks one check of a fixture group end to end (ADR 0648 §6, ADR 0391 §1). +- **One seat list for both readers of a group's heads.** Inside a group's check the checker makes one seat list from + the members' heads and hands it to the manifest validator and the composer (ADR 0644 §4, ADR 0636 §4). +- **Its tools.** The checker's read of a check names the checking program's build that judged it, its fingerprint and + the heads it was built from (ADR 0644 §7); `checker_first_tier` lists a check's first-tier builds, each with its + acting part, its fingerprint and its outcome, and asks one of them again (ADR 0648 §7). Asking a whole check again + stays the checker's existing ask-again. +- **What it costs.** A change to an acting part costs one first-tier build per changed acting part; an ordinary change + costs nothing more; a group's check costs one build of its checking program (ADR 0648, ADR 0644, Consequences). +- **How it is checked**, in the checker's whole-module integration test: the registry group passes its one check with + its own checker, validator and composer; a change that breaks a rule of the checking program fails its own check; a + change that removes a rule passes, and its verdict and the ask name the removal; a fixture checking program that + tries to reach the bus or the network fails; a fixture whose acting part does not build fails naming it; a fixture + build module invoking a verb no running holder serves fails naming it and the verb; a change to an ordinary module + asks no first-tier build; a group that changes the assigner's placing is checked with its own assigner; a fixture + group whose heads add a seat has that seat in the list both the validator and the composer receive (ADR 0648 §8, + ADR 0644 §8). ### A try: a delivery group's check at exact commits @@ -651,8 +1025,9 @@ pull request, and it owes the forge nothing. - **Two reads across the seam stay until issue 1966 moves them.** The indexer reads the checker's previews, and the checker watches the indexer's `candidates.`. Both are readers of another module's bus state that ADR 0596 §3, as ADR 0615 changes it, lets stay until their module moves; issue 1966 tracks the move to the owner's tools - or events. The forge bridge's read of the gate's `merges` state (*Taken in by the indexer it names*, below) is - the same kind. + or events, and from research 085's milestone the revision view replaces both (ADR 0649 §2). The forge bridge's + read of the gate's `merges` state (*Taken in by the indexer it names*, below) was the same kind, and goes to the + seat `mesh-delivery`'s verb `groups` (ADR 0650 §4). - **A try event is never lost.** The checker publishes each try event with retry until the stream `checks` acknowledges it, and `try.ended` carries the state on every end; whether it was sent is kept in the try's own state, so an end after a checker restart still sends it. Only the checker's account may publish `try.*` on its @@ -760,6 +1135,10 @@ pull request, and it owes the forge nothing. assigner writes each want when its six rules hold. A merge is never refused, held or dropped once it is made. What of it is taken in waits only for the indexer its source revision names, or for the rest of its group (*Taken in by the indexer it names*, below; ADR 0633). +- **From research 085's milestone, the wants follow the trunk's assignment graph.** A merge taken in makes a + catalog graph revision and then an assignment graph revision; the assigner writes each want from that revision, + its rules unchanged, and each acting part's new version acts first in its own step (ADR 0645 §4, §7, ADR 0646 §3; + *Two graphs, one source of truth*, above). - **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. @@ -828,7 +1207,7 @@ timer. A group's merges arrive together. changes ADR 0603 §1 and §9). - **A group's merges are taken in together.** The forge bridge sets the group on each member's merged message, from the gate's `merges` state, a read of another module's bus state that ADR 0596 §3 lets stay until issue 1966 - moves it, and once every approved member is merged it publishes `forge.group.merged` on + moves it (from research 085's milestone, from the seat `mesh-delivery`'s verb `groups`, ADR 0650 §4), and once every approved member is merged it publishes `forge.group.merged` on its own stream `forge`, after the last member's merged message, naming the members and their merge commits. The indexer hears both through its one consumer, keeps each member's merged message in `pending` until the group's end, and then takes the members in as one source revision under the first bullet. A refused member is no @@ -849,7 +1228,8 @@ timer. A group's merges arrive together. (take the pending revisions, or a group gathered so far, in with the running indexer, when the named indexer can never run or the group's end never comes) and `indexer_drop_pending` (drop a pending merge a later one replaced), and the forge bridge's `bridge_groups` (read the groups it holds open) and `bridge_group_end_again` (publish a - group's end again from the gate's `merges` state) (ADR 0633 §5). Both of the indexer's hand acts emit + group's end again from the gate's `merges` state; from research 085's milestone from the verb `groups`, ADR 0650 + §4) (ADR 0633 §5). Both of the indexer's hand acts emit `take-in.taken`: a hand take-in as any take-in does, and a hand drop naming the drop, for a merge whose wait was said pending, so the watchman's `take-in-waits` clears; a drop of a merge never said pending emits none (ADR 0633 §5, ADR 0639 §9). @@ -1166,6 +1546,9 @@ assignments bucket is kept equal to it by the holder until ADR 0547's third mile | placement candidate | while a proposal is open: one node's placement as the proposal lays it, which that node composes in shadow and answers | the assigner | the seat's state `candidates` | | assignment | until ADR 0547's third milestone: the module and node, pinned or not, ended or not, written by `assign` and `unassign` after an approved placement change, so that it equals the placement (ADR 0567) | the controller, called by the holder | `mesh-controller_assignments` | | 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` | +| catalog graph revision | from research 085's milestone: every module as its manifest declares it at one source revision, with the seats' acting rules (ADR 0645 §1, §3) | the indexer | objects of the indexer's own | +| assignment graph revision | from research 085's milestone: every module version on a node at one revision, its edges, and the revisions of its inputs (ADR 0645 §2, §3) | the assigner | objects of the seat `mesh-wants` | +| delivery record | from research 085's milestone: one milestone's delivery, its group's state, its trace and each entry's outcome on each node (ADR 0650 §1) | the gate | a ledger of the seat `mesh-delivery`'s holder | 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 grants part's state (`user-list`, the memberships it last @@ -1226,6 +1609,26 @@ forge module's files of what it announced (ADR 0406 §6). `times`, `what-if`, `release`, `stop` and `retire-history` went at release 6; each is answered that it no longer exists. +From research 085's milestone the seat gains (ADR 0650 §4, ADR 0651 §1, §2): + +| Verb or event | Answers or does | +|---|---| +| `groups` with a group | that group's members, which the forge bridge reads in place of the gate's `merges` state | +| `review` | records a reviewer's verdict at the full head it judged, the reviewer taken from the caller's bus account (ADR 0597 §7), refusing a review by the head's author; once it runs, no description line is read (ADR 0496 §3, issue 1782) | +| milestone events | the one Approve ask per milestone, held until answered (ADR 0493 §9 as ADR 0496 §2 changes it, issue 1783), said on a subject of their own, so a waiter on one member's pull request wakes only on that member's `transition` | +| `pinned`, `freed`, `heads-replaced` | the events by which the indexer and the assigner keep or drop graph revisions (*The delivery record*) | + +**The seats `mesh-catalog` and `mesh-wants`** gain, from research 085's milestone, `revision` on each (the two halves +of the revision view), and `entry` and `difference` on `mesh-wants` (ADR 0645 §3, ADR 0647 §1, ADR 0649 §1), with the +events of *What each step says*. + +**Links of the trace** (ADR 0651 §3, §4): the issue tracker gains link kinds from an issue to the decision and to the +research effort it carries, made by a tool call (ADR 0493 §4); the knowledge base links a research effort to each +decision it graduated into (`became`) at its graduation, and a decision to the milestone of the issue tracker that +builds it. How it is checked: live, research 085's milestone's record reads back research 085 to its decisions, its +milestone, its issues, its pull requests and their reviews with no text match; whole (gate), a waiter on one member's +pull request wakes only on that member's transition, and a review by the head's author is refused (ADR 0651 §5). + **The status view's tools** read the keys and change nothing: `assigner_wants`, `assigner_want`, `assigner_differences` and `node_haves`, beside the indexer's and the builder's. Its events are `delivered`, `moving`, `settled` and `stuck` (*A delivery* above). @@ -1402,6 +1805,33 @@ From ADR 0548 and ADR 0551 (issue 568): and the forge's statuses; issue 568 is resolved only once this has passed on the mesh (ADR 0548 §10, ADR 0551 §2). +From research 085 (ADR 0644 to ADR 0651; each section above names its tests and their level): + +26. **The milestone checks itself.** Research 085's milestone's group check runs on the checking program built from + that group's own heads, read from the check's record, and no member of it was delivered ahead of it (ADR 0644 §8, + ADR 0647 §7). +27. **A new acting part needs no code elsewhere.** A module added with a seat whose definition declares an acting + rule gets its edges and its waits, and a search of the delivery parts' code finds no other module's name + (ADR 0646 §11). +28. **A failed acting part leaves the mesh on what runs.** A build module whose new build fails leaves the modules it + builds on their running builds, and the condition names it (ADR 0646 §3). +29. **A change is delivered as its difference.** A group that changes the indexer, the checker and a module that + needs both is delivered with no delivery ahead of it, each acting part's new version first in its own step, a node + asleep throughout catching up when it wakes; the group's preview before its merge is that same difference, read + by one call (ADR 0647 §8). +30. **A check never passes on the running version's word.** A change whose acting part does not build fails its + check naming it; the registry group passes its one check with its own checker, validator and composer + (ADR 0648 §8). +31. **One view.** A pull request adding a seat and a module using it is validated and checked with the same + definitions, and both pass (ADR 0649 §6). +32. **One record traces a delivery.** One call traces an issue of the registry milestone to each node's running build, + also after six later merges, and a group approved before the switch to the records is not asked again (ADR 0650 + §7). +33. **The trace is links.** Research 085's milestone reads back from research 085 to its reviews with no text match + (ADR 0651 §5). +34. **The milestone can be undone.** A revert of research 085's milestone passes its check under the milestone's own + checker (research 085, Direction, One milestone). + ## What retires - The "release branches" and the controller's check of them (ADR 0358, superseded by ADR 0401). @@ -1445,6 +1875,15 @@ From ADR 0548 and ADR 0551 (issue 568): view's events instead; the assigner's comparison with the send; the node-engine's queue of whole declarations, its orders, put-backs and five-minute reconcile; the buckets of plan state; the stop of a shared plan (ADR 0299, superseded by ADR 0539 §18); and a declaration sent by hand (ADR 0526 §4, changed by ADR 0539 §10). +- At research 085's milestone's delivery: the indexer's map from language to build module, and the checker's own + cases for a change to the manifest validator and to the Go build module (ADR 0646 §1); a build module's edge as a + trigger, with the extra build per recipe change (ADR 0603 §3, as ADR 0646 §3 changes it); composing from manifests a + module whose changed build module the check cannot run (ADR 0603 §10 and ADR 0614 §7, as ADR 0648 §3 replaces it); + the module graph's one key per module with five past values (ADR 0603 §2, as ADR 0645 §3, §5 change it); the tiers + worked out from five live sources (ADR 0603 §6, as ADR 0647 §1 changes it); a seat list compiled into a part, and + every read of another module's bus state the revision view replaces (ADR 0649 §2); the gate's `merges` and `turns` + as its own state, carried into the delivery records (ADR 0650 §3); and the review line in a pull request's + description, once the verb `review` runs (ADR 0651 §1). ## Milestones @@ -1494,6 +1933,8 @@ release reports the controller's code lines against research 063's baseline (acc | L5 | Control records leave the controller, and the controller is not changed (ADR 0565): mesh-config keeps each module's declared config in its state `declared` and publishes the predefined keys, which the indexer reads from the forge bridge's messages with each open pull request's config candidate; config switches to that source only on the operator's take-over, refused while `compare` shows a difference; each node agent writes its node's declared packages (the node seat `node-engine`, verb `packages`); the assigner holds the new seat `mesh-wants` with the upgrade policy a person chose and the bus step; the hand-act log (`hand-act`, `hand-acts`, `warranted`) is the stream of the new seat `mesh-hand-acts`, held by a new module in mesh-catalog, which every recorder calls from this delivery with no switch; the checker and the assigner's composition check read the held values of their pull requests from mesh-config's state `kept`; from the lease write a trusted config value is set only on the operator's Approve; `settings`, `move-config` and `move-placement` end with the lease and nothing replaces them. each person's six policy choices are set through `mesh-wants.upgrade` and recorded as hand acts, `upgrade compare` and the assigner's finding `policy-split` show any split, and the lease write waits for `compare` to be empty (ADR 0565 §8). One delivery group, built before the lease write of L3, which waits for the group delivered, the six choices set, mesh-config's `compare` empty and its take-over done, `mesh-wants.upgrade compare` empty, and the readings of ADR 0565 §12 (ADR 0565 §14; ADR 0348 §9, ADR 0502 §2, ADR 0539 §14, §15, ADR 0547 §11) | — | mesh-sdk, mesh-catalog (mesh-config, mesh-hand-acts, pacman, the forge module, claude-code, mesh-knowledge, mesh-conditions, mesh-healers), mesh-delivery (indexer, assigner, checker, grants part, forge bridge), the node-engine (`mesh-host`); mesh-controller is not a member | 1953 | | L6 | Provisioning leaves the controller (ADR 0570): every provision is one key of the seat `mesh-provisioner`, held by mesh-provisioner, holding a reference and never a value, and each placed module's provisioning plan a key of its state `plans`, both composed from placement, the wants and the manifests on change events; each provider acts once all a provision depends on is provided; the assigner moves a want only once its build's provisions are provided; a provision no want needs is retiring, and its account or credential is removed only on the operator's Approve, its data never; the vault mints each provision's secret sealed to the consumer's and the provider's node, and the consumer's node-engine writes it; a wait for a person is a provision's state, which the watchman reads; bus permissions stay with the grants part (ADR 0349, ADR 0230, ADR 0547 §11) | — | mesh-sdk, the node-engine (`mesh-host`), mesh-tools (the tool runner's provisioner client), mesh-catalog (mesh-provisioner, the vault, the provisioner client, postgres, keycloak, gitea, route-adapter), mesh-delivery (assigner, watchman) | 1954 | | L7 | History and records leave the controller (ADR 0571): the builder keeps its build log, one entry at a build's start and one at its end, from which build history and durations are read and the module mesh-catalog asks the builds it missed; the artifact sweep is the seat `mesh-artifact-sweep`, held by artifact-store-tools beside the artifact store, its keep set from the store's own listing, the wants and the build log, sweeping at each build's end from the lease write and recording each deletion in the hand-act log; disk readings are disk-load's own state on every node; who holds which seat is the state `seat-holders` of the seat `mesh-placement` (now `mesh-module-assigner`), and tools are found by the tool runners' announcements; what a node runs is its want and its have; the grants part writes `grants..` and keeps memberships in its own state; root-free is a probe of the self-check; no manifest but the controller's reads, invokes or consumes `mesh-controller`, but a named list kept to the lease write, so the lease write's check passes (ADR 0189, ADR 0547 §11, ADR 0549 §6) | — | mesh-sdk, mesh-controller (its pin only), mesh-delivery (builder, indexer, assigner, grants part, view), mesh-catalog (artifact-store-tools, disk-load, the backup seat's holder, mounts, nfs-server, minio, mesh-watcher, the messenger, the self-check, the module mesh-catalog, docker), mesh-tools (the tool runner) | 1955 | +| B0 | The bootstrap delivery: a delivery group's check runs a checking program built from the group's own heads in the build seat's sandbox, and hands the manifest validator and the composer the heads' one seat list; it brings no seat definition, so the running checker checks it (ADR 0644) | 26 needs it | mesh-delivery (checker), mesh-catalog (mesh-build-go), mesh-delivery-contracts (the seat `node-build-go`'s ask `run`) | 1921 | +| G | Two graphs and one revision view: the catalog graph and the assignment graph kept per revision, a change delivered as its graph difference, the acting parts' rules on their seats as bounded waits, the check on the change's own acting parts, the revision view and each process's own build, the gate's delivery record, and the trace's links (ADR 0645 to ADR 0651); the registry milestone's reviewed heads are joined to its group as members | 26 to 34 | mesh-sdk (the runtime: the fingerprint, the view, the definition reader), mesh-contracts and the domains' contracts modules (`acts`, the new verbs and events), mesh-delivery (indexer, assigner, checker, builder, grants part, gate's view, forge bridge), mesh-catalog (the gate, the build modules, mesh-issues, mesh-knowledge), the node-engine (`mesh-host`), hq | 1966 (with the registry milestone's heads), 1961, 1660, 1962, 1972, 1721, 1783, 1785, 1794, 1791, 1373, 1782 | An issue is in one row only (ADR 0493 §2): where a row named an issue another row names too, the last row keeps it and the earlier row says so in words (the operator, 2026-10-26). Milestone M1 makes each row a record of the issue tracker @@ -1525,8 +1966,45 @@ the Approve, it is proved again by milestone 3. R4's prepare step on 2026-10-20 cut release 4 by its orders into R4a to R4g, each one release (ADR 0453, the operator's Approve): the SDK ships before its users, the new parts run dark before anything relies on them, the status switch follows a measured run, and the scripts and build-agent go last; R4d, the three image reworks (route-proxy, nats, automx; n8n left by ADR 0506), had no order of its own and was delivered between R4a and R4e. Where a record dates a rule by release 4, it reads the R4 release that builds the rule (ADR 0453 clause 15). +### The bootstrap delivery, and the one milestone after it + +*ADR 0644; ADR 0612 §3, ADR 0603 §10, ADR 0614 §7, ADR 0633 §6, ADR 0636 §4; research 085, Direction.* + +Milestone G changes the checker and the seat definitions the running checker reads, so the running checker could +never pass it. One bootstrap delivery, B0, goes first: the only delivery ever made ahead of a change, said in ADR 0644 +and in no other record, which changes ADR 0612 §3 for that one case (ADR 0644 §1, §2). + +- **What it carries.** Of ADR 0648, the checking program built from a group's heads and run in the build seat's + sandbox through the seat `node-build-go`'s ask `run`; of issue 1966, the one seat list the checker hands the manifest + validator and the composer (ADR 0644 §3, §4, §6). It decides nothing new about the seat list (ADR 0636 §4). +- **The running checker checks it.** Its group changes no seat definition and no contract, so the running checker + reads every manifest of it; ADR 0603 §10 and ADR 0614 §7 stay in force for its own group, what the running checker + cannot run being composed from its manifest and named in the verdict (ADR 0644 §5). +- **Milestone G keeps the rest**: the first tier for every acting part, the verdict that fails by name, the revision + view, the two graphs, the difference, the acting rules, the delivery record and the trace's links, with the + registry milestone's reviewed heads joined to its group (ADR 0644 §6). It is one milestone, one group and one check, + its fixtures folded into the existing whole-module tests of the checker, the gate, the indexer and the assigner, and + it ends with no higher test count in any repository than it starts with (research 085, Direction, One milestone). +- **The order inside milestone G is the module graph's**, never a delivery ahead: each acting part's new version acts + first in its own step (*Order without a person*); the node-engine handing the fingerprint composes the modules + whose runtime reads it; the indexer's own steps keep *Taken in by the indexer it names*. +- **How it is checked.** The bootstrap group's own check passes on the running checker, naming any module composed + from its manifest; milestone G's group check runs on the checking program built from its own heads, read from the + check's record (ADR 0644 §8). + ## What is not decided here +- **Left by the records, settled here as proposals for the review** (issue 1921): the acting rule's fields and their + mesh-sdk cost, the fingerprint handover's form, the build seat's ask `run`, the first tier's bound of 20 minutes, + the step events' names and subjects (*Two graphs, one source of truth*). Whether mesh-sdk's runtime decoder refuses + an unread field in a seat definition today was not read; it decides whether `acts` alone would rebuild every module. +- What a process started by a node-engine that hands no fingerprint does beyond saying `own build unknown`, for a part + other than the indexer. +- Whether the new gate keeps `merges` and `turns` current after the switch or writes them back at a rollback + (ADR 0650 §3 says only that a rollback reads them back). +- Whether the indexer's keys keep ADR 0603 §2's five past values until the graph moves to objects within milestone G. +- Whether a catalog graph revision has a size bound of its own, as the assignment graph revision's is tested. + - How long the checker's stream `checks` keeps its events (*A try*, above). - Who is granted `checker_try` and the take-in hand tools: the operator's grants, outside this design. - A web view of deliveries beyond the pull request's comment.