Merge pull request 'Design 47 milestone G: the prepare's answers, so the design is complete for develop' (#541) from design/47-G-prepare-answers into main

This commit was merged in pull request #541.
This commit is contained in:
2026-11-11 02:17:01 +00:00
13 changed files with 428 additions and 69 deletions
+2 -1
View File
@@ -596,7 +596,8 @@ controller (the planner, the rollout) until release 6 of ADR 0429; from each rel
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 0656). From milestone G's delivery it is kept once per **watched branch**, and its edges run between
**artifact references**, of six kinds, the reverse order holding when something goes away (ADR 0666 §6, §14).
Nothing stores the order. Not the **assignment graph**, computed from it.
Nothing stores the order. Only the indexer reads the manifests; every other part reads the catalog graph (the operator,
2026-11-11; design 47 G §442). Not the **assignment graph**, computed from it.
*Not:* ~~build graph~~
- **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
@@ -1,7 +1,7 @@
---
layer: to-be
status: in-progress
code: [mesh-controller, mesh-catalog modules/mesh-delivery-gate, mesh-catalog modules/gitea, mesh-delivery, mesh-host, mesh-sdk, mesh-vault, mesh-contracts, hq 00-META/checks]
code: [mesh-controller, mesh-catalog modules/mesh-delivery-gate, mesh-catalog modules/gitea, mesh-delivery, mesh-host, mesh-sdk, mesh-vault, mesh-contracts, mesh-tools, mesh-networking, hq 00-META/checks]
updated: 2026-11-11
decisions:
- "ADR 0667"
@@ -273,7 +273,7 @@ source revision is derived from the keys: every **want** equals its module's **f
delivery it runs the composition step, and writes a want only from a revision whose every `required` pipeline step
passed, on the watched branch a placement chose (ADR 0666 §9, §17).
- **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
its own node** with the composition of `mesh-delivery-sdk` from the catalog graph's entry of the build (from milestone G; before it, the manifest by digest), the module's resolved values from
mesh-config, its secrets and bus credential asked of the vault sealed to the node's key, its licences and what
its providers contribute, applies one module at a time and only what differs from what runs, backs up a data
module first, and writes its haves with the fingerprint and the digest of the composition it runs (ADR 0547 §2,
@@ -724,7 +724,7 @@ From its delivery, a check is this:
issue 482). A trunk move asks no check but a carry, which runs only what the move changed (ADR 0548 §5).
- **The composition check is the assigner's.** Whether the machines still compose with a change is checked by
the part that owns what each machine should run. The assigner reads the modules, fingerprints and manifests
the indexer holds and the builds the builder holds; the machines, their roles, assignments and settings, and
the indexer holds (from milestone G, the catalog half alone: design 47 G §442) and the builds the builder holds; the machines, their roles, assignments and settings, and
the grants and credentials it reads from the grants part's state and the vault's accounts, and the rest from the buckets it
names in its manifest's `reads` (ADR 0237 §1, ADR 0408 §3, ADR 0547 §4). It clones no repository but at most the change's
own, and
@@ -1060,7 +1060,7 @@ backup holder backs up nothing, and the have says so.
*ADR 0360 §8, §9, ADR 0377, ADR 0429 §4, §6, ADR 0539 §9, §14 to §16, ADR 0546 §5, §6, ADR 0547 §2 to §9, ADR 0549, ADR 0555.*
- **Each node composes its own.** For each want `want.<node>.<module>` the node agent composes that module for
its own node with the composition of `mesh-delivery-sdk` from the manifest by digest the indexer wrote, the module's resolved
its own node with the composition of `mesh-delivery-sdk` from the catalog graph's entry of the build, from milestone G (before it, the manifest by digest the indexer wrote), the module's resolved
values read from mesh-config's resolved state filtered to its node, its secrets and bus credential asked of the
vault sealed to the node's key (ADR 0349 §11), its licences, and what its providers contribute; and the node's
own composition (adoption, firewall openings, accounts, the resolver, identities and groups) from the same
@@ -1074,8 +1074,9 @@ backup holder backs up nothing, and the have says so.
assigner's credential alone on an approved proposal and said by `assignments-changed` (ADR 0567, ADR 0641);
- **the node records**, each in its node's own have key `<node>.node`, written by that node alone and heard as
the key's change (ADR 0555 §3);
- **the manifests**, the indexer's `modules.<module>` and its manifests by digest, or the digest the composing
node's want names where it runs another build; the private network's manifest is its holder `mesh-wireguard`'s
- **the manifests**, until milestone G the indexer's `modules.<module>` and its manifests by digest, or the digest the composing
node's want names where it runs another build; from milestone G the catalog graph's entries of the catalog half,
the indexer being the only part that reads a manifest (design 47 G §442); the private network's manifest is its holder `mesh-wireguard`'s
own (ADR 0636 §4);
- **the config values**, mesh-config's resolved state, the composing node's slice alone for a node agent; a module
in the settings form (its manifest declares no config, so mesh-config holds none for it) has its values in the
@@ -1654,8 +1655,8 @@ list:
assigner and gate wanted; a module delivered during milestone G keeps its fingerprint while they wait; no want goes
to a fingerprint older than the trunk's; the operator is asked again only for an ask raised after the restore
point. A revert whose restore point is missing is held, naming it. Proved with the real builds of the indexer, the
assigner and the gate from before milestone G, not fixtures (whole, checker, gate, assigner, indexer, node-engine,
backup holder, bus module).
assigner and the gate from before milestone G, not fixtures, started by their fingerprints in the artifact store
(whole, in `mesh-host`: checker, gate, assigner, indexer, node-engine, backup holder, bus module; design 47 G §405).
37. **Nothing is delivered ahead.** Research 085's milestone is delivered with no part delivered ahead of it, read
from its delivery record (ADR 0656, How it is checked).
38. **A newer indexer is reached.** A merged revision naming a newer indexer gives, from the running indexer, a catalog
@@ -1699,7 +1700,7 @@ Each change ADR 0656 makes in an earlier record, and its test:
and act once the view is back, clearing it; the node-engine waits only for the catalog half; a candidate's heads
are read by the indexer's candidate pass and by no running part (whole).
48. **A process reports its handed build** (ADR 0639 §7). A part started while its node's want differs from what runs
reports the build it was started with, and `node_process_builds` reads it (whole, node-engine).
reports the build it was started with, and the node-engine seat's verb `process-builds` reads it (whole, node-engine).
49. **The forge bridge reads a group from the gate's verb** (ADR 0633 §4, §5). The forge bridge sets the group on each
merged message and publishes a group's end again from the seat `mesh-delivery`'s verb `groups`, and its account
holds no read of the gate's `merges` state, so a read of it is refused (whole, forge bridge).
@@ -235,7 +235,7 @@ check and deliver milestone G itself (ADR 0667 §2); each of them says so in a l
and an `approval` step is not; a module with no integration tests shows `nothing to run`, and a `required` unit-test
step on a module with no tests holds its delivery; a bypassed step is said; a runner restarted mid-step hears the
step's end and finishes the pipeline; two runners writing one pipeline key, one loses by compare-and-set; a test step's
counts are in `step-ended` and a repository over budget is named in `pipeline-ended`. Whole (Go build module): `steps`
counts are in `step-ended` and a catalog module over budget is named in `pipeline-ended` (§419). Whole (Go build module): `steps`
answers the steps of a fixture artifact, a `step` ask ends with `step-ended` on its own node's subject, one on another
node's subject is refused by the bus, and a build module restarted mid-step finishes it. Unit (manifest validator): a manifest naming a status is refused. Tests 65, 66, 73
and 88.
@@ -255,7 +255,7 @@ check and deliver milestone G itself (ADR 0667 §2); each of them says so in a l
revision the runner says one `group-ended` once every member's modules have ended, and the assigner writes the
group's wants only on it: a member's own `pipeline-ended` writes nothing (ADR 0666 §9).
- §30 **A failed `optional` step holds nothing.** It is shown in `pipeline-ended`, in the delivery record and in the runner's
`show`; a person may accept it by the runner's verb `accept`, recorded in the hand-act log with who and why.
`show`; the operator may accept it by the runner's verb `accept` (§394), recorded in the hand-act log with who and why.
- §31 **A newer commit supersedes an older pipeline of a module whose fingerprint it changed.** On a newer commit of the
same watched branch the runner ends a module's older running pipeline as `superseded` only when the newer commit
changed that module's build-input fingerprint (ADR 0666 §9); a module the commit leaves as it was finishes its
@@ -372,7 +372,7 @@ check and deliver milestone G itself (ADR 0667 §2); each of them says so in a l
program's cycle rule goes with the checker.
- §50 **A format's reader first.** A format a running reader cannot read is preceded by its reader, an edge of kind 4 on
every watched branch (ADR 0666 §14): the indexer's manifest validator for a new field of a seat definition or a
manifest, and on each node the node-engine that reads a manifest's new fields before any manifest that writes them
manifest, and on each node the node-engine that reads a catalog graph entry's new fields before any manifest that writes them
(ADR 0667 §4).
- §51 **How it is checked.** Unit (indexer's graph): a chain per artifact where modules would cycle; two programs needing
each other's new verb are one step; two artifacts each needing the other's new package to build are refused, naming
@@ -55,9 +55,9 @@ One file of milestone G's part of [design 47](../47-delivery-from-commit-to-deli
event, read within its call's bound or its consumer's lag, so its expiry is not a removal of kept data that ADR 0595
§4 holds to a person's word (the design's choice; 7 days is a guess at the longest a consumer lags, read from the
fill tools once G runs). A full sent store is the bus module's `full` and its condition (ADR 0595 §6), and the sender
then refuses the large reply or event loudly, naming the store. The grants part derives from the manifests a standing grant to read them: the
then refuses the large reply or event loudly, naming the store. The grants part derives from the catalog graph (§442), never from a manifest, a standing grant to read them: the
callers its seat definition names for the verbs it serves, and the consumers whose `consumes` declare its events;
no other module may read them (ADR 0666 §16). The grant follows the manifests, so it is written when they change,
no other module may read them (ADR 0666 §16). The grant follows the catalog graph, so it is written at each `catalog-revision` that changes it,
never per object. A consumer's reader of
the form is delivered before its producer writes it, an edge of kind 4.
- §60 **Its tools come with the package.** The package serves each module that imports it `<module>_state_objects` (the
@@ -117,7 +117,7 @@ One file of milestone G's part of [design 47](../47-delivery-from-commit-to-deli
- §68 **Callers per verb, in the seat's definition.** Each seat definition names, per verb, the callers allowed to call it,
in its field `callers` (holder roles, modules, the operator, the healers), which the grants part reads as its one
source of caller limits; the runner's verbs are the first (ADR 0666 §20). A verb whose definition names no `callers`
admits only the seat's holder roles and the operator, so a field left out opens nothing. It replaces the holder's
takes the default of its class (§391), so no verb is closed for lack of a list. It replaces the holder's
trusted config value `callers` of the seat `git` and the package seats (design 51), which no holder set for most
verbs. A format its running reader cannot read, so its reader is delivered first (ADR 0667 §4).
- §69 **A step's result from its holder only.** The runner takes a step's result only from the bus account of that step's
@@ -129,7 +129,7 @@ One file of milestone G's part of [design 47](../47-delivery-from-commit-to-deli
registration*; issue 1966, note 157).
- §71 **A widening is said, never refused.** A change that alters any part serving a step (the runner, step detection, the
lint rule, a build seat's test runner, the composer), or widens an acting rule, a grant or a credential, says so in
its `pipeline-ended`, its field `widens` naming each. The running runner computes it, from the sources of the change
its `pipeline-ended`, its field `widens` naming each. The running runner computes it, the serving parts from the seat list by fingerprint and the grants through the seat `mesh-grants`' verb `grants-for` (§441), from the sources of the change
against those of the watched branch, never the runner built from the change, so a change cannot hide its own
widening; nothing refuses it for that (ADR 0666 §23, the operator, 2026-11-10). The teller passes `widens` on to every
channel, as it does `recovery-merged`. This is what replaces ADR 0656 §8's naming in the Approve ask.
@@ -235,7 +235,7 @@ and an estimated 2 mesh-sdk publishes a day, each rebuilding about 120 artifacts
| the watchman, the keeper | `machine-away`, `machine-back` (§389); `findings-asked` (§390) | the seats' definitions | 90 days; 7 days | 16 MiB each |
| the runner | `aged`: three step-log sequences (§330) | old `state` section | never deleted | bytes |
| the teller | `widens-said` (§335) | the template `state` | until the branch is unwatched | a few KiB; the template's |
| each build module | `steps` (§326) | the template `state` | one key per artifact, dropped by `steps` with `drop` | under 1 MiB; the template's |
| each build module | `detected-steps` (§326, §414) | the template `state` | one key per artifact, dropped by `steps` with `drop` | under 1 MiB; the template's |
| the indexer | `registrations` and its stream `registration-history` | old `state` and `streams` sections | the life of the mesh, never derived again | 64 MiB (*A module's registration*) |
| the indexer | catalog graph revisions, per watched branch | objects in the old form (ADR 0619 §2) | while a record pins it or it is its branch's current | 512 MiB, as *Two graphs, one source of truth*; a second watched branch on a few modules adds a few MiB |
| the gate | `source`: one key per watched branch | its old `state` section, as today | 64 revisions of each key; a branch's key deleted when `registration-changed` says the last registration watching it unwatched it (`unwatch`) | a few KiB |
@@ -275,7 +275,7 @@ step keys and the builder's build log, against the checker's last week (test 99)
them; the manifest validator for the manifests' new words (`version`, §368; a `*` emitter in `consumes`, §386; the
finding stream an observer declares, §383, §387) and the grants part that makes a `*` entry's durable consumers
(§386), before the keeper's or any observer's manifest using them; on each node the node-engine that reads `form`
and `catch-up` before any manifest writing them. The running checker's validator makes G's own check, so the reading
and `catch-up` from the catalog graph before any manifest writing them. The manifest validator the running checker asks for G's own check is the indexer's, so the reading
of these words goes in the reader release of §340, whether or not that validator already takes one of them.
- §90 **The stream maker first** (ADR 0667 §5): the grants part, which makes each kept seat stream and its durable
consumers, before the parts that hear a kept stream.
@@ -341,10 +341,10 @@ step keys and the builder's build log, against the checker's last week (test 99)
| §121 The six kinds derived from existing words, `needs` per artifact only where nothing says it | one form of each fact (ADR 0656 §6); the catalog entry's `needs` already exists from G |
| §122 The cycle rule in the indexer's graph | the graph is the indexer's, and the checking program goes with the checker |
| §123 The builder's seat `mesh-builds` and its event `package-published` | the record has the builder say the publication as an event of its seat (ADR 0666 §15); its waits move only when a later change gives the seat its verbs |
| §124 Each state's object store `<state>-objects` through mesh-sdk's small package, sent objects readable by a standing grant derived from the manifests, and the package's two tools | one object store per state, granted to its owner; the sender's declared callers and consumers read what it sends (ADR 0666 §16); only its users import it, so nothing else is rebuilt |
| §124 Each state's object store `<state>-objects` through mesh-sdk's small package, sent objects readable by a standing grant derived from the catalog graph, and the package's two tools | one object store per state, granted to its owner; the sender's declared callers and consumers read what it sends (ADR 0666 §16); only its users import it, so nothing else is rebuilt |
| §125 The `run` ask published by the runner's account and the indexer's; the verb `run` called by the sessions and the operator only | the steps and the validation run code from the change, in the sandbox only, and each asker reads only its own step keys (ADR 0363 §2); a run publishes tagged packages, so nothing else may ask one |
| §126 The checker's step `check` becomes `pipeline`; `kept` starts empty | the runner is an acting part in the checker's place (ADR 0666 §19); a step's result is taken only from its seat holder (ADR 0666 §21), so no verdict of the checker's is taken in, at the cost of one round of every module's tests |
| §127 The field `callers` in a seat definition replaces the holders' trusted `callers`, a missing field admitting the holder roles and the operator only | the record makes the definition the grants part's one source (ADR 0666 §20); a field left out must open nothing |
| §127 The field `callers` in a seat definition replaces the holders' trusted `callers`, a missing field taking the default of the verb's `class` (§391) | the record makes the definition the grants part's one source (ADR 0666 §20); a field left out must open nothing |
| §128 `widens` in `pipeline-ended`, computed by the running runner over every part serving a step, passed on by the teller | a widening is said and nothing refuses it (ADR 0666 §23, §26); a change must not compute its own |
| §129 `merge-pull` judged from the forge module's own `failed-steps`, heard from `step-ended`, any run at the head's fingerprint counting unless a later rerun of that step passed, the protection read again on every `branch-moved` | the record has it judge from the events it consumes, never by a call, so a head merges while the runner is down (ADR 0666 §11, ADR 0596) |
| §130 The new assigner before the new `merge-pull` and the runner, by `needs`, both switching on the first `registration-changed` | a merge with no Approve must never reach an assigner that writes wants without a pipeline (ADR 0667 §10) |
@@ -3,7 +3,7 @@ layer: to-be
status: in-progress
design: 47
milestone: G
updated: 2026-11-10
updated: 2026-11-11
decisions:
- "ADR 0666"
- "ADR 0656"
@@ -284,16 +284,17 @@ Findings 11). How each is kept, read and retained is this design's choice under
must read every revision it moved between, and a revision neither pinned nor current is read by nobody.
- §179 **An unchanged entry is stored once.** A revision is kept as its list of entries' digests, and each entry as an
object of its own named by its digest, so an entry that two revisions share is stored once; an entry object is
removed when no kept revision lists it. Consecutive revisions differ by the few entries a delivery moves, so this
removed when no kept revision lists it and no want or running build names its fingerprint (§443). Consecutive revisions differ by the few entries a delivery moves, so this
keeps the growth to what changes. It is chosen over a larger cap because whole revisions would grow with every
revision whatever changed, and a cap would only delay the same fill.
- §180 **The caps and the growth** (estimates, to be read from the fill tools once the milestone runs). A whole assignment
graph revision of about 120 modules on four nodes is under the bus's 256 KiB value limit (its unit test), and a
catalog graph revision of about 120 entries about 120 KiB. A record pins the revisions before and after its
catalog graph revision's list of about 120 entries about 4 KiB, its entries, each carrying its manifest whole
(§443), about 15 KiB each. A record pins the revisions before and after its
delivery, and consecutive records share one, so at an estimated 20 deliveries a day about 20 revisions of each graph
a day stay pinned. A delivery moving 5 modules on four nodes adds about 20 assignment entries of about 1 KiB and a
list of about 15 KiB, and 5 catalog entries and a list of about 4 KiB: about 0.7 MiB a day of assignment graph and
0.2 MiB of catalog graph, about 63 MiB and 18 MiB at the records' default retention of 90 days. The caps are 512 MiB
list of about 15 KiB, and 5 catalog entries of about 15 KiB and a list of about 4 KiB: about 0.7 MiB a day of assignment graph and
1.6 MiB of catalog graph, about 63 MiB and 144 MiB at the records' default retention of 90 days. The caps are 512 MiB
for each, many times the steady state. Placement-only and capability-only revisions are pinned by no record and go
when they stop being current.
- §181 **A store filling is said before it is full.** The indexer, the assigner and the gate each say their fill against
@@ -3,7 +3,7 @@ layer: to-be
status: in-progress
design: 47
milestone: G
updated: 2026-11-10
updated: 2026-11-11
decisions:
- "ADR 0667"
- "ADR 0666"
@@ -57,13 +57,14 @@ One file of milestone G's part of [design 47](../47-delivery-from-commit-to-deli
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 0656, which changes ADR 0636 §4 in that the candidate pass joins
them). From G's delivery a running part acts on a revision of a watched branch as on a trunk revision, and a
candidate's view is read only by a run on request's steps and the indexer's candidate pass (ADR 0666 §6, §18).
candidate's view is read only by a run on request's steps, the grants part's `grants-for` (§441) and the indexer's
candidate pass (ADR 0666 §6, §18).
- §196 **Every other reader of which modules exist reads the catalog half, in the same milestone.** From milestone G the
indexer declares no state `modules` and serves neither its tool `indexer_read_modules` nor a view of it (*Reverted*,
above), so every module that learns from it which modules exist moves in milestone G, not after: the watchman (its
manifest findings), the status view (`view_reach`), the forge module (which repositories its account writes), the
holders of the seats `mesh-config`, `mesh-provisioner` and `mesh-self-check`, the claude-code module and the tool
runner. Each takes a first view of the catalog half by the seat `mesh-catalog`'s verb `revision` and follows its
holders of the seats `mesh-config`, `mesh-provisioner` and `mesh-self-check`, the claude-code module, the tool
runner and the node-engine (§421). Each takes a first view of the catalog half by the seat `mesh-catalog`'s verb `revision` and follows its
event `catalog-revision`, through `meshcatalogclient` in Go or the seat's generated TypeScript contract in the forge
module, names the seat and never the indexer, and keeps no list of its own (ADR 0656 §6, ADR 0596 §2; ADR 0615 §1,
under which every reader of the indexer's state moves in one milestone). A reader that misses a `catalog-revision`
@@ -105,8 +106,8 @@ One file of milestone G's part of [design 47](../47-delivery-from-commit-to-deli
indexer's whole-module test, started with a definition on a contracts trunk that no event announced, the first
manifest claiming that seat is judged with it.
- §199 **Who holds a seat is applied by one rule, from what each node runs.** The node-engine and the grants part decide a
seat's pass by mesh-sdk's `SeatsToPassOn` (ADR 0660 §3), reading the manifest of the build each assignment runs
(ADR 0660 §2). What each node runs is heard, never asked: each part keeps it from the node-engine seat's events
seat's pass by mesh-sdk's `SeatsToPassOn` (ADR 0660 §3), reading the catalog graph's entry of the build each assignment
runs, never a manifest (ADR 0660 §2; §442). What each node runs is heard, never asked: each part keeps it from the node-engine seat's events
`running.<node>.<module>` (*What each step says*), through a durable consumer of its own declared in its `consumes`,
so a pass is decided with no call to a node that may be away. The seat's stream keeps the last message per subject
with no age limit, so the last `running` of every module on every node stays on it however long ago it was said,
@@ -115,7 +116,7 @@ One file of milestone G's part of [design 47](../47-delivery-from-commit-to-deli
digest of the build's manifest, which is the indexer's manifest of that build (ADR 0660 §2's "the indexer's
manifest of it"), read by digest from the catalog half; the builder's done key is not needed, since the event names
the digest it would give. A node that has said no `running` for a module since the part's consumer began counts by
the trunk's manifest, as ADR 0660 §2 has it where the running build cannot be read, and both parts apply that same
the catalog graph's entry of the module on its placement's branch, as ADR 0660 §2 has it where the running build cannot be read, and both parts apply that same
fallback in the one function (ADR 0660 §3). Never another node's have key, its want or the assignment half (ADR 0596
§2; *Each part acts on its own entries*). The design's choice under ADR 0660 §2: the node that runs a build says what
it runs, and an event kept by a durable consumer answers when that node is away. How it is checked: test 56.
@@ -241,11 +242,11 @@ One file of milestone G's part of [design 47](../47-delivery-from-commit-to-deli
| §242 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) |
| §243 The milestone events on a subject of their own | a waiter on one member's pull request otherwise wakes on every member's |
| §244 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) |
| §245 The view's state read and asked again by mesh-sdk's `go/views` tools `<module>_first_views` and `<module>_first_view_again`, which gain the revision a part holds and what it waits for; the typed first view and the following of each half in the seats' client packages `meshcatalogclient` and `meshwantsclient`, built on `go/views`; the finding `view-waits` after five minutes; and `node_process_builds` | every part's view and every process's own build is read and steered by a tool; `go/views` already follows an owner's events durably and serves those two tools, so a second follower or a second pair of tools would be two forms of one thing; a view tool typed by the two seats would make mesh-sdk import contracts (ADR 0635 §4), so the typed half sits in the seats' client packages (ADR 0625 §4); a part waiting for the view is raised on the bound the seat list's readers keep |
| §245 The view's state read and asked again by mesh-sdk's `go/views` tools `<module>_first_views` and `<module>_first_view_again`, which gain the revision a part holds and what it waits for; the typed first view and the following of each half in the seats' client packages `meshcatalogclient` and `meshwantsclient`, built on `go/views`; the finding `view-waits` after five minutes; and the node-engine seat's verb `process-builds` (§440) | every part's view and every process's own build is read and steered by a tool; `go/views` already follows an owner's events durably and serves those two tools, so a second follower or a second pair of tools would be two forms of one thing; a view tool typed by the two seats would make mesh-sdk import contracts (ADR 0635 §4), so the typed half sits in the seats' client packages (ADR 0625 §4); a part waiting for the view is raised on the bound the seat list's readers keep |
| §246 The seat list's reader and its two tools wired once by mesh-sdk's runtime | ADR 0636 §7 puts them in the runtime bundle; four hand-wired copies would each learn `acts` apart |
| §247 The trunk's heads from the catalog half, and nothing read of the gate by the checker | ADR 0596 §2; with the hold and turns removed nothing of the gate is left for the checker to read |
| §248 The indexer reads every contracts trunk's definitions at its start, before it judges | a definition merged while it was down is never judged against a list that lacks it (ADR 0636 §1) |
| §249 Another node's running build kept from the node-engine seat's `running` events by a durable consumer, the event carrying the fingerprint and the manifest's digest, the trunk's manifest for a node that said nothing | ADR 0660 §2 reads the manifest of the build each node runs; an event kept by a durable consumer answers while a node is away, where a call would wait on it; one fallback in the one function keeps the two parts agreed (ADR 0660 §3) |
| §249 Another node's running build kept from the node-engine seat's `running` events by a durable consumer, the event carrying the fingerprint and the manifest's digest, the catalog graph's entry for a node that said nothing | ADR 0660 §2 reads the manifest of the build each node runs; an event kept by a durable consumer answers while a node is away, where a call would wait on it; one fallback in the one function keeps the two parts agreed (ADR 0660 §3) |
| §250 What the gate and the checker owe the forge said as the event `owed` per repository and pull request, each act safe to repeat at the forge, each outcome said as `owed.ended` and recorded, an unanswered act said again at the gate's start and stalled after 15 minutes | ADR 0596 §1, §2 end the watches of the gate's and the checker's keys; an act safe to repeat cannot be lost between the act and its record, where an id recorded first could; an outcome said and recorded leaves no act unseen |
| §251 A merge made at the forge opens a `forge-made` delivery record | its trace and outcomes are kept like every delivery's, and no later merge waits behind a merge the gate never heard |
| §252 Every delivery part and the gate reach the forge only through the seat `git`'s verbs and events, the act verbs granted by the holder's trusted `callers` to the forge bridge alone, a failed read answered as an error | the delivery parts name no other module (ADR 0656 §1, acceptance test 27); the forge's answers are typed in the seat's contract instead of guessed in each caller; the bridge stays the one part that acts on the forge; an error read as an empty answer would hide a forge down |
@@ -266,9 +267,10 @@ and the assignment graph revisions; an entry taken in, built, checked, composed,
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 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; a seat event's name has no dot, since it is read
as a subject's token, and it is kept on the stream `SEAT_<seat>_<event>`, which the grants part makes with its durable
consumers, keeping it by the age and cap the definition's `keep` names, 90 days unless it names less. **An event a node publishes carries the node in
declared in its definition and its holder's manifest claims the seat; an event whose definition names `keep` has no
dot in its name and is kept on the stream `SEAT_<seat>_<event>`, which the grants part makes with its durable
consumers, keeping it by the age and cap `keep` names (§396), and an event naming no `keep` stays on its seat's family
stream. **An event a node publishes carries the node in
its subject**, and the grants part grants each node-engine's account only its own node's subjects, so one node cannot
say another runs a build (ADR 0363 §2); the gate's events are granted to the gate's account alone.
@@ -318,8 +320,8 @@ what it heard and how far it is behind, and `<module>_first_view_again`, granted
read the view again now. `go/views` stays seat-neutral, naming no seat and no seat's type (ADR 0635 §4); the typed
first view of each half and the following of its events are the seats' client packages, `meshcatalogclient` for
`mesh-catalog` and `meshwantsclient` for `mesh-wants`, each built on `go/views` (ADR 0625 §4), so no part follows the
view by a follower of its own. A tool
of the node-engine, `node_process_builds`, reads the build each process was started with. The tools answer the four
view by a follower of its own. The node-engine's seat
verb `process-builds` (§440) 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.
@@ -3,7 +3,7 @@ layer: to-be
status: in-progress
design: 47
milestone: G
updated: 2026-11-10
updated: 2026-11-11
decisions:
- "ADR 0667"
- "ADR 0666"
@@ -338,7 +338,7 @@ later change of a kept data's form, not as a case of this milestone.
catch-up tool the newer manifest declares beside that kept data. A failed
backup holds that module as any failed backup does.
- §297 **A revert restores it before the reverted build starts.** When a want takes a module back across a change of a
kept data's `form`, the node agent applying it asks that seat's verb `restore` for the restore point of that module,
kept data's `form`, the node agent applying it stops the newer build, then asks that seat's verb `restore` (§405) for the restore point of that module,
kept data and form, waits for the seat's event `restored`, and only then starts the reverted build. The node agent
that restores is the one running when the revert starts. As every restore is, it is brought back beside the live data
and never over it: the live kept data of the newer form is set aside under a name of its own, and only the operator
@@ -3,7 +3,7 @@ layer: to-be
status: in-progress
design: 47
milestone: G
updated: 2026-11-10
updated: 2026-11-11
decisions:
- "ADR 0667"
- "ADR 0666"
@@ -59,8 +59,8 @@ of each verb (ADR 0666 §7, §20, §25):
| `run` | the run on request of one or more members, each a module at a named commit; delivers nothing | the sessions (the agents' bus identities the tool runner proves) and the operator, nothing else |
| `start` | a delivering pipeline for a watched branch's head, by hand | the operator, the healers |
| `show`, `list`, `stands`, `why-carried`, `kept` | one pipeline whole with its step log; the pipelines and runs of a module, a branch or a commit; what stands still; where a result was carried from; the kept results | any person, an agent session, the healers |
| `review` | a code review's result for a commit and fingerprint | the reviewers the definition names; refused from the commit's author |
| `rerun`, `accept`, `cancel`, `ask-again` | one step again; a failed `optional` step accepted with why; a pipeline ended, its asks dropped; a declined `approval` asked again | the operator, the healers (`accept` and `ask-again` the operator) |
| `review` | a code review's result for a commit and fingerprint | sessions; refused from the commit's author (§394) |
| `rerun`, `accept`, `cancel`, `ask-again` | one step again; a failed `optional` step accepted with why; a pipeline ended, its asks dropped; a declined `approval` asked again | the operator, the healers (`accept` and `ask-again` the operator; §391, §394) |
§307 **The seat `mesh-catalog`** gains, from milestone G's delivery, `register`, `policy`, `watch`, `unwatch` and
`registrations`, and the event `registration-changed` (*A module's registration*), and `catalog-revision` names its
@@ -77,7 +77,7 @@ each step says*.
§309 **The seat `node-engine`**'s event `running.<node>.<module>` carries, from research 085's milestone, the module, its
fingerprint and the digest of its build's manifest, so the node-engine of another node and the grants part decide a
seat's pass from it (ADR 0660 §2; *Who holds a seat is applied by one rule*). No verb is added.
seat's pass from the catalog graph's entry of that build (ADR 0660 §2; *Who holds a seat is applied by one rule*). No verb is added.
§310 **The seat `git`.** The seat `git` (design 26, *The git seat*), of the Delivery domain, defined in
`mesh-delivery-contracts`, holds no verb today, and the delivery parts and the gate reach the forge by naming the forge
@@ -106,9 +106,9 @@ parts' manifests declare in `invokes` and `consumes` and what their code calls,
| Event of the seat | Says | Heard by (today's event) |
|---|---|---|
| `pull.updated`, `pull.merged`, `pull.closed` | a pull request's new head, its merge with the merge commit, its close | the forge bridge, the gate (`gitea.pull.*`) |
| `forge.pull`, `forge.status`, `forge.delete` | the forge's own webhook of a pull request, of a commit status, of a deleted branch | the gate (`forge.pull`, `forge.status`), the forge bridge (`forge.delete`) (`gitea.forge.*`) |
| `repo.writable` | a repository the forge can write again | the gate (`gitea.repo.writable`) |
| `pull-updated`, `pull-merged`, `pull-closed` (§396) | a pull request's new head, its merge with the merge commit, its close | the forge bridge, the gate (`gitea.pull.*`) |
| `forge-pull`, `forge-status`, `forge-delete` | the forge's own webhook of a pull request, of a commit status, of a deleted branch | the gate (`forge.pull`, `forge.status`), the forge bridge (`forge.delete`) (`gitea.forge.*`) |
| `repo-writable` | a repository the forge can write again | the gate (`gitea.repo.writable`) |
| `branch-moved` | from milestone G's delivery: a branch's new head, by a merge or an admitted push, from the forge's push webhook | the forge bridge |
§311 Each is said on `mesh.seat.git.event.<event>`, declared in the seat's definition, and heard through the hearer's
@@ -62,7 +62,7 @@ record it follows from, and replaces the builder's own choice where one was made
unit step leaves the approval `not asked`; its passing rerun asks it, and once approved the second `pipeline-ended`
writes the want.
- §326 **A build seat keeps its `steps` answer.** The build module keeps each artifact's detected steps in its state
`steps`, from the template `state`, one key per artifact holding the answer for that artifact's newest build-input
`detected-steps` (§414), from the template `state`, one key per artifact holding the answer for that artifact's newest build-input
fingerprint, replaced when a newer fingerprint is detected and by `steps` with `again`; a key whose artifact no
longer exists is dropped by `steps` with `drop`, on a person's word, written in the hand-act log. With one key per
artifact (about 120) the state needs no aging and no read time. Why: ADR 0666 §25 asks a tool for "the steps
@@ -90,7 +90,8 @@ record it follows from, and replaces the builder's own choice where one was made
30 days each `kept` digest the entry names whose `last-read` is past 30 days; at 90 days the passed pipeline the
entry names, unless it is its branch's newest. It then moves the sequence; nothing is scanned whole. Each delete
writes a line in the runner's journal naming the key or object and its retention. A foundation part's sent store
(`sent-objects`) is aged the same way by its owner at each send, from the sequence of its own sends. Nothing waits on
(`sent-objects`) is aged the same way by its owner at each send, from the sequence of its own sends, which mesh-sdk's
sender keeps in the owner's old `state` section (§410). Nothing waits on
a timer, and nothing but the owner deletes. Why: an old section cannot declare an age, and deleting one's own entries
is the owner's act, not the removal of a store ADR 0595 §4 holds to a person's word; §57's rule that only the drop
tool removes an object holds for a template's `<state>-objects`, while the runner's `step-outputs` are its own old
@@ -99,10 +100,10 @@ record it follows from, and replaces the builder's own choice where one was made
- §331 **The kept event streams' caps, and when one is full.** On the seat `mesh-pipeline-runner`, each kept 90 days:
`pipeline-started` 32 MiB, `pipeline-ended` 192 MiB, `group-ended` 64 MiB, `run-started` 16 MiB, `step-started`
and `step-ended` 128 MiB each, `wait-held` and `wait-ended` 32 MiB each; the seat `git`'s `branch-moved` 64 MiB; each
build seat's `step-ended` 128 MiB; `mesh-wants`'s `step-ended` 32 MiB; `mesh-builds`' `package-published` and
`mesh-catalog`'s `registration-changed` 16 MiB each; `package-published` 128 MiB; `version-released` 128 MiB,
`version-delivered` 64 MiB, `toolchain-agreed` 16 MiB, and `versions-filled` 1 MiB with no age limit; all others
90 days. At about 300 releases a day (a mesh-sdk publish rebuilding about 120 modules), `package-published` of about
build seat's `step-ended` 128 MiB; `mesh-wants`'s `step-ended` 32 MiB; `mesh-catalog`'s `registration-changed` 16 MiB;
`mesh-builds`' `package-published` 128 MiB; `mesh-delivery`'s `owed` 7 days and 64 MiB (§396); `version-released` 128 MiB,
`version-delivered` 64 MiB, `toolchain-agreed` 16 MiB, and `versions-filled` 1 MiB with no age limit; every other kept
event 90 days and 16 MiB (§396). At about 300 releases a day (a mesh-sdk publish rebuilding about 120 modules), `package-published` of about
two artifacts each and `version-released` each say about 0.6 MiB a day, about 54 MiB in 90 days, and
`version-delivered` about 27 MiB. Why: about 300 pipelines a day of about 6 steps
(*The runner's kept data*) say about 1,800 step events a day of about 0.5 KiB, about 80 MiB in 90 days, and about 300
@@ -151,7 +152,8 @@ record it follows from, and replaces the builder's own choice where one was made
`persons`, and every other text the names the design gives that verb. Why: ADR 0666 §20 makes the definition the
grants part's one source of caller limits, in a form it reads; `invokers`, which ADR 0666 §20's list does not name,
is the operator's choice for the verbs whose text said "any caller whose role grants it" (Telegram, 2026-11-11 02:13
CET: "Any declaring module"), and by the same answer, that a verb open today stays open to any module declaring it,
CET: "Any declaring module"; every verb's default by its class is §391, a holder role and a module written
`seat:<seat>` and `module:<module>`, §392), and by the same answer, that a verb open today stays open to any module declaring it,
for the fifteen verbs of the Connectivity domain's seats that name no `callers` on main, which §68 would otherwise
close to their holders and the operator: `node-hostname`'s `entries`, `add` and `remove`;
`node-intrusion-prevention`'s `status`, `banned`, `ban` and `unban`; `node-packet-filter`'s `rules`, `reload` and
@@ -175,7 +177,7 @@ record it follows from, and replaces the builder's own choice where one was made
above. Why: one source of caller limits (ADR 0666 §20). How it is checked: the generator's test refuses an unknown
entry.
- §340 **The reader release first.** mesh-sdk's seat-definition reader released before G's check reads `callers` as text
or as a list; G's own reader refuses text. The same release carries mesh-sdk's manifest reader of the new words of
or as a list; G's own reader refuses text; it reads every new form G writes (§409). The same release carries mesh-sdk's manifest reader of the new words of
§89 (`version`, a `*` emitter in `consumes`, an observer's finding stream), which the running checker's validator
reads before G's manifests use them. Why: readers first (ADR 0667 §4), and every definition is a list from G; it is merged ahead of G's check because the
running checker, which makes G's own check (ADR 0667 §2), must read G's definitions, the operator's choice of a
@@ -384,7 +386,7 @@ record it follows from, and replaces the builder's own choice where one was made
`builder_versions` also answers each reserved version with its artifacts' digests (§369), so a registry holder still
on its version before G, which asks `builder_versions`, stores a publish of a reserved version made between the
builder's delivery and its own (§381). The builder's state
`versions`, the floor and its tool `builder_floor_again`, the event `numbered`, `builder_versions`, and `tag-asks` are
`versions`, the floor and its tool `builder_floor_again` and `builder_versions` are
removed in the first change after the first pipeline after G's delivery has delivered a change end to end, the state
through `drop` on a person's word (ADR 0595 §4). Why: numbering reads only the catalog's released versions (§348),
and without this every first version under G would start below today's and Go's `@latest` would never move (the design's choice, round 2 of the review by architectural domain, 2026-11-10).
@@ -39,12 +39,11 @@ record says so in its Why. Round 3 of the review by architectural domain (2026-1
next statement of §384 covers a lost one), published on `mesh.stream.<module>.event.<event>.<node>`, the node it runs
on in the subject (ADR 0363 §2; §260). `finding-written` is said when a finding is raised or what it says changes,
and only then (ADR 0289 §1, §4); `finding-cleared` when the observer no longer observes it. `finding-written`
carries `scope`, `id` and `kind` (the key `<scope>.<id>.<kind>` of ADR 0564 §2), `severity`, `subject`, `evidence`,
ADR 0253's words (`headline`, `explanation`), `since` and `at`; `finding-cleared` carries `scope`, `id`, `kind`, `at`
carries the finding's layout whole, plus `scope`, `id` and `kind` (the key `<scope>.<id>.<kind>` of ADR 0564 §2) and
`since` (§437); `finding-cleared` carries `scope`, `id`, `kind`, `at`
and `why`. The observer and the node are the subject's alone: the grants part grants each module's account publish
on its own stream's subjects of its own node's segment only, the keeper takes both from the subject, and it refuses
an event whose body names another observer or node, said in its journal. mesh-sdk's finding writer (`go/views`'
`FindingWriter`) says them for every part, after the key it writes in the part's own state `findings`, which stays
an event whose body names another observer or node, said in its journal. The writer generated from the seat `mesh-conditions`' definition (§439) says them for every part, after the key it writes in the part's own state `findings`, which stays
the owner's and is read only by the owner's read tool; a publish the bus does not acknowledge is sent again for one
minute, then written in the part's journal as an error naming the finding, and the next statement covers it. The
keeper takes a finding only from a source of its own list (§388) and raises or changes a condition on
@@ -102,9 +101,8 @@ record says so in its Why. Round 3 of the review by architectural domain (2026-1
`*.<event>` takes the event `<event>` from every module whose manifest declares it, and is the one generic form for
hearing an event that many modules say; the keeper's `*.finding-written`, `*.finding-cleared` and
`*.findings-stated` are the first. The manifest validator takes `*` only as the whole emitter, and only before an
event that a seat's definition or a contract in mesh-sdk defines, with its fields (for the finding events, mesh-sdk's
finding writer); it refuses `*` before any other event, `*.>`, and `*` in part of an emitter's name. The grants part,
from the manifests as it derives every grant (§59), makes on each declaring module's stream one durable consumer
event that a seat's definition or a contract in mesh-sdk defines, with its fields (for the finding events, the seat `mesh-conditions`' definition, §439); it refuses `*` before any other event, `*.>`, and `*` in part of an emitter's name. The grants part,
from the catalog graph as it derives every grant (§59, §442), makes on each declaring module's stream one durable consumer
for the consumer, named `<machine>_<module>` as ADR 0363 §5 names one, with its grants to read and acknowledge it and
its membership's word to bind it; it drops that consumer when the module no longer declares the event, and makes one
for a module that declares it later, with no change to the consumer's manifest. A `*` entry never reaches a
@@ -141,7 +139,7 @@ record says so in its Why. Round 3 of the review by architectural domain (2026-1
the catalog's holder stopped it raises and clears from its kept sources' events, raises `view-waits` after five
minutes itself, and clears nothing with `module left the node` until the assignment half answers.
- §389 **The watchman says a machine's presence as events.** The seat `mesh-watchdogs` gains the events `machine-away`
and `machine-back` (`mesh.seat.mesh-watchdogs.event.machine-away.<node>`, `.machine-back.<node>`, carrying the node,
and `machine-back` (`mesh.seat.mesh-watchdogs.event.machine-away.<machine>`, `.machine-back.<machine>`, §436, carrying the machine,
`at` and since when it was last heard), said by the watchman when its presence key of a machine expires and when the
machine is heard again (ADR 0564 §4), declared in the seat's definition and kept 90 days, 16 MiB. The keeper
consumes them for `findings-unstated` (no machine away is named, and an ask is said again to a module of a machine
@@ -0,0 +1,352 @@
---
layer: to-be
status: in-progress
design: 47
milestone: G
updated: 2026-11-11
decisions:
- "ADR 0670"
- "ADR 0668"
- "ADR 0667"
- "ADR 0666"
- "ADR 0656"
- "ADR 0636"
- "ADR 0625"
- "ADR 0615"
- "ADR 0596"
- "ADR 0595"
- "ADR 0564"
- "ADR 0363"
---
# 47, milestone G: the answers to the questions of G's final prepare
One file of milestone G's part of [design 47](../47-delivery-from-commit-to-delivered.md); the part opens at
[G.md](G.md). Its design lines are numbered across every file of the part and cited as "design 47 G §n".
## What G's final prepare found open, answered by this design (2026-11-11)
*G's final prepare (lead-47, 2026-11-11) collected about a hundred questions from its preparers, each cited here by
its id in that prepare: Q1 to Q19 (mesh-contracts), S1 to S18 (mesh-sdk), Q-H1 to Q-H11 (`mesh-host`), Q-T1 to Q-T8
(mesh-tools), C1 to C22 (mesh-catalog) and D1 to D19 (mesh-delivery). Each line is the design's own choice within the
records it cites, or the operator's intent already given, or the operator's answer, said as such. Where several
preparers asked one thing, one line answers all. A line that changes an earlier line amends it there; the earlier
line says so.*
### Who may call a verb
- §391 **Every verb takes a default of callers by its class.** From the operator's answers of 2026-11-11 (02:13 CET,
"Any declaring module"; 02:47 and 02:56 CET, "As proposed"), a verb's definition names its class in the field
`class`, and a verb whose definition names no `callers` takes its class's default, which the seat-definition reader
applies and the manifest validator says per verb ("`<seat>.<verb>` takes the default of `<class>`"): a `read` takes
`invokers`, `persons` and `sessions`; an `act` (a new act that changes what the mesh does: registers, sets a policy,
watches or unwatches a branch, recovers, restores) takes `operator` and `sessions`; a `warrant` (a verb that runs on
the operator's warrant) takes `operator` and carries the approval mark; `accept` is the operator's alone (§394). A
verb on main that names no class is a `read`, so every verb open today stays open; a verb G adds must name its
`class`, and the definition reader refuses one that does not. A verb that names `callers` keeps them, so no verb is
closed by §68 for lack of a list; §68, §127 and §306 point here. Why: ADR 0666 §20 makes the definition the one source
of caller limits; the operator asked on 2026-11-11 why caller questions kept coming, and answered them as one rule
(Q1, S3, C3, D2's reads, Q18). How it is checked: unit (seat-definition reader), a table test with one row per class,
a row for a verb with `callers` of its own, and a row refusing a verb G adds without `class`; unit (manifest
validator), the default each verb took is said.
- §392 **A caller entry names its kind of name.** In `callers`, a holder role is written `seat:<seat>` and a module
`module:<module>`, beside `operator`, `healers`, `persons`, `sessions`, `invokers` and `holder:<seat>@same-node`
(§336), since a name such as `mesh-grants` is both a seat and a module. Why: the design's choice (Q2). How it is
checked: unit (definition reader), a bare name refused, both prefixed forms accepted.
- §393 **The node-engine's eleven verbs name today's callers.** The eleven verbs of the seat `node-engine` that name
no `callers` on main get, in their definition, the callers the node-engine's compiled callers table names for each
on main, written in §392's forms, and that table goes from the node-engine's code: the definition is the one
source (§68). Why: the design's choice (Q-H8). How it is checked: unit (definition reader), each of the eleven names
its callers; the code review finds no callers table in the node-engine.
- §394 **The callers of G's new trusted acts.** `mesh-catalog`'s `register`, `policy`, `watch` and `unwatch`, and
`mesh-delivery`'s `recovery`, are of class `act`: the operator and sessions; `registrations` is a `read`.
`mesh-pipeline-runner`'s `review` is called by sessions, and refused from the change's author (§70); its `accept` by
the operator alone, which amends §30's "a person". `operator-channel`'s `ask-again` is a seat verb, its callers the
operator and the healers (§83, §40). Why: the operator, 2026-11-11 02:56 CET on Telegram, "As proposed" (S4, S10,
C18, D2, D3, D4). How it is checked: whole (indexer, runner, operator-channel), a call from any other caller is
refused by the bus; unit (definition reader), each verb's class and callers.
- §395 **An accepted kind naming no callers keeps today's grant.** `operator-channel`'s kinds `ask` and `condition`
keep the grant they have today, open to every asker, so the runner's approval (§37), the seed ask (§8) and every
other asker are not refused (§338); `cancel` stays limited to each asker's own subject (ADR 0259 §3). Why: the
operator's intent, a verb open today stays open (Q18). How it is checked: whole (operator-channel), an asker's `ask`
is taken and its `cancel` of another asker's ask is refused by the bus.
### The forms of a seat's definition
- §396 **A dot only where no stream is named from the event; `keep`'s form.** An event whose definition names `keep`
has no dot in its name, since its stream `SEAT_<seat>_<event>` is named from it; an event naming no `keep` stays on
the shared stream EVENTS, its seat's family, kept 7 days, and may have a dot. `keep` is an object of three fields:
`max-age-days` (days; `0` is the one value for no age limit), `max-mib`, and `last-per-subject` (yes or no); unless
it names others its age is 90 days, its cap 16 MiB and `last-per-subject` no (§331). The seat `git`'s events take
hyphens: `pull-updated`, `pull-merged`, `pull-closed`, `forge-pull`, `forge-status`, `forge-delete` and
`repo-writable` (§310). The gate's `owed` is kept on its seat stream `SEAT_mesh-delivery_owed`, 7 days and 64 MiB
(§162), its one name. This amends §260. Why: the design's choice (Q3, Q4, S5, C1, C2). How it is checked: unit
(definition reader), a dotted event with `keep` refused, one without accepted, `keep`'s defaults and `0` read as no
age limit.
- §397 **The forms of `subject`, `acts.on` and `bound`.** `subject` is the words after `mesh.seat.<seat>.event.` with
`<part>` tokens, `<node>` written out; `acts.on` is one string, `every`, a language, or `kind:image`; `bound` is a
duration such as `30m`. Why: the design's choice (Q5). How it is checked: unit (definition reader), each form
accepted and another refused.
- §398 **The step `place` is `mesh-wants`'.** The step `place` is declared in the definition of the seat `mesh-wants`,
where §260's table has the assigner's placing waits. Why: the design's choice (Q6). How it is checked: the seat's
fixtures.
- §399 **A binding names its objects and its sent store.** The binding of a state, as the seat `mesh-broker` answers
it, gains `objects`, the bus name of its `<state>-objects` (§58), and a module's sent store is a binding entry
`sent-objects` (§59), so a module learns both names from its bindings. Why: the design's choice (Q7). How it is
checked: unit (mesh-broker's contract), a binding with both read.
- §400 **No new verb is optional.** A verb G adds is not `optional`: the order of its holder's delivery is §298's
edges, and a claim refused meanwhile is a gap of the delivery system built within G (§93). Why: the design's choice
(Q9). How it is checked: unit (definition reader), no verb G adds is marked `optional`.
- §401 **The seat `mesh-grants` has one verb in G.** Its definition carries its rule, its four events and the read
`grants-for` (§441); its module's tools `grants_waits`, `grants_release`, `grants_callers` and `grants_why_refused` stay its own. Why: the
design's choice (Q12, amended by D15, §441). How it is checked: the seat's fixtures.
- §402 **A placement's `build` is a fingerprint, and `unwatch` waits for the placements.** A placement's `build` names a
fingerprint; `unwatch` refuses while a placement names the branch, naming the placement. Why: the design's choice
(Q13). How it is checked: whole (indexer), `unwatch` of a placed branch refused.
- §403 **A held-back ask.** A held-back ask (§83, design 46 §6) is answered in `asks` with the state `held-back` and the
field `held-since`, and no field `behind`. Why: the design's choice (Q14). How it is checked: the seat's fixtures.
- §404 **The node-engine's events' bodies.** `capabilities-changed` carries the node record's stated capabilities whole
and `at`; `composed` the module, the fingerprint and the composition's digest; `running` with `stopped` carries
`stopped: true` and no fingerprint (§365), and mesh-sdk's `SeatsToPassOn` counts such a module as not running on that
node. Why: the design's choice (Q17). How it is checked: the seat's fixtures; unit (`SeatsToPassOn`), a row where a
`stopped` holder passes no seat.
### Kept data on the bus, restore points and the reader release
- §405 **The bus module's restore points and node-backup's verbs.** The seat `mesh-broker` gains `snapshot-kept` and
`restore-kept`, of class `act`, their callers `holder:node-backup@same-node` alone (§337): the bus module's account is
the one that moves bus data, so `restore-kept` sets the live kept data aside under a name of its own and then
restores the restore point beside it, with the argument `aside-only` it sets the live data aside and restores
nothing, and with the argument `discard-aside`, naming data set aside, it removes that data and restores nothing.
The seat `node-backup`'s `now`, `restore` and `aside` (class `act`, callers by §391's default) and `discard-aside`
(callers `operator` alone) gain `kept`, `form` and `fingerprint` and call those verbs; listing stays `backed-up`
(§302). Before any live data is set aside, the node agent stops the newer build of the module (§297). `now` and
`restore` say `ended` and `restored` on `mesh.seat.node-backup.event.ended.<node>.<module>.<kept>` and
`.restored.<node>.<module>.<kept>`, carrying the module, the kept data, its form, the fingerprint and `outcome`
(`done` or `failed`, with its `error`); the node agent's wait for either is bounded at 30 minutes, past which its
have says the wait, naming the seat, and the watchman's `delivery-waits` raises it. Test 36's whole case lives in
`mesh-host`, and starts the builds from before G by their fingerprints in the artifact store. Why: the design's
choice, one answer to three preparers (Q8, S9, Q-H6, C19; lead-47's ruling, 2026-11-11). How it is checked: test 36;
a call of `snapshot-kept` from another node's `node-backup` holder, and a `discard-aside` from any caller but the
operator, are refused by the bus; a failed restore says `restored` with `failed` and its error.
- §406 **A catch-up names its tool and arguments.** A restore point records the catch-up tool and its arguments whole
(§299), and the fingerprint of the newer build it was taken before; the grants part derives the grant of that tool to
`holder:node-engine@same-node` from the catalog graph's entry of that recorded fingerprint (§443). Why: the design's
choice (Q-H7). How it is checked: whole (node-engine), a restore runs its recorded catch-up, granted from the
recorded build's entry.
- §407 **The object store package.** mesh-sdk's object store package is `go/stateobjects`; it also takes a foundation
part's old `objects` section (§58, §346). A reply or event over the limit is made an object by that package through
§345's put session, and read back through the same session form for a get; the call that reads a sent object is
`mesh/objects.sent-get`, under the existing capability (§347). A foundation part's bundle is bound to its old
`objects` section as its states are (§176, §194). Why: the design's choice (S14, D17, Q-T3, S13, Q-T4, Q-T5). How it
is checked: unit (`go/stateobjects`), an old section and a template store each take a large value; whole (tool
runner), a large reply read back.
- §408 **The ledger's calls.** The ledger's fill and removal calls are in mesh-sdk's `buscalls`, under the existing
`ledger` calls (§155, §159, §181); no capability word `ledger-fill` is added. Why: the design's choice (S15, Q-T6).
How it is checked: the code review.
- §409 **The reader release reads every new form G writes.** The reader release of §340 reads every new definition
form and manifest word G writes: `callers`, `class`, `keep`, `subject`, `acts`, the step `pipeline`, `on`
`kind:image`, `version`, the `*` emitter, an observer's finding stream, and an artifact's `needs`; `check` stays
beside `pipeline` until the checker is removed (§97, §203). Why: readers first (ADR 0667 §4; S2, S18). How it is
checked: unit (the release's reader), each form read.
- §410 **A foundation part's sent store keeps its send sequence.** mesh-sdk's sender keeps, per node, the sequence of
a foundation part's sends in the owner's old `state` section `sent-log`, one key `<node>` written by compare-and-set
at each send, and ages `sent-objects` from it at each send (§330); `<module>_state_objects` reads it. Why: an
`objects` section has no sequence (S7). How it is checked: unit (sender), a send past 7 days ages the oldest, and two
sends at once lose none by compare-and-set.
### Versions
- §411 **`version` replaces the old field, and `series` goes.** Every manifest's top-level `version` takes the
`MAJOR.MINOR` of §368 in the same change, replacing today's `"1"`, and each artifact's `series` goes, refused by the
manifest validator; a contracts module's version is `0.1` unless §372's fill gives higher. Why: one version per
module (§52, §374; Q15, S1, Q-H3, D14). How it is checked: unit (manifest validator), `series` refused.
- §412 **The first fill's sources.** §372's fill reads, per module, the packages its catalog entry names in their
ecosystems (the Go module path, the npm name); where the builder holds no version of a package, the forge's tags of
its repository (`go/vMAJOR.MINOR.PATCH`) are the floor, only tags the forge protects. The fill is a kept call that
waits until both sources have answered for every module, and fills nothing until then, never part of the modules.
Why: the live builder answers none for mesh-sdk while the forge holds `go/v0.1.14` (S17, C9). How it is checked:
whole (indexer), a module with tags and no builder versions fills from the tags; with the forge down, nothing is
filled and `call-unanswered` is raised after five minutes; an unprotected tag is not read.
- §413 **`tag-asks` and `version.numbered` go at G's delivery.** The builder's `tag-asks` and its event
`version.numbered` are removed at G's delivery, as §373 has for the tagged versions; the build modules consume
`version.numbered` no more from G. This amends §372. Why: the design's choice (D19). How it is checked: the
catalog's validation at G's heads finds no `consumes` of `version.numbered`.
### Steps, tests and pipelines
- §414 **The build seats' state is `detected-steps`.** The state §326 names `steps` is `detected-steps`, apart from
today's step keys `steps`. This amends §326. Why: the design's choice (C5, D13). How it is checked: whole (Go build
module), as §326.
- §415 **Kinds on the stream `check`, and a recovery's steps.** A step ask is the kind `check.step`, a run on request's
`check.run`; a recovery's steps are `delivery.step`, which the runner may publish (§86). Why: the design's choice
(D5, C6). How it is checked: whole (runner, Go build module), a recovery's step is taken from `delivery` first.
- §416 **A step ask carries the kept results.** The runner's step ask carries the kept results by package digest
(§25), so a build seat runs only the packages without one. Why: the design's choice (C7). How it is checked: whole
(Go build module), a carried package is not run.
- §417 **Go's lint is gofmt and vet.** Go's lint step runs gofmt and go vet, in the lint step only (§328). Why: the
design's choice (C8). How it is checked: whole (Go build module), a vet failure fails lint and no unit step.
- §418 **The repository checks run as a step.** Each repository's own checks, which the checker runs today, run as a
pipeline step of its build seat from G's delivery, keyed per repository and source revision, so a repository's
checks run once for a source revision however many of its modules it moves (ADR 0548); hq's check (its `go test
./...` at its root) runs on the seat `node-build-go`. Why: the checker goes (C20). How it is checked: whole (runner),
a failing repository check fails its step, and a revision moving two modules of one repository runs it once.
- §419 **How tests are counted.** A test is a top-level Go test function or a TypeScript `test(` call, counted per
catalog module. A module ends G with no more tests than it starts with, and a module over its budget at its start
whose tests G's change touches ends with fewer (the test budget); the new runner stays within 50 integration and 500
unit tests. `pipeline-ended` carries per module `tests` (`unit`, `integration`) and `over-budget` (yes or no); G's own
check, made by the running checker (§340), counts by the same rule. Why: the test budget per module (S16, D6). How it
is checked: `pipeline-ended`'s counts; unit (runner), a module over budget is named `over-budget`.
- §420 **A run on request's key, and the step-run package.** A run on request is keyed by the run's id under its named
branch (§54, §64, §85); the step-run code is the delivery SDK's package `sdk/steprun`, and the runner's
client sits beside the other seats' clients; the runner's kept data layouts are the seat's `states` (§27, §306). Why:
the design's choice (D16, D8, D10). How it is checked: whole (runner), two runs of one commit are two pipelines.
### Readers, branches and the node-engine
- §421 **The node-engine reads the entry its want names.** The node-engine joins §196's readers: it reads, from the
catalog half, the catalog graph's entry of the fingerprint its want names (§443), never a manifest and never by
branch, so a want needs no field `branch`, and the parts by digest from its want (§379); its reads of the indexer's
and builder's states go. When the catalog half no longer holds that entry, the node-engine holds the want and its
have says the phase `entry-missing`, naming the fingerprint. The tool runner follows every watched branch's newest
`catalog-revision`, as §365. Why: ADR 0596 §2 (Q-H1, Q-H2, Q-T8; review of step 0b). How it is checked: the
node-engine's account holds no read of another module's state; test 61, extended to the node-engine; whole
(node-engine), a want naming an entry the half does not hold says `entry-missing`.
- §422 **The node-engine's first-view tools are seat verbs.** The node-engine serves its view's two tools as the seat
`node-engine`'s verbs `first-views` and `first-view-again`, beside its seat-list verbs, since it serves no module
tools: `first-views` a `read`, its callers any person and the healers, and `first-view-again` an `act`, its callers
the operator and the healers, as §204 names them. Why: the design's choice (Q-H4). How it is checked: the seat's
fixtures; whole (node-engine), a call from another caller is refused by the bus.
- §423 **A kept-build wait says the existing words.** A have waiting for a kept build (§271) says the existing phase and
words, with no new field. Why: the design's choice (Q-H10). How it is checked: whole (node-engine).
- §424 **Each process's own build, and each bundle's.** A process says `own build unknown` in its
`<module>_first_views` (§205); each tools bundle's composed environment carries its module's fingerprint. Why: the
design's choice (S12, Q-T7). How it is checked: whole (tool runner), a bundle reads its fingerprint.
- §425 **A kept call asks again what its asker names.** An asker passes the kept-call form the ask's key and the event
that replaces it, and the form asks again only while that key is open and no replacing event was heard (§351). Why:
the design's choice (S11). How it is checked: unit (kept-call form).
- §426 **The tool runner keeps no waits list.** §74's session waits use `mesh_wait` on any event (ADR 0670), and
`gitea.forge.status` goes (§133). Why: ADR 0670 (Q-T2). How it is checked: the tool runner's manifest has no waits.
### The gate, the forge and the move
- §427 **The contracts and SDK folders move, importers in the group.** The delivery repository's contracts and SDK
move to `modules/mesh-delivery-contracts` and `modules/mesh-delivery-sdk`, their Go module paths and TypeScript names
renamed to match, and every importer moves in the same group. Why: design it as it should be (C4, D1). How it is
checked: the group's check builds every importer.
- §428 **The fixed names G removes.** Each name is read from the registrations, the catalog half or the seat list
(§7): in mesh-delivery, module names of the delivery parts, the forge module, the build modules, `mesh-grants`,
`mesh-config`, `mesh-vault`, `mesh-wireguard`, the tool runner and the bus module, and the branch `main`; in
mesh-catalog, the gate's merge branch, the SDK's repository and the teller's, view's and forge bridge's module
names, the forge module's base branch and the indexer's name and tool, and the build modules' indexer tool; in
`mesh-host`, the node-engine's own module name in its guard, compose and bootstrap; in mesh-sdk, the node-engine's
names (§364); in mesh-tools, the assigner's first views by name; in mesh-networking, `mesh-wireguard` and
`mesh-provisioner`. Why: the design's choice (Q-H9, C10, D7). How it is checked: the code review (§7).
- §429 **Lines "until G's delivery".** The new gate builds the forms from G's delivery and the switch (§156, §169)
alone; what holds only until G's delivery is not rebuilt. Why: the design's choice (C11). How it is checked: whole
(gate), test 36's gate half.
- §430 **The gate's sources before the first registrations.** The gate keeps `source.<branch>` per repository and
watched branch, the branch escaped as §73, following the registrations, and writes `source.<default branch>` for
every repository from its start, before the first registrations (§15, §95). It starts from its own kept `source`
keys; the forge's heads it asks as a kept call (ADR 0668), so a gate started while the forge is down serves what it
kept, writes nothing for a repository it has no key of, and raises `call-unanswered` after five minutes. Why: the
design's choice (C12, D18). How it is checked: whole (gate), `source` answers before any registration, and with the
forge stopped it serves its kept keys and says `call-unanswered`.
- §431 **The fate of the gate's other parts.** From G's delivery the gate's `asks` go with the Approve per merge;
`deliveries`, `show`, `groups` and `stalled` are answered from the delivery records; `checks` and `settle` go with the
merge states, and the five verbs of release 6 leave the definition; the events `group` and `merged` go, while
`transition` stays; their readers move: the knowledge base's delivery overview (what `knowledge-base.progress`
draws) reads the seat `git`'s `pull-merged` and the runner's `group-ended`, and the issue tracker and the tool runner
the same. The reads of the teller's answers and the view's reach are by their events, and of the checker's verdicts
go with it. Readers of the gate's `source` move to the verb `source` and `source-moved`, and the assigner reads no
`merges`. Why: the design's choice (C13, C14, D9, D11). How it is checked: whole (gate), each verb served or not as
named; whole (knowledge base), the overview shows a group's end from `group-ended`.
- §432 **The edges a `needs` names.** An artifact's `needs` names artifact references `<module>:<artifact>` of the
catalog graph's edges (§95, §121). Why: the design's choice (C21). How it is checked: unit (manifest validator).
- §433 **The bus module reads the catalog half.** The bus module's `consumes` and its call of `indexer_bus_state` are
replaced by its view of the catalog half (§344). Why: ADR 0596 §2 (C22). How it is checked: its manifest.
- §434 **Findings name their owner and whom they wait on, and the keeper reads by events.** A finding of §33, §8 and
§75 carries `owner` and `waiting-on`; the keeper's other reads are by events or verbs, and no homes rows are added.
Hand-written finding code in Go moves to the generated writer (§439). Why: the design's choice (C16, C17, C15's Go
half). How it is checked: the code review; the keeper's manifest reads nothing.
- §435 **`compose-candidate` goes with the checker.** The node-engine's verb `compose-candidate`, whose caller is the
checker, is kept in G and removed in the change that removes the checker (§97), with the check's candidates. Why:
the design's choice (Q16, Q-H1's candidates). How it is checked: the seat's fixtures at G's heads keep it.
- §436 **A presence event names the machine, not its publisher.** `machine-away` and `machine-back` carry the machine
as a subject part named `<machine>`, which the grants part does not bind to the publisher's node, since the
watchman says them for another machine; publish on them is granted to the holder of `mesh-watchdogs` alone. This
amends §389. Why: `<node>` in a subject is the publishing node (§260; S8). How it is checked: whole (watchman), the
event for an away machine is published by the watchman's account; the grants part's table test, a row refusing the
same event from any other account.
- §437 **`finding-written` carries the finding's layout whole.** `finding-written` and each entry of `findings-stated`
carry the fields §439 lists, so a condition built from the event alone loses nothing. This amends §383. Why: the
design's choice (Q19). How it is checked: unit (writer), the event's body holds every field of the key.
- §438 **The record names every repository G builds.** Design 47's milestones row and frontmatter `code:` name
mesh-tools and mesh-networking, and design 51's line on what a node-engine hears says it consumes the node-engine
seat's `running` (§199). Why: the design's choice (Q-T1, Q-H11). How it is checked: the index test.
### Lead-47's rulings on the four stopped items, and the operator's rule on manifests (2026-11-11)
- §439 **The finding events' layout is a seat contract, and its writers are generated.** The seat `mesh-conditions`'
definition defines, in its section `bodies` (the bodies other modules say on their own streams, from which the grants
part makes no seat event or stream), the finding and the bodies of `finding-written`, `finding-cleared` and
`findings-stated`, beside `findings` and `findings-asked`. A finding's fields, the one list: `kind`, `scope`, `id`,
`at`, `since`, `severity`, `summary`, `headline`, `explanation`, `subject`, `evidence`, `source`, `observer`,
`owner`, `waiting-on`, `actions`, `needs`, `resolver`, `ref` and `run`; `finding-cleared` carries `kind`, `scope`,
`id`, `at` and `why`; `findings-stated` carries `at`, `asked`, `findings` and `pending`. The seat generator (seatgen)
generates the Go and the TypeScript writers from it, so the forge module's TypeScript writer comes with it. mesh-sdk's
`go/views` writer takes the subject handed in by the seat's client and names no seat (§262). This amends §383, §386
and §434. Why: lead-47's ruling, 2026-11-11, on Q10, S6 and C15, one answer for the three; the list is the design's
choice. How it is checked: unit (seat generator), both writers generated from the definition say the same bodies;
unit (grants part), a body of `bodies` makes no stream; whole (forge module), its writer says `finding-written`.
- §440 **`process-builds` is a node-engine seat verb.** The read of the build each process was started with is the
seat `node-engine`'s verb `process-builds`, a `read`, its callers any person, agent sessions and the healers, since
the node-engine serves seat verbs and no module tools (§422). This amends §262 and test 48. Why: lead-47's ruling,
2026-11-11, on Q11 and Q-H5. How it is checked: test 48; the grants part's table test, its three callers.
- §441 **The seat `mesh-grants` answers the grants a candidate composes.** The seat `mesh-grants` gains the read
`grants-for`. Its argument is the candidate: a source revision or a run's id, and its watched branch. The grants part
takes that candidate's catalog half by `mesh-catalog`'s `revision` (one of §195's readers of a candidate's view) and
answers, per module, the grants it would compose added and removed against the branch's newest, each named by its
subject and verb. Its callers are §391's default. The running runner reads a change's grants for `widens` through it,
as a kept call, and its serving parts from the seat list by fingerprint (§71); while the grants part does not answer,
`pipeline-ended`'s `widens` says `could not run`, naming `mesh-grants`, and holds nothing (§71: a widening is said,
never refused). This amends §401. Why: lead-47's ruling, 2026-11-11, on D15 and Q12. How it is checked: whole (grants
part, runner), a change widening a grant names it in `widens` from `grants-for`, and with the grants part stopped
`widens` says `could not run`.
- §442 **Only the indexer reads a manifest.** The indexer alone reads the manifests, to build the catalog graph, whose
entry carries the validated manifest whole (§443); every other part (the grants part, the condition keeper, the
assigner, the runner, the tool runner, the node-engine, the checks and the reviews) reads the catalog graph's entry
of the build concerned from the catalog half (§196, §421). Today's readers move: in mesh-catalog, `brother`,
`distribution`, the forge module's package registry and `mesh-build-go` read the entry they need by `mesh-catalog`'s
`entry` or `revision`; in `mesh-host`, the node-engine reads the entry its want names (§421). The one exception is
the bootstrap: `mesh-host`'s `mesh-bootstrap` and `mesh-compose` read the manifests from a checkout of the catalog repository, before
any indexer runs. This amends §50, §59, §89, §199, §249, §309, §386, §406 and §421, and the main file's node agent,
its inputs and the composition check. Why: the operator, 2026-11-11 about 03:05 CET at the terminal: "only the
indexer uses the manifest to build the module catalog". How it is checked: test 61, extended to the node-engine and
the grants part: whole cases whose accounts hold no read of a manifest; the grants part's table test derives each
grant from a catalog graph fixture with no manifest.
### From the review of step 0b (2026-11-11)
- §443 **The catalog graph's entry carries the manifest, and is kept while a build names it.** Each catalog graph
entry carries the validated manifest whole beside the fields §174 names, kept as an object of the indexer's old
`objects` section by its digest (§179), so no size limit applies to it. The indexer keeps an entry while a kept
revision lists it, or a want (heard by `mesh-wants`' `wanted`) or a running build (heard by the node-engine seat's
`running.<node>.<module>`) names its fingerprint, and removes it at the first revision after none does; the seat
`mesh-catalog` gains the read `entry`, which answers one entry by its fingerprint, so a build older than the newest
is read by the want's fingerprint. This amends §179 and §180. Why: §442; the design's choice. How it is checked:
whole (indexer), an entry no revision lists stays readable by `entry` while a want names its fingerprint, and goes
after the want moves on.
- §444 **The grants part derives each module's grants from the build placed.** The grants part derives each module's
grants from the catalog graph's entry of the build its want names (heard by `wanted`), never from a branch's newest
revision, so a change on a branch no placement names grants nothing. This amends §59 and §386. Why: §442; a grant
follows what runs. How it is checked: the grants part's table test, a widening on a branch no placement names
grants nothing, and the same widening once wanted is granted.
- §445 **The indexer keeps the manifests by digest for node-engines before G.** Until no node runs a node-engine from
before G, the indexer keeps writing each manifest by digest in its state `manifests`, which those node-engines
read; that state and its writing go in the first change after the node-engine seat's `running` events say every
node runs G's node-engine, the state through `drop` on a person's word (ADR 0595 §4). The node-engine's own manifest
in G uses no word the node-engine of the version before refuses, since that reader refuses unknown fields; the
manifest validator holds it to that reader's words at G's heads. Why: readers first (ADR 0667 §4). How it is
checked: unit (manifest validator), a row refusing a node-engine manifest with a word the older reader refuses;
whole (node-engine of the version before), it composes from a manifest by digest written by G's indexer.
+4 -2
View File
@@ -5,6 +5,7 @@ design: 47
milestone: G
updated: 2026-11-11
decisions:
- "ADR 0670"
- "ADR 0668"
- "ADR 0667"
- "ADR 0666"
@@ -75,7 +76,7 @@ file on 2026-11-10, and is cited as "design 47 G §n". A sentence that holds a d
stayed in the main file, and G builds what it says from G's delivery. A section named in italics is in this part, or,
when it is not here, in the main file.
The part is eight files, each read whole, its design lines numbered across them:
The part is nine files, each read whole, its design lines numbered across them:
- [G-1-pipelines-registration-and-steps](G-1-pipelines-registration-and-steps.md): pipelines per module: registration, watched branches, steps and policy, what holds a delivery, approval, groups, dependencies, a publish.
- [G-2-pipelines-sizes-checks-and-tools](G-2-pipelines-sizes-checks-and-tools.md): pipelines per module: any size, the pipeline makes the check, who may say what, health, recovery, tools, kept data, how G itself is delivered, the choices under ADR 0666 and ADR 0667.
@@ -84,4 +85,5 @@ The part is eight files, each read whole, its design lines numbered across them:
- [G-5-acting-parts-check-and-kept-data](G-5-acting-parts-check-and-kept-data.md): the acting parts, the removed hold, the check on the change's own acting parts, after the merge, taken in, and kept data on the bus.
- [G-6-verbs-and-retires](G-6-verbs-and-retires.md): the verbs G adds and what retires.
- [G-7-answers](G-7-answers.md): the answers to the builders', the reviewers' and the operator's questions (§322 to §382).
- [G-8-findings-heard-as-events](G-8-findings-heard-as-events.md): the operator's answers of 2026-11-11, findings heard as events (§383 on).
- [G-8-findings-heard-as-events](G-8-findings-heard-as-events.md): the operator's answers of 2026-11-11, findings heard as events (§383 to §390).
- [G-9-prepare-answers](G-9-prepare-answers.md): the answers to the questions of G's final prepare (§391 on).
@@ -239,7 +239,7 @@ the verb.
matches `settled` by the holder its declaration names. A change of the seat's holder composes the declaration
again, so the name it carries is the holder of now. The seat and the holder are not part of what a container is
(they are not in its digest), so a declaration composed again for them replaces no container. **The seam that changes is the grants part's list of what a node-engine
hears** (`NodeAgentHears`; the node-engine declares no `consumes` of its own): it gains one entry, the status
hears** (`NodeAgentHears`; from design 47's milestone G the node-engine also declares its `consumes` of the node-engine seat's `running`, design 47 G §199, §438): it gains one entry, the status
view's `settled` family, which the node-engine filters for the holder of the seat its failed image names. **At its
own start** the node-engine also applies once more every have that failed naming an image of a store, so a restart
or an absence across the swap misses nothing. A module already being applied is not applied a second time; a retry