Merge pull request 'Amend design 47 for milestone G: the gate's record, the seat git, the merge on the Approve alone' (#530) from design/47-G-amendment into main

This commit was merged in pull request #530.
This commit is contained in:
2026-11-09 19:38:46 +00:00
4 changed files with 677 additions and 120 deletions
+30
View File
@@ -38,6 +38,7 @@ import (
// holders the glossary says no seat's holder: no seat "held by" or "claimed by" a named module, no named module // holders the glossary says no seat's holder: no seat "held by" or "claimed by" a named module, no named module
// "holder of" a seat, no module that "holds the seat" (the operator, 2026-11-09). Who holds a seat is read // "holder of" a seat, no module that "holds the seat" (the operator, 2026-11-09). Who holds a seat is read
// from the mesh's assignments, and the glossary's head says where. // from the mesh's assignments, and the glossary's head says where.
// domains no retired domain heads a section of the glossary (ADR 0641 §5: Placement).
// copy with MESH_CATALOG_DIR set to a checkout of the catalog, its copies of the retired words and the // copy with MESH_CATALOG_DIR set to a checkout of the catalog, its copies of the retired words and the
// daemons' lines equal this glossary's and this list (skipped, with its reason, when unset). // daemons' lines equal this glossary's and this list (skipped, with its reason, when unset).
// //
@@ -830,3 +831,32 @@ func TestHoldersRefusesANamedHolderAndPassesARole(t *testing.T) {
} }
} }
} }
// domains: a retired domain is no heading of the glossary. ADR 0641 §1 retired Placement into Core (module
// assignment) and Delivery (the wants), and §5 has this test refuse it as a domain heading.
var retiredDomains = []string{"Placement"}
func checkRetiredDomains(text string) []string {
var out []string
for _, d := range retiredDomains {
rx := regexp.MustCompile(`(?m)^##\s+` + regexp.QuoteMeta(d) + `\b`)
for _, loc := range rx.FindAllStringIndex(text, -1) {
out = append(out, fmt.Sprintf("%s:%d: %q is a retired domain (ADR 0641 §1) and heads no section", glossaryFile, lineOf(text, loc[0]), d))
}
}
return out
}
func TestWordsGlossaryHasNoRetiredDomainHeading(t *testing.T) {
expectNone(t, checkRetiredDomains(readFile(rootFS(), glossaryFile)))
}
func TestRetiredDomainsRefusesTheHeadingAndPassesProse(t *testing.T) {
if len(checkRetiredDomains("## Placement — what runs on which node\n")) == 0 {
t.Error("a Placement heading was not refused")
}
if got := checkRetiredDomains("## Core\n\nwhich was the Placement domain until ADR 0641\n"); len(got) != 0 {
t.Errorf("prose refused: %v", got)
}
}
+47 -40
View File
@@ -165,8 +165,8 @@ and repair).
**Purpose.** To hold, check and resolve every value a module reads that someone may change, and to say **Purpose.** To hold, check and resolve every value a module reads that someone may change, and to say
where each resolved value came from. **Recorded by** the `mesh-config` module, in its buckets on the bus, where each resolved value came from. **Recorded by** the `mesh-config` module, in its buckets on the bus,
with its store as the history behind them. **Upstream of** Provisioning, which places the values; with its store as the history behind them. **Upstream of** Provisioning, which places the values;
downstream of Module and Placement. **Decided by** ADR 0262, 0277, 0348. downstream of Module and Core. **Decided by** ADR 0262, 0277, 0348.
**Uses:** module, node, manifest (Module), assignment (Placement), provision (Provisioning), proposal **Uses:** module, node, manifest (Module), assignment (Core), provision (Provisioning), proposal
(Operator and conversation). (Operator and conversation).
- **template file** — a file a module ships with placeholders, such as `${config:<key>}`, which the provisioner - **template file** — a file a module ships with placeholders, such as `${config:<key>}`, which the provisioner
@@ -225,10 +225,13 @@ downstream of Module and Placement. **Decided by** ADR 0262, 0277, 0348.
## Core — the mesh's own machinery ## Core — the mesh's own machinery
**Purpose.** To keep the controller, the bus, the store and every node's engine running and agreed, so **Purpose.** To keep the controller, the bus, the store and every node's engine running and agreed, so
every other domain has something to run on. **Recorded by** the controller and the store. every other domain has something to run on; and to decide and apply what each node runs, and say why: module
**Upstream of** every domain but Module; the others use the bus and the store as they are. assignment, which was the Placement domain until ADR 0641 §1 retired it into this one. **Recorded by** the
**Decided by** ADR 0005, 0006, 0067, 0106, 0141, 0175, 0227, 0229, 0289. controller and the store; for module assignment, by the seat `mesh-module-assigner`, in its states on the bus
**Uses:** node, module, seat. (ADR 0567). **Upstream of** every domain but Module; the others use the bus and the store as they are.
**Decided by** ADR 0005, 0006, 0067, 0100, 0106, 0126, 0141, 0175, 0176, 0181, 0207, 0221, 0227, 0229, 0252, 0261,
0289, 0411, 0539, 0549, 0559, 0565, 0567, 0571, 0634, 0641.
**Uses:** node, machine, module, seat, manifest (Module), config value (Config), proposal (Operator and conversation).
- **controller** — the component that decides what each node should be, holds the mesh's records, and - **controller** — the component that decides what each node should be, holds the mesh's records, and
tells nodes over the bus. The relationship is *controller and nodes*, and no node is subordinate: a tells nodes over the bus. The relationship is *controller and nodes*, and no node is subordinate: a
@@ -299,22 +302,8 @@ every other domain has something to run on. **Recorded by** the controller and t
text is about the controller's records; the builder's *mirrored* `upstream` image (Delivery) is text is about the controller's records; the builder's *mirrored* `upstream` image (Delivery) is
a different thing, a copy of an outside image in the artifact store. a different thing, a copy of an outside image in the artifact store.
## Placement — what runs on which node
**Purpose.** To decide, send and apply what each node runs, and to say why.
**Recorded by** the controller's `inventory` database; from ADR 0567, by the seat `mesh-module-assigner`, in its states on
the bus. **Upstream of** Provisioning, Connectivity, Data
and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 0252, 0261, 0411, 0539, 0549, 0559, 0565, 0567, 0571, 0634, 0656.
**Uses:** node, machine, module, seat, manifest (Module), config value (Config), proposal (Operator and conversation).
- **assignment** — a module put on a node. Its config values on that node (module-assignment config, - **assignment** — a module put on a node. Its config values on that node (module-assignment config,
Config) are `mesh-config`'s, never part of what the controller records (ADR 0348 §9). 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;
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 - **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 decided of the node, as one key per node in the state `placement` of the seat `mesh-module-assigner`. It changes only by
a placement proposal the operator approves, and no repository holds it or names a node (ADR 0567). Until ADR a placement proposal the operator approves, and no repository holds it or names a node (ADR 0567). Until ADR
@@ -323,11 +312,8 @@ and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 02
- **mesh-module-assigner** — the seat, held once for the mesh, that keeps placement: its states - **mesh-module-assigner** — the seat, held once for the mesh, that keeps placement: its states
`placement`, `proposals` and `candidates`, and its seven verbs `placement`, `proposals`, `propose`, `withdraw`, `placement`, `proposals` and `candidates`, and its seven verbs `placement`, `proposals`, `propose`, `withdraw`,
`again`, `adopt` and `hand-back`. Only the holder writes its states (ADR 0567, renamed by ADR 0634 §9). Its `again`, `adopt` and `hand-back`. Only the holder writes its states (ADR 0567, renamed by ADR 0634 §9). Its
contract is in `mesh-placement-contracts` (ADR 0634 §7). contract is in `mesh-contracts`, module assignment being of this domain (ADR 0641 §1).
*Not:* ~~mesh-placement~~ *Not:* ~~mesh-placement~~
- **mesh-wants** — the seat, held once for the mesh, that keeps what each node should run, one want
per node and module (`want.<node>.<module>`), and a person's upgrade policy, served as its verb `upgrade`
(ADR 0565 §7, ADR 0571 §8). Its contract is in `mesh-placement-contracts` (ADR 0634 §6, §7).
- **seat holders** — the state `seat-holders` of the seat `mesh-module-assigner`, written by its holder: one - **seat holders** — the state `seat-holders` of the seat `mesh-module-assigner`, written by its holder: one
key per seat naming each holder and its node, composed from placement and the manifests' claims as the indexer key per seat naming each holder and its node, composed from placement and the manifests' claims as the indexer
holds them, and rewritten only when a key differs. The tool runner and every other reader of who holds a seat holds them, and rewritten only when a key differs. The tool runner and every other reader of who holds a seat
@@ -409,9 +395,9 @@ and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 02
**Purpose.** To resolve which module serves a provision for which consumer, to wire the two, and to **Purpose.** To resolve which module serves a provision for which consumer, to wire the two, and to
place every value a module needs into its files on its node. **Recorded by** the controller and place every value a module needs into its files on its node. **Recorded by** the controller and
`mesh-provisioner`. **Upstream of** Data; downstream of Module, Placement, Config and Identity. `mesh-provisioner`. **Upstream of** Data; downstream of Module, Core, Config and Identity.
**Decided by** ADR 0027, 0084, 0138, 0225, 0230, 0263, 0349. **Decided by** ADR 0027, 0084, 0138, 0225, 0230, 0263, 0349.
**Uses:** module, seat, node-engine (Core), declaration (Placement), config value (Config), credential **Uses:** module, seat, node-engine (Core), declaration (Core), config value (Config), credential
and vault (Identity and access). and vault (Identity and access).
- **provision** — a service one module `provides` and others `require`; the mesh resolves a provider - **provision** — a service one module `provides` and others `require`; the mesh resolves a provider
@@ -467,7 +453,7 @@ and vault (Identity and access).
**Purpose.** To issue, hold, rotate and check the credentials and grants by which modules, nodes, agents **Purpose.** To issue, hold, rotate and check the credentials and grants by which modules, nodes, agents
and the operator act. **Recorded by** the controller's `identity` and `licences` databases and the vault. and the operator act. **Recorded by** the controller's `identity` and `licences` databases and the vault.
**Upstream of** Provisioning, Delivery, and Operator and conversation. **Upstream of** Provisioning, Delivery, and Operator and conversation.
**Decided by** ADR 0085, 0113, 0183, 0225, 0234, 0386, 0387, 0388, 0411, 0413, 0414, 0550, 0571, 0587, 0634. **Decided by** ADR 0085, 0113, 0183, 0225, 0234, 0386, 0387, 0388, 0411, 0413, 0414, 0550, 0571, 0587, 0634, 0636, 0656, 0660.
**Uses:** module, node, seat, tool (Module), operator, consumer and provision (Provisioning), agent and ask (Operator and conversation). **Uses:** module, node, seat, tool (Module), operator, consumer and provision (Provisioning), agent and ask (Operator and conversation).
- **credential** — anything that proves an identity: a password, a key, a token. A **pair credential** - **credential** — anything that proves an identity: a password, a key, a token. A **pair credential**
@@ -514,6 +500,11 @@ and the operator act. **Recorded by** the controller's `identity` and `licences`
is issued. The bus server calls its accounts *users*; the mesh says bus account. Each module's membership is issued. The bus server calls its accounts *users*; the mesh says bus account. Each module's membership
is kept in the grants part's state `memberships` (seat `mesh-grants`), one key `<node>.<module>` written is kept in the grants part's state `memberships` (seat `mesh-grants`), one key `<node>.<module>` written
only when it differs, and the runtime reads its membership there (ADR 0571 §10). only when it differs, and the runtime reads its membership there (ADR 0571 §10).
- **mesh-grants** — the seat, held once for the mesh, that composes who may say what on the bus: each module's
membership, the bus's user list and `grants.<module>.<fingerprint>`, applying mesh-sdk's `SeatsToPassOn` for a
seat's pass (ADR 0660 §3). From research 085's milestone it is defined whole in `mesh-identity-and-access-contracts`,
this domain's contracts module (ADR 0636 §5), as an acting part of the step `grant` (ADR 0656 §1), with the events
`wait-held` and `wait-ended` (design 47).
- **rotate** — replacing a credential without a consumer holding one the provider does not know. - **rotate** — replacing a credential without a consumer holding one the provider does not know.
- **licence** — a model-access account the licence manager holds and **binds** to a consumer, the - **licence** — a model-access account the licence manager holds and **binds** to a consumer, the
coding agent on a node (ADR 0183). coding agent on a node (ADR 0183).
@@ -535,8 +526,8 @@ 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 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 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. 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, 0656. **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, 0641, 0644, 0656, 0659.
**Uses:** module, node, declaration and send (Placement), health (Health and repair), person. **Uses:** module, node, declaration and send (Core), health (Health and repair), person.
- **merge check** — what a pull request carries before it may merge, judging the merge of its head into a - **merge check** — what a pull request carries before it may merge, judging the merge of its head into a
named **trunk commit**, made in a clone of its own on a build node and never pushed (ADR 0323). One status, named **trunk commit**, made in a clone of its own on a build node and never pushed (ADR 0323). One status,
@@ -550,8 +541,18 @@ controller (the planner, the rollout) until release 6 of ADR 0429; from each rel
ADR 0656, from which each delivery part orders a source revision by its own rule: provisions, bus state, a served 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 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 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). Nothing stores the order. Not the **assignment graph** (Placement), computed from it. its step (ADR 0656). Nothing stores the order. Not the **assignment graph**, computed from it.
*Not:* ~~build graph~~ *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
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**, whose entries are modules, not
versions on nodes; not an **assignment**, one module put on one node.
- **mesh-wants** — the seat, held once for the mesh, that keeps what each node should run, one want
per node and module (`want.<node>.<module>`), and a person's upgrade policy, served as its verb `upgrade`
(ADR 0565 §7, ADR 0571 §8). Of this domain: the wants are what the delivery asks of the nodes, so its contract is in
`mesh-delivery-contracts` (ADR 0641 §2).
- **acting part** — the holder of a seat whose definition carries a rule: the step its holder acts in and the modules - **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 0656), 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 node-engine, the grants part, the assigner. Within a revision its new version acts first in its step, a wait with a
@@ -600,7 +601,9 @@ controller (the planner, the rollout) until release 6 of ADR 0429; from each rel
to merge there in the order of their Approve, and the check each waits for. It holds new checks off that to merge there in the order of their Approve, and the check each waits for. It holds new checks off that
repository until the merge is done (ADR 0548 §3). Written only while the check gates merges (the gate's repository until the merge is done (ADR 0548 §3). Written only while the check gates merges (the gate's
setting `check-gates-merge`); while it does not, no turn is written and an approved merge goes in at once setting `check-gates-merge`); while it does not, no turn is written and an approved merge goes in at once
(ADR 0551 §1). (ADR 0551 §1). Goes at research 085's milestone with the hold and the setting, once the record that ends them is
accepted (the operator, 2026-11-09; design 47); the word goes to a *Not:* line with the as-is update after that
delivery.
- **build seat** — a language's node seat, held on a node by that language's build module: `node-build-go`, - **build seat** — a language's node seat, held on a node by that language's build module: `node-build-go`,
`node-build-node` and `node-build-image` (ADR 0525 §2). Its accepted kinds are the **build streams**, and its `node-build-node` and `node-build-image` (ADR 0525 §2). Its accepted kinds are the **build streams**, and its
verbs `current`, `pause` and `resume` serve that node's pulls. It replaces the seat `node-build-agent`, retired verbs `current`, `pause` and `resume` serve that node's pulls. It replaces the seat `node-build-agent`, retired
@@ -809,7 +812,11 @@ controller (the planner, the rollout) until release 6 of ADR 0429; from each rel
nodes; what a lab run declares; and a recorded failure run again to prove a fix (ADR 0016, ADR 0237). nodes; what a lab run declares; and a recorded failure run again to prove a fix (ADR 0016, ADR 0237).
- **git seat** — the seat `git`, held once for the mesh, delivering the provision `git`: the - **git seat** — the seat `git`, held once for the mesh, delivering the provision `git`: the
repositories a build comes from ([26 — The seats](../03-DESIGN/01-to-be/26-the-seats.md) *The git seat*). A seat of repositories a build comes from ([26 — The seats](../03-DESIGN/01-to-be/26-the-seats.md) *The git seat*). A seat of
this domain. this domain, defined in `mesh-delivery-contracts`. From research 085's milestone its verbs are the one way a
delivery part and the gate reach the forge: reads (`pull`, `open-pulls`, `tags`, `trees`, `file`, `contains`,
`statuses`) for the parts that declare them, acts (`status`, `comment`, `view`, `note`, `merge-pull`) for the forge
bridge alone, as the holder's trusted value `callers` names, and the forge's events (`pull.*`, `forge.*`,
`repo.writable`) as the seat's (design 47, *The verbs*). Not the **forge** itself, the server, nor the forge module's own tools.
## Health and repair — what is wrong, and putting it right ## Health and repair — what is wrong, and putting it right
@@ -1254,18 +1261,18 @@ renaming one sense, the old sense moves to a *Not:* line and becomes mechanical.
| Word | Sense | Say | Domain | | Word | Sense | Say | Domain |
|---|---|---|---| |---|---|---|---|
| plan | what the controller would send one node, until release 6 | that node's **declaration** (verb `plan`) | Placement | | plan | what the controller would send one node, until release 6 | that node's **declaration** (verb `plan`) | Core |
| | what a delivery would do to the mesh, until release 6 | **delivery plan** | Delivery | | | what a delivery would do to the mesh, until release 6 | **delivery plan** | Delivery |
| | the sending of one batch of commits across nodes, until release 6 | **rollout** (verb `plans`) | Delivery | | | the sending of one batch of commits across nodes, until release 6 | **rollout** (verb `plans`) | Delivery |
| | a step a person starts, like the bus's | **planned step** | Core | | | a step a person starts, like the bus's | **planned step** | Core |
| composition | one module's resources for one node at one fingerprint, signed, from release 6 | **composition** | Placement | | composition | one module's resources for one node at one fingerprint, signed, from release 6 | **composition** | Core |
| | the function in `mesh-delivery-sdk` that composes them, which the node agents, the assigner and the grants part run (ADR 0635 §4) | **the composition of `mesh-delivery-sdk`** | Placement | | | the function in `mesh-delivery-sdk` that composes them, which the node agents, the assigner and the grants part run (ADR 0635 §4) | **the composition of `mesh-delivery-sdk`** | Core |
| | whether the machines a change touches still compose | **composition check** | Delivery | | | whether the machines a change touches still compose | **composition check** | Delivery |
| membership | the subjects a bus account is issued | **membership** | Provisioning | | membership | the subjects a bus account is issued | **membership** | Provisioning |
| binding | the names on the bus of a module's bus state, in its membership | **binding** of bus state | Data | | binding | the names on the bus of a module's bus state, in its membership | **binding** of bus state | Data |
| | a consumer's tie to the data a provider keeps for it | **sticky binding** | Data | | | a consumer's tie to the data a provider keeps for it | **sticky binding** | Data |
| | which host ports and addresses a placement gives a module | a placement's **bindings** | Placement | | | which host ports and addresses a placement gives a module | a placement's **bindings** | Core |
| | an account in a group of the machine | **account group** | Placement | | | an account in a group of the machine | **account group** | Core |
| domain | an area of the mesh that owns a set of concepts and the one word for each (ADR 0244), the sections of this page; the one sense "domain" keeps bare | **mesh domain** | The record | | domain | an area of the mesh that owns a set of concepts and the one word for each (ADR 0244), the sections of this page; the one sense "domain" keeps bare | **mesh domain** | The record |
| | one of the eight concerns a direction and a design are reviewed against (playbook 01); never written bare | **architectural domain** | The record | | | one of the eight concerns a direction and a design are reviewed against (playbook 01); never written bare | **architectural domain** | The record |
| configuration | the settings of a storage type, which a template fixes or a module gives | **configuration** of a storage type | Data | | configuration | the settings of a storage type, which a template fixes or a module gives | **configuration** of a storage type | Data |
@@ -1278,7 +1285,7 @@ renaming one sense, the old sense moves to a *Not:* line and becomes mechanical.
| | one choice of an ask to a person | an ask's **option** | Operator and conversation | | | one choice of an ask to a person | an ask's **option** | Operator and conversation |
| effect | what an operation does to a ledger's state | **ledger effect** | Data | | effect | what an operation does to a ledger's state | **ledger effect** | Data |
| | a tool's mark: reads, acts or dangerous | a tool's **effect** | Identity and access | | | a tool's mark: reads, acts or dangerous | a tool's **effect** | Identity and access |
| push | the controller giving nodes their declarations, until release 6 | **send** (verb `push`) | Placement | | push | the controller giving nodes their declarations, until release 6 | **send** (verb `push`) | Core |
| | a git push | **git push** | The record | | | a git push | **git push** | The record |
| | a phone notification | **push notification** | Operator and conversation | | | a phone notification | **push notification** | Operator and conversation |
| release | a person letting a held delivery go on | **release** | Delivery | | release | a person letting a held delivery go on | **release** | Delivery |
@@ -1288,7 +1295,7 @@ renaming one sense, the old sense moves to a *Not:* line and becomes mechanical.
| gate | the judgement on a delivery's first node | **first-node gate** | Delivery | | gate | the judgement on a delivery's first node | **first-node gate** | Delivery |
| | the check of what a change makes of the machines it touches, a pull request status until release 4 of ADR 0429 | ~~merge gate~~ (hq); the **composition check** | Delivery | | | the check of what a change makes of the machines it touches, a pull request status until release 4 of ADR 0429 | ~~merge gate~~ (hq); the **composition check** | Delivery |
| | the part that merges a group and moves the source revision | **gate part** (`mesh-delivery-gate`) | Delivery | | | the part that merges a group and moves the source revision | **gate part** (`mesh-delivery-gate`) | Delivery |
| | a failed step stopping its module's later steps (ADR 0136) | *a failed step holds its module* | Placement | | | a failed step stopping its module's later steps (ADR 0136) | *a failed step holds its module* | Core |
| tier | a level of the mesh | **layer** | Core | | tier | a level of the mesh | **layer** | Core |
| | a step of a rollout | **tier** | Delivery | | | a step of a rollout | **tier** | Delivery |
| | how much proof an ask needs | **assurance level** | Identity and access | | | how much proof an ask needs | **assurance level** | Identity and access |
@@ -1307,7 +1314,7 @@ renaming one sense, the old sense moves to a *Not:* line and becomes mechanical.
| | an entry in the build queue | **build request** (an ask on a build stream) | Delivery | | | an entry in the build queue | **build request** (an ask on a build stream) | Delivery |
| store | the one database server | **store** | Core | | store | the one database server | **store** | Core |
| | the OCI registry | **artifact store** | Delivery | | | the OCI registry | **artifact store** | Delivery |
| | a node's own copy of its last declaration | **last declaration** | Placement | | | a node's own copy of its last declaration | **last declaration** | Core |
| | the seat holding the mail accounts | **`mail-store`** | Mail | | | the seat holding the mail accounts | **`mail-store`** | Mail |
| record | a numbered decision | **decision record** | The record | | record | a numbered decision | **decision record** | The record |
| | the literal reader of this repository, searched first for a symptom | **the record** (the `records` module) | Operator and conversation | | | the literal reader of this repository, searched first for a symptom | **the record** (the `records` module) | Operator and conversation |
+19 -4
View File
@@ -15,8 +15,9 @@ code:
- mesh-catalog modules/gitea/module.json - mesh-catalog modules/gitea/module.json
- mesh-controller internal/inventory/migrations/0063-a-machines-names-are-one-seats.sql - mesh-controller internal/inventory/migrations/0063-a-machines-names-are-one-seats.sql
- mesh-controller internal/inventory/migrations/0064-the-resolver-file-is-the-uplinks.sql - mesh-controller internal/inventory/migrations/0064-the-resolver-file-is-the-uplinks.sql
updated: 2026-11-06 updated: 2026-11-09
decisions: decisions:
- "ADR 0641"
- "ADR 0636" - "ADR 0636"
- "ADR 0634" - "ADR 0634"
- "ADR 0635" - "ADR 0635"
@@ -255,14 +256,21 @@ defined whole or at the seat list's grain (ADR 0635 §2). In the milestone of AD
| contracts module | domain | seats | held by | | contracts module | domain | seats | held by |
|---|---|---|---| |---|---|---|---|
| `mesh-delivery-contracts` | Delivery | `mesh-catalog`, `mesh-delivery-checker`, `mesh-delivery`, `node-build-go`, `node-build-image`, `node-build-node`, `npm-package-registry`, `go-package-registry`, `container-image-registry`, `oci-artifact-registry` | the indexer, the checker, the gate part, the three build modules, the forge (two), `distribution` (two) | | `mesh-delivery-contracts` | Delivery | `mesh-catalog`, `mesh-delivery-checker`, `mesh-delivery`, `mesh-wants`, `git`, `node-build-go`, `node-build-image`, `node-build-node`, `npm-package-registry`, `go-package-registry`, `container-image-registry`, `oci-artifact-registry` | the indexer, the checker, the gate part, the assigner, the three build modules, the forge (three), `distribution` (two) |
| `mesh-placement-contracts` | Placement | `mesh-module-assigner`, `mesh-wants` | the assigner |
| `mesh-health-and-repair-contracts` | Health and repair | `mesh-conditions`, `mesh-self-check`, `mesh-healers`, `mesh-watchdogs`, `mesh-hand-acts` | the condition keeper, mesh-self-check, mesh-healers, the watchman, mesh-hand-acts | | `mesh-health-and-repair-contracts` | Health and repair | `mesh-conditions`, `mesh-self-check`, `mesh-healers`, `mesh-watchdogs`, `mesh-hand-acts` | the condition keeper, mesh-self-check, mesh-healers, the watchman, mesh-hand-acts |
| `mesh-provisioning-contracts` | Provisioning | `mesh-provisioner` | mesh-provisioner | | `mesh-provisioning-contracts` | Provisioning | `mesh-provisioner` | mesh-provisioner |
| `mesh-identity-and-access-contracts` | Identity and access | `mesh-vault`, `mesh-node-enroller` | the vault, the module `mesh-enrolment` | | `mesh-identity-and-access-contracts` | Identity and access | `mesh-vault`, `mesh-node-enroller` | the vault, the module `mesh-enrolment` |
| `mesh-connectivity-contracts` (mesh-networking repository, ADR 0636 §6) | Connectivity | `the-private-network` | `mesh-wireguard` | | `mesh-connectivity-contracts` (mesh-networking repository, ADR 0636 §6) | Connectivity | `the-private-network` | `mesh-wireguard` |
| `mesh-operator-and-conversation-contracts` | Operator and conversation | `operator-channel` | the router | | `mesh-operator-and-conversation-contracts` | Operator and conversation | `operator-channel` | the router |
| `mesh-contracts` | Core, and Config | `node-engine`, `mesh-broker`, `mesh-config` | the node-engine, the bus module, mesh-config | | `mesh-contracts` | Core, and Config | `node-engine`, `mesh-broker`, `mesh-config`, `mesh-module-assigner` | the node-engine, the bus module, mesh-config, the assigner |
ADR 0641 retired the Placement domain: module assignment is Core's, so `mesh-module-assigner` is defined in
`mesh-contracts`, and the wants are Delivery's, so `mesh-wants` is defined in `mesh-delivery-contracts`; the module
`mesh-placement-contracts` is not created (ADR 0641 §1, §2). From research 085's milestone (design 47) the seat
`mesh-grants` is defined whole in `mesh-identity-and-access-contracts` (ADR 0636 §5), and the seat `git` gains in
`mesh-delivery-contracts` the verbs by which every delivery part reaches the forge (*The git seat*, below). How it is
checked: the indexer refuses a definition of these seats from any other contracts module, naming both (ADR 0636 §5),
and its domain check refuses a definition naming the domain Placement (ADR 0641 §5).
**How it is checked**: each of these definitions' conformance fixtures names every event's subject, the seat's and **How it is checked**: each of these definitions' conformance fixtures names every event's subject, the seat's and
the holder's own, and a case of the holder's whole-module test takes a fixture from the running holder (an event the holder's own, and a case of the holder's whole-module test takes a fixture from the running holder (an event
@@ -681,6 +689,13 @@ difference: it receives a URL either way.
With the seat unheld, a build from the seat is refused and says why. External builds carry on. With the seat unheld, a build from the seat is refused and says why. External builds carry on.
**The seat's verbs, from research 085's milestone.** The delivery parts reach the forge through the seat `git`'s
verbs alone, never by the forge module's own tools: reads for the parts that declare them in their `invokes`, and
acts (a status, a comment, the delivery's view, a line on the commit's note, a merge) for the forge bridge alone, as
the holder's trusted value `callers` names; the forge's events (a pull request updated, merged or closed, the forge's
own webhooks, a repository writable again) are the seat's events. Design 47, *The verbs*, lists them with their
callers and how they are checked.
**Not yet designed:** a credential for cloning a private repository. The mesh's own repositories are **Not yet designed:** a credential for cloning a private repository. The mesh's own repositories are
public. The natural place for a clone credential is a `secret` from the vault, and that is a decision public. The natural place for a clone credential is a `secret` from the vault, and that is a decision
still to take. still to take.
@@ -1,11 +1,16 @@
--- ---
layer: to-be layer: to-be
status: in-progress 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] 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]
updated: 2026-11-06 updated: 2026-11-09
decisions: decisions:
- "ADR 0663"
- "ADR 0661"
- "ADR 0660"
- "ADR 0659"
- "ADR 0656" - "ADR 0656"
- "ADR 0644" - "ADR 0644"
- "ADR 0641"
- "ADR 0639" - "ADR 0639"
- "ADR 0638" - "ADR 0638"
- "ADR 0637" - "ADR 0637"
@@ -14,6 +19,8 @@ decisions:
- "ADR 0634" - "ADR 0634"
- "ADR 0633" - "ADR 0633"
- "ADR 0632" - "ADR 0632"
- "ADR 0625"
- "ADR 0621"
- "ADR 0619" - "ADR 0619"
- "ADR 0618" - "ADR 0618"
- "ADR 0615" - "ADR 0615"
@@ -42,6 +49,7 @@ decisions:
- "ADR 0549" - "ADR 0549"
- "ADR 0548" - "ADR 0548"
- "ADR 0547" - "ADR 0547"
- "ADR 0546"
- "ADR 0539" - "ADR 0539"
- "ADR 0536" - "ADR 0536"
- "ADR 0534" - "ADR 0534"
@@ -140,7 +148,7 @@ release 6 each node takes a merged change from its wants, the module's canary fi
milestones are features delivered one after another. The trunk is what runs; there is no "release branch"** milestones are features delivered one after another. The trunk is what runs; there is no "release branch"**
(ADR 0401, ADR 0418 §1, ADR 0421 §2). (ADR 0401, ADR 0418 §1, ADR 0421 §2).
**From the delivery of issues 1781 to 1783, a milestone is a record of the issue tracker and the unit that is released.** Its issues are linked to it, and pull requests and commits to the issues, by the issue tracker's link verb, never matched from a description; a review is recorded by a verb of the delivery seat; the mesh builds and checks each pull request as it comes in, and asks the operator once to release the milestone when every issue is ready; its pull requests are the delivery group, in whatever repositories and on whatever branches, and nothing ships outside a released milestone (ADR 0493 §1 to §11). Until that delivery the branch-name rules in this design stay what runs, kept by hand (ADR 0493 §12). A change across any repositories, the mesh-sdk included, is one group whose developer orders no release, from R4e's delivery for a group with a mesh-sdk member; until then an SDK change ships before its users (ADR 0482 §1, §7). **From the delivery of issues 1781 to 1783, a milestone is a record of the issue tracker and the unit that is released.** Its issues are linked to it, and pull requests and commits to the issues, by the issue tracker's link verb, never matched from a description; no part reads a pull request's description to hold, allow or withdraw an ask or a merge, and a review, if a verb records it, gates nothing (ADR 0659 §1, §2); the mesh builds and checks each pull request as it comes in, and asks the operator once to release the milestone when every issue is ready; its pull requests are the delivery group, in whatever repositories and on whatever branches, and nothing ships outside a released milestone (ADR 0493 §1 to §11). Until that delivery the branch-name rules in this design stay what runs, kept by hand (ADR 0493 §12). A change across any repositories, the mesh-sdk included, is one group whose developer orders no release, from R4e's delivery for a group with a mesh-sdk member; until then an SDK change ships before its users (ADR 0482 §1, §7).
**Every step starts on an event, and the state lives on the bus.** The forge's events, the parts' keys and the **Every step starts on an event, and the state lives on the bus.** The forge's events, the parts' keys and the
nodes' haves move a delivery; nothing collects merges, plans them or orders them in tiers. From release 6 each nodes' haves move a delivery; nothing collects merges, plans them or orders them in tiers. From release 6 each
@@ -178,8 +186,10 @@ no part calls another, there is no plan object and no orchestrator, and each key
source revision is derived from the keys: every **want** equals its module's **fingerprint**, and every source revision is derived from the keys: every **want** equals its module's **fingerprint**, and every
**have** equals its want and is healthy. **have** equals its want and is healthy.
- **The forge bridge** turns the forge's events into stream messages and is the only part that calls the - **The forge bridge** turns the forge's events into stream messages and is the only part that acts on the
forge. forge. From research 085's milestone every delivery part reaches the forge through the seat `git`'s verbs alone,
never by the forge module's own tools or events: the forge bridge for every act and read it makes, the checker,
the indexer and the gate for the reads they make and the events they hear (*The seat `git`*, under *The verbs*).
- **The indexer** computes each module's fingerprint at the merge preview and writes the candidates of each - **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 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 bridge carries nothing of placement (ADR 0567). From research 085's milestone it keeps the catalog graph per
@@ -202,12 +212,13 @@ source revision is derived from the keys: every **want** equals its module's **f
From research 085's milestone its judging rules are a **checking program** built from the change's heads (ADR 0656) 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 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). 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 - **The gate** merges a group's pull requests once the check and the operator's Approve agree on the same
heads, and then moves the mesh's source revision in one write. While the check gates merges, it holds an heads, reading no review line (ADR 0659 §1), and then moves the mesh's source revision in one write. While the
approved merge for another delivery's running check of the repositories the merge goes into, and keeps the check gates merges, it holds an approved merge for another delivery's running check of the repositories the merge
merge's **merge turn** there (ADR 0548 §2, §3, as ADR 0551 §1 bounds them; *Nothing merges into a repository goes into, and keeps the merge's **merge turn** there (ADR 0548 §2, §3, as ADR 0551 §1 bounds them); research 085's
under check*, below). From research 085's milestone it keeps one delivery record per milestone's delivery as a milestone removes the hold, the turns and the setting (*Nothing merges into a repository under check*, below). From
ledger instance (ADR 0656), its `merges` and `turns` carried into the records (*The delivery record*, below). that milestone it keeps one delivery record per milestone's delivery as a ledger instance (ADR 0656), its `merges`
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 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 - **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` fingerprint is not held, the node is the module's **canary** or the canary runs it healthy, at most `step`
@@ -238,7 +249,9 @@ source revision is derived from the keys: every **want** equals its module's **f
§3; ADR 0539 §16). Nothing composed crosses the bus, so nothing is signed; of other nodes it reads only their §3; ADR 0539 §16). Nothing composed crosses the bus, so nothing is signed; of other nodes it reads only their
public records and the manifests wanted on them. On the node holding `mesh-broker` it also writes the bus's user public records and the manifests wanted on them. On the node holding `mesh-broker` it also writes the bus's user
list, alone and with no want (*The bus's user list*, below). list, alone and with no want (*The bus's user list*, below).
- **The grants part** (module `mesh-grants`, holding the seat `mesh-grants`) composes who may say what on the bus - **The grants part** (module `mesh-grants`; from research 085's milestone it claims the seat `mesh-grants`, defined
whole in `mesh-identity-and-access-contracts`, its domain's contracts module, ADR 0636 §5, as an acting part of the
step `grant`, ADR 0656 §1) composes who may say what on the bus
with mesh-sdk's bus composer, whose parts that name a seat or a holder's state are the grants part's own package with mesh-sdk's bus composer, whose parts that name a seat or a holder's state are the grants part's own package
(ADR 0635 §4): each module's membership, the buckets, logs and streams a manifest declares, the (ADR 0635 §4): each module's membership, the buckets, logs and streams a manifest declares, the
bus's user list, and `grants.<module>.<fingerprint>`, written from L7's delivery once the list the bus loaded bus's user list, and `grants.<module>.<fingerprint>`, written from L7's delivery once the list the bus loaded
@@ -341,7 +354,9 @@ The target (ADR 0547):
- **The forge module** (`gitea`) publishes every forge event on the bus through the forge's system webhook - **The forge module** (`gitea`) publishes every forge event on the bus through the forge's system webhook
(issue 729): pull requests updated, synchronized, merged and closed, and commit statuses; no label or comment (issue 729): pull requests updated, synchronized, merged and closed, and commit statuses; no label or comment
moves a delivery, and the gate subscribes to none (ADR 0421 §11). It sets statuses, keeps the delivery's view moves a delivery, and the gate subscribes to none (ADR 0421 §11). It sets statuses, keeps the delivery's view
as one comment on the pull request, and appends to the commit's note under `refs/notes/mesh-plan`. as one comment on the pull request, and appends to the commit's note under `refs/notes/mesh-plan`; from research
085's milestone it does these, and answers every read a delivery part makes of the forge, as the verbs of the seat
`git` it claims (*The verbs*).
- **Each node's backup seat** (`node-backup`) backs up the data a module keeps on its node before the node agent - **Each node's backup seat** (`node-backup`) backs up the data a module keeps on its node before the node agent
applies a new fingerprint of it, and says on the bus when that backup ended (ADR 0404, ADR 0539 §16). applies a new fingerprint of it, and says on the bus when that backup ended (ADR 0404, ADR 0539 §16).
@@ -381,8 +396,8 @@ Its id is `<owner>/<repository>@<twelve characters of its commit>`. The gate hol
- the pull request (number, base, head branch, description), or none for a commit that reached the trunk - the pull request (number, base, head branch, description), or none for a commit that reached the trunk
without one; without one;
- its **state** and its **transitions** (the last hundred, each with when, the event, from, to and why); - its **state** and its **transitions** (the last hundred, each with when, the event, from, to and why);
- its **Approve**: the ask, the operator's answer with its warrant, and the review record the pull request was - its **Approve**: the ask and the operator's answer with its warrant (ADR 0421 §8); the ask carries no review
opened with (ADR 0421 §5, §8); record (ADR 0659 §1);
- once merged, **the commit it landed on the trunk as** and the source revision its merge moved. Every member of - once merged, **the commit it landed on the trunk as** and the source revision its merge moved. Every member of
a delivery group moves the same source revision (ADR 0429 §11). a delivery group moves the same source revision (ADR 0429 §11).
@@ -415,7 +430,7 @@ From research 085's milestone the gate, holder of the seat `mesh-delivery`, keep
milestone's delivery, a ledger instance (ADR 0595's template `ledger`, ADR 0597) it alone writes (ADR 0656). It milestone's delivery, a ledger instance (ADR 0595's template `ledger`, ADR 0597) it alone writes (ADR 0656). It
holds: holds:
- **the group's state**: the heads, the verdicts, the checks and the asks, which `merges` and `turns` hold today; - **the group's state**: the heads, the verdicts, the checks and the asks, which `merges` holds today;
- **the trace**: the milestone, its issues, its pull requests, their commits, and the graph revisions the delivery - **the trace**: the milestone, its issues, its pull requests, their commits, and the graph revisions the delivery
moved between; moved between;
- **what happened to each entry on each node**: for every entry of the graph difference, taken in, built, checked, - **what happened to each entry on each node**: for every entry of the graph difference, taken in, built, checked,
@@ -466,8 +481,9 @@ ADR 0656.
research 085, not a measurement) the ledger grows about 4 MiB a day, about 360 MiB at the default retention; its cap research 085, not a measurement) the ledger grows about 4 MiB a day, about 360 MiB at the default retention; its cap
is 768 MiB, twice that, so a busier month than estimated still fits. Removing a record at its retention removes its is 768 MiB, twice that, so a busier month than estimated still fits. Removing a record at its retention removes its
operations and its snapshot with it, so the ledger's size follows the retention, not the mesh's age. operations and its snapshot with it, so the ledger's size follows the retention, not the mesh's age.
- **The switch carries today's state in, once.** At the new gate's start, `merges`, `turns` and every group in - **The switch carries today's state in, once.** At the new gate's start, `merges` and every group in flight become
flight become records, and from then on the gate writes `merges` and `turns` no more. The switch is safe to run records, and from then on the gate writes `merges` no more; `turns`, which nothing writes while the check gates no
merge, is dropped with the hold (*Nothing merges into a repository under check*). The switch is safe to run
twice: a group in flight becomes a record keyed by its milestone and heads, and a switch that finds that record twice: a group in flight becomes a record keyed by its milestone and heads, and a switch that finds that record
already there leaves it as it is, so delivering milestone G again after a revert makes no second record and asks already there leaves it as it is, so delivering milestone G again after a revert makes no second record and asks
nothing again. A revert of the gate is the delivery system's restore of its kept data (*A module's kept data on the nothing again. A revert of the gate is the delivery system's restore of its kept data (*A module's kept data on the
@@ -475,14 +491,16 @@ ADR 0656.
- **The forge bridge asks the seat for a group.** It reads a group's members from the seat `mesh-delivery`'s verb - **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 `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 0656, which changes ADR 0633 §4 and §5; ADR 0596). Its account holds no grant to read `merges`. end again (ADR 0656, which changes ADR 0633 §4 and §5; ADR 0596). Its account holds no grant to read `merges`.
- **What the gate owes the forge is said, not watched, and a merge made at the forge has a record too** (*What the
gate owes the forge*, below).
- **Its tools**, against the four lines a module's tools answer: - **Its tools**, against the four lines a module's tools answer:
| Line | The gate | | Line | The gate |
|---|---| |---|---|
| read everything it holds | `gate_record` (one record whole: the group's state, the trace, each entry's outcome per node, the nodes away), `gate_records` (every record with its fill against the value limit, and the ledger's fill against its cap), `gate_consumer` (its durable consumer: the last event applied per family, the events waiting, the age of the oldest) | | read everything it holds | `gate_record` (one record whole: the group's state, the trace, each entry's outcome per node, the nodes away), `gate_records` (every record with its fill against the value limit, and the ledger's fill against its cap), `gate_consumer` (its durable consumer: the last event applied per family, the events waiting, the age of the oldest) |
| do by hand what it does itself | `gate_record_repair` (for one record, asks each owner for the outcome of each entry missing one through that owner's read verb: the indexer's `take-in` read, the builder's build read, the checker seat's check read, the seat `mesh-wants`'s `entry`, and the node-engine seat's have read of that node; applies the answers as the consumer would) | | do by hand what it does itself | `gate_record_repair` (for one record, asks each owner for the outcome of each entry missing one through that owner's read verb: the indexer's `take-in` read, the builder's build read, the checker seat's check read, the seat `mesh-wants`'s `entry`, and the node-engine seat's verb `composition` of that node; applies the answers as the consumer would) |
| 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`) | | 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 | | one seat, many tools | the seat `mesh-delivery`'s verbs, with `groups` answering a group's members and the acts said for it |
- **How it is checked.** In the gate's whole-module test: the gate stopped and restarted in the middle of a delivery - **How it is checked.** In the gate's whole-module test: the gate stopped and restarted in the middle of a delivery
leaves the record complete with no outcome counted twice; the events `pinned`, `freed`, `heads-replaced` and leaves the record complete with no outcome counted twice; the events `pinned`, `freed`, `heads-replaced` and
@@ -499,6 +517,73 @@ ADR 0656.
outcome taken on waking; a record of 30 modules on four nodes stays under 256 KiB; a group checked again at old outcome taken on waking; a record of 30 modules on four nodes stays under 256 KiB; a group checked again at old
heads after a main move is not asked of the operator again (issue 1972). heads after a main move is not asked of the operator again (issue 1972).
### What the gate owes the forge
*ADR 0596 §1, §2, ADR 0656 §7, ADR 0437 §8, ADR 0441 §5, ADR 0633 §1, §4, ADR 0363 §2, ADR 0564 §2; from research 085's
milestone, this design's choices under ADR 0596 and ADR 0656 §7.*
The forge bridge today performs what the gate's states `merges` and `owed` ask (a merge, a status, the delivery's
view, a comment, a line on the commit's note) by watching those keys (ADR 0437 §8), and the forge module writes the
checker's `mesh/check` from a watch of the checker's state `owed`: reads of another module's bus state that ADR 0596
§2 ends when their owner moves. From research 085's milestone:
- **Every act is an event, under one id.** The gate says each act it owes as the event `owed` of the seat
`mesh-delivery`, on `mesh.seat.mesh-delivery.event.owed.<repository>.<number>`, carrying the act, the pull request,
the head and an id; the checker says its status the same way, as the event `owed` of the seat
`mesh-delivery-checker` on `mesh.seat.mesh-delivery-checker.event.owed.<repository>.<number>`. Only the owner's
account publishes each (ADR 0363 §2). The subject per repository and pull request lets the bridge, a person and a
test read one pull request's acts alone. The seat events are kept on each owner's stream `owed`, 7 days and at most
64 MiB (an estimated 20 deliveries a day, with about 15 acts of about 1 KiB each, is about 2 MiB over 7 days).
- **Every act is safe to repeat at the forge.** A status and the delivery's view replace what stands; a merge of a
pull request already merged at that head is answered performed; a comment and a line of the note carry the act's
id, and the seat `git`'s verb skips an id the pull request or note already holds. This is chosen over recording the
id before the act: an id recorded and then not performed (the bridge stopped between the two) would be lost, while
an act repeated changes nothing. The bridge's own state `performed`, a key-value state in the new form (ADR 0595),
form 1, one key per id with the outcome and when, kept 7 days as the stream is and capped at 16 MiB, is therefore a
saving and a read, never what keeps an act from happening twice.
- **Every outcome is said, and the gate records it.** The bridge says each act's outcome on its own stream `forge` as
the event `owed.ended`, with the id and one of `performed`, `refused` (the forge's own words), `could not be
performed` (the forge did not answer within the call's bound, with the error) or `undecodable` (an act it cannot
read, with why): an act it cannot decode is said, never only logged. The gate hears the stream `forge` through its
durable consumer, writes the outcome into the delivery record, and says an act's id is answered only once an
outcome is recorded. The checker does the same for its own acts: it hears `owed.ended` for its own ids, records each
outcome in its own state (it watches only its own state), says again at its start, under the same id, every act of
its own still unanswered, and lists one unanswered past 15 minutes in its own stalled read.
- **What is unanswered is said again, and stalls by a bound.** At its start the gate says again, under the same id,
every act its records hold unanswered. An act unanswered 15 minutes after it was said is listed by `stalled`, which
the condition keeper raises as the stalled line (ADR 0421 §7, ADR 0564 §2): fifteen minutes is many times a
forge call's time, and short beside the check's hour.
- **A group's merges follow one another.** The gate says a group's next `merge-pull` only once the previous member's
merged message is heard (ADR 0441 §5), so a member the forge refuses holds the rest, and none is merged ahead.
- **The bridge catches up from the seat.** At its start the bridge resumes its durable consumer and also reads
`groups`, which answers, per group, the acts the gate said with their ids and their recorded outcomes; an id said
and not answered is performed. Its tools: `bridge_owed` (the ids it performed with their outcomes, and its
consumer's backlog: the last event applied, the events waiting, the age of the oldest), `bridge_owed_again`
(perform one id again now) and `bridge_owed_drop` (drop one id with its reason, written in the hand-act log of the
seat `mesh-hand-acts`, and said as `owed.ended` with the outcome `dropped`).
- **The switch carries what is owed.** At the new gate's start (*The switch carries today's state in, once*) every key
of `owed` and `merges` the old bridge has not performed becomes an act of its record, with an id made of the key and
its revision; the new bridge counts as performed every id whose key and revision the old bridge's own bookkeeping
names, so nothing is done twice and nothing dropped. A merge handed to the forge during the switch is such an act:
its merged message finds the record holding it, so it opens no `forge-made` record.
- **A merge made at the forge has a record too.** A merge the forge reports for which no record holds a `merge-pull`
of that pull request at that head (a person merged it in the forge's own page, as on 2026-11-07 and 11-09) is taken
in like any other merge (*Taken in by the indexer it names*), and the gate opens a delivery record for it, marked
`forge-made`, with no Approve, so its trace and its outcomes on the nodes are kept like every delivery's and no
later merge waits behind a merge the gate never heard. The gate says it as the delivery's `transition` with the why
`forge-made`, which the teller passes on to the operator (the operator, 1921's note of 2026-11-07: "a merge made in
the forge is taken in like any other").
- **How it is checked.** In the forge bridge's whole-module test: an `owed` said while the bridge is stopped is
performed once after its restart; the bridge stopped between an act and its `owed.ended` performs it again on its
restart and the forge holds it once (the comment and the note by their id); an act said twice is performed once; an
undecodable act is said `undecodable`; `bridge_owed`, `bridge_owed_again` and `bridge_owed_drop` answer, the drop
writing the hand-act log; its account cannot read the gate's or the checker's state. In the gate's: an act left
unanswered is said again at the gate's start under its id and listed by `stalled` after 15 minutes; a group's second
`merge-pull` is said only after the first member's merged message; the switch with a merge handed and not yet
merged makes no `forge-made` record; a merged message with no record's merge opens a `forge-made` record, said as
`transition` with why `forge-made`, and a later merge in the same repository is taken in behind it. Acceptance
tests 53 and 51.
## The state table ## The state table
*ADR 0539 §17.* *ADR 0539 §17.*
@@ -512,7 +597,7 @@ state has a **bound**: how long it may be held before `stalled` lists it, for a
| proposed | a head was announced and is being checked | 1 hour from when its check is asked; none while its verdict is out of date and no check is asked | | proposed | a head was announced and is being checked | 1 hour from when its check is asked; none while its verdict is out of date and no check is asked |
| ready | it passed; its Approve is asked (a group member's once the group is ready), and it waits for it and the merge | none | | ready | it passed; its Approve is asked (a group member's once the group is ready), and it waits for it and the merge | none |
| rejected | it failed its check | none | | rejected | it failed its check | none |
| held | it waits for a person, a carry or a check: an approved merge whose verdict is being carried to the trunk's head, a conflict, a member the forge refused, and, while the check gates merges, an approved merge waiting on its merge turn for another delivery's running check (ADR 0548 §2, §8, ADR 0551 §1) | 1 day; a merge turn 30 minutes | | held | it waits for a person, a carry or a check: an approved merge whose verdict is being carried to the trunk's head, a conflict, a member the forge refused, and, until research 085's milestone and while the check gates merges, an approved merge waiting on its merge turn for another delivery's running check (ADR 0548 §2, §8, ADR 0551 §1) | 1 day; a merge turn 30 minutes, until that milestone |
| merged | merged on its trunk; its source revision moved | final | | merged | merged on its trunk; its source revision moved | final |
| closed | closed without a merge | final | | closed | closed without a merge | final |
@@ -535,7 +620,7 @@ module's progress on each node is its want against its have, shown by the view (
## Two graphs, one source of truth ## Two graphs, one source of truth
*ADR 0656, which supersedes ADR 0645 to ADR 0648; 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, ADR 0596, ADR 0603 §2, §6, §7, ADR 0615 §1 to §6, ADR 0621 §1, §2, ADR 0614 §3, ADR 0567 §5, ADR 0571 §8, ADR 0614 §4, ADR 0618 §2, ADR 0619 §1 to §3, ADR 0636 §1,
§3, §4, §7, ADR 0639 §7, §8, ADR 0564 §2, ADR 0363 §2.* §3, §4, §7, ADR 0639 §7, §8, ADR 0564 §2, ADR 0363 §2.*
From research 085's milestone. One graph answered two questions, which modules exist and which version runs where, From research 085's milestone. One graph answered two questions, which modules exist and which version runs where,
@@ -625,7 +710,7 @@ Findings 11). How each is kept, read and retained is this design's choice under
| Part | Kept data before G (form 0) | After G | Restored at a revert | | Part | Kept data before G (form 0) | After G | Restored at a revert |
|---|---|---|---| |---|---|---|---|
| the indexer | the state `modules` (ADR 0603 §2's one key per module) and its durable consumer's position on the forge bridge's stream `forge` | catalog graph revisions as objects, form 1; `modules` no longer declared | yes: `modules` as it stood at G's delivery, and the consumer's position | | the indexer | the state `modules` (ADR 0603 §2's one key per module) and its durable consumer's position on the forge bridge's stream `forge`; the states `holds`, `engine-reads` and `hold-bounds` of its mesh-wide hold | catalog graph revisions as objects, form 1; `modules` no longer declared, nor its tool `indexer_read_modules` or its view; the mesh-wide hold, its three states and its tools `indexer_holds` and `indexer_engine_reads` gone, the wait per node being the assigner's (*Composing waits per node, by the assigner*); every reader of it reading the catalog half (*Every other reader of which modules exist*, under *The revision view*, below) | yes: `modules` and the hold's three states as they stood at G's delivery, and the consumer's position |
| the gate | the states `merges` and `turns` | the delivery record's ledger, form 1; `merges` and `turns` no longer declared | yes: `merges` and `turns` as they stood at G's delivery | | the gate | the states `merges` and `turns` | the delivery record's ledger, form 1; `merges` and `turns` no longer declared | yes: `merges` and `turns` as they stood at G's delivery |
| the assigner | the wants, written from the indexer's `modules` | the same wants, form 0, written from the assignment graph; the assignment graph revisions as objects, form 1 | no | | the assigner | the wants, written from the indexer's `modules` | the same wants, form 0, written from the assignment graph; the assignment graph revisions as objects, form 1 | no |
@@ -634,7 +719,11 @@ Findings 11). How each is kept, read and retained is this design's choice under
fingerprints until the reverted assigner computed them again; leaving them, the nodes keep what runs and the reverted fingerprints until the reverted assigner computed them again; leaving them, the nodes keep what runs and the reverted
assigner writes them again from the caught-up indexer. The assigner's placement and every other kept data of the assigner writes them again from the caught-up indexer. The assigner's placement and every other kept data of the
three keep form 0 and are never restored, so nothing decided since (a placement, a verdict, the source revision) is three keep form 0 and are never restored, so nothing decided since (a placement, a verdict, the source revision) is
set back. set back. The restored `modules` is as it stood at G's delivery, so a module added since is missing from it until
the reverted indexer takes in its next source revision, and a reverted reader that learns which modules exist from
`modules` does not name it until then. What a reader granted since stays: the forge module's write grants on a
repository it learnt of from the catalog half are kept, since it grants writes and takes none away, so a revert
costs no repository its account's writes.
### A change's graph difference is its delivery ### A change's graph difference is its delivery
@@ -686,11 +775,72 @@ Findings 11). How each is kept, read and retained is this design's choice under
candidate's view is read only by the parts that judge a candidate, inside the check its manifest validator and 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 composer, and the indexer's candidate pass (ADR 0656, which changes ADR 0636 §4 in that the candidate pass joins
them). them).
- **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
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`
(a gap in the revisions it heard) asks `revision` once more, said in its log (ADR 0615 §5). The design's choice
under ADR 0656 §6: one form of the fact, never `modules` kept beside the catalog graph for these readers, which
would be a second source of the same fact. How it is checked: test 61.
- **The forge module's tools come from mesh-sdk's TypeScript side.** mesh-sdk's TypeScript side has no view
today; milestone G adds there a view follower with its read and ask-again tools, beside the proved caller, a
verb's `callers` and a seat's publish, so the forge module, reading through the seat's TypeScript contract,
answers `<module>_first_views` and `<module>_first_view_again` as the Go parts do from `go/views`, with no
follower or tool of its own. Its cost: a release of the TypeScript side rebuilds every TypeScript module, which
the delivery carries like any change of a package its users build in.
- **The order is the module graph's, and the foundation's own rule where the graph has no edge.** Six of the
readers declare the verb in their `invokes`, so the served-verb edge delivers none of them to any node before a
build serving `revision` runs (ADR 0615 §2, ADR 0614). Two are left out of the graph's order (ADR 0614 §3, ADR
0615 §2): the tool runner, a foundation part, and the forge module, on a cycle with the indexer, which reads the
forge through the seat `git`. For both the order is carried by ADR 0615 §4 and §6: the owner answers at once from
what it holds, and a reader started before it waits, saying so. The tool runner asks `revision` of the indexer's
own runtime, never through itself, the tool's `callers` list naming it (ADR 0663, which changes ADR 0621 §1, §2 and
ADR 0615 §3; proposed, to be accepted before G's push); the forge
module answers the indexer's reads through the seat `git` before it has a first view of its own, so neither waits
on the other.
- **With no view, a reader waits; it never reads "no modules".** All eight follow *A part with no view says it
waits* (below): an empty or missing view is never taken as a mesh with no modules, each says `view-waits` after
five minutes, and once it has a first view it keeps working on what it heard while the indexer is down (ADR 0615
§6).
- **A candidate's revision moves no reader.** `catalog-revision` says whether it carries a trunk revision or a
candidate's, and a candidate's changes nothing in any of these readers; the forge module grants no write before
its first view and none from a candidate's revision (ADR 0656 §6: a running part acts only on a trunk revision's
view).
- **The trunk's heads come from the catalog half.** The checker takes the trunk heads a check merges onto from the
catalog half, which carries the heads, and never reads the gate's state `source` (ADR 0596 §2); with the hold and
the turns removed it reads nothing of the gate at all (*Nothing merges into a repository under check*).
- **The indexer reads every definition before it judges.** At its start the indexer reads the seat definitions of
every contracts module's trunk through the forge (the seat `git`'s verbs) before it judges a manifest or answers
`seat-definitions`, and only then follows the forge bridge's stream; a definition merged while it was down is
therefore never judged against a list that lacks it. The design's choice under ADR 0636 §1 and §4, as the operator
asked it (1921's note of 2026-11-07: "the indexer reads its seat definitions at start"). How it is checked: in the
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.
- **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
`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,
and each part's durable consumer starts from the last message per subject, never from now: a consumer made after a
node's last `running`, and two parts' consumers made at different times, hold the same builds. The event carries the module, the fingerprint and the
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
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.
- **A part with no view says it waits.** It names the revision it has no view for, acts on nothing new, and keeps - **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 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 0656, which changes ADR 0636 §1); the node-engine waits wait too, and wait for the view, not only the seat list (ADR 0656, which changes ADR 0636 §1); the node-engine waits
for the catalog half as ADR 0636 §1 already has it wait for the seat list. Each answers `waits` in its runtime tool for the catalog half as ADR 0636 §1 already has it wait for the seat list. Each answers in its runtime's first-view
(below) with the revision it waits for and since when, and after five minutes without a view writes the finding tool (below) the revision it holds, the one it waits for and since when, and after five minutes without a view writes the finding
`view-waits` naming itself and the revision, as a reader of the seat list does, which the condition keeper raises `view-waits` naming itself and the revision, as a reader of the seat list does, which the condition keeper raises
(ADR 0564 §2); it clears when the view arrives. Five minutes is the bound the seat list's readers already keep, so an (ADR 0564 §2); it clears when the view arrives. Five minutes is the bound the seat list's readers already keep, so an
indexer or assigner down for a restart raises nothing. A part restarted while the indexer or the assigner is down indexer or assigner down for a restart raises nothing. A part restarted while the indexer or the assigner is down
@@ -718,7 +868,18 @@ ADR 0656 leaves how each part is built to this design, under issue 1921; these f
(ADR 0656, Consequences); that is the same rebuild the fingerprint handover makes, so the milestone rebuilds every (ADR 0656, Consequences); that is the same rebuild the fingerprint handover makes, so the milestone rebuilds every
module once in all, and no other module's code changes. A definition carrying `acts` reaches only readers built with module once in all, and no other module's code changes. A definition carrying `acts` reaches only readers built with
that runtime: the seat definitions that gain it are members of milestone G's group, and every reader is rebuilt in that runtime: the seat definitions that gain it are members of milestone G's group, and every reader is rebuilt in
the same delivery. the same delivery. The bootstrapped definitions every reader carries from its start (ADR 0636 §2), four of which
gain `acts` (`mesh-catalog`, `mesh-delivery-checker`, `node-engine`, `node-backup`), are made again from the new
definitions in the same change, and mesh-sdk's existing test that each bootstrapped copy equals its definition holds
them to it.
- **One wiring of the seat list's reader.** The reader of the seat list and its two tools of ADR 0636 §7 are wired once,
by mesh-sdk's runtime (`go/seatlist`), for every part that reads the list; no part wires its own. Four delivery
parts (the assigner, the checker, the indexer and the grants part) each carry a hand-wired copy today, each with its
own pair of tools, and each copy would have to learn `acts` apart. The design's choice under ADR 0636 §7, which puts
the tools in the runtime bundle: one wiring learns `acts` once, and every part's two tools are the same, named by
their module, with the same callers (any person and the healers to read, the operator and the healers to read
again), the node-engine's among them. How it is checked: mesh-sdk's seat-list test registers both tools for a
fixture part; a search of the delivery parts' code finds no wiring of its own.
- **The fingerprint handover.** The node-engine starts each process, a service or a container alike, with the - **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 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 0656). 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
@@ -794,7 +955,19 @@ ADR 0656 decides the direction and leaves every choice made in working it out to
| 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) | | 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 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) | | 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, 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, and a part waiting for the view is raised on the bound the seat list's readers keep | | 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 |
| 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 |
| 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 |
| 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) |
| 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) |
| 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 |
| 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 |
| 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 |
| A check that failed because a part of the mesh was not heard says `could not run`, naming the part, releases its claim, and is asked again once per heads and part on that part's `running` event, raising `check-could-not-run` after 60 minutes | the operator sees a mesh fault apart from a failing change, and the check is asked again on the one event that can change its outcome, never on a timer (issue 1373) |
| A module held for its claim raises `module-held` until it is composed | a module left out in silence would look delivered (the mesh's rule that failure is loud) |
| The indexer waits for the seat `git` at most 2 minutes at its start, then judges from its kept definitions and raises `view-waits` after five | longer than a forge's restart, and no start held behind a forge down for good |
| The forge before the forge bridge before the gate, reverted the other way | the verbs are served before they are called, and `owed` is said only to a bridge that hears it |
| The store seat's holder's own new build kept on its build node and fetched by `kept-artifact` when its seat is broken | its own build needs the store it replaces; a step of the delivery replaces the hand bootstrap |
| Every drop and release tool writes the hand-act log | a hand act that changes what the mesh runs or keeps is recorded with who did it and why, as every hand act is (seat `mesh-hand-acts`) | | Every drop and release tool writes the hand-act log | a hand act that changes what the mesh runs or keeps is recorded with who did it and why, as every hand act is (seat `mesh-hand-acts`) |
Each choice is checked by the tests its section names; the review by architectural domain judges them. Each choice is checked by the tests its section names; the review by architectural domain judges them.
@@ -813,14 +986,14 @@ say another runs a build (ADR 0363 §2); the gate's events are granted to the ga
| Step | Event | Owner: the seat, then the module | Subject | Declared in | | Step | Event | Owner: the seat, then the module | Subject | Declared in |
|---|---|---|---|---| |---|---|---|---|---|
| a catalog graph revision kept | `catalog-revision` | `mesh-catalog`, the indexer | `mesh.seat.mesh-catalog.event.catalog-revision` | the seat's definition in `mesh-delivery-contracts` | | a catalog graph revision kept, saying whether it is a trunk revision or a candidate's | `catalog-revision` | `mesh-catalog`, the indexer | `mesh.seat.mesh-catalog.event.catalog-revision` | the seat's definition in `mesh-delivery-contracts` |
| an assignment graph revision kept | `assignment-revision` | `mesh-wants`, the assigner | `mesh.seat.mesh-wants.event.assignment-revision` | the seat's definition in `mesh-placement-contracts` | | an assignment graph revision kept | `assignment-revision` | `mesh-wants`, the assigner | `mesh.seat.mesh-wants.event.assignment-revision` | the seat's definition in `mesh-delivery-contracts` (ADR 0641 §2) |
| a difference worked out | `difference` | `mesh-wants`, the assigner | `mesh.seat.mesh-wants.event.difference` | the same | | a difference worked out | `difference` | `mesh-wants`, the assigner | `mesh.seat.mesh-wants.event.difference` | the same |
| an entry taken in | `take-in.taken`, which gains the entries | the indexer's own | `mesh.stream.mesh-delivery-indexer.event.take-in.taken` | the indexer's manifest | | an entry taken in | `take-in.taken`, which gains the entries | the indexer's own | `mesh.stream.mesh-delivery-indexer.event.take-in.taken` | the indexer's manifest |
| an entry built | `build.ended` | the builder's own | `mesh.stream.mesh-delivery-builder.event.build.ended` | the builder's manifest | | an entry built | `build.ended` | the builder's own | `mesh.stream.mesh-delivery-builder.event.build.ended` | the builder's manifest |
| an entry checked | `checked` | `mesh-delivery-checker`, the checker | `mesh.seat.mesh-delivery-checker.event.checked` | the seat's definition in `mesh-delivery-contracts` | | an entry checked | `checked` | `mesh-delivery-checker`, the checker | `mesh.seat.mesh-delivery-checker.event.checked` | the seat's definition in `mesh-delivery-contracts` |
| an entry wanted | `wanted` | `mesh-wants`, the assigner | `mesh.seat.mesh-wants.event.wanted` | the seat's definition in `mesh-placement-contracts` | | an entry wanted | `wanted` | `mesh-wants`, the assigner | `mesh.seat.mesh-wants.event.wanted` | the seat's definition in `mesh-delivery-contracts` (ADR 0641 §2) |
| an entry composed, and running healthy | `composed`, `running` | `node-engine`, the node-engine on each node | `mesh.seat.node-engine.event.composed.<node>`, `.running.<node>` | the seat's definition in `mesh-contracts` | | an entry composed, and running healthy | `composed`, `running` | `node-engine`, the node-engine on each node | `mesh.seat.node-engine.event.composed.<node>`, `.running.<node>.<module>`, the latter on a stream kept last per subject with no age limit | the seat's definition in `mesh-contracts` |
| a node's capabilities changed | `capabilities-changed` | `node-engine`, the node-engine on that node | `mesh.seat.node-engine.event.capabilities-changed.<node>` | the same | | a node's capabilities changed | `capabilities-changed` | `node-engine`, the node-engine on that node | `mesh.seat.node-engine.event.capabilities-changed.<node>` | the same |
| a wait held, and ended | `wait-held` (step, acting part, its version, the entry, since when, its bound), `wait-ended` (the same, and how: ran, released) | each holder: `mesh-wants` for the assigner (placing, wanting and composing), `mesh-grants` for the grants part, the builder's own stream | `mesh.seat.<seat>.event.wait-held`, `.wait-ended`; `mesh.stream.mesh-delivery-builder.event.wait-held`, `.wait-ended` | each seat's definition; the builder's manifest | | a wait held, and ended | `wait-held` (step, acting part, its version, the entry, since when, its bound), `wait-ended` (the same, and how: ran, released) | each holder: `mesh-wants` for the assigner (placing, wanting and composing), `mesh-grants` for the grants part, the builder's own stream | `mesh.seat.<seat>.event.wait-held`, `.wait-ended`; `mesh.stream.mesh-delivery-builder.event.wait-held`, `.wait-ended` | each seat's definition; the builder's manifest |
| a store filling, full, and back below its cap | `filling`, `full`, `room` | `mesh-catalog`, `mesh-wants`, `mesh-delivery` | `mesh.seat.<seat>.event.filling`, `.full`, `.room` | each seat's definition | | a store filling, full, and back below its cap | `filling`, `full`, `room` | `mesh-catalog`, `mesh-wants`, `mesh-delivery` | `mesh.seat.<seat>.event.filling`, `.full`, `.room` | each seat's definition |
@@ -840,15 +1013,20 @@ on another node's subject is refused by the bus.
| Line | The assigner | The indexer | | Line | The assigner | The indexer |
|---|---|---| |---|---|---|
| read everything it holds | `assigner_revision` (one assignment graph revision whole, with the revisions of its inputs), `assigner_revisions` (every kept revision with what pins it, and the store's fill against its cap), `assigner_entry` (one entry, with the seat rule that gave each edge), `assigner_difference` (a change's difference), `assigner_waits` (*Order without a person*), `assigner_candidate_graphs` (every candidate's graphs: its heads, its revisions, since when), `assigner_consumer` (its consumer of the gate's events: the last applied, the waiting) | `indexer_catalog_revision` (one catalog graph revision), `indexer_catalog_revisions` (every kept revision with what pins it, and the store's fill against its cap), `indexer_candidate_graphs` (every candidate's catalog half), `indexer_consumer` (the same as the assigner's) | | read everything it holds | `assigner_revision` (one assignment graph revision whole, with the revisions of its inputs), `assigner_revisions` (every kept revision with what pins it, and the store's fill against its cap), `assigner_entry` (one entry, with the seat rule that gave each edge), `assigner_difference` (a change's difference), `assigner_waits` (*Order without a person*), `assigner_candidate_graphs` (every candidate's graphs: its heads, its revisions, since when), `assigner_consumer` (its consumer of the gate's events: the last applied, the waiting), `assigner_puts` (each put with its step, since when, held or not, the `running` that ended it, and for a put without hold whether it is past its 30-minute bound; a put older than the trunk's newest build of its module said so) | `indexer_catalog_revision` (one catalog graph revision), `indexer_catalog_revisions` (every kept revision with what pins it, and the store's fill against its cap), `indexer_candidate_graphs` (every candidate's catalog half), `indexer_consumer` (the same as the assigner's) |
| do by hand what it does itself | `assigner_recompute` (compute a revision again from its named inputs and compare it with the one kept) | `indexer_recompute` (compute a catalog graph revision again from its source revision and compare it with the one kept) | | do by hand what it does itself | `assigner_recompute` (compute a revision again from its named inputs and compare it with the one kept) | `indexer_recompute` (compute a catalog graph revision again from its source revision and compare it with the one kept) |
| recover without help | `assigner_drop_candidate_graph` (drop a candidate's graphs whose gate event never came), `assigner_release` (*Order without a person*) | `indexer_drop_candidate_graph` (the same for its half) | | recover without help | `assigner_drop_candidate_graph` (drop a candidate's graphs whose gate event never came), `assigner_release` (*Order without a person*) | `indexer_drop_candidate_graph` (the same for its half) |
| one seat, many tools | `mesh-wants`: `revision`, `entry`, `difference` | `mesh-catalog`: `revision`, beside `seat-definitions` | | one seat, many tools | `mesh-wants`: `revision`, `entry`, `difference` | `mesh-catalog`: `revision`, beside `seat-definitions` |
Every drop and release tool writes its act, who did it and why, in the hand-act log of the seat `mesh-hand-acts`. Every drop and release tool writes its act, who did it and why, in the hand-act log of the seat `mesh-hand-acts`.
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 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: `waits`, which reads which view revision a part holds and what it list again, the view is read and steered by the two tools mesh-sdk's `go/views` already serves every part that takes a
waits for and since when, and one, granted as ADR 0636 §7's second is, that makes it read the view again now. A tool first view: `<module>_first_views` gains which view revision the part holds, what it waits for and since when, beside
what it heard and how far it is behind, and `<module>_first_view_again`, granted as ADR 0636 §7's second is, makes it
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 of the node-engine, `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 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. steered by a tool.
@@ -874,9 +1052,14 @@ places; the builder and the grants part read their entries only through the seat
the node-engine reads its want and the catalog half and never the assignment half. Whole (node-engine): a part started the node-engine reads its want and the catalog half and never the assignment half. Whole (node-engine): a part started
while its node's want differs from what runs reports the build it was started with. Live: a search of the readers' while its node's want differs from what runs reports the build it was started with. Live: a search of the readers'
code finds none of the reads the revision view replaces, each by name: the indexer's read of the checker's previews, code finds none of the reads the revision view replaces, each by name: the indexer's read of the checker's previews,
the checker's watch of the indexer's `candidates.<try id>`, the forge bridge's read of the gate's `merges`, the the checker's watch of the indexer's `candidates.<try id>`, the forge bridge's read of the gate's `merges` and `owed`,
checker's validator request with no seat definitions, and a seat list compiled into the node-engine, the checker, the the checker's read of the gate's `source` and `turns`, the forge module's watch of the checker's `owed` (its `mesh/check`
builder or the grants part; an old node-engine that wakes takes its new build in a form it reads. status, now the checker's `owed` event performed by the forge bridge) and its read of the gate's `source`, the grants
part's read of the assigner's state `wants`, any module's read of the indexer's `modules` (its tool
`indexer_read_modules` in an `invokes`, its view in a `consumes`), the
checker's validator request with no seat definitions, a seat list compiled into the node-engine, the checker, the
builder or the grants part, a seat list's reader wired by a part itself, and a call of the forge module's own tools by
a delivery part or the gate; an old node-engine that wakes takes its new build in a form it reads.
## Order without a person ## Order without a person
@@ -899,7 +1082,8 @@ per module and node from the keys:
- **An SDK change ships with its users.** mesh-sdk is a library built into the modules that use it, so no - **An SDK change ships with its users.** mesh-sdk is a library built into the modules that use it, so no
module waits for it to be sent anywhere (ADR 0482 §1). module waits for it to be sent anywhere (ADR 0482 §1).
- **No `after:` line is read.** The gate reads no `after:` line, no refusal asks for one, and a description - **No `after:` line is read.** The gate reads no `after:` line, no refusal asks for one, and a description
that holds one is told once on its pull request that the line is not read (ADR 0419 §2). that holds one is told once on its pull request that the line is not read (ADR 0419 §2), until milestone G, in
which that notice goes with the gate's last read of a description (ADR 0659 §4; *The Approve and the merge*).
### An acting part's new version acts first, a wait with a bound ### An acting part's new version acts first, a wait with a bound
@@ -930,7 +1114,7 @@ names go, since every new acting part needed code changes elsewhere (research 08
event says. event says.
- **Composing waits per node, by the assigner.** A node's wants wait only for that node's own node-engine, never for - **Composing waits per node, by the assigner.** A node's wants wait only for that node's own node-engine, never for
another node's, so a node away holds only itself (ADR 0603 §7). The want gains no field: the assigner, which writes another node's, so a node away holds only itself (ADR 0603 §7). The want gains no field: the assigner, which writes
the wants, holds a node's other wants until the node-engine seat's `running.<node>` says the new node-engine version the wants, holds a node's other wants until the node-engine seat's `running.<node>.<module>` says the new node-engine version
runs on that node, and writes that node-engine's own want first. A node-engine of before milestone G thus gets its runs on that node, and writes that node-engine's own want first. A node-engine of before milestone G thus gets its
own want first and every other want once it runs the new one, so an old node-engine never composes a module it own want first and every other want once it runs the new one, so an old node-engine never composes a module it
cannot read. The clock of that node's bound starts when the node is present and its node-engine's want is written, cannot read. The clock of that node's bound starts when the node is present and its node-engine's want is written,
@@ -952,6 +1136,30 @@ names go, since every new acting part needed code changes elsewhere (research 08
what its new version is built from or needs (a base, a package, a provider) is acted on by its running version, 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 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. module builds the rest, so ADR 0614 §6's cycle through them stays allowed, now for that reason.
- **The artifact store's holder takes its own new build even when its seat is the one broken.** A build module
stores the artifacts it builds through the seat `oci-artifact-registry`, so the
holder of that seat is in its own build's path: its new build needs the store it replaces. As every holder's own
inputs are (above), that store is acted on by the running holder: the running holder stores its new build, and only
then is the new one wanted. When the running holder is what is broken (the seat refuses or does not answer a store,
as in the hand bootstrap of 2026-11-07 to 11-09), the build module keeps that one build on its own node among its
kept builds (*The bootstrap delivery*: `build_go_kept`), says in its step key that it is kept on that node, and the
builder's done key names it so with its digest; the node-engine composing the holder fetches it through the build
seat's verb `kept-artifact` of that node, and the new holder, once it runs, takes the store of every build after it.
- The verb sits in the build seats' definitions (`node-build-go`, `node-build-node`, `node-build-image`, in
`mesh-delivery-contracts`), and its callers are the node-engines alone: the definition names them, and the grants
part grants it to no other account.
- It answers only for a module that claims the seat `oci-artifact-registry`, and refuses every other, naming the
module, so a store outage never turns into delivering from build nodes.
- The bytes go as an object by digest on the bus (the old `objects` form, ADR 0619 §2), never in a value, since an
artifact is over the bus's value limit; the node-engine checks the bytes it fetched against the digest in the
builder's done key and applies nothing that differs.
- While the keeping node is away, or its sweep removed the build, the want waits, and the node-engine says in its
have that it waits for that node or for a build no longer kept.
This is the one artifact the mesh delivers from a build node instead of the store, and only for the holder of
`oci-artifact-registry`; the design's choice under ADR 0656 §3 (a wait skips what the holder's own new version needs) and ADR
0526 §2, whose build by a session's call it makes a step of the delivery instead of a hand act. How it is checked:
test 60.
- **The check refuses a cycle among the waits within one step** (ADR 0656, 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 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. through a holder's own inputs, is none.
@@ -1041,7 +1249,17 @@ commit on the SDK's trunk or the head of an SDK pull request the forge holds, op
request's key and stops when the head in it moves, without asking the forge (issue 726); an ended check request's key and stops when the head in it moves, without asking the forge (issue 726); an ended check
delivers no verdict, so none of its builds is reused. A trunk move never ends a check: its verdict goes out of delivers no verdict, so none of its builds is reused. A trunk move never ends a check: its verdict goes out of
date when it ends, and is carried. A check that failed because a part of the mesh was not heard is still asked date when it ends, and is carried. A check that failed because a part of the mesh was not heard is still asked
again when the nodes change, which judges heads no check judged. again when the nodes change, which judges heads no check judged. From research 085's milestone its verdict says
`could not run`, naming the part not heard, and the check releases its claim on the verdict key, so the heads can
be judged again. The part's return is the one event that can change the outcome: the node-engine seat's
`running.<node>.<module>` naming that part (a node waking, the forge module or a build module starting again alike), on which
the check is asked again, once per set of heads and per part returning, never on a timer; a `running` of the same
part at the same fingerprint after that asks nothing. A `could not run` verdict not asked again within 60 minutes
becomes the checker's finding `check-could-not-run`, naming the heads and the part, which the condition keeper
raises (ADR 0564 §2): an hour is the check's own bound. The finding clears when the heads are checked again or
replaced, or their pull request closes. A second check of the same heads asked while one runs, or after one that
erred without releasing its claim, claims nothing and writes no status, by the claim above (issue 1373; ADR 0548 §1, ADR 0656 §5). How it
is checked: test 58.
- **A failed build node loses nothing.** An ask a build module took and never acknowledged goes to another node by the - **A failed build node loses nothing.** An ask a build module took and never acknowledged goes to another node by the
stream's own acknowledgement wait, with no timer of a part; a step's end is written on the build module's step key named stream's own acknowledgement wait, with no timer of a part; a step's end is written on the build module's step key named
by the ask's id (ADR 0525 §6). by the ask's id (ADR 0525 §6).
@@ -1103,7 +1321,26 @@ the check gates merges.*
### Nothing merges into a repository under check ### Nothing merges into a repository under check
*ADR 0548 §2 to §4, §9, §10, as ADR 0551 bounds them.* *ADR 0548 §2 to §4, §9, §10, as ADR 0551 bounds them; from research 085's milestone removed by ADR 0661 (proposed,
needs the operator's Approve; below).*
**Removed at research 085's milestone.** The hold, the merge turns, their stalled line, the gate's tools for them and
the setting `check-gates-merge` go in milestone G, the gate's and the forge module's alike (the operator, on Telegram,
2026-11-09 01:11 UTC, choosing "Remove them in G"; the forge's merge then judges no check, *The seat `git`*). The setting has been false since 2026-10-25, so the gate wrote no turn and held no merge in that time, and the
operator's word for G is that no check gates delivery (1921's note of 2026-11-07). From G's delivery an approved merge
is handed to the forge bridge at once; a check running on a repository the merge goes into ends on the commit it read,
and its verdict is carried (*A move of the trunk carries every verdict*); the checker reads nothing of the gate, and
the gate no longer watches the checker's verdicts for a hold. **Its record is to be accepted before the push:** ADR
0548 §2 to §4, §9 and §10, ADR 0551 and ADR 0534 §4's judgement of `mesh/check` by the merge are in force, and ADR
0661, which ends the first two and changes the third (proposed, needs the operator's Approve), is to be accepted before
milestone G's pull requests are pushed; until it is accepted, the rule below holds as those records have it. ADR 0662
is withdrawn; G builds ADR 0661. Beside it, ADR 0663 (proposed: the indexer answers `revision` in its own runtime to
exactly the parts that invoke it, the tool runner among them) is to be accepted before the push too, since the tool
runner's first view of the catalog half rests on it (*Every other reader of which modules exist*). How it is checked: in the gate's whole-module test an approved merge into a
repository under a running check is handed at once, and the gate's manifest declares no `turns` and no setting
`check-gates-merge`; in the checker's, a check claims at once with no gate state granted to read.
Until milestone G's delivery:
**Only while the check gates merges.** The hold, the merge turns and their stalled line hold only while the **Only while the check gates merges.** The hold, the merge turns and their stalled line hold only while the
setting `check-gates-merge` of mesh-delivery-gate, set together with the forge module's, is true. While it is setting `check-gates-merge` of mesh-delivery-gate, set together with the forge module's, is true. While it is
@@ -1374,12 +1611,12 @@ pull request, and it owes the forge nothing.
## The Approve and the merge ## The Approve and the merge
*ADR 0421, ADR 0398 §3, ADR 0406 §1.* *ADR 0421, ADR 0398 §3, ADR 0406 §1, ADR 0659.*
- **Asked as soon as the checks pass.** When a pull request's delivery reaches `ready` (both `mesh/merge-gate` and - **Asked as soon as the checks pass.** When a pull request's delivery reaches `ready` (both `mesh/merge-gate` and
`mesh/repo-check` passed at its head against its trunk's head), mesh-delivery asks the operator's Approve of its `mesh/repo-check` passed at its head against its trunk's head), mesh-delivery asks the operator's Approve of its
merge into main at once, on a channel that proves who answered (ADR 0274; Telegram today). The ask names the merge into main at once, on a channel that proves who answered (ADR 0274; Telegram today). The ask names the
pull request, its issues, the reviewer's verdict, the modules it moves and the trunk commit the checks judged. A pull request, its issues, the modules it moves and the trunk commit the checks judged, and no review (ADR 0659 §1). A
verdict that names a trunk commit the trunk had already left raises no ask: the checker carries it to the verdict that names a trunk commit the trunk had already left raises no ask: the checker carries it to the
trunk's head, and the carried verdict raises the ask (ADR 0421 §1, as ADR 0548 §8 changes it). trunk's head, and the carried verdict raises the ask (ADR 0421 §1, as ADR 0548 §8 changes it).
- **A group is asked once.** One ask names every member and its head, once every member is `ready` and the - **A group is asked once.** One ask names every member and its head, once every member is `ready` and the
@@ -1388,24 +1625,34 @@ pull request, and it owes the forge nothing.
milestone is not asked (ADR 0493 §9, §11, which change ADR 0421 §1 and §2); the Approve it asks is also written milestone is not asked (ADR 0493 §9, §11, which change ADR 0421 §1 and §2); the Approve it asks is also written
into the wait list of the session a `Waited-by: <name>@<node>` line on the pull request names, and only when the into the wait list of the session a `Waited-by: <name>@<node>` line on the pull request names, and only when the
pull request carries that line; without it the pull request is asked as today (ADR 0491 §3, §5). pull request carries that line; without it the pull request is asked as today (ADR 0491 §3, §5).
- **The reviewer's verdict is attached, not a gate.** The review finishes before the push (playbook 07), and the - **The review is the session's, and no part reads it.** The review finishes before the push (playbooks 07 and 08);
session that opens a pull request gives its review record: who reviewed it, the commit the review approved and the session may name its reviewer in the description for people, and nothing reads it: the gate raises the ask
the verdict; from the delivery of issue 1782 a verb of the delivery seat records it at the head it judged, and no without any review line, the ask carries no review record, and an edit of the description withdraws nothing
description is read (ADR 0493 §5, §6). The ask carries it; with none, or one naming another commit, the ask says so in its first line and (ADR 0659 §1 to §3, which supersedes ADR 0496 and changes ADR 0493 §5, §9, §12). A review verb of the delivery
the operator decides (ADR 0421 §5). seat, if issue 1782 builds it, records a review people may read and gates nothing (ADR 0659 §2). Every wait of the
gate is on a state or an event of the bus (ADR 0659 §5).
- **The description's last three reads go in milestone G.** The issue numbers the ask names, the author a stalled
line names and the one notice that `after:` lines are not read are the three reads of a description ADR 0659 §4
leaves until they move to the bus. In milestone G the issue numbers come from the issue tracker's links of the
milestone (ADR 0493 §4, issue 1783), the author from the forge's pull request record, read through the seat
`git`'s verb `pull`, and the notice goes, so no part of the mesh reads a description at all. How it is checked: a
test over the gate's code, beside ADR 0659 §6's rows, finds no read of a description field.
- **The merge.** mesh-delivery merges through the forge's merge tool at the heads the Approve names, only while - **The merge.** mesh-delivery merges through the forge's merge tool at the heads the Approve names, only while
they are still the heads, their check passed against the trunk's head, and, while the check gates merges, no they are still the heads, their check passed against the trunk's head, and, while the check gates merges, no
check of other heads runs on a repository the merge goes into (*Nothing merges into a repository under check*, check of other heads runs on a repository the merge goes into (*Nothing merges into a repository under check*,
above). When the trunk moved, the merge waits for the carried verdict, and the event of its line asks the merge above, which milestone G removes). Until milestone G, when the trunk moved, the merge waits for the carried
again; no timer asks it, no person rechecks, and the Approve is not asked again (ADR 0421 §3, §12, as ADR 0548 verdict, and the event of its line asks the merge again; no timer asks it, no person rechecks, and the Approve is
§8 changes them). The merge tool still refuses a verdict naming a trunk commit other than the trunk's head and not asked again (ADR 0421 §3, §12, as ADR 0548 §8 changes them); and the merge tool refuses a verdict naming a trunk
asks nothing (ADR 0534 §4); the carry makes the verdict current. commit other than the trunk's head and asks nothing (ADR 0534 §4), the carry making the verdict current. From
milestone G the merge waits on nothing but the Approve's heads and a trunk that takes no push: the forge bridge
merges through the seat `git`'s verb `merge-pull`, which judges those two and no check, and a trunk move holds no
merge for its carry (ADR 0661, to be accepted before the push; *The seat `git`*, under *The verbs*).
- **A push or a Decline ends the Approve.** A new head ends its ask or its Approve, for a group every member's, and - **A push or a Decline ends the Approve.** A new head ends its ask or its Approve, for a group every member's, and
is said once on the pull request; the new head is asked again once its checks pass. A Decline merges nothing and is said once on the pull request; the new head is asked again once its checks pass. A Decline merges nothing and
is said once (ADR 0421 §6). is said once (ADR 0421 §6).
- **A failure is said, never merged past.** An approved head whose check failed is said once on the pull request - **A failure is said, never merged past.** An approved head whose check failed is said once on the pull request
and listed by `stalled`; so is a merge the merge tool kept refusing for an hour (ADR 0421 §7). and listed by `stalled`; so is a merge the merge tool kept refusing for an hour (ADR 0421 §7).
- **Recorded.** The ask, the answer with its warrant and the review record are kept on the delivery, shown by - **Recorded.** The ask and the answer with its warrant are kept on the delivery, shown by
`show` and said in mesh-delivery's log; the merge's transition names the Approve (ADR 0421 §8). `show` and said in mesh-delivery's log; the merge's transition names the Approve (ADR 0421 §8).
## After the merge: the source revision and the wants ## After the merge: the source revision and the wants
@@ -1498,6 +1745,15 @@ timer. A group's merges arrive together.
held group (ADR 0441 §3, §4); the gate passes the group's end by without counting it a refusal. A later merge in held group (ADR 0441 §3, §4); the gate passes the group's end by without counting it a refusal. A later merge in
a member's repository waits behind the group; a merge in another repository is taken in alone, unless a revision a member's repository waits behind the group; a merge in another repository is taken in alone, unless a revision
is pending for its indexer (ADR 0633 §4, which builds ADR 0429 §11 for take-in). is pending for its indexer (ADR 0633 §4, which builds ADR 0429 §11 for take-in).
- **A merge the gate did not make is taken in like any other.** When the forge says a pull request merged and the
gate holds no merge of it (a person merged it in the forge's own page), the forge bridge reads that pull request
by its merge commit (from milestone G through the seat `git`'s verb `pull`) and publishes its merged message with
the merge's trees as for any merge; the indexer takes it in under the bullets above, and a later merge's take-in
that its repository's taken merge covers ends with it, so nothing waits behind it. The gate opens a `forge-made`
record for it (*The delivery record*). The design's choice under ADR 0633 §1 and §4, as the operator asked it (1921's
note of 2026-11-07); built in the issue 1966 recovery (mesh-delivery #185, #187), kept whole in milestone G. How it is
checked: in the forge bridge's whole-module test a merge with no merge of the gate's publishes its merged message,
and in the indexer's take-in table a merge its taken merge covers is ended.
- **A wait is bounded, said and recoverable.** The indexer's tool `indexer_pending` reads the pending revisions and - **A wait is bounded, said and recoverable.** The indexer's tool `indexer_pending` reads the pending revisions and
the members still gathered, each with its merges, the indexer build it waits for, since when and `refused`; the the members still gathered, each with its merges, the indexer build it waits for, since when and `refused`; the
view names a module waiting for its revision's indexer through that tool (ADR 0633 §5, which changes ADR 0603 view names a module waiting for its revision's indexer through that tool (ADR 0633 §5, which changes ADR 0603
@@ -1651,7 +1907,7 @@ later change of a kept data's form, not as a case of this milestone.
## Compositions, wants and the apply ## Compositions, wants and the apply
*ADR 0360 §8, §9, ADR 0377, ADR 0429 §4, §6, ADR 0539 §9, §14 to §16, ADR 0547 §2 to §9, ADR 0549, ADR 0555.* *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 - **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 manifest by digest the indexer wrote, the module's resolved
@@ -1682,7 +1938,7 @@ later change of a kept data's form, not as a case of this milestone.
- **How placement is changed.** The seat `mesh-module-assigner`, held once for the mesh by the assigner, keeps three - **How placement is changed.** The seat `mesh-module-assigner`, held once for the mesh by the assigner, keeps three
states: `placement`, one key `placement.<node>` per node; `proposals`; and `candidates`. Only the holder's states: `placement`, one key `placement.<node>` per node; `proposals`; and `candidates`. Only the holder's
credential writes them, and the contract (the states' layouts among it) is the seat's, in credential writes them, and the contract (the states' layouts among it) is the seat's, in
`mesh-placement-contracts` (ADR 0634 §6, §7). No repository holds `mesh-contracts`, module assignment being of the Core domain (ADR 0634 §6, ADR 0641 §1). No repository holds
placement and none names a node: what differs between nodes is bus state, and a build module's capacity and placement and none names a node: what differs between nodes is bus state, and a build module's capacity and
build hours are values on each node's layer of mesh-config. A key holds what a person decides of the node and build hours are values on each node's layer of mesh-config. A key holds what a person decides of the node and
nothing a machine observes: nothing a machine observes:
@@ -1726,7 +1982,7 @@ later change of a kept data's form, not as a case of this milestone.
holder hears that key's change; nothing polls. The nodes that must answer are each node whose key the proposal holder hears that key's change; nothing polls. The nodes that must answer are each node whose key the proposal
changes and each node whose composition the holder finds changed with the current inputs on both sides, not every changes and each node whose composition the holder finds changed with the current inputs on both sides, not every
placed node, so a node gone for good or asleep blocks only a proposal that touches it. The contract (the state, placed node, so a node gone for good or asleep blocks only a proposal that touches it. The contract (the state,
its key, the answer) is the seat's, in `mesh-placement-contracts` (ADR 0567, ADR 0634 §6, §7); the composition with its key, the answer) is the seat's, in `mesh-contracts` (ADR 0567, ADR 0634 §6, ADR 0641 §1); the composition with
a given placement is the composition of `mesh-delivery-sdk` (ADR 0635 §4), and the comparison is the node-engine's a given placement is the composition of `mesh-delivery-sdk` (ADR 0635 §4), and the comparison is the node-engine's
own package (ADR 0634 §1). own package (ADR 0634 §1).
- **The holder judges the answers and the operator approves.** The holder computes, by node, the modules the - **The holder judges the answers and the operator approves.** The holder computes, by node, the modules the
@@ -1767,6 +2023,14 @@ later change of a kept data's form, not as a case of this milestone.
the node composing it keeps what runs until the vault holds it. Likewise a consumer of `model-access` answered by a the node composing it keeps what runs until the vault holds it. Likewise a consumer of `model-access` answered by a
licence record, placed before the vault serves licences (ADR 0550 §3, issue 569), is refused by the same guard and licence record, placed before the vault serves licences (ADR 0550 §3, issue 569), is refused by the same guard and
its node keeps what runs; none is placed today. its node keeps what runs; none is placed today.
- **A claim problem holds its module, never the node's pass.** When a module's claim cannot be held (its seat's
definition missing, removed or refused, a claim another holder keeps, a credential the vault refuses), the node agent
composes that module as left out, keeping its openings, says why in its have, and composes and applies every other
module of the node; it never refuses the whole pass for one module's claim (ADR 0636 §3: a refused definition blocks
new claims of that seat only). Met on 2026-11-08, when one claim problem refused a node's every module (issue 1966).
A module held so is no silent leave-out: the node-engine writes the finding `module-held` naming the node, the
module and why, and the condition keeper keeps the condition (ADR 0564 §2) until the module is composed again or is
no longer wanted on that node, when the node-engine clears the finding. How it is checked: test 55.
- **The order a node takes to composing its own.** One delivery group carries every part: the seat `mesh-module-assigner` - **The order a node takes to composing its own.** One delivery group carries every part: the seat `mesh-module-assigner`
on the assigner, the controller's verb `placement-export` (as it is) and the controller's pin only, the node-engine on the assigner, the controller's verb `placement-export` (as it is) and the controller's pin only, the node-engine
(its record and its own composer), the vault's `own`, the grants part's reads, and mesh-config's reading of (its record and its own composer), the vault's `own`, the grants part's reads, and mesh-config's reading of
@@ -1819,6 +2083,38 @@ later change of a kept data's form, not as a case of this milestone.
fingerprint, the digest, the phase and the health after the module's start window. A failed apply is loud, fingerprint, the digest, the phase and the health after the module's start window. A failed apply is loud,
retried by the next change of the want or the composition, never by a clock, and fixed forward (ADR 0360 §8, retried by the next change of the want or the composition, never by a clock, and fixed forward (ADR 0360 §8,
ADR 0539 §9). ADR 0539 §9).
- **A put without hold ends itself once the node runs it.** A put the assigner's tool `assigner_put` writes with
`hold` false ends when the node's have runs its fingerprint healthy, and the assigner's rules write the want again
from their next pass (ADR 0546 §5); a held put stays until `assigner_release`, which also ends a put without hold
(ADR 0546 §6). The design's choice under ADR 0546 §5: the fact the node already says ends the put, so a put never
pins a want by being forgotten, as a session's puts of a node-engine build did for seven hours on 2026-11-09 (issue
1966), and milestone G's one logged put of its own indexer ends by itself.
- **Until milestone G, from the have; from G, from `running`.** The issue 1966 recovery ends the put by the read of
the node's have the assigner already makes, and keeps that end until G. That read crosses the seam against ADR
0596 §2, kept on purpose until G, because no `running` event carries a fingerprint before G. In G the end moves
to the node-engine seat's `running.<node>.<module>` naming the put's fingerprint, which milestone G gives that
event, heard through a durable consumer of the assigner's own declared in its `consumes`, the one its composing
waits hear too (*Composing waits per node*); from then it never reads the node's have. A `running` without a
fingerprint, as a node-engine from before G says it, ends no put: a put on a node whose node-engine is from before
G ends on the first `running` with a fingerprint from that node's new node-engine, which the composing waits move
first on that node, and `put-stands` says it meanwhile.
- **Ended at once when the node already runs it.** At the put's ask, and at the assigner's start for every put not
ended (one written before the upgrade among them), a put ends at once when the last `running` the assigner holds
for that node and module names its fingerprint; a put of the running build pins nothing. A `running` naming
another fingerprint ends nothing.
- **The end is a step the put already has.** The put ends with its existing step `done`, or `released` when a
release ends it, written on its key and said as the assigner's event `put`, carrying the fingerprint and the
`running` that ended it. No new step is added, so a reverted assigner, which knows `done`, `released` and
`refused` as ended, never reads an ended put as running.
- **A put without hold that stands is said, by the watchman.** When a put without hold has its want written, the
assigner says `wait-held` on the seat `mesh-wants` for it (node, module, fingerprint, since when) with a bound of
30 minutes, and `wait-ended` when it ends. The watchman times it as it times every wait, and past the bound writes
the finding `put-stands`, naming the node, the module and the fingerprint, which the condition keeper raises
(ADR 0564 §2) and clears on `wait-ended`; at its own start the watchman seeds its open puts from `assigner_puts`,
as it seeds `acting-part-late`, so a put whose assigner stopped after writing its want is still timed. Thirty
minutes is many times a module's start window and the canary's wait, so a put moving normally raises nothing. A
held put is listed by `assigner_puts` as held, with since when, and raises nothing: holding is what it was asked
for. `assigner_puts` also lists a put older than the trunk's newest build of its module. How it is checked: test 62.
- **The bus module is wanted like any module; only a warranted want replaces its server** (ADR 0594, changing - **The bus module is wanted like any module; only a warranted want replaces its server** (ADR 0594, changing
ADR 0539 §14 and §15, ADR 0546 §8 and ADR 0565 §7 for the bus module). The assigner writes the bus module's want by ADR 0539 §14 and §15, ADR 0546 §8 and ADR 0565 §7 for the bus module). The assigner writes the bus module's want by
the same rules as every module's, and the node agent applies what that want brings (its files, its processes' bus the same rules as every module's, and the node agent applies what that want brings (its files, its processes' bus
@@ -1975,7 +2271,7 @@ forge module's files of what it announced (ADR 0406 §6).
| Verb | Answers or does | | Verb | Answers or does |
|---|---| |---|---|
| `deliveries` | every delivery not final, the final ones of the last day, and every one `stalled` still lists | | `deliveries` | every delivery not final, the final ones of the last day, and every one `stalled` still lists |
| `show` | one delivery or group whole: the Approve, transitions, the review record, the source revision its merge moved | | `show` | one delivery or group whole: the Approve, transitions, the source revision its merge moved; no review record from milestone G (ADR 0659 §1) |
| `groups` | every group with its members and its derived state | | `groups` | every group with its members and its derived state |
| `table` | the state table, with its bounds | | `table` | the state table, with its bounds |
| `stalled` | every merge or check held past its bound | | `stalled` | every merge or check held past its bound |
@@ -1989,8 +2285,9 @@ From research 085's milestone the seat gains:
| Verb or event | Answers or does | | 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 0656) | | `groups` with a group | that group's members, which the forge bridge reads in place of the gate's `merges` state (ADR 0656), and the acts the gate said it owes the forge for it, each with its id and its recorded outcome (*What the gate owes the forge*) |
| `milestone.asked`, `milestone.withdrawn`, `milestone.answered` | 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 `mesh.seat.mesh-delivery.event.milestone.<milestone>.<event>`, apart from each delivery's `transition`, which stays as it is, so a waiter on one member's pull request wakes only on that member's `transition` | | `owed` | an act the gate owes the forge (a merge, a status, the delivery's view, a comment, a line on the commit's note), with its pull request, head and id, on `mesh.seat.mesh-delivery.event.owed.<repository>.<number>`, said only from the gate's account and heard by the forge bridge through a durable consumer (*What the gate owes the forge*) |
| `milestone.asked`, `milestone.withdrawn`, `milestone.answered` | the one Approve ask per milestone (ADR 0493 §9 as ADR 0659 §1 changes it, issue 1783), held until it is answered, or withdrawn by a new head and asked again (ADR 0441 §1); said on `mesh.seat.mesh-delivery.event.milestone.<milestone>.<event>`, apart from each delivery's `transition`, which stays as it is, 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, said only from the gate's account (*The delivery record*) | | `pinned`, `freed`, `heads-replaced` | the events by which the indexer and the assigner keep or drop graph revisions, said only from the gate's account (*The delivery record*) |
| `record-ended`, `filling`, `full`, `room` | a delivery record ended; the ledger past 80 % of its cap; the ledger full; the ledger back below its cap (*The delivery record*) | | `record-ended`, `filling`, `full`, `room` | a delivery record ended; the ledger past 80 % of its cap; the ledger full; the ledger back below its cap (*The delivery record*) |
@@ -1998,8 +2295,84 @@ From research 085's milestone the seat gains:
of the revision view, ADR 0656), and `entry` and `difference` on `mesh-wants` (ADR 0656), with the events of *What of the revision view, ADR 0656), and `entry` and `difference` on `mesh-wants` (ADR 0656), with the events of *What
each step says*. each step says*.
**Links of the trace.** A review stays the line in a pull request's description, as ADR 0496 §3 has it, until issue **The seat `node-engine`**'s event `running.<node>.<module>` carries, from research 085's milestone, the module, its
1782 builds the review verb and settles who may review and its grant, outside milestone G. The trace's links are this 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.
**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
module's own tools and events and guessing the shape of their answers (on 2026-11-09 one guess, an answer wrapped in a
`result` field, made 316 conditions stand, issue 1966). From research 085's milestone the seat's definition carries the
verbs and events below, their inputs and answers typed in its contract, served and said by the module that claims the
seat; every delivery part and the gate call and hear the seat, never the forge module by name (acceptance test 27).
They are this design's choice under ADR 0596 §1, §2 (a module's events are subscribed to and its data asked through
its seat verbs) and ADR 0625 §1 (a seat's contract is generated from its definition). The table is built from what the
parts' manifests declare in `invokes` and `consumes` and what their code calls, read on main on 2026-11-09 (mesh-delivery
042b8d1f, mesh-catalog's gate); a declaration nothing calls (the checker's `gitea_commits`, `gitea_compare`,
`gitea_list_branches`) gets no verb and is dropped from its manifest:
| Verb | Answers or does | Called by (today's call) |
|---|---|---|
| `pull` | one pull request, by its repository and number or by its merge commit: number, base, head branch, head, merge commit, author, state | the forge bridge (a merge the gate did not make; `gitea_api`), the gate (a stalled line's author) |
| `open-pulls` | every open pull request of every repository, its head and base, the statuses its base requires and those its head has | the forge bridge at its start and each reconnect (ADR 0443 §5), the indexer, the gate (`gitea_open_pulls`) |
| `tags` | a repository's tags, paged, the page's bound said when more exist | the forge bridge, for the builder's floor (`gitea_api`) |
| `trees` | the trees of one commit | the forge bridge, the checker, the indexer (`gitea_commit_trees`) |
| `file` | one file at one commit | the forge bridge, the checker, the indexer (`gitea_get_file`) |
| `contains` | whether one commit contains another | the indexer, the gate (`gitea_contains`) |
| `statuses` | the statuses a commit carries | the gate (`gitea_commit_statuses`) |
| `status`, `comment`, `view`, `note` | a commit status, a comment, the delivery's one view comment, a line on the commit's note under `refs/notes/mesh-plan`; a comment and a note line carry the act's id and an id already held is skipped | the forge bridge alone, performing the gate's and the checker's `owed` (`gitea_commit_status`, `gitea_add_comment`, `gitea_delivery_view`, `gitea_note_append`) |
| `merge-pull` | merges a pull request at the head the operator's Approve names; refuses a head that moved, a branch no rule guards, a head the Approve does not name and a merge git refuses; judges no check (below); a pull request already merged at that head is answered performed | the forge bridge alone (`gitea_merge_pull_request`) |
| 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`) |
Each is said on `mesh.seat.git.event.<event>`, declared in the seat's definition, and heard through the hearer's
`consumes` of the seat.
- **A failed read answers an error, never an empty answer.** When the forge does not answer, refuses or answers what
the contract cannot type, the verb answers an error naming why; an empty list or an absent file is answered only
when the forge said so. A caller never reads an error as "none". How it is checked: the seat's fixtures hold an
error answer for each verb, and each caller's unit table has a row for it (the forge bridge, the checker, the
indexer, the gate).
- **Who may call an act.** The holder's trusted config value `callers`, which today names per verb who may call the
two package seats' verbs (design 51), gains a line per verb of the seat `git`: the act verbs name the forge bridge
alone, the reads name each part that declares them in `invokes`; the grants part grants by it, and the holder
refuses a caller it does not name. The forge module's own acting tools (`gitea_merge_pull_request`,
`gitea_commit_status`, `gitea_delivery_view`, `gitea_note_append`, `gitea_add_comment`) retire with the milestone,
and so do its watch of the checker's state `owed` and its read of the gate's `source`, so the bridge stays the one
part that acts on the forge. How it is checked: test 51 reads the grants, not the code.
- **`merge-pull` judges no check.** The operator's answer that no check gates delivery (Telegram, 2026-11-09 01:11 UTC,
"Remove them in G") covers the forge module's own setting `check-gates-merge` as well as the gate's: both are
removed, and `merge-pull` merges an approved head whatever its `mesh/check` says. The record that ends ADR 0551 and
ADR 0548 §2 to §4, §9 and §10 also changes ADR 0534 §4's judgement of `mesh/check` by the merge; it is to be accepted
before the push (*Nothing merges into a repository under check*).
- **The order is the module graph's, and each step has its way back.** The verbs are a served-verb edge (ADR 0614):
the forge module's new build runs before the forge bridge's, and the forge bridge's before the gate's, since the
bridge calls the verbs and performs the gate's `owed`, and the gate says `owed` only to a bridge that hears it; all
three are ahead of the acting parts' steps, which read through the seat. While the new forge runs and the old bridge
still calls the retired acting tools, the old bridge's acts fail loudly and stay unperformed in the old gate's keys,
and the switch carries them (*What the gate owes the forge*). A revert goes back in the other order: the gate, then
the bridge, then the forge, each wanted only once the one after it in the forward order runs its reverted build, so
no part calls a verb nobody serves. ADR 0656 §3 stands beside it: the acting parts' new versions act first in their
own steps. Two things cover the gap while the forge is still on its old build and serves no verb of the seat: the
indexer starts on its kept definitions (below), and a check whose read through the seat `git` fails says `could not
run`, naming the forge, and is asked again on the forge module's `running` (*A check runs to its end*).
- **A part that cannot read the forge keeps what it has, and says so.** The indexer, at its start, waits for the
seat `git` at most 2 minutes; with no answer it judges from the last definitions it kept, says in its
`<module>_first_views` that it waits for `git` and since when, writes `view-waits` after five minutes, and reads the
definitions once the seat answers; it then judges again every manifest it judged from kept definitions. Two minutes is longer than a forge's restart, and short enough that a start is
not held behind a forge down for good. How it is checked: test 54.
- **How it is checked.** The seat definition's conformance fixtures hold one answer and one error of each verb and one
of each event, and the forge module's tool tests answer each fixture; the forge bridge's, the checker's, the
indexer's and the gate's unit fakes answer from the same fixtures; a call of an act verb from an account other than
the forge bridge's is refused (test 51); live, a search of the delivery parts' and the gate's code finds no name of
the forge module's tools or events.
**Links of the trace.** No part reads a review line (ADR 0659 §1 to §3); who may review and the review verb's grant
stay issue 1782's, outside milestone G, and that verb gates nothing (ADR 0659 §2). The trace's links are this
design's choices under ADR 0656, so that one call traces research to the running build 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 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 it carries, made by a tool call and never by text, as ADR 0493 §4 has every link made; the knowledge base gains a
@@ -2011,6 +2384,14 @@ an issue linked to a decision and to a research effort reads both back; a decisi
back. Live: research 085's milestone's record reads back research 085 to its decisions, its milestone, its issues and back. Live: research 085's milestone's record reads back research 085 to its decisions, its milestone, its issues and
its pull requests with no text match. its pull requests with no text match.
**A session hears that a record was accepted** (issue 595). The knowledge base already says, on its holder's own
stream, the event `reviewed` for every judgement of a record; from milestone G that event carries, when the operator's
Approve accepts a record, that it was accepted and by the operator, with the warrant, and the tool runner's account is
granted to hear it, so a session waiting on a record wakes on it. The design's choice under ADR 0596 §1 (a module's
events are subscribed to): a new event of the seat `knowledge-base` would be a second path for the same fact (lead-47,
2026-11-09). How it is checked: in the knowledge base's whole-module test an Approve that accepts a record says
`reviewed` with what was accepted and by whom, and the tool runner's account hears it.
**The status view's tools** read the keys and change nothing: `assigner_wants`, `assigner_want`, **The status view's tools** read the keys and change nothing: `assigner_wants`, `assigner_want`,
`assigner_differences` and `node_haves`, beside the indexer's and the builder's. Its events are `delivered`, `assigner_differences` and `node_haves`, beside the indexer's and the builder's. Its events are `delivered`,
`moving`, `settled` and `stuck` (*A delivery* above). `moving`, `settled` and `stuck` (*A delivery* above).
@@ -2179,7 +2560,8 @@ development, the check's share about a minute):
From ADR 0548 and ADR 0551 (issue 568): From ADR 0548 and ADR 0551 (issue 568):
25. **One check per delivery.** A delivery group of two repositories is under check, and a lone pull request into 25. **One check per delivery.** A delivery group of two repositories is under check, and a lone pull request into
one of them is approved during the run. While the check gates merges, it waits, `mesh-delivery.show` says one of them is approved during the run. From milestone G it merges at once, as it does today with the setting
false, and nothing of the hold is left to read (test 52). Until then: while the check gates merges, it waits, `mesh-delivery.show` says
what it waits for, and it merges when the group's verdict is written; while it does not, it merges at once and what it waits for, and it merges when the group's verdict is written; while it does not, it merges at once and
the group's running check ends on the commit it read. Either way the group's verdict is then carried to the the group's running check ends on the commit it read. Either way the group's verdict is then carried to the
new trunk commit with no test run for an unchanged digest, and the group merges on its Approve with no second new trunk commit with no test run for an unchanged digest, and the group merges on its Approve with no second
@@ -2268,7 +2650,7 @@ Each change ADR 0656 makes in an earlier record, and its test:
their check naming the part, and no module of them is composed from its manifest (whole, checker). their check naming the part, and no module of them is composed from its manifest (whole, checker).
47. **A part waits for the revision view** (ADR 0636 §1, §4). With the indexer stopped, then with the assigner stopped, 47. **A part waits for the revision view** (ADR 0636 §1, §4). With the indexer stopped, then with the assigner stopped,
and on a cold control-node whose parts all start with no view, the checker, the builder and the grants part each and on a cold control-node whose parts all start with no view, the checker, the builder and the grants part each
keep running what they run, answer `waits` with the revision and since when, write `view-waits` after five minutes, keep running what they run, answer in `<module>_first_views` the revision they wait for and since when, write `view-waits` after five minutes,
and act once the view is back, clearing it; the node-engine waits only for the catalog half; a candidate's heads 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). 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 48. **A process reports its handed build** (ADR 0639 §7). A part started while its node's want differs from what runs
@@ -2277,6 +2659,92 @@ Each change ADR 0656 makes in an earlier record, and its test:
merged message and publishes a group's end again from the seat `mesh-delivery`'s verb `groups`, and its account 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). holds no read of the gate's `merges` state, so a read of it is refused (whole, forge bridge).
What milestone G's prepare found, and its test:
50. **No description is read** (ADR 0659 §4). The Approve ask names the issues read from the milestone's links and a
stalled line the author read through the seat `git`'s `pull`, no notice of an `after:` line is said, and a test over
the gate's code finds no read of a description field (whole, gate).
51. **The forge is reached through its seat.** Every act the forge bridge performs and every read the forge bridge,
the checker, the indexer and the gate make of the forge goes through a verb of the seat `git`, and every forge
event they hear is the seat's; each answer is decoded as its contract's type and a failed read as an error; the
grants composed from the holder's `callers` give the act verbs to the forge bridge's account alone, a call of one
from another account is refused, and the forge module serves none of its retired acting tools (whole, forge bridge,
grants part; live, the grants read with `grants_bindings`).
52. **Nothing holds an approved merge for another check.** Once ADR 0661 (proposed, needs the operator's Approve; to
be accepted before the push), which ends ADR 0551 and ADR 0548 §2 to §4, §9, §10 and changes ADR 0534 §4, is
accepted: an approved merge into a repository under a running check is handed at once and merged whatever that
check says; a merge after a trunk move is not held for the carry; neither the gate nor the forge module
declares `check-gates-merge`, the gate declares no `turns`, and the checker is granted no read of the gate's state
(whole, gate, checker and forge module).
53. **What is owed is said, answered and kept.** An `owed` said while the forge bridge is stopped is performed once after
its restart; the bridge stopped between an act and its `owed.ended` repeats it and the forge holds it once; an
undecodable act is said `undecodable`; an act unanswered 15 minutes is listed by `stalled`; the switch with a merge
handed and not yet merged opens no `forge-made` record; a merge made at the forge opens one, said as `transition`
with why `forge-made`, and a later merge in its repository follows it; the checker's `mesh/check` is performed by
the bridge from the checker's `owed`, and a checker status the forge refuses is recorded in the checker's own
state and listed in its stalled read (whole, gate, checker and forge bridge).
54. **One reader of the seat list per part, and one view machinery.** Every part that reads the seat list has the two
tools of ADR 0636 §7 from the runtime and no wiring of its own; every part that takes a first view answers its
held and awaited revision in `<module>_first_views`. With the forge on its old build, serving no verb of the seat
`git`: the indexer starts within 2 minutes on its kept definitions, raises `view-waits` after five, and once the
seat answers judges again every manifest it judged from kept definitions; a check whose read through the seat
fails says `could not run` naming the forge, and is asked again on the forge module's `running` (unit, mesh-sdk;
whole, indexer and checker; live search).
55. **A claim problem holds one module, and says so.** A node with one module whose claim is refused applies the
others; that module's have names why, and `mesh-conditions.conditions` reads its `module-held` condition until the
module is composed again or no longer wanted on that node, when it clears (whole, node-engine and condition
keeper).
56. **One rule picks a seat's holder, also with a node away** (ADR 0660 §1 to §3). With one node away whose last
`running` named a build that no longer claims the seat, and one node that has said nothing since the parts'
consumers began, the node-engine and the grants part each pick the same holder, the silent node counted by the
trunk's manifest; a consumer made after a node's last `running`, and the two parts' consumers made at different
times, still apply that build's manifest and pick the same holder; neither reads another node's have key, and
neither calls a node (whole, node-engine and grants part).
57. **The indexer reads every definition at its start.** Started with a definition on a contracts trunk that no event
announced, the indexer judges the first manifest claiming that seat with it, and answers it in
`seat-definitions` (whole, indexer).
58. **A check that could not run says so and is asked once more.** A check that a part of the mesh it needs does not
answer (the composer, the forge, a build seat's holder) reads `could not run` and names that part in
`mesh-delivery.show`; the claim is released; the part's `running` asks the check again once, and a second `running` of the same part at the same fingerprint asks no second check; a
`could not run` not asked again within 60 minutes raises `check-could-not-run`, which reads cleared once the heads
are checked again, replaced, or their pull request closes; a placed node away is not such a part: the check passes it
with a warning (ADR 0593 §9) (whole, checker; live, read through `mesh-delivery.show`).
59. **A session hears an accepted record** (issue 595). An Approve that accepts a record makes the knowledge base say
`reviewed` with what was accepted, by the operator and with the warrant, and the tool runner's account hears it, so
a session waiting with `mesh_wait` wakes on it (whole, knowledge base; live).
60. **The store's holder takes its own build when its seat is broken.** With a fixture holder of `oci-artifact-registry`
that refuses every store, its new build is kept on the build node, named in the builder's done key, fetched by the
node-engine through `kept-artifact`, and once it runs the next build is stored through the seat, with no hand act;
a call of `kept-artifact` from an account other than a node-engine's is refused; it is refused for a module that
does not claim `oci-artifact-registry`; fetched bytes that differ from the done key's digest are not applied; an
artifact over the bus's value limit is fetched whole as an object; with the keeping node away, or the build swept,
the want waits and the have says why (whole, builder, build module and node-engine).
61. **No module reads the indexer's `modules`.** The watchman's manifest findings, the status view's `view_reach`, the
forge module's writable repositories and the reads of the holders of `mesh-config`, `mesh-provisioner` and
`mesh-self-check`, of the claude-code module and of the tool runner each answer from the catalog half: after a
merge that adds a module, each names it once `catalog-revision` is said, with no call of the indexer by name; the
indexer's manifest declares no `modules`; a reader that misses a `catalog-revision` asks `revision` again and then
names the module (in `meshcatalogclient`'s test and the forge module's); a candidate's `catalog-revision` changes
nothing in any reader, and the forge module grants no write before its first view nor from a candidate; the tool
runner started before the indexer says it waits, takes no empty view as no modules, raises `view-waits` after five
minutes, and once it has its first view keeps answering while the indexer is stopped; the forge module answers
`<module>_first_views` with the revision it holds and the one it waits for (each module's existing tests, a row
each; whole, tool runner and forge module; live, a search of the catalog's and mesh-tools' code and manifests finds no
`indexer_read_modules` and no view `modules`, and after milestone G's first merge that adds a module the status
view's `view_reach` and the watchman's manifest findings name it, as the operator sees them).
62. **A put without hold ends itself.** A put with `hold` false of a fingerprint the node does not run yet ends on that
node's `running` naming its fingerprint, at the step `done` carrying the fingerprint and that `running`, and the
next pass of the rules writes the want, so a later build is wanted with no `assigner_release`; a `running` of
another fingerprint ends nothing; a `running` without a fingerprint ends no put, and the node's new node-engine's
`running` with one ends it; a put of the build the node already runs ends at its ask; a put written before the
assigner's start, whose node already runs it, ends at that start; a put whose `running` was said while the
assigner was stopped ends after its restart; a reverted assigner reads the ended put as ended; a put without hold
not ended 30 minutes after its want says `wait-held` and the watchman raises `put-stands`, which clears on its
`wait-ended`, and with the assigner stopped after the want is written `put-stands` is still raised; a held put
past 30 minutes raises nothing and is listed by `assigner_puts` as held with since when; `assigner_release` ends a
put without hold at the step `released`; a held put stays until released (whole, assigner and watchman; live,
`assigner_puts` after milestone G's put of its own indexer).
## What retires ## What retires
- The "release branches" and the controller's check of them (ADR 0358, superseded by ADR 0401). - The "release branches" and the controller's check of them (ADR 0358, superseded by ADR 0401).
@@ -2326,8 +2794,11 @@ Each change ADR 0656 makes in an earlier record, and its test:
from manifests a module whose changed build module the check cannot run (ADR 0603 §10 and ADR 0614 §7, as ADR 0656 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 as what parts read (ADR 0603 §2, as changes them); the module graph's one key per module with five past values as what parts read (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 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); and list compiled into a part, and every read of another module's bus state the revision view replaces (ADR 0656); the
the gate's `merges` and `turns`, carried into the delivery records and written no more. gate's `merges`, carried into the delivery records and written no more, and its `owed`, said as events; the hold,
the merge turns, their stalled line and tools and the setting `check-gates-merge`, once their record is accepted;
the last three reads of a pull request's description (ADR 0659 §4); every delivery part's call of the forge module's
own tools, for the seat `git`'s verbs; and the four seat-list readers the delivery parts wire by hand.
## Milestones ## Milestones
@@ -2378,7 +2849,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 | | 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 | | 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: every check, a lone pull request's as a group of one and a verdict carried after a trunk move included, is judged by a checking program built from the change's own heads in the build seat's sandbox, which also makes the heads' one seat list that the check hands the manifest validator and the composer; it brings no seat definition and no manifest field, so the running checker checks it (ADR 0644; *The bootstrap delivery, and the one milestone after it*) | 26 needs it | mesh-sdk (`go/delivery`: the seat `node-build-go`'s ask `run` and the checker's record of which checking program judged; `go/composer`: the request's seat list), mesh-catalog (mesh-build-go: the run step, the refused answer, the kept programs' tools and sweep), mesh-delivery (checker: the checking program and its command), hq (this design, the glossary) | 1921 | | B0 | The bootstrap delivery: every check, a lone pull request's as a group of one and a verdict carried after a trunk move included, is judged by a checking program built from the change's own heads in the build seat's sandbox, which also makes the heads' one seat list that the check hands the manifest validator and the composer; it brings no seat definition and no manifest field, so the running checker checks it (ADR 0644; *The bootstrap delivery, and the one milestone after it*) | 26 needs it | mesh-sdk (`go/delivery`: the seat `node-build-go`'s ask `run` and the checker's record of which checking program judged; `go/composer`: the request's seat list), mesh-catalog (mesh-build-go: the run step, the refused answer, the kept programs' tools and sweep), mesh-delivery (checker: the checking program and its command), hq (this design, the glossary) | 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 trace's links (ADR 0656); the registry milestone's reviewed heads are joined to its group as members | 26 to 49 | 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-backup` holder, nats: a module's kept data on the bus as a backed-up item), the node-engine (`mesh-host`), hq | 1966 (with the registry milestone's heads), 1961, 1660, 1962, 1972, 1721, 1783, 1785, 1794, 1791, 1373 | | 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 trace's links (ADR 0656); no part reads a pull request's description (ADR 0659); every delivery part reaches the forge through the seat `git` and names no other module; nothing holds an approved merge for another check | 26 to 60 | mesh-sdk (the runtime: the fingerprint, the view, the definition reader, the seat list's one wiring), mesh-contracts and the domains' contracts modules (`acts`, the new verbs and events, the seat `mesh-grants`, the seat `git`'s verbs), mesh-delivery (indexer, assigner, checker, builder, grants part, gate's view, forge bridge, watchman), mesh-catalog (the gate, the build modules, the forge module, mesh-issues, mesh-knowledge, the `node-backup` holder, nats: a module's kept data on the bus as a backed-up item), the node-engine (`mesh-host`), hq | 1966, 1961 (retargeted to this row's shape), 1660, 1972, 1721, 1783, 1785, 1794, 1791, 1373, 595; 1962 goes back with 1958, whose assignment entry it needs (ADR 0641 §3) |
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 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 earlier row says so in words (the operator, 2026-10-26). Milestone M1 makes each row a record of the issue tracker
@@ -2456,10 +2927,10 @@ order inside one milestone, for this one case (ADR 0644).
the first seat G defines; a program built from the heads reads what the heads define. the first seat G defines; a program built from the heads reads what the heads define.
- **Where its types live.** B0 adds the ask `run`, its answer and the verdict's record of which checking program - **Where its types live.** B0 adds the ask `run`, its answer and the verdict's record of which checking program
judged it where the seats' types live on today's trunk, mesh-sdk's `go/delivery`, and the request's `seats` where the judged it where the seats' types live on today's trunk, mesh-sdk's `go/delivery`, and the request's `seats` where the
composer's request lives, mesh-sdk's `go/composer`. `mesh-delivery-contracts` and `mesh-delivery-sdk` are created by composer's request lives, mesh-sdk's `go/composer`. The registry milestone, merged after B0 and before milestone G,
the registry group, which joins milestone G (ADR 0634 §7, §8), so they exist on no trunk before G; G's merge carries made `mesh-delivery-contracts` and `mesh-delivery-sdk` (ADR 0634 §7, §8) and carried these types with `go/delivery`
these types with `go/delivery` into the seats' contracts in `mesh-delivery-contracts` (ADR 0634 §4) and the request into the seats' contracts in `mesh-delivery-contracts` (ADR 0634 §4) and the request with `composer` into
with `composer` into `mesh-delivery-sdk` (ADR 0635 §4), and mesh-sdk keeps no copy. The checking program, its rules `mesh-delivery-sdk` (ADR 0635 §4); mesh-sdk keeps no copy, and milestone G builds on them where they are. The checking program, its rules
and its command `mesh-checking-program` are the checker module's own package in mesh-delivery, and the run step is and its command `mesh-checking-program` are the checker module's own package in mesh-delivery, and the run step is
mesh-build-go's own (ADR 0634 §1). mesh-build-go's own (ADR 0634 §1).
- **The trunk's validator still judges inside a check.** The indexer's new manifest is also validated with the - **The trunk's validator still judges inside a check.** The indexer's new manifest is also validated with the
@@ -2494,8 +2965,7 @@ B0's own choices, each checked by the rows of *How it is checked* below:
checking program (ADR 0644, Consequences), and every check costs one more ask in the build seat, within the checking program (ADR 0644, Consequences), and every check costs one more ask in the build seat, within the
checker's step bound (ADR 0639 §5), the program built once per build and reused. checker's step bound (ADR 0639 §5), the program built once per build and reused.
- **Milestone G keeps the rest**: the first tier for every acting part, the verdict that fails by name, the revision - **Milestone G keeps the rest**: the first tier for every acting part, the verdict that fails by name, the revision
view, the two graphs, the difference, the acting rules, the delivery record and the trace's links, with the view, the two graphs, the difference, the acting rules, the delivery record and the trace's links. It is one milestone, one group and one check, its fixtures
registry milestone's reviewed heads joined to its group. It is one milestone, one group and one check, its fixtures
folded into the existing whole-module tests of the checker, the gate, the indexer and the assigner, and it ends with 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). 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 - **The order inside milestone G is the module graph's**, never a delivery ahead: each acting part's new version acts
@@ -2521,8 +2991,20 @@ B0's own choices, each checked by the rows of *How it is checked* below:
## What is not decided here ## What is not decided here
- Who may review a change, and the review verb's grant: issue 1782, outside milestone G; until it is built the review - Who may review a change, and the review verb's grant: issue 1782, outside milestone G; no part reads a review line
stays the line in a pull request's description (ADR 0496 §3). meanwhile, and the verb, if built, gates nothing (ADR 0659 §2, §3).
- **A session's merge of a recovery fix.** The operator asked that a session merge a recovery fix through a verb of
the seat `mesh-delivery`, recorded in the gate like any merge and said as an event, with no Approve (1921's note of
2026-11-07; the instruction the operator approved on 2026-11-09 says the session uses that verb once the seat serves
it). No record decides a merge without the operator's Approve: ADR 0421 §1 and ADR 0398 §3 ask it for every merge,
and the forge's merge tool merges only a head the operator approved (ADR 0534 §4). The shape this design would give
it, once a record decides it: the verb `merge` of the seat `mesh-delivery`, taking the pull requests at their heads
and the reason; callable only by the callers the gate's trusted config value `recovery-callers` names; refusing a
change that adds or widens an acting rule, a grant or a credential, which ADR 0656 §8 has named to the operator in
the Approve ask and which a recovery merge has none of; opening a delivery record marked `recovery` with the caller
as the runtime proves it; and saying the event `recovery-merged`, which the teller tells the operator on every
channel, so a recovery merge cannot go untold. It waits for its own record; until that record is accepted it is not
built, and a recovery fix is asked the operator's Approve like any change.
- What a process started by a node-engine that hands no fingerprint does beyond saying `own build unknown`, for a part - What a process started by a node-engine that hands no fingerprint does beyond saying `own build unknown`, for a part
other than the indexer. other than the indexer.
- The caps' and the growth's numbers are estimates (*Two graphs, one source of truth*); the fill tools read the real - The caps' and the growth's numbers are estimates (*Two graphs, one source of truth*); the fill tools read the real
@@ -2552,7 +3034,7 @@ and what answers it:
| tools | no fill read; the repair tool's path; the indexer's hand tool; the data set aside at a restore | fill in each read tool; `gate_record_repair` names each owner's verb; `indexer_recompute`; `backed-up` lists it and `discard-aside` removes it | | tools | no fill read; the repair tool's path; the indexer's hand tool; the data set aside at a restore | fill in each read tool; `gate_record_repair` names each owner's verb; `indexer_recompute`; `backed-up` lists it and `discard-aside` removes it |
| running qualities | storage that grows without limit; the build module's wait ended two ways; a checking program built per check; the wait clocks; a revert whose assigner starts before its indexer catches up | 90-day records, unpinned revisions removed, entries stored once, caps with `filling`, `full` and `room`; the agreed toolchain; one build per fingerprint; clocks from the build's end, composing per node; the ordering edges of a revert | | running qualities | storage that grows without limit; the build module's wait ended two ways; a checking program built per check; the wait clocks; a revert whose assigner starts before its indexer catches up | 90-day records, unpinned revisions removed, entries stored once, caps with `filling`, `full` and `room`; the agreed toolchain; one build per fingerprint; clocks from the build's end, composing per node; the ordering edges of a revert |
| testing | a revert test that needed a second check; the view with the assigner down | whole-module revert tests on the real builds from before milestone G; the assigner stopped and a cold control-node | | testing | a revert test that needed a second check; the view with the assigner down | whole-module revert tests on the real builds from before milestone G; the assigner stopped and a cold control-node |
| health and events | waits with no event or bound; a record that never ends; parts waiting for the view unreported; when a wait is first said | `wait-held` at the start with its bound, timed by the watchman; held and failed outcomes and `record-ended`; `view-waits` after five minutes | | health and events | waits with no event or bound; a record that never ends; parts waiting for the view unreported; when a wait is first said; a put that never ends | `wait-held` at the start with its bound, timed by the watchman; held and failed outcomes and `record-ended`; `view-waits` after five minutes; `put-stands`, timed by the watchman from the put's `wait-held` |
| security | a checking program hiding a removed rule; forged events; the `run` ask's grant; a kept build overwritten by the program it built; the review line retired before the review verb's grant | the running checker names every change of the checking program's fingerprint; the node in event subjects and grants per account; builds kept only from a step that runs nothing; the review verb left to issue 1782 | | security | a checking program hiding a removed rule; forged events; the `run` ask's grant; a kept build overwritten by the program it built; the review line retired before the review verb's grant | the running checker names every change of the checking program's fingerprint; the node in event subjects and grants per account; builds kept only from a step that runs nothing; the review verb left to issue 1782 |
| upgrade | a newer indexer never wanted after milestone G; a revert across a change of kept data's form | the stand-in catalog graph revision; restore points taken before a move across a `form` change, restored at a revert before the reverted build starts, the node-engine back last | | upgrade | a newer indexer never wanted after milestone G; a revert across a change of kept data's form | the stand-in catalog graph revision; restore points taken before a move across a `form` change, restored at a revert before the reverted build starts, the node-engine back last |
@@ -2566,6 +3048,29 @@ on the step key, the wording of a failed program's verdict as an exception until
verdict's program is built; each is now written as built, with its reason. The lead's rulings on that round then moved verdict's program is built; each is now written as built, with its reason. The lead's rulings on that round then moved
the input onto the checker's verb `input` (ADR 0596 §2) and the cycle rule into the checking program (ADR 0656 §5). the input onto the checker's verb `input` (ADR 0596 §2) and the cycle rule into the checking program (ADR 0656 §5).
The amendment for milestone G's prepare (2026-11-09) writes what that prepare found where the records and the code
or this design disagreed: the homes of `mesh-module-assigner` and `mesh-wants` after ADR 0641; ADR 0659's end of every
description read and ADR 0660's one rule for a seat's pass; the checker's and the forge bridge's reads of the gate's
state replaced (the trunk's heads from the catalog half, `owed` said as an event and answered by `groups`); the hold
and the merge turns removed by the operator's word, their record still to be written; a merge made at the forge taken
in and recorded; the indexer reading every definition at its start; the seat `mesh-grants` defined in its domain's
contracts module; the seat `git`'s verbs for every call the delivery parts make of the forge; the seat list's reader
wired once by the runtime; `go/views` as the view's machinery, with the seats' client packages typed over it; a check
that could not run asked again on the missing part's `running`; and a claim problem holding one module. Its review by
architectural domain then ran, four domains side by side, and lead-47 ruled on round 1 (2026-11-09): a seat's pass is
decided from the node-engine seat's `running` events kept by durable consumers, with the trunk's manifest for a node
that said nothing, instead of a call to a node that may be away; every act owed to the forge is safe to repeat, its
outcome said and recorded, unanswered acts said again and stalled after 15 minutes, a group's merges said one after
another, and the switch carrying what is owed; the seat `git` covers every forge call and event of the delivery parts
and the gate, its act verbs granted by the holder's trusted `callers`, the forge's acting tools and its watch of the
checker retired, and `merge-pull` judging no check, its record to be accepted before the push; the order forge, bridge,
gate with its way back, and the indexer's start without the forge; `module-held`, an error for a failed forge read and
the re-ask of a check that could not run; numbered tests 56 to 60; and the store seat's holder's own build. Round 3
takes in three findings of G's second prepare refresh, as lead-47 ruled (2026-11-09): every other module that read the
indexer's `modules` reads the catalog half in milestone G (*The revision view*, *Reverted*; test 61); a put without
hold ends itself on the node's `running`, built first in the issue 1966 recovery (*Compositions, wants and the apply*;
test 62); and ADR 0662, which decided the same switch as ADR 0661 another way, is withdrawn, so G builds ADR 0661.
Left as notes on issue 1921, not in this amendment: a conformance check that a changed layout raises its `form`; the Left as notes on issue 1921, not in this amendment: a conformance check that a changed layout raises its `form`; the
size and retention of restore points and set-aside data; who may call `restore` for bus data and which manifest grants size and retention of restore points and set-aside data; who may call `restore` for bus data and which manifest grants
the catch-up call; the hold's bound while a large backup is taken; the granting and placing bound read from the first the catch-up call; the hold's bound while a large backup is taken; the granting and placing bound read from the first