Design 47 follows ADR 0656 alone and writes its own choices with their reasons

The operator ruled that research 085 graduates into one record per question:
ADR 0656 holds the whole answer and supersedes ADR 0645 to 0648, and the short
records 0649 to 0655, 0657 and 0658 are withdrawn. The design now cites ADR 0656
or ADR 0644 for what they decide, and what they leave is no longer an open
point but this design's choice, listed with its reason, so the review can
judge each one.

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-06 20:56:35 +01:00
parent cad2693361
commit dbc047bf56
2 changed files with 195 additions and 185 deletions
+15 -15
View File
@@ -298,9 +298,9 @@ and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 02
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 nothing else writes it
(ADR 0656 §1); it keeps each revision naming the revisions of its inputs (ADR 0657), served by the seat
`mesh-wants`, and writes the wants from a trunk revision's alone (ADR 0656 §2). Not the **catalog graph** (Delivery), whose entries are modules, not
assigner computes it from the catalog graph, the placements and the nodes' capabilities, and nothing else writes it;
it keeps each revision naming the revisions of its inputs, served by the seat `mesh-wants`, and writes the wants
from a trunk revision's alone (ADR 0656). 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
@@ -521,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, 0644, 0649–0658.
**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, 0656.
**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
@@ -531,33 +531,33 @@ controller (the planner, the rollout) until release 6 of ADR 0429; from each rel
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).
- **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 (ADR 0656 §1), one
revision per source revision it takes in (ADR 0657). Its other name is **module graph**, the word for it before
requires, invokes and serves), with the acting rules the seats declare; the indexer keeps it, one
revision per source revision it takes in (ADR 0656). Its other name is **module graph**, the word for it before
ADR 0656, 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 0653). Nothing stores the order. Not the **assignment graph** (Placement), computed from it.
its step (ADR 0656). Nothing stores the order. Not the **assignment graph** (Placement), computed from it.
*Not:* ~~build graph~~
- **acting part** — the holder of a seat whose definition carries a rule: the step its holder acts in and the modules
it acts on (ADR 0652), in the field `acts` (design 47): the indexer, the checker, the build modules, the
it acts on (ADR 0656), in the field `acts` (design 47): the indexer, the checker, the build modules, the
node-engine, the grants part, the assigner. Within a revision its new version acts first in its step, a wait with a
bound (ADR 0653); when it fails or is late, the modules it was to act on stay on their running builds and a
condition names it (ADR 0654). Not every
bound (ADR 0656); when it fails or is late, the modules it was to act on stay on their running builds and a
condition names it (design 47). 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 (ADR 0657); the assigner serves it by the seat `mesh-wants`'s verb `difference` (design 47). Not a **delivery plan**,
it (ADR 0656); the assigner serves it by the seat `mesh-wants`'s verb `difference` (design 47). 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; the verbs' names, design 47). A part with none for the current revision waits
and says so (ADR 0649).
served by its one owner (ADR 0656; the verbs' names, design 47). A part with none for the current revision waits
and says so (ADR 0656).
- **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 what happened to each entry on each node (ADR 0650). It holds no tiers and nothing
revisions it moved between) and what happened to each entry on each node (ADR 0656). It holds no tiers and nothing
else orders by it. Not a **delivery**, one commit on its way.
- **checking program** — the rules every check applies, built from the change's heads (ADR 0658, ADR 0644) and run in
- **checking program** — the rules every check applies, built from the change's heads (ADR 0656, ADR 0644) and run in
a build seat's sandbox (ADR 0448 §2) 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 (design 47). 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
@@ -4,16 +4,7 @@ status: in-progress
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 0658"
- "ADR 0657"
- "ADR 0656"
- "ADR 0655"
- "ADR 0654"
- "ADR 0653"
- "ADR 0652"
- "ADR 0651"
- "ADR 0650"
- "ADR 0649"
- "ADR 0644"
- "ADR 0639"
- "ADR 0638"
@@ -157,22 +148,20 @@ 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) (ADR 0656 §1), both kept
per revision, and a change's **graph difference** against the current assignment graph is its delivery, with no
plan stored (ADR 0657). A part that acts on other modules in one step, an **acting part**, says so by a rule on its
seat's definition, which the assigner turns into edges (ADR 0652); its new version acts first in that step, a wait
with a bound (ADR 0653), and when it fails or is late its modules stay on their running builds and a condition names
it (ADR 0654). A check uses the acting parts built from the change's own heads and fails, naming the part, when one
cannot be built or run (ADR 0658); every part acts on one **revision view**, served as a pair by the indexer and the
assigner (ADR 0649); the node-engine hands every process its own build's fingerprint (ADR 0655); the gate keeps one
**delivery record** per milestone's delivery (ADR 0650) and records a review from the reviewer's own bus account
(ADR 0651). One delivery goes before that milestone, the only delivery ever made ahead of a change (ADR 0644). These
records keep only their choices (the operator, 2026-11-06: a decision record is a question, its options and the
choice made); what they build on is this design's, and a statement in the sections that follow with no record
beside it is this design's own, listed under *What is not decided here*. *Two graphs, one source of truth* and *The
check on the change's own acting parts* hold the whole of it.
**From research 085's milestone, every change is checked and delivered by the acting parts built from its own
heads** (ADR 0656, which supersedes ADR 0645 to ADR 0648). The acting parts, the parts that act on other modules'
changes, declare in their seats' definitions what they act on and are versions in the module graph like any module.
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), each per revision; a
change's **graph difference** against the current assignment graph is its delivery, its acting parts' new versions
acting first within a bound; its check runs on the acting parts built from its heads and fails, naming one that
cannot be built or run; every part reads one **revision view**, served by the indexer and the assigner; and the gate
keeps one **delivery record** per milestone's delivery (ADR 0656). One delivery goes before that milestone, the only
delivery ever made ahead of a change (ADR 0644). ADR 0656 answers one question and leaves how each part is built to
this design (the operator, 2026-11-06: one record per question, the choices within it the design's own, written with
their reasons). A statement in the sections that follow with no record beside it is such a choice; *Choices this
design makes under ADR 0656*, under *Two graphs, one source of truth*, gives each one's reason. *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
@@ -193,8 +182,8 @@ source revision is derived from the keys: every **want** equals its module's **f
- **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). 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 0656 §1, ADR 0657,
ADR 0649).
revision and serves its half of the revision view by a verb of its seat `mesh-catalog` (ADR 0656,
ADR 0656).
- **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
@@ -209,7 +198,7 @@ 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 (ADR 0658)
From research 085's milestone its judging rules are a **checking program** built from the change's heads (ADR 0656)
and run in a build seat's sandbox (ADR 0448 §2); the running checker only asks, records and publishes (*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
@@ -217,7 +206,7 @@ source revision is derived from the keys: every **want** equals its module's **f
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). From research 085's milestone it keeps one delivery record per milestone's delivery as a
ledger instance (ADR 0650), its `merges` and `turns` carried into the records (*The delivery record*, below).
ledger instance (ADR 0656), its `merges` and `turns` carried into the records (*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`
@@ -237,9 +226,9 @@ source revision is derived from the keys: every **want** equals its module's **f
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. From research 085's milestone it computes the assignment graph from the
catalog graph, the placements and the nodes' capabilities (ADR 0656 §1), keeps each revision (ADR 0657) as objects
catalog graph, the placements and the nodes' capabilities, keeps each revision (ADR 0656) as objects
in its manifest's existing `objects` section (ADR 0619 §2), serves it and a change's graph difference by verbs of
its seat `mesh-wants`, and writes the wants from a trunk revision's assignment graph alone (ADR 0656 §2).
its seat `mesh-wants`, and writes the wants from a trunk revision's assignment graph alone (ADR 0656).
- **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
@@ -418,21 +407,21 @@ watches that key and stops only when the head in it moves; a trunk move never en
### The delivery record
*ADR 0650; ADR 0595, ADR 0596, ADR 0597, ADR 0603 §7, ADR 0493 §3, §11, ADR 0633 §4, §5, ADR 0441 §1, ADR 0548 §8.*
*ADR 0656; ADR 0595, ADR 0596, ADR 0597, ADR 0603 §7, ADR 0493 §3, §11, ADR 0633 §4, §5, ADR 0441 §1, ADR 0548 §8.*
From research 085's milestone the gate, holder of the seat `mesh-delivery`, keeps one **delivery record** per
milestone's delivery, a ledger instance (ADR 0595's template `ledger`, ADR 0597) it alone writes (ADR 0650). It
milestone's delivery, a ledger instance (ADR 0595's template `ledger`, ADR 0597) it alone writes (ADR 0656). 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 graph revisions the delivery
moved between;
- **what happened to each entry on each node**: for every entry of the graph difference, taken in, built, checked,
composed, wanted, running healthy, or away (ADR 0650).
composed, wanted, running healthy, or away (ADR 0656).
It holds no tiers, and only the gate orders work by it, so it is no second copy of the keys (ADR 0650). ADR 0650
leaves the record's fields, retention and tools here (its Consequences): what follows with no record beside it is
this design's.
It holds no tiers, and only the gate orders work by it, so it is no second copy of the keys, the objection research
063 had to a stored plan (research 085, Findings 10). Its fields, retention and tools are this design's choices under
ADR 0656.
- **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). The consumer resumes from the last event applied; an event
@@ -461,7 +450,7 @@ this design's.
until a later change removes them, so a gate rolled back reads current state and no approved group is asked again.
- **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, which changes ADR 0633 §4 and §5; ADR 0596).
end again (ADR 0656, 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 and a
64 MiB bucket (research 085, Findings 8).
- **Its tools**, against the four lines a module's tools answer:
@@ -473,10 +462,10 @@ this design's.
| 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 |
- **How it is checked.** ADR 0650's own: the gate's whole-module test stops and restarts the gate in the middle of a
- **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; live, one call of `gate_record` traces an
issue of the registry milestone to each node's running build (ADR 0650, How it is checked). This design's, in the
gate's whole-module test: the events `pinned`, `freed` and `heads-replaced` are said; a group approved before the
issue of the registry milestone to each node's running build . In the gate's whole-module
test: the events `pinned`, `freed` and `heads-replaced` are said; a group approved before the
switch is not asked again after it, nor after a rollback; a record ends once every present node runs its entries,
naming the nodes away; a node away that wakes adds its outcomes and is no longer shown away; a group's heads
approved and checked again ask the operator nothing again; a small fix's merge gets a record of its own; a record
@@ -521,14 +510,14 @@ module's progress on each node is its want against its have, shown by the view (
## Two graphs, one source of truth
*ADR 0656 and ADR 0657, which supersede ADR 0645 and ADR 0647, ADR 0649, ADR 0655; ADR 0595,
*ADR 0656, which supersedes ADR 0645 to ADR 0648; ADR 0595,
ADR 0596, ADR 0603 §2, §6, §7, ADR 0567 §5, ADR 0571 §8, ADR 0614 §4, ADR 0618 §2, ADR 0619 §1 to §3, ADR 0636 §1,
§4, §7, ADR 0639 §7, §8.*
From research 085's milestone. One graph answered two questions, which modules exist and which version runs where,
and one module running as several placed versions would have given one entry two shapes and one key two writers; two
graphs answer them, the second computed from the first, so there is one source of truth (ADR 0656, Context and
Considered Options). How each is kept, read and retained is this design's (ADR 0656, Consequences).
graphs answer them, the second computed from the first, so there is one source of truth (ADR 0656; research 085,
Findings 11). How each is kept, read and retained is this design's choice under ADR 0656.
```
manifests ──► indexer (mesh-catalog) ──► catalog graph revision ──┐
@@ -540,7 +529,7 @@ Considered Options). How each is kept, read and retained is this design's (ADR 0
```
- **The catalog graph is the indexer's.** The indexer, holder of the seat `mesh-catalog`, keeps the modules as their
manifests declare them; it is today's module graph, and *module graph* stays its other name (ADR 0656 §1). At each
manifests declare them; it is today's module graph, and *module graph* stays its other name (ADR 0656). At each
revision it holds one entry per module: its bases, its packages, the toolchain version and recipe version of the
build module that builds it as ADR 0603 §2 has them, its provides and requires, its invokes and serves, and its
fingerprint, with the rules the seats declare (*An acting part's new version acts first*, below).
@@ -548,18 +537,18 @@ Considered Options). How each is kept, read and retained is this design's (ADR 0
`mesh-module-assigner` and `mesh-wants`, computes the module versions placed on nodes, with the edges between
versions, from the catalog graph, the placements and the nodes' capabilities, and nothing else writes it (ADR 0656
§1). Each entry is one module version on a node; its edges are provisioning, contribution, and the acting parts'
versions that are to act on it (ADR 0652), whose rules and versions come in with the catalog graph. It is kept, but
versions that are to act on it (ADR 0656), whose rules and versions come in with the catalog graph. It is kept, but
it is no stored plan: it has one writer, no part orders work by a stored plan, and 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 (ADR 0656, Considered Options 3).
- **Each graph is kept per revision, and each revision names its inputs** (ADR 0657). The indexer keeps a catalog
derivation, never a second source of the kind research 063 removed (research 085, Findings 5).
- **Each graph is kept per revision, and each revision names its inputs** (ADR 0656). The indexer keeps a catalog
graph revision for each source revision it takes in; the assigner keeps an assignment graph revision for each change
of its inputs, naming the catalog graph revision, the placements and the capability readings it was computed from.
Both parts are the foundation (ADR 0619 §1), so both keep their revisions as objects declared in their manifests'
existing `objects` sections, each with a cap it declares there, never in the new form (ADR 0619 §2), and neither
waits on the bus module to start; the manifest validator refuses either manifest that declares them in the new form
(ADR 0619 §3). An assignment graph revision is announced by an event of the seat `mesh-wants` and served by its
verbs. This replaces ADR 0603 §2's one key per module with five past values (ADR 0657, which changes ADR 0603 §2);
verbs. This replaces ADR 0603 §2's one key per module with five past values (ADR 0656, which changes ADR 0603 §2);
until research 085's milestone is delivered, those keys and their five values stay as they are.
- **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
@@ -569,45 +558,46 @@ Considered Options). How each is kept, read and retained is this design's (ADR 0
names, is kept as long as a delivery record points at it: the indexer and the assigner remove one only on the gate's
event `freed`, never on a timer and never by reading the gate's state (ADR 0596; *The delivery record*, above).
While records are kept for good, the revisions they pin are kept with them. This is the graphs' retention in place
of ADR 0603 §2's five past values, which ADR 0657 leaves here (its Consequences).
of ADR 0603 §2's five past values, which ADR 0656 leaves here (its Consequences).
- **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 0650).
wanted or runs healthy is said by the parts as their events and kept in the delivery record (ADR 0656).
- **The want stays the one record a node reads.** The assigner writes `want.<node>.<module>` from a trunk
revision's assignment graph only; a node-engine reads its want, never the graph, and the have stays what it runs
(ADR 0656 §2, which changes ADR 0571 §8).
(ADR 0656, 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. Compared with the
current revision, the difference names the new versions, the moved edges, the touched nodes and the order, read off
the edges, and no plan is stored (ADR 0657). The assigner serves it by the seat `mesh-wants`'s verb `difference`,
the edges, and no plan is stored (ADR 0656). The assigner serves it by the seat `mesh-wants`'s verb `difference`,
for two revisions of the assignment graph or for a candidate against trunk. ADR 0603 §6's tiers, as ADR 0633 §5
changes it, are a view worked out from that difference (ADR 0657, which changes ADR 0603 §6), read through
changes it, are a view worked out from that difference (ADR 0656, which changes ADR 0603 §6), read through
`difference`, with the waits and holds read through their owners' tools and the pending revisions through
`indexer_pending`.
- **The preview is a candidate's difference.** Issue 1874's plan preview of a group before its merge is its
candidate's difference, read by one call of `difference`, and needs no code of its own (ADR 0657, Consequences).
candidate's difference, read by one call of `difference`, and needs no code of its own: a candidate's graphs are computed for its check
anyway, so the preview costs nothing more.
- **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 0657, How it is checked).
check fails naming it.
- **A candidate's graphs are kept apart, and dropped with its heads.** A candidate's two graphs are computed per
check, kept apart from trunk's, and dropped on the gate's event `heads-replaced`, said when the candidate's heads
were replaced or its pull request closed. A candidate costs a computed graph per check.
- **Only a trunk revision writes wants**, whether a merge taken in or a placement or capability change made it; a
candidate's graph writes none (ADR 0656 §2).
candidate's graph writes none (ADR 0656).
- **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 (ADR 0657), reading them through the seat
`mesh-wants`'s verbs and events, never its bus state (ADR 0596, ADR 0649), and naming no other module (ADR 0652).
when their own entries in the new revision differ from what they run (ADR 0656), reading them through the seat
`mesh-wants`'s verbs and events, never its bus state (ADR 0596, ADR 0656), and naming no other module (ADR 0656).
- **A node asleep catches up when it wakes.** A node away holds nothing and catches up by its wants (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' new versions
first in their own steps (ADR 0653); the one exception is the delivery before research 085's milestone (*The
first in their own steps (ADR 0656); the one exception is the delivery before research 085's milestone (*The
bootstrap delivery, and the one milestone after it*, under *Milestones*; ADR 0644).
### The revision view
- **A pair, each half served by its one owner** (ADR 0649). For a trunk revision, or for a candidate's heads before
- **A pair, each half served by its one owner** (ADR 0656). 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`: an assignment graph revision, named by its own revision and naming its
@@ -616,25 +606,25 @@ Considered Options). How each is kept, read and retained is this design's (ADR 0
(ADR 0636 §4), and the catalog half carries the same definitions at its revision.
- **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 the two verbs and then follow the two seats'
events, never a list compiled into their build nor another module's bus state (ADR 0649, ADR 0596). Of the view the
events, never a list compiled into their build nor another module's bus state (ADR 0656, ADR 0596). Of the view the
assigner reads only the catalog half, never its own output back; its other inputs stay the placements and the
capabilities (ADR 0656 §1). A running part acts only on a trunk revision's view; a candidate's view is read only by
capabilities (ADR 0656). A running part acts only on a trunk revision's view; a candidate's view is read only by
the parts that judge a candidate, inside the check its manifest validator and composer, and the indexer's candidate
pass (ADR 0649, which changes ADR 0636 §4 in that the candidate pass joins them).
pass (ADR 0656, which changes ADR 0636 §4 in that the candidate pass joins them).
- **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, as ADR 0636 §1 has a reader of the seat list do; the checker, the builder and the grants part
wait too, and wait for the view, not only the seat list (ADR 0649, which changes ADR 0636 §1). A part restarted
wait too, and wait for the view, not only the seat list (ADR 0656, which changes ADR 0636 §1). A part restarted
while the indexer is down waits and says so.
- **Each process knows its own build from its start.** The node-engine hands every process it starts the
fingerprint of the build it starts it with, and the process takes its own build from that, never learning it later
(ADR 0655, which changes ADR 0639 §7 from the indexer to every process). *The fingerprint handover*, below, says its
(ADR 0656, which changes ADR 0639 §7 from the indexer to every process). *The fingerprint handover*, below, says its
form.
### What the records leave to this design
### What ADR 0656 leaves to this design
Each of these the records name and leave here, under issue 1921 (ADR 0652, ADR 0655 and ADR 0658, Consequences).
ADR 0656 leaves how each part is built to this design, under issue 1921; these four needed a shape of their own.
- **An acting rule's fields** (ADR 0652 leaves them here). A seat's definition gains one optional field `acts`, with
- **An acting rule's fields.** The seat's definition is where ADR 0656 has an acting part declare what it acts on. 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
@@ -642,14 +632,14 @@ Each of these the records name and leave here, under issue 1921 (ADR 0652, ADR 0
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 (ADR 0655, Consequences), so
rebuilds every module once. That rebuild is the same one the fingerprint handover makes (ADR 0656, Consequences), so
the milestone rebuilds every module once in all, and no other module's code changes. 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 (ADR 0655). A process started with no value says `own build
process's start and holds it as the process's own build (ADR 0656). 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 (ADR 0655, Consequences), and one of the
change of mesh-sdk's runtime, which rebuilds every module once (ADR 0656, Consequences), 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.
- **The build seat's ask that runs a program in the sandbox.** The checker asks the seat `node-build-go` for an ask
@@ -658,10 +648,40 @@ Each of these the records name and leave here, under issue 1921 (ADR 0652, ADR 0
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 acting parts and the composer a check builds from a change all run through it (ADR 0658, ADR 0644).
program, the acting parts and the composer a check builds from a change all run through it (ADR 0656, ADR 0644).
- **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 and the checker's step bound (ADR 0639 §5); an acting part not built within it is
one the first tier cannot build, and the check fails naming it (ADR 0658).
one the first tier cannot build, and the check fails naming it (ADR 0656).
### Choices this design makes under ADR 0656
ADR 0656 decides the direction and leaves every choice made in working it out to this design, each with its reason
(ADR 0656, Consequences; the operator, 2026-11-06 20:3x). The choices, and why:
| Choice | Why |
|---|---|
| Both graphs kept as objects in the indexer's and the assigner's existing `objects` sections, each with a cap | both parts are the foundation, whose new kept data goes on the old sections so neither waits on the bus module to start (ADR 0619 §1, §2) |
| ADR 0603 §2's keys and five past values stay until the milestone's delivery | what runs keeps reading them until the parts that read revisions are delivered in the same milestone |
| A revision kept while a delivery record pins it, removed only on the gate's `freed` | a trace must read every revision it moved between; a timer or a read of the gate's state would drop one still pointed at, or cross the seam (ADR 0596) |
| A candidate's graphs kept apart and dropped on `heads-replaced` | a candidate must never write wants or be read by a running part, and its graphs mean nothing once its heads are gone |
| The verbs `revision`, `entry` and `difference` on the two seats | each half of the view, and the difference, is served by its one owner through its seat, never read from its state |
| The step events, their fields and their subjects | every outcome the delivery record keeps reaches it as the event of the part that did it, with the revisions and the fingerprint that tie it to the trace (research 085, Findings 7) |
| A first tier of only the changed acting parts, bounded at 20 minutes | an ordinary change pays nothing more; a bound turns a build that never ends into a named failure inside the check's hour |
| The build seat's ask `run` | the program is a long job pulled where capacity is, run in the sandbox every check already uses (ADR 0448 §2) |
| Every program built from a change run with no network and no bus account | a change not yet merged is not trusted, and the sandbox already keeps the logins outside (ADR 0448 §2, §4) |
| A removed or altered rule of the checking program, and an added acting rule, named in the verdict and the Approve ask | either widens or narrows what judges or acts on every module, so the operator sees it before approving |
| A rule matching a module with no holder for its step held by name, and its check failed | a rule nobody serves would otherwise pass in silence |
| Each step's wait held by the part that does the step, read by `assigner_waits` and steered by `assigner_release` and `builder_build_again` | the part that does the step already holds its state; the tools are those ADR 0603 §11 has |
| The acting rule's field `acts` with `step` and `on` | the steps and the language match are what the indexer's map and the checker's cases held in code (research 085, Findings 2) |
| The fingerprint handed as `MESH_FINGERPRINT` at a process's start | one value every runtime reads before anything else, a service and a container alike |
| The delivery record's consumer, end, node away and wake, switch with `merges` and `turns` kept current, retention and tools | a restart must lose and double nothing; a node asleep must not hold a delivery open; a gate rolled back must find current state and ask no approved group again |
| A small fix's own record | a small fix is a milestone of one issue (ADR 0493 §3) |
| An Approve given held while its heads stand (issue 1972) | the operator approved those heads; a check of them asked again changes nothing they approved (ADR 0441 §1, ADR 0548 §8) |
| The milestone events on a subject of their own | a waiter on one member's pull request otherwise wakes on every member's |
| The issue tracker's link kinds to a decision and a research effort, and the knowledge base's link from a decision to its milestone | the trace from research to the running build is then links all the way, with no text match (research 085, Findings 7; ADR 0493 §4) |
| Two view tools in mesh-sdk's runtime bundle beside ADR 0636 §7's, and `node_process_builds` | every part's view and every process's own build is read and steered by a tool, as the seat list already is |
Each choice is checked by the tests its section names; the review by architectural domain judges them.
### What each step says
@@ -669,7 +689,7 @@ Each step says what it did as its own event, the event of the part that did it.
carries the source revision; an assignment graph revision kept and a difference worked out carry the source revision
and the assignment graph revisions; an entry taken in, built, checked, composed, wanted and running also carries the
entry's fingerprint and its node. The gate's delivery record is built from them. The seat's event comes first where
the parts follow it through a seat (ADR 0649); a holder's own event stays under its own subject, declared in its own
the parts follow it through a seat (ADR 0656); a holder's own event stays under its own subject, declared in its own
manifest's `streams` and published on `mesh.stream.<module>.event.<event>` (ADR 0363 §1, §2). A seat's event is
declared in its definition and its holder's manifest claims the seat.
@@ -685,7 +705,9 @@ declared in its definition and its holder's manifest claims the seat.
| 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.<event>` | the seat's definition in `mesh-delivery-contracts` |
The events, their fields, their subjects and which are a seat's are this design's. How it is checked: each seat
The events, their fields, their subjects and which are a seat's are this design's choices: a seat's event where
other parts follow the step through the seat, a holder's own event where only the delivery record hears it, so that
nothing reads another module's bus state (ADR 0596). 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, with exactly the fields this section gives it.
@@ -702,16 +724,17 @@ each row through its durable consumer, with exactly the fields this section give
Beside ADR 0636 §7's two tools in mesh-sdk's runtime bundle, which read a reader's seat list and make it read the
list again, the bundle gains two for the view: one reads which view revision a part holds and what it waits for, the
other, granted as ADR 0636 §7's second is, makes it read the view again now. A tool of the node-engine,
`node_process_builds`, reads the build each process was started with. The tools are this design's.
`node_process_builds`, reads the build each process was started with. The tools answer the four lines every module's
tools answer (design 26), so that every state these parts keep is read and every act they do is steered by a tool.
**How it is checked.** The records' own: a revision of the assignment graph computed again from its named inputs
equals the one kept (unit, assigner; ADR 0656, How it is checked); a fixture change with a new fingerprint and an
**How it is checked.** a revision of the assignment graph computed again from its named inputs
equals the one kept (unit, assigner); a fixture change with a new fingerprint and an
empty difference is refused, naming its module (unit, assigner), and a group's preview before its merge is its
difference (live) (ADR 0657, How it is checked); a pull request that adds a seat and a module using it is validated by
difference (live) ; 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 (whole), and a search of the
readers' code finds no compiled seat list (live) (ADR 0649, How it is checked); a part started while its node's want
differs from what runs reports the build it was started with (whole, node-engine; ADR 0655, How it is checked). This
design's: unit (assigner), one revision of about 120 modules on four nodes stays under the bus's value limit, and of
readers' code finds no compiled seat list (live) ; a part started while its node's want
differs from what runs reports the build it was started with (whole, node-engine). Unit
(assigner): one revision of about 120 modules on four nodes stays under the bus's value limit, and of
the view the assigner reads only the catalog half; unit (indexer), a catalog graph revision holds one entry per module
of its source revision. Whole (indexer): a source revision taken in gives one catalog graph revision kept as objects
in the old `objects` section within the cap its manifest declares; the manifest validator refuses the indexer's or
@@ -730,8 +753,8 @@ its new build in a form it reads.
## Order without a person
*ADR 0419 §1, §2, ADR 0429 §6, ADR 0539 §6, §7; from research 085's milestone ADR 0652, ADR 0653 and ADR 0654, of
which ADR 0653 changes ADR 0603 §1, §2, §3 and ADR 0614 §1, §6.*
*ADR 0419 §1, §2, ADR 0429 §6, ADR 0539 §6, §7; from research 085's milestone ADR 0656, of
which ADR 0656 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
@@ -753,37 +776,40 @@ per module and node from the keys:
### An acting part's new version acts first, a wait with a bound
*ADR 0652, which supersedes ADR 0646, ADR 0653, ADR 0654; ADR 0603 §1 to §4, §8, §11, ADR 0614 §1, §3, §6, ADR 0633
*ADR 0656, which supersedes ADR 0646; ADR 0603 §1 to §4, §8, §11, ADR 0614 §1, §3, §6, ADR 0633
§1, ADR 0539 §7, ADR 0584 §1.*
From research 085's milestone. A seat's definition may carry a rule, the step its holder acts in and the modules it
acts on, and a holder of such a seat is an **acting part** (ADR 0652): the indexer taking in and validating, the
acts on, and a holder of such a seat is an **acting part** (ADR 0656): the indexer taking in and validating, the
checker checking, the build modules building, the node-engine composing, the grants part granting, the assigner
placing. *What the records leave to this design*, above, gives the rule's fields. Adding one needs its manifest and
placing. *What ADR 0656 leaves to this design*, above, gives the rule's fields. 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 module
names go (ADR 0652, Consequences).
names go, since every new acting part needed code changes elsewhere (research 085, Findings 2).
- **The rule becomes edges between versions.** In the assignment graph the assigner gives an edge from the acting
part's version to each version its rule names, and no part names another module in its code to order by (ADR 0652).
part's version to each version its rule names, and no part names another module in its code to order by (ADR 0656).
- **Within a revision the new version acts first, a wait with a bound.** The entries an acting part acts on wait for
its new version in its own step, with a bound (ADR 0653), the part's own as ADR 0603 §8 has every wait. For a build
its new version in its own step, with a bound (ADR 0656), the part's own as ADR 0603 §8 has every wait. For a build
module the entry waits until the agreed toolchain (ADR 0584 §1) names the new build module, so the module's
fingerprint names the new recipe and it is built once, by the new one: a module changed with its build module is no
longer built with the running recipe and again later, and a build module's edge, a trigger no want waited on,
becomes this wait (ADR 0653, which changes ADR 0603 §1, §3 and ADR 0614 §1, §6). ADR 0603 §3's fingerprint naming
becomes this wait (ADR 0656, which changes ADR 0603 §1, §3 and ADR 0614 §1, §6). ADR 0603 §3's fingerprint naming
the agreed toolchain stands.
- **A failed or late new version holds its modules, and a condition names it.** When the new version fails, or does
not run within its bound, the entries waiting for it stay held, the modules stay on their running builds, and the
watchman raises a condition naming the acting part; an entry moves on only once the new version runs, or a tool
releases it (ADR 0654), and the condition clears when the wait ends (ADR 0654, How it is checked). The operator sees
each stuck acting part as one condition, and `assigner_release` steers it (ADR 0654, Consequences).
- **A wait holds only within its step, and skips the holder's own inputs** (ADR 0653). An entry waits only for its
releases it (ADR 0656: its new versions act first within a bound), and the condition clears when the wait ends. The
operator sees each stuck acting part as one condition, and `assigner_release` steers it. Going on with the running
version instead would build or check a change with a part it replaced, the cause of the failures of research 085,
Findings 4; stopping the whole delivery would hold modules the failed part does not act on (the operator, 2026-11-06
17:0x).
- **A wait holds only within its step, and skips the holder's own inputs** (ADR 0656). 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 through them stays allowed, now for that reason.
- **The check refuses a cycle among the waits within one step** (ADR 0653, which changes ADR 0603 §2's refusal of a
- **The check refuses a cycle among the waits within one step** (ADR 0656, which changes ADR 0603 §2's refusal of a
cycle), counted beside the edges ADR 0614 §3 and §6 list; a cycle through an acting part's edges across two steps, or
through a holder's own inputs, is none.
- **The indexer's own steps have no wait.** Taking in and validating stay as *Taken in by the indexer it names* has
@@ -794,21 +820,20 @@ names go (ADR 0652, Consequences).
- **An acting rule grants nothing.** A holder's bus grants come from the grants part as today (ADR 0539 §7). An
acting rule changes what a part acts on across every module it matches, so the operator's Approve ask of a change
names any acting rule it adds.
- **Each step's wait is its own part's** (ADR 0653 leaves it here, its Consequences). Building: the builder's
- **Each step's wait is its own part's**, so that each wait has one owner that already holds that step's state. 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.
- **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, as ADR 0603 §11 has them.
- **How it is checked.** The records' own: a fixture seat declaring a rule, with a fixture holder, gets its edges
- **How it is checked.** a fixture seat declaring a rule, with a fixture holder, gets its edges
with no code change elsewhere (whole, assigner), and a search of the delivery parts' code finds no other module's
name (live) (ADR 0652, How it is checked); a fixture group changing the shared contracts and the build module that
name (live) ; a fixture group changing the shared contracts and the build module that
builds them is delivered, the contracts built by the running build module first and the rest by the new one (whole,
assigner and builder), and a cycle among waits within one step is refused (unit, graph) (ADR 0653, How it is
checked); a fixture build module whose new build fails, and one that does not run within its bound, each leave
assigner and builder), and a cycle among waits within one step is refused (unit, graph) ; a fixture build module whose new build fails, and one that does not run within its bound, each leave
their modules on their running builds and raise the condition naming it, which clears when the wait ends (whole,
assigner and builder; ADR 0654, How it is checked). This design's: whole (assigner, builder), a module with no
assigner and builder). Whole (assigner, builder): a module with no
holder for its step is held by name, and the check of a change bringing it fails naming the missing holder;
`assigner_release` moves a held entry on; a group changing the indexer and a module is taken in by the new indexer
with no build waiting on it; each step's wait ends on the acting part's new version running healthy as the
@@ -1008,36 +1033,36 @@ From its delivery, a check is this:
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). 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 (ADR 0658; *The check on the change's own acting
heads in the check's first tier and composes with its own code (ADR 0656; *The check on the change's own acting
parts*, below).
### The check on the change's own acting parts
*ADR 0658, which supersedes ADR 0648, ADR 0644; ADR 0448 §2, §4, ADR 0391 §1, ADR 0603 §10, ADR 0614 §7, ADR 0633
*ADR 0656, which supersedes ADR 0648, ADR 0644; ADR 0448 §2, §4, ADR 0391 §1, ADR 0603 §10, ADR 0614 §7, ADR 0633
§6, ADR 0636 §4, ADR 0639 §5.*
From research 085's milestone. ADR 0603 §10 and ADR 0614 §7 let a check pass while the part that would build or
check the change never ran: 7 of 24 failures since 2026-11-01 (ADR 0658, Context). The acting parts a change alters,
check the change never ran: 7 of 24 failures since 2026-11-01 (research 085, Findings 4). The acting parts a change alters,
and the checking program, the rules every check applies, are built from the change's heads and check it; the running
versions never check in their place, and a check fails, naming the part, when one cannot be built or run (ADR 0658).
versions never check in their place, and a check fails, naming the part, when one cannot be built or run (ADR 0656).
- **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, since building every acting part for
every check would make an ordinary change pay for builds that change nothing (ADR 0658, Considered Options 3). The
every check would make an ordinary change pay for builds that change nothing. The
second tier runs the check's levels with those programs and with the revision view of the change's heads
(ADR 0649). This keeps ADR 0603 §10's building of changed build modules first and widens it to every acting part.
(ADR 0656). 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 and runs it with the revision view as its input; when it cannot be built or run, the check
fails naming it, and the running checker's own rules never judge in its place (ADR 0658).
fails naming it, and the running checker's own rules never judge in its place (ADR 0656).
- **Every program built from a change runs only in the build seat's sandbox.** The acting parts the first tier builds
and the checking program run in the run step, with no network (ADR 0448 §2) and no bus account, the logins staying
outside (ADR 0448 §4), through the seat `node-build-go`'s ask `run` (*What the records leave to this design*), as
outside (ADR 0448 §4), through the seat `node-build-go`'s ask `run` (*What ADR 0656 leaves to this design*), as
the validator, the composer and the Go build module already run; a change not yet merged is not trusted. The running
checker alone asks, reads the program's verdict, records it and publishes it.
- **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 (ADR 0658, which changes ADR 0603 §10 and ADR 0614 §7), and ADR 0614 §7's reason, a changed build module
manifest (ADR 0656, which changes ADR 0603 §10 and ADR 0614 §7), and ADR 0614 §7's reason, a changed build module
invoking a verb no running holder serves, is one reason the first tier cannot run an acting part: the check fails
naming the build module and the verb. An acting part not built within the first tier's bound of 20 minutes is one
it cannot build.
@@ -1045,7 +1070,7 @@ versions never check in their place, and a check fails, naming the part, when on
Approve ask.
- **ADR 0633 §6 stays, beside the change's own validator.** Whether the running parts can take the change in is
still checked with the trunk's manifest validator, built from the trunk (ADR 0633 §6); the change's own validator,
built in the first tier, judges the change's manifests besides (ADR 0658). A change fails if either refuses it.
built in the first tier, judges the change's manifests besides (ADR 0656). A change fails if either refuses it.
- **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 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
@@ -1055,12 +1080,11 @@ versions never check in their place, and a check fails, naming the part, when on
the heads it was built from; `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. Asking a whole check again stays the checker's existing
ask-again.
- **What it costs.** A check of a change to an acting part costs one build per changed acting part (ADR 0658,
Consequences), within the checker's step bound (ADR 0639 §5); an ordinary change costs nothing more; a group's
- **What it costs.** A check of a change to an acting part costs one build per changed acting part, within the checker's step bound (ADR 0639 §5); an ordinary change costs nothing more; a group's
check costs one build of its checking program.
- **How it is checked.** The record's own: a fixture change whose acting part does not build, and one whose checking
program does not run, each fail their check, naming the part (whole, checker; ADR 0658, How it is checked). This
design's, in the checker's whole-module integration test: a checking program that builds but does not run fails
- **How it is checked.** A fixture change whose acting part does not build, and one whose checking
program does not run, each fail their check, naming the part (whole, checker). In the checker's
whole-module integration test: a checking program that builds but does not run fails
naming it; 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 build module invoking a verb no running holder serves fails naming it and the verb; a
@@ -1106,9 +1130,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.<try id>`. 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, and from research 085's milestone the revision view replaces both (ADR 0649). The forge bridge's
or events, and from research 085's milestone the revision view replaces both (ADR 0656). 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).
seat `mesh-delivery`'s verb `groups` (ADR 0656).
- **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
@@ -1218,7 +1242,7 @@ pull request, and it owes the forge nothing.
(*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 (ADR 0656 §2), and each acting part's new version acts first in its own step (ADR 0653; *Two
its rules unchanged (ADR 0656), and each acting part's new version acts first in its own step (ADR 0656; *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
@@ -1288,7 +1312,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 (from research 085's milestone, from the seat `mesh-delivery`'s verb `groups`, ADR 0650), 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 0656), 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
@@ -1309,7 +1333,7 @@ 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; from research 085's milestone from the verb `groups`, ADR 0650)
group's end again from the gate's `merges` state; from research 085's milestone from the verb `groups`, ADR 0656)
(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
@@ -1627,9 +1651,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 0656 §1, ADR 0657), kept while a delivery record pins it | the indexer | objects in its manifest's existing `objects` section (ADR 0619 §2) |
| 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 0656 §1, ADR 0657), kept while a delivery record pins it | the assigner | objects in its manifest's existing `objects` section (ADR 0619 §2), served by the seat `mesh-wants` |
| delivery record | from research 085's milestone: one milestone's delivery, its group's state, its trace and what happened to each entry on each node (ADR 0650), kept for good unless the gate's manifest sets a retention | the gate | a ledger instance of the gate's (ADR 0595, ADR 0597) |
| 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 0656), kept while a delivery record pins it | the indexer | objects in its manifest's existing `objects` section (ADR 0619 §2) |
| 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 0656), kept while a delivery record pins it | the assigner | objects in its manifest's existing `objects` section (ADR 0619 §2), served by the seat `mesh-wants` |
| delivery record | from research 085's milestone: one milestone's delivery, its group's state, its trace and what happened to each entry on each node (ADR 0656), kept for good unless the gate's manifest sets a retention | the gate | a ledger instance of the gate's (ADR 0595, ADR 0597) |
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
@@ -1694,22 +1718,22 @@ From research 085's milestone the seat gains:
| 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 (ADR 0650) |
| `review` | records a reviewer's verdict at the full head it reviewed, the reviewer taken from the caller's bus account, and refuses a review by the head's author; once it runs, the line in a pull request's description is read no more (ADR 0651, which changes ADR 0493 §5; ADR 0496 §3, issue 1782). The caller's account is the one the bus authenticated (ADR 0597 §7) |
| `groups` with a group | that group's members, which the forge bridge reads in place of the gate's `merges` state (ADR 0656) |
| `review` | records a reviewer's verdict at the full head it reviewed, the reviewer taken from the caller's bus account, and refuses a review by the head's author; once it runs, the line in a pull request's description is read no more (ADR 0656, which changes ADR 0493 §5; ADR 0496 §3, issue 1782). The caller's account is the one the bus authenticated (ADR 0597 §7) |
| milestone events | the one Approve ask per milestone (ADR 0493 §9 as ADR 0496 §2 changes it, issue 1783), held until it is answered, or withdrawn by a new head and asked again (ADR 0441 §1); said on a subject of their own, while each delivery's transitions stay as they are, 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, ADR 0649), and `entry` and `difference` on `mesh-wants` (ADR 0657), with the events of *What
each step says*. The verbs' names are this design's.
of the revision view, ADR 0656), and `entry` and `difference` on `mesh-wants` (ADR 0656), with the events of *What
each step says*.
**Links of the trace.** A session reviews under its own bus account (ADR 0651, Consequences), and the trace's other
links are this design's. The issue tracker gains link kinds from an issue to the decision and to the research effort
**Links of the trace.** A session reviews under its own bus account (ADR 0656, which changes ADR 0493 §5), and the
trace's other links are this design's choices under ADR 0656, so that one call traces research to the running build
with no text match (research 085, Findings 7). The issue tracker gains link kinds from an issue to the decision and to the research effort
it carries, made by a tool call and never by text, as ADR 0493 §4 has every link made; the knowledge base gains a
typed link from a decision to the milestone of the issue tracker that builds it, made by a tool call, which joins the
link kinds of its link-fits rule (design 55), beside the `became` link a research effort gets at its graduation
(playbook 02). How it is checked: whole (gate), a review by the head's author is refused (ADR 0651, How it is
checked), and the verdict is read from the verb, not the description; one ask per milestone, withdrawn by a new head;
(playbook 02). How it is checked: whole (gate), a review by the head's author is refused, and the verdict is read from the verb, not the description; one ask per milestone, withdrawn by a new head;
a waiter on one member's pull request wakes only on that member's transition. Whole (issue tracker, knowledge base):
an issue linked to a decision and to a research effort reads both back; a decision linked to its milestone reads it
back. Live: research 085's milestone's record reads back research 085 to its decisions, its milestone, its issues,
@@ -1891,41 +1915,40 @@ 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, ADR 0649 to ADR 0658; each section above names its tests and their level, and which
are the records' own):
From research 085 (ADR 0644 and ADR 0656; each section above names its tests and their level; 26 and 30 are ADR
0656's own checks, and ADR 0656 leaves the rest to this list):
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 (ADR 0644, How it is checked), and no member of it was
delivered ahead of it.
27. **A new acting part needs no code elsewhere.** A fixture seat declaring a rule, with a fixture holder, gets its
edges with no code change elsewhere, and a search of the delivery parts' code finds no other module's name
(ADR 0652, How it is checked).
.
28. **A change to a build module is built by the new one, once.** A group changing the shared contracts and the build
module that builds them is delivered, the contracts built by the running build module first and the rest by the
new one; a cycle among waits within one step is refused (ADR 0653, How it is checked).
new one; a cycle among waits within one step is refused.
29. **A failed acting part leaves the mesh on what runs.** A build module whose new build fails, and one that does not
run within its bound, each leave the modules it builds on their running builds and raise the condition naming
it, which clears when the wait ends (ADR 0654, How it is checked).
it, which clears when the wait ends.
30. **A change is delivered as its difference.** A fixture change with a new fingerprint and an empty difference is
refused, naming its module, and a group's preview before its merge is its difference (ADR 0657, How it is
checked); a group that changes the indexer, the checker and a module that needs both is delivered with no
refused, naming its module, and a group's preview before its merge is 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.
31. **A check never passes on the running version's word.** A change whose acting part does not build, and one whose
checking program does not run, each fail their check naming the part (ADR 0658, How it is checked); the registry
checking program does not run, each fail their check naming the part ; the registry
group passes its one check with its own checker, validator and composer.
32. **One view.** A pull request adding a seat and a module using it is validated by the indexer's candidate pass and
checked by the checker with the same definitions, and a search of the readers' code finds no compiled seat list
(ADR 0649, How it is checked).
.
33. **Each process knows its own build.** A part started while its node's want differs from what runs reports the
build it was started with (ADR 0655, How it is checked).
build it was started with.
34. **Two graphs, one source.** A revision of the assignment graph computed again from its named inputs equals the one
kept (ADR 0656, How it is checked).
kept.
35. **One record traces a delivery.** Stopping and restarting the gate in the middle of a delivery leaves the record
complete, with no outcome counted twice, and one call traces an issue of the registry milestone to each node's
running build (ADR 0650, How it is checked), also after six later merges; a group approved before the switch to
running build, also after six later merges; a group approved before the switch to
the records is not asked again.
36. **The trace is links.** A review by the head's author is refused (ADR 0651, How it is checked), and research 085's
36. **The trace is links.** A review by the head's author is refused, and research 085's
milestone reads back from research 085 to its reviews with no text match.
37. **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).
@@ -1974,14 +1997,14 @@ are the records' own):
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
module names and its cases for a change to the manifest validator and to the Go build module (ADR 0652); a build
module's edge as a trigger, with the extra build per recipe change (ADR 0603 §3, as ADR 0653 changes it); composing
from manifests a module whose changed build module the check cannot run (ADR 0603 §10 and ADR 0614 §7, as ADR 0658
changes them); the module graph's one key per module with five past values (ADR 0603 §2, as ADR 0657 changes it);
the tiers worked out from five live sources (ADR 0603 §6, as ADR 0657 changes it); a seat list compiled into a
part, and every read of another module's bus state the revision view replaces (ADR 0649); the gate's `merges` and
module names and its cases for a change to the manifest validator and to the Go build module (ADR 0656); a build
module's edge as a trigger, with the extra build per recipe change (ADR 0603 §3, as ADR 0656 changes it); composing
from manifests a module whose changed build module the check cannot run (ADR 0603 §10 and ADR 0614 §7, as ADR 0656
changes them); the module graph's one key per module with five past values (ADR 0603 §2, as ADR 0656 changes it);
the tiers worked out from five live sources (ADR 0603 §6, as ADR 0656 changes it); a seat list compiled into a
part, and every read of another module's bus state the revision view replaces (ADR 0656); the gate's `merges` and
`turns` as its own state, carried into the delivery records and kept current beside them until a later change
removes them; and the review line in a pull request's description, once the verb `review` runs (ADR 0651,
removes them; and the review line in a pull request's description, once the verb `review` runs (ADR 0656,
ADR 0496 §3).
## Milestones
@@ -2033,7 +2056,7 @@ release reports the controller's code lines against research 063's baseline (acc
| 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.<module>.<fingerprint>` 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 that hold their modules when the new version fails, 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 review verb and the trace's links (ADR 0649 to ADR 0658); the registry milestone's reviewed heads are joined to its group as members | 26 to 37 | 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 |
| 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 that hold their modules when the new version fails, 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 review verb and the trace's links (ADR 0656); the registry milestone's reviewed heads are joined to its group as members | 26 to 37 | 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
@@ -2097,10 +2120,10 @@ order inside one milestone, for this one case (ADR 0644).
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 (ADR 0653; *Order without a person*); the node-engine handing the fingerprint composes the
first in its own step (ADR 0656; *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 record's own: milestone G's group check runs on the checking program built from that
group's own heads, read from the check's record (live; ADR 0644, How it is checked). This design's: in the checker's
- **How it is checked.** Milestone G's group check runs on the checking program built from that group's own heads,
read from the check's record (live; ADR 0644, How it is checked). In the checker's
whole-module test, a fixture group whose checker change alters a rule is judged by its own checking program, which
has no bus account, a fixture group whose heads add a seat has that seat in the list both the validator and the
composer receive, and the check's read names the checking program's build and heads; live, B0's own check passes on
@@ -2110,19 +2133,6 @@ order inside one milestone, for this one case (ADR 0644).
## What is not decided here
- **Settled by this design on research 085's records, which keep only their choices** (the operator, 2026-11-06;
issue 1921), for the review by architectural domain to judge, with no record of their own: the graphs' keeping
beyond ADR 0619 §2 (the cap, the interim of ADR 0603 §2's five values until the milestone's delivery), their
retention while a delivery record pins them and the gate's events `pinned`, `freed` and `heads-replaced`; a
candidate's graphs kept apart and dropped on `heads-replaced`; the verbs `revision`, `entry` and `difference` and
their names; the step events, their fields and subjects; the first tier and its bound of 20 minutes; the build
seat's ask `run`; a change that alters or removes a rule of the checking program named in its verdict and Approve
ask, and an added acting rule named in the Approve ask; a rule with no holder held by name; which part holds each
step's wait and the tools that read and steer it; the acting rule's fields and their mesh-sdk cost; the fingerprint
handover's form; the delivery record's consumer, end, node away and wake, switch and rollback, retention and tools;
a small fix's record; the Approve held at its heads (issue 1972); the milestone events' own subject; the issue
tracker's and the knowledge base's new link kinds; the view's tools in mesh-sdk's runtime bundle; and every test
this design marks as its own.
- 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