From da83f29f47378ff4836de855da7a4336d08df730 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 10 Nov 2026 20:22:23 +0100 Subject: [PATCH] Give milestone G its own part of design 47, and answer its builders' open questions there G's builders read a 443 KB design by searching it and filled what they did not find; playbook 02's shape gives each milestone a part read whole. G's lines move whole into 47-milestones/G.md, numbered as design lines, and the questions G's prepare and develop met within the records are written as the design's own choices (the operator, 2026-11-10: small design choices are the design's, only architectural ones are asked). The size bounds are bent for this split on the lead's word; research 087 takes them up. Claude-Session: https://claude.ai/code/session_01JG73KK8HD1gufnqyFxMFdW --- .../47-delivery-from-commit-to-delivered.md | 1811 +------------- 03-DESIGN/01-to-be/47-milestones/G.md | 2101 +++++++++++++++++ 2 files changed, 2120 insertions(+), 1792 deletions(-) create mode 100644 03-DESIGN/01-to-be/47-milestones/G.md diff --git a/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md b/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md index aba7df40..fd70539e 100644 --- a/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md +++ b/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md @@ -183,8 +183,14 @@ commit on a watched branch runs the module's pipeline steps (lint, tests, compos seat `mesh-pipeline-runner`; only a `required` step that did not pass holds a delivery; the order comes from edges between artifacts; and no Approve is asked per merge, a session merging a pull request through the seat `git`. The checker and its try go. Milestone G builds this with research 085's two graphs as one milestone, and until its -delivery the sections it replaces hold and check and deliver it (ADR 0667 §1, §2). *Pipelines per module*, below, -holds the whole of it. +delivery the sections it replaces hold and check and deliver it (ADR 0667 §1, §2). *Pipelines per module*, in +milestone G's part, holds the whole of it. + +**Every line milestone G builds is in its part,** [47-milestones/G.md](47-milestones/G.md), cited as "design 47 G +§n": the pipelines per module and the two graphs, the delivery record, the acting parts, the check on the change's own +acting parts, the kept data on the bus restored with a delivery, and the verbs and what retires at G's delivery. A +section this file names in italics and does not hold is there, under the same name. A sentence that holds a delivered +line and G's change together stays here. This is the delivery of [to-be 10](10-delivery.md) carried out. To-be 10 says what is built: the comparison of source and artifacts decides, and nothing here changes that. This design says who answers for one @@ -421,661 +427,6 @@ The target (ADR 0547): delivery (ADR 0666 §9, §11; *Pipelines per module*). The trunk is still what runs, on each module's watched branches, which a placement chooses. -## Pipelines per module - -*ADR 0666, ADR 0667; ADR 0595, ADR 0596, ADR 0448 §2, §4, ADR 0548 §5, ADR 0564 §2, §4, ADR 0283, ADR 0656 §4, §6, ADR 0633 §5, -ADR 0664 §4, ADR 0398 §2, ADR 0593 §9; research 086, Direction.* - -From milestone G's delivery. A change of any module, the delivery system's own parts included, goes from a commit to -the machines through that module's **pipeline**: the pipeline steps its **policy** names, run for each commit or group -on each of the module's **watched branches** by the seat `mesh-pipeline-runner`, ordered by the catalog graph's edges -between artifacts, with no hand act (ADR 0666 §1). Milestone G is the one milestone that builds it, beside the two -graphs, the revision view and the delivery record (ADR 0667 §1). Until G's delivery the sections this one replaces -(*Checks*, *A try*, *The Approve and the merge*, the state table and the trunk-only want) hold as written, and they -check and deliver milestone G itself (ADR 0667 §2); each of them says so in a line of its own. - -``` - a session ──merge-pull (seat git)──► forge ──commit on a watched branch──► forge bridge ──► indexer (mesh-catalog) - │ registrations; a catalog graph - │ per watched branch; the revision - │ validated before take-in - ▼ take-in.taken - pipeline runner (mesh-pipeline-runner) ── asks each pipeline step on the serving seat's work queue, hears step-ended: - │ lint, unit tests, integration tests ──► the build seats (node-build-go, node-build-node, node-build-image) - │ composition ──────────────────────────► the assigner (mesh-wants) - │ code review ──────────────────────────► the runner's own verb `review`, from the reviewer's bus account - │ approval ─────────────────────────────► operator-channel: accepted kind ask, then decided - ▼ pipeline-ended (every step's result), keyed by source revision - assigner ──► wants from a revision whose required steps passed, on the watched branch a placement chose - gate ──► the delivery record keeps the step and pipeline events -``` - -### A module's registration - -- **What it holds.** The seat `mesh-catalog` keeps each module's **registration**: its git origin, the path of its - manifest, its watched branches and its policy, on the bus, every version with who changed it and the warrant of the - operator's Approve (ADR 0666 §2). The indexer is a foundation part, so the registrations are kept in its old sections - (ADR 0619 §1 to §3, ADR 0666 §4): one key per module in its old `state` section `registrations`, and every version on - its old `streams` section's stream `registration-history`, kept with no age limit. - The catalog graph is derived from the registrations and the manifests they point to; the mesh knows modules, and a - repository only as a module's git origin. -- **Changing one is a trusted act.** The seat's verbs `register` (a module whole), `policy` (one module's step - statuses, per artifact), `watch` and `unwatch` (add or remove a watched branch) each raise an authorising ask of tier - approve through the seat `operator-channel` (design 46 §10), naming every value the change moves, one line each - ("`mesh-grants:program` unit tests: `required` → `bypass`"), and write the version only on its warrant; a Decline or - an expiry writes nothing (ADR 0666 §2). Until a record binds each forge account to its bus identity, `register` and - `policy` refuse code review as a `required` step, naming why, so no review gates while its author cannot be told - (ADR 0666 §22; issue 1966, note 157). A manifest moved to another path is the one manifest change that changes the - registration; any other manifest change is a commit, judged at its revision. -- **Said and read.** Each written change is said as the seat's event `registration-changed` (the module, the version, - what moved); the verb `registrations` answers every registration, or one with its history. The indexer derives the - modules it keeps from them, and the forge bridge its watched branches, each by a first view of `registrations` and - then that event, never by reading the ledger (ADR 0666 §3, ADR 0596). -- **An unprotected branch is refused.** `register` and `watch` read a branch's protection through the seat `git`'s read - verb `branch` (its head, and whether a rule refuses a direct push and admits only merges), and refuse a watched branch - the forge does not protect, naming it (ADR 0666 §3). -- **The foundation parts are the manifest validator's list.** The manifest validator's list (ADR 0619 §3) holds - exactly the foundation parts, ADR 0619 §1's and the runner, which joins them (ADR 0666 §4); the checker leaves the - list when it is removed (*How milestone G itself is checked and delivered*). A registration holds no foundation - value. How it is checked: a unit test of the manifest validator refuses a template in the manifest of every part on - its list, the runner's included, and judges every other part's manifest as any part's. -- **No part fixes a name.** Every branch, repository and module name a part needs is read from the registrations and the - catalog graph; the lint step refuses such a name in a string, a constant or a table of code logic, a Go import path - not being code logic (ADR 0666 §5). About 39 such names in 9 parts were found on 2026-11-09 (research 086, Findings); - milestone G removes them. -- **The first registrations are one ask.** At its first start on G's build the indexer, holding no registration, - proposes one registration for every module its trunk revision holds, from what it took in (the origin and path of - each), its watched branch the repository's default branch read through the seat `git`, and the statuses the check - judged until then: lint, unit tests, integration tests and composition `required`, code review `optional`, approval - `bypass`; it raises them as one ask naming every registration, as the seat `mesh-module-assigner`'s `adopt` proposes - placement whole (ADR 0567). Until that Approve the runner starts no delivering pipeline and says why, so the - operator is told of this one ask before G's delivery starts. A Decline or an expiry leaves the seed unwritten and - says so; the indexer's tool `indexer_seed_again` raises the ask again, recorded in the hand-act log. -- **Kept for the life of the mesh**, never derived again (research 086, choice 25): the history stream's cap is 64 MiB. - About 120 registrations of about 1 KiB, and an estimated change a week each (a guess, not a measure), grow about 6 MiB - a year, so the cap holds about ten years; past 80 % the indexer says `filling`, as every store of *Two graphs, one - source of truth* does. -- **How it is checked.** Whole (indexer): an unprotected watched branch is refused, naming it; a policy change without - the warrant writes nothing, and a declined one writes nothing; a change from `required` to `bypass` asks, showing - that line; `registration-changed` is said and `registrations` answers the history; the first start proposes the seed - as one ask, and `indexer_seed_again` asks it again after a Decline and after an expiry; a policy making code review - `required` is refused. Unit (the Go build module's lint step): a module name in a string, a constant and a table is - refused, an import path is not. Tests 75, 68 and 83. - -### Watched branches and the catalog graph per branch - -- **Only a watched branch starts a pipeline.** The forge bridge hears every commit of every watched branch the - registrations name, through the seat `git`'s event `branch-moved` (a branch's new head, from the forge's push - webhook, which a merge and an admitted push alike say), and takes the commit from the forge's own record by the seat's - verb `branch`, never from the event's body (ADR 0666 §6). One event for every way a branch moves, because a merge is - not the only one. `branch-moved` is kept on the seat's stream `SEAT_git_branch-moved`, which the bridge hears through - a durable consumer, so a move said while the bridge is down is heard when it starts; at its start it also reads each - watched branch's head the same way. -- **A head with no pipeline is a finding.** A watched branch's head that starts no pipeline within five minutes is the - watchman's finding `pipeline-stands`, naming the branch and its head, raised by the condition keeper (ADR 0564 §2), - unless it waits as progress not owed: a member of a gathered group is governed by ADR 0633 §5's 30-minute bound, and - a merge behind a pending revision of the same branch by its 60-minute bound (ADR 0666 §24). The finding clears on the - runner's `pipeline-started` for that head. -- **The catalog graph per watched branch.** The indexer keeps the catalog graph once per watched branch, from that - branch's manifests at each source revision (ADR 0666 §6): each revision names its branch, and the stores, caps and - pins of *Two graphs, one source of truth* hold per branch. -- **A placement names the branch.** Each module of a placement key names the watched branch its node runs, by default the - registration's first, set by a placement proposal like every other placement change (ADR 0567, ADR 0666 §6). The - assigner computes each node's entries from the catalog graph of the branch its placement names, so a module watched on - `main` and `beta` runs `beta` only where a placement chose it. -- **A source revision per watched branch.** The gate keeps one source revision per watched branch, `source.`, - in place of `source.main` (ADR 0429 §11 to §13 as ADR 0666 §6 changes them), in the old `state` section `source` - already holds, its key's layout being the only change. The gate is no foundation part: the bus module's delivery - waits on no act of the gate's, since the indexer takes a revision in from the forge bridge's stream and the assigner - writes wants from the runner's events, so the gate's other kept data stay in ADR 0595's templates (ADR 0666 §4), and serves it by the seat - `mesh-delivery`'s verb `source` with the branch, saying `source-moved` on each new revision; the indexer and the - node-engine's catch-up read it there, never the gate's state (ADR 0596). Each want names a build-input fingerprint - computed at one such revision. -- **Validated before any take-in, on every branch.** Before it takes a revision in, on every watched branch, the running - indexer asks the manifest validator built from the revision's heads to judge it in the build seat's sandbox (the - ask `run`, *What ADR 0656 leaves to this design*). A revision it refuses stays pending under ADR 0633 §5's - 60-minute bound, its hand acts and its condition `take-in-waits`; the way back is a revert, an ordinary merge - (ADR 0666 §6, §26). A revision on the branch the indexer's own placement chose is taken in only by the indexer it - names (ADR 0633 §1). This validation is no pipeline step and waits on no pipeline, so every delivering pipeline runs - on a revision already taken in. -- **A branch whose protection was removed starts nothing.** On every `branch-moved` the forge bridge reads the - branch's protection again; a move of a watched branch whose protection was removed starts no delivering pipeline, and - the forge bridge writes the finding `branch-unprotected`, naming the branch, which the condition keeper raises and - clears once the protection is back (ADR 0666 §6). -- **A pending revision holds its own branch only.** A merge waits behind a pending revision only on the same watched - branch; other branches move on (ADR 0666 §6, which changes ADR 0633 §3). -- **A refused new indexer holds its branch until a revert lands.** A merge of a new indexer whose own validator refuses - its revision has already landed when it is refused, since the validation runs before take-in and after the merge - (ADR 0666 §6). It stays pending, and every later merge on that watched branch waits behind it, said by - `take-in-waits` at the 60-minute bound, until a revert, an ordinary merge through its pipeline (ADR 0666 §26), lands - and is taken in; nothing takes a later merge in past it. This is the cost of validating every revision with the - validator built from its own heads, the design's reading of ADR 0666 §6, and the operator is told it with the - condition, which names the pending revision and the revert as the way on. -- **How it is checked.** Whole (forge bridge): a commit of a branch no registration names starts nothing; a commit on a - watched branch is taken from the seat's `branch` read, not the event; a head missed while the bridge was stopped is - read at its start. Whole (indexer, assigner): a commit on `beta` gives a revision of the `beta` graph only and moves - only the want of the node whose placement chose `beta`; a revision whose own validator refuses it stays pending and - holds `beta` while `main` moves on. Whole (watchman): a head with no pipeline for five minutes raises - `pipeline-stands`, cleared by `pipeline-started` for that head, and a gathered member does not; a move said while the - bridge was stopped is heard from the seat's stream. Tests 64, 68, 76, 78 and 82. - -### Pipeline steps and the policy - -- **The runner.** The seat `mesh-pipeline-runner`, held once for the mesh by the module `mesh-delivery-pipeline`, - runs each pipeline (ADR 0666 §7). It is a foundation part, since the bus module's own delivery waits on its pipeline - (ADR 0666 §4): its kept data are in old sections (ADR 0619 §2), it waits on no bus module process to start, and it - joins the manifest validator's list of foundation parts, which refuses its manifest asking a template (ADR 0666 §4, - which changes ADR 0619 §1 and §3). It reads the policy from the registrations, asks each step that is not `bypass` of - the seat that serves it, and says each step's start and end and the pipeline's end (*Health and going back*, below). -- **The steps and who serves them.** Lint, unit tests and integration tests are the build seats' (`node-build-go`, - `node-build-node`, `node-build-image`): each gains the verb `steps`, which answers which pipeline steps an artifact - can run by its language's convention (as *The check from release 4* says the tests are found), and the accepted kind - `step` on its stream `check`, which runs one. Composition is the assigner's, an accepted kind `step` of the seat - `mesh-wants`. Code review comes in through the runner's own verb `review`. Approval is asked as the seat - `operator-channel`'s accepted kind `ask`, on its work queue by the runner's name (design 46 §10, *Asks, warrants and answers on the bus*; - the seat has no verb `ask`), and heard on its event `decided` (ADR 0666 §7, §10). A step with nothing to do ends at once as - `nothing to run`, never as passed. -- **The policy.** Each step's status, per module and per artifact, is `required` (runs; holds the delivery until it - passes), `optional` (runs; a failure is shown and may be accepted) or `bypass` (nothing runs; said as bypassed), - kept in the registration and never in a manifest: the manifest validator refuses a manifest that names a status - (ADR 0666 §7; research 086, R3). A `required` step that ends `nothing to run` holds the delivery and names the step. -- **Asked on a work queue, ended by an event.** The runner asks each step on the serving seat's work queue and hears - its end as that seat's event `step-ended` (the record's `step ended`), on - `mesh.seat..event.step-ended.`, the node that ran it in the subject and each holder's account granted only - its own node's subject, through a durable consumer of its own, so a step outlives a restart of either side (ADR 0666 - §7, ADR 0363 §2). A build seat's holder restarted mid-step gets the step again from its work queue and finishes it - (ADR 0664 §1). A unit or integration test step says its test counts in `step-ended`, and `pipeline-ended` names any - repository over 50 integration or 500 unit tests, and any catalog module over them (ADR 0666 §8; the test budget). A step's outcome is one of `passed`, `failed`, `nothing to run`, - `bypassed`, `carried` (with the pipeline it was carried from), `could not run` (naming the part not heard), - `waiting on `, `accepted` (a failed `optional` step a person accepted, with who and why), `superseded` and - `cancelled`. -- **Carried, not run.** A step whose build-input fingerprint and policy did not change is carried by its package - digests, as ADR 0548 §5 holds, the runner making the carry instead of the checker: a test step runs only the packages - with no kept result for their digest, and a run on request's results are reused when the merged commit's inputs match - (ADR 0666 §8; research 086, choice 24). An `approval` step is never carried. -- **Approval comes last.** The runner asks the `approval` step only once every other `required` step of the pipeline - passed, so the operator approves a commit the mesh already judged, the one place ADR 0661 §3 had the check gate the - ask. A failure after an approval is said, as a failed `optional` step is, and the approval stays. -- **Kept on the bus, in old sections.** The runner keeps each pipeline's state in its old `state` section `pipelines`, - one key per pipeline keyed by its watched branch, source revision and module, written by compare-and-set so a holder - replaced mid-pipeline and its successor never both write one; its step log on its old `streams` section's stream - `step-log`; each step's output in its old `objects` section `step-outputs`, named in the log; and each package's - passing result per level in its old `state` section `kept`, under the digest of what its tests read (ADR 0666 §4, §8; - *The runner's kept data*, below). At its first start it takes the checker's kept verdicts into `kept`, read by the - checker's tool `checker_kept`, so the first pipelines after G carry what the checker had judged. -- **How it is checked.** Whole (runner): a step with unchanged fingerprint and policy is carried and says from where, - and an `approval` step is not; a module with no integration tests shows `nothing to run`, and a `required` unit-test - step on a module with no tests holds its delivery; a bypassed step is said; a runner restarted mid-step hears the - step's end and finishes the pipeline; two runners writing one pipeline key, one loses by compare-and-set; a test step's - counts are in `step-ended` and a repository over budget is named in `pipeline-ended`. Whole (Go build module): `steps` - answers the steps of a fixture artifact, a `step` ask ends with `step-ended` on its own node's subject, one on another - node's subject is refused by the bus, and a build module restarted mid-step finishes it. Unit (manifest validator): a manifest naming a status is refused. Tests 65, 66, 73 - and 88. - -### What holds a delivery - -- **The assigner writes a want only from a passed pipeline.** The runner says each pipeline's end as `pipeline-ended` - (the record's `pipeline ended`), keyed by source revision, with every step's result. The assigner consumes it, and - writes a want only from a source revision whose every `required` step passed for the modules it moves, on the watched - branch a placement chose, by compare-and-set on a newer revision, so an older revision ending after a newer one - writes nothing (ADR 0666 §9). The compare-and-set is keyed per module and watched branch: it compares a revision only - with the last one written for the same module on the same watched branch, so a revision of `beta` ending after a - newer one of `main` writes its own want and refuses neither (the design's choice under ADR 0666 §9: source - revisions are kept per watched branch, `source.`, and two branches' revisions have no order between them). This is one more rule beside the assigner's others (ADR 0429 §6), checked per module. - From G's delivery it replaces the trunk-only want (ADR 0656 §2 as ADR 0666 §9 changes it). For a group's source - revision the runner says one `group-ended` once every member's modules have ended, and the assigner writes the - group's wants only on it: a member's own `pipeline-ended` writes nothing (ADR 0666 §9). -- **A failed `optional` step holds nothing.** It is shown in `pipeline-ended`, in the delivery record and in the runner's - `show`; a person may accept it by the runner's verb `accept`, recorded in the hand-act log with who and why. -- **A newer commit supersedes an older pipeline of a module whose fingerprint it changed.** On a newer commit of the - same watched branch the runner ends a module's older running pipeline as `superseded` only when the newer commit - changed that module's build-input fingerprint (ADR 0666 §9); a module the commit leaves as it was finishes its - pipeline. A newer publish of a package likewise supersedes the rebuild pipelines an older publish of it started. A - superseded pipeline's waiting asks are dropped by each build seat's `drop` (ADR 0664 §4), naming - the newer commit as the cause, so a cancelled pipeline leaves no ask on a stream (a gap G's prepare found: a cancelled - build withdrew only the builder's wait). -- **A step nothing starts ends its pipeline.** A step whose prerequisite nothing starts (a seat with no holder, a - prerequisite step `bypass`) ends the pipeline refused within five minutes, naming the step and what it waits for, - never as a silent wait (research 086, R5); a step whose seat has no holder ends its pipeline failed, naming the seat - (ADR 0666 §17). -- **A failed head is said to its author, then to the operator.** A `required` step that failed, or ended `could not - run`, on a watched branch's head is the runner's finding `pipeline-failed`, naming the module, the branch, the commit - and the step; the condition keeper raises it as the commit's author's for two hours and then the operator's, as ADR - 0505 §5 and §6 have a delivery whose cure is its author's new head, and clears it when a newer revision of that branch - passes that step (ADR 0666 §24). The author is the forge's record of the commit, read through the seat `git`. -- **The delivery record keeps every step.** The gate's delivery record consumes the step and pipeline events and keeps - them as long as the record (ADR 0666 §9; *The delivery record*). -- **How it is checked.** Whole (assigner): a failed `required` step writes no want; a failed `optional` step holds - nothing; an older revision's `pipeline-ended` after a newer one's writes nothing, and a revision of one watched branch - ending after a newer one of another writes its own want; a group with one member passed and - another still running writes no want until `group-ended`. Whole (runner): a newer commit that changed a module's - fingerprint supersedes its older pipeline and drops its asks, and one that left it unchanged lets it finish; a step - with no holder ends the pipeline naming the seat within five minutes; a failed `required` step on a head raises - `pipeline-failed`, the author's for two hours and then the operator's, cleared by a newer passing revision. Tests 66, - 67, 87, 89 and 98. - -### Approval is a step, and a session merges a pull request - -- **No Approve per merge.** The operator's approval is the pipeline step `approval`, its status in each module's policy; - no Approve is asked per merge, and the delivery gate's merge turns and its Approve per merge go (ADR 0666 §10, which - changes ADR 0661 §3 to §5). The operator is asked only where a module's policy says `approval`, and for registrations - and policy changes. -- **The approval is an ask of the runner's.** The runner raises an authorising ask of tier approve as the seat - `operator-channel`'s accepted kind `ask`, under its own name, its `about` the module and the watched branch only, so a newer commit's ask - replaces the older one's (design 46 §10). The warrant ends the step passed; an ask that is declined, expires or is - refused ends it `declined`, and one that is replaced ends it `superseded`. Only a declined `approval` step is asked - again, by the runner's verb `ask-again` (ADR 0666 §10). While it waits the runner - says `wait-held` waiting on the operator, never a stall (ADR 0283). -- **A session merges a pull request.** Any session the tool runner proves, and the operator, merges by calling the seat - `git`'s verb `merge-pull` over the mesh, which merges with the forge tools' account (ADR 0398 §2) at the head the - caller names. It judges that this is still the pull request's head and that the branch's protection refuses a direct - push, the protection read again on every `branch-moved` of the branch, and it judges the head's runs by its modules' - policies: it refuses a head when any run at its build-input fingerprint failed a step a policy marks `required`, and - merges a head whose `required` steps passed or that has no run yet, a failed `optional` or a `bypass` step refusing - nothing; it never waits for a run and never asks an Approve (ADR 0666 §11). The forge keeps only its branch protection. -- **Judged from its own state, never by a call.** The holder of the seat `git` consumes the runner's `step-ended` - through a durable consumer of its own and keeps, in its own state `failed-steps`, each failed `required` step by - module and build-input fingerprint, with the commits it was seen at and the run that failed it, until none of those - commits is a watched branch's head or the head an open pull request names (*The runner's kept data*); so a head - merges while the runner is down, judged on what it already heard (ADR 0666 §11, ADR 0596). A head's fingerprints are - those its runs named for its commit; a step that failed at that fingerprint in any run, a group's or another commit's - of the same content included, refuses it, unless a later run of that same step at that fingerprint, asked again by - the operator or the healers (the runner's `rerun`), passed: that pass clears the failure from `failed-steps` (ADR 0666 - §11). The runner's `step-ended` says that the step was a rerun and the caller the runtime proved, and the forge module - clears a failure only for a rerun whose caller is the operator or a healer; a plain pass, or a rerun asked by anyone - else, clears nothing. A run still running is judged by the steps it has ended, since the merge never waits. A refusal names the run, the module and the step, so the session knows what to fix. The gate merges nothing, and its forge merge token is - removed with the checker's buckets and bus account, after the first pipeline after G's delivery has delivered a change - end to end and on the operator's word (ADR 0667 §12; *How milestone G itself is checked and delivered*); the forge bridge hears the landed commit as it hears every commit of a watched - branch. -- **The operator-channel hides no ask.** It keeps design 46's three open asks per asker, never holds the newest back, - and replaces an open ask by the same asker's ask with the same `about` (ADR 0666 §12; design 46 §6). -- **How it is checked.** Whole (forge module, forge bridge): a session's `merge-pull` at its head merges with no run yet, - and with a passed one, and asks no Approve; with the runner stopped a head merges; a head at whose fingerprint any - run failed a `required` step, a head that moved and a branch whose protection was removed since its last move are - refused, each naming why; a failed `optional` step refuses nothing. Whole (runner): an `approval` step is asked last, - a Decline and an expiry each end it `declined` and `ask-again` asks it once more, and a newer commit's ask replaces the - older and ends its step `superseded`. - Live: a declined approval and a fourth ask each reach the operator. Tests 71 and 91. - -### Groups - -- **Formed from the branch name.** The gate forms a group from a shared branch name carrying its issue number, as it - does today without the fixed list of trunk names (ADR 0666 §13). -- **A member reaches its group by landing.** A member has reached its group when its commit lands on its modules' - watched branch. The forge bridge sets the group on each landed member's commit, reading the members from the seat - `mesh-delivery`'s verb `groups`, and publishes `forge.group.merged` when that verb says every member has (ADR 0666 §13, - which changes ADR 0633 §4). -- **One source revision, one pipeline per branch.** The indexer keeps landed members pending until the group's end and - takes them in together as one source revision of that watched branch, saying `take-in.taken`; the runner starts the - group's one pipeline per watched branch on that event, and a member of a gathered group starts no pipeline of its own - (ADR 0666 §13). - When one member's `required` step fails, none of the group's modules is delivered (research 086, R5). -- **A group that never completes is said.** By ADR 0633 §5's 30-minute bound and its condition; `bridge_group_end_again` - says a group's end again from the gate's group verb, never the gate's `merges` state (ADR 0666 §13, which changes ADR - 0633 §5). -- **How it is checked.** Whole (indexer, gate, forge bridge): a group of three repositories, its own packages included, - is one source revision and one pipeline; one member's failed `required` step delivers none; a group with a member that - never lands raises `take-in-waits` at 30 minutes. Tests 67 and 81. - -### Dependencies between artifacts - -- **Six kinds of edge between artifact references.** The catalog graph's edges run between **artifact references**, - `:`, such as `mesh-grants:program`, of six kinds (ADR 0666 §14): - - | Kind | B before A | Derived from | - |---|---|---| - | 1 | B published before A builds | a package A's build source imports (ADR 0573 §3) | - | 2 | B published before A delivers | an artifact A's manifest fetches by reference at its start | - | 3 | B delivered before A builds | a build module A is built by, and the toolchain its agreed version names (ADR 0584 §1) | - | 4 | B delivered before A delivers | a provision A requires and B provides, bus state among them (ADR 0614 §5), and a format's reader (below) | - | 5 | B has acted for A's new version | a seat's acting rule (*What ADR 0656 leaves to this design*): a grant, a credential, a verdict, bus state | - | 6 | B runs a version that serves A | a verb or a manifest word A uses and B serves or reads (ADR 0614 §2, §4), the build seats' `kept-artifact` among them | - - Each kind is derived from what manifests and seat definitions already say, and declared per artifact in the manifest's - artifact entry, its field `needs`, only where nothing else says it. Today's edges run between modules, and only a - package edge names an artifact; at module level the tool runner and the grants part looked like a cycle, per artifact - they are a chain (`mesh-grants:program`, then `node-tools:runtime`, then `mesh-grants:tools`). -- **Removal runs the other way.** When something goes away the order is reversed: a seat moved to a new holder has its - old holder released before the new one claims (ADR 0666 §14). -- **The edges alone order.** The build and the delivery order by these edges alone; a cycle of delivery edges (kinds 2, - 4, 5, 6) is delivered as one step, and a cycle of build edges (kinds 1 and 3) is refused, naming every artifact on it - (ADR 0666 §14; research 086, R17). The cycle rule is the indexer's, in the catalog graph it keeps, so the checking - program's cycle rule goes with the checker. -- **A format's reader first.** A format a running reader cannot read is preceded by its reader, an edge of kind 4 on - every watched branch (ADR 0666 §14): the indexer's manifest validator for a new field of a seat definition or a - manifest, and on each node the node-engine that reads a manifest's new fields before any manifest that writes them - (ADR 0667 §4). -- **How it is checked.** Unit (indexer's graph): a chain per artifact where modules would cycle; two programs needing - each other's new verb are one step; two artifacts each needing the other's new package to build are refused, naming - both; a seat moved to a new holder releases the old first. Live: the tool runner and the grants part delivered in - the order `mesh-grants:program`, `node-tools:runtime`, `mesh-grants:tools`. Test 79. - -### A publish rebuilds - -- **Numbered at publication.** The builder numbers a package's version when it is published, never only when a build - is claimed, and says the publication as the event `package-published` of its seat `mesh-builds` (ADR 0666 §15; design - 51, *The versions*). The seat is new, held once for the mesh, defined in `mesh-delivery-contracts`; the builder held - none until now, and its waits stay on its own stream in this milestone. -- **Every dependent is rebuilt against it.** On `package-published` every artifact with a kind-1 edge to the package is - rebuilt against the new version, and the runner, which consumes the event, starts its pipeline; nothing else is - rebuilt, and a change to tests alone publishes nothing (ADR 0666 §15; research 086, R18). -- **A second start writes nothing.** The runner starts a pipeline on two events, the indexer's `take-in.taken` (ADR - 0666 §13) and `package-published` (ADR 0666 §15). When both reach it for the same source revision and module, the - second start writes nothing: the runner writes a pipeline's key (watched branch, source revision and module, *The - runner's kept data*) by compare-and-set on its absence, so one revision and module has one pipeline. The design's - choice under ADR 0666 §13 and §15: the key the runner already keeps is the one place a start is judged, so neither - event's producer needs to know of the other. -- **Unread packages refuse.** A build that cannot read the published packages refuses and names the unread state - (ADR 0666 §15). -- **How it is checked.** Whole (builder, indexer): a mesh-sdk merge changing one package publishes one version, and only - the artifacts importing that package rebuild; a merge changing only tests rebuilds nothing; a build whose packages - cannot be read refuses naming the state. Whole (runner): a `take-in.taken` and a `package-published` for the same - source revision and module start one pipeline, the second writing nothing. Tests 70, 80 and 101. - -### Any size - -- **A value over the limit is an object.** mesh-sdk's own small object store package (ADR 0595 §9) puts a value over - the bus's per-value limit in the object store beside its state and keeps the object's name in the key; a verb's reply or an event over the - per-message limit carries the object's name (ADR 0666 §16). A replace writes the new object and sets the key by - compare-and-set; the object it replaced stays, as one whose key was deleted does, listed as `key gone` since no key - names it, and only the drop tool removes either, on a person's word: the mesh removes kept data only through `drop` - and `recreate`, each on a person's word (ADR 0595 §4; ADR 0666 §16). -- **One object store per state, granted to its owner.** Each state asked by the template `state` gets its object store - beside it, `-objects`, a template form of ADR 0595 that the bus module provides and the grants part grants to - the state's owner alone (ADR 0666 §16); a foundation part's large values go in an old `objects` section of its own. - Its size is the template's (ADR 0595 §3). An object store holds no space until a value is written to it, so the many - it adds reserve nothing; the few values over the limit (a delivery record, a catalog graph revision list, a test's - output) are estimated, as a guess, at under 1 GiB across the mesh. -- **An object sent is readable by the modules it is for.** A reply's or an event's object is written to the sender's - **sent store**, `_sent-objects`: the bus module plans it, with no manifest field, for every module of the new - form that serves a verb or emits an event, and a foundation part declares it as an old `objects` section - `sent-objects` (ADR 0619 §2). Its cap is the objects template's (ADR 0595 §3), and it keeps an object 7 days, after - which the bus expires it. That age is transport, not kept data: an object sent exists only to carry one reply or one - event, read within its call's bound or its consumer's lag, so its expiry is not a removal of kept data that ADR 0595 - §4 holds to a person's word (the design's choice; 7 days is a guess at the longest a consumer lags, read from the - fill tools once G runs). A full sent store is the bus module's `full` and its condition (ADR 0595 §6), and the sender - then refuses the large reply or event loudly, naming the store. The grants part derives from the manifests a standing grant to read them: the - callers its seat definition names for the verbs it serves, and the consumers whose `consumes` declare its events; - no other module may read them (ADR 0666 §16). The grant follows the manifests, so it is written when they change, - never per object. A consumer's reader of - the form is delivered before its producer writes it, an edge of kind 4. -- **Its tools come with the package.** The package serves each module that imports it `_state_objects` (the - objects of each state, with their size, the key that names each or `key gone`, and the fill against its cap), - `_state_objects_drop` (drop the objects whose key is gone, on a person's word as ADR 0595 §4 removes kept - data), `_sent_objects` (each sent object, its size, when it was sent and to which verb or event, its age - against the store's and the fill against its cap) and `_sent_objects_drop` (drop sent objects older than an - age a person names); each drop names who asked and is recorded in the hand-act log. -- **Its cost.** Only the modules that import the package are built with it, so no other module is rebuilt for it: a - package published before its users build (ADR 0573 §2, ADR 0667 §3). -- **How it is checked.** Whole (mesh-sdk, against the real bus): values of one, ten and a hundred times the per-value - limit stored, sent as a reply and as an event, and read back whole by a caller and a consumer the manifests declare, - and refused to a module that declares neither; a replaced large value leaves its old object listed `key gone` beside - the new one, and a key deleted leaves its object listed `key gone`, each removed by the drop tool and by nothing else; - a sent object is readable within its 7 - days and expired after; each drop without who asked is refused. Tests 69 and 90. - -### The pipeline makes the check, and the checker goes - -- **Every step runs on parts built from the change.** Every pipeline step that runs a change's code runs on parts built - from the change's own heads, in the build seat's sandbox, with no network and no bus account (ADR 0666 §17, ADR 0448 - §2, §4): the composition step composes each machine's declaration with the composer built from the heads and refuses - a change in which two modules own one path; the build seats' steps run lint and tests. A step whose serving part the - change alters runs from the change's build of it, built within 20 minutes or ending `waiting for a build node` or - `did not build`, the first tier of *The check on the change's own acting parts* made the runner's. -- **The run on request.** The runner's verb `run` takes one or more members, each a module at a named commit, runs them - through their pipelines and delivers nothing, replacing the checker's try (ADR 0666 §18). Its callers are the - sessions, as the agents' bus identities the tool runner proves, and the operator, and nothing else, since a run of a - group builds and publishes its packages' tagged versions (design 51). The runner says `run-started`, the indexer builds - the run's candidate from it, and the candidate's composition step writes no want (ADR 0656 §9); the candidate is - dropped on that run's `pipeline-ended`. A step that could not run ends `could not run`, never as passed. A - composition step for a node that sleeps passes it with a warning (ADR 0593 §9). -- **The runner is an acting part in the checker's place.** The acting rule's step `check` becomes the runner's step - `pipeline` (*What ADR 0656 leaves to this design*): its own change runs on its own new version, a failing new runner - holds while the old one runs pipelines (ADR 0656 §4), and the pipelines in flight when its holder is replaced are - taken up again from its kept state (ADR 0666 §19). -- **What the checker did, and where it goes.** - - | The checker's | From G's delivery | - |---|---| - | the merge check, one status `mesh/check` | the pipeline, its result in `pipeline-ended`, the runner's `show` and the delivery record; no status on the forge | - | the try | the run on request | - | the composition check | the composition step, the assigner's | - | the kept verdicts and the carry | the runner's `kept`, taken from the checker's at the runner's first start, and its carry (ADR 0548 §5) | - | the checking program: the manifest validator at the heads, the cycle rule, the composer, the rule names | the indexer's validation before take-in; the indexer's cycle rule; the composition step; `widens` in the pipeline's end | - | the `run` ask, published by the checker's account | published by the runner's account and the indexer's (its validation), each with step keys under its own name | - | its buckets and bus account | removed with the gate's forge merge token after the first pipeline after G's delivery has delivered a change end to end, on the operator's one word, the buckets through `drop` after its snapshot, whose restore is tested first (ADR 0667 §12) | - -- **How it is checked.** Whole (runner, assigner): a run on request of `feature/1966-x` delivers nothing, and a call of - `run` from another account is refused; a composition step refuses two modules owning one path; a step whose part - cannot be heard ends `could not run`; a node asleep passes with a warning; a runner stopped mid-step takes its - pipelines up again. Live: once the checker is removed no module claims the seat `mesh-delivery-checker`. Tests 64, - 84 and 88. - -### Who may say what - -- **Callers per verb, in the seat's definition.** Each seat definition names, per verb, the callers allowed to call it, - in its field `callers` (holder roles, modules, the operator, the healers), which the grants part reads as its one - source of caller limits; the runner's verbs are the first (ADR 0666 §20). A verb whose definition names no `callers` - admits only the seat's holder roles and the operator, so a field left out opens nothing. It replaces the holder's - trusted config value `callers` of the seat `git` and the package seats (design 51), which no holder set for most - verbs. A format its running reader cannot read, so its reader is delivered first (ADR 0667 §4). -- **A step's result from its holder only.** The runner takes a step's result only from the bus account of that step's - seat holder, naming the commit and the build-input fingerprint; a result from another account, or naming another - commit or fingerprint, is refused and said (ADR 0666 §21). -- **A review gates, once it can.** A code review's result is taken through the verb `review` from the reviewer's bus - account and refused from the commit's author, so a review gates where a policy says `required` (ADR 0666 §22, which - changes ADR 0659 §2). Until a record binds each forge account to its bus identity no policy may say it (*A module's - registration*; issue 1966, note 157). -- **A widening is said, never refused.** A change that alters any part serving a step (the runner, step detection, the - lint rule, a build seat's test runner, the composer), or widens an acting rule, a grant or a credential, says so in - its `pipeline-ended`, its field `widens` naming each. The running runner computes it, from the sources of the change - against those of the watched branch, never the runner built from the change, so a change cannot hide its own - widening; nothing refuses it for that (ADR 0666 §23, the operator, 2026-11-10). The teller passes `widens` on to every - channel, as it does `recovery-merged`. This is what replaces ADR 0656 §8's naming in the Approve ask. -- **How it is checked.** Whole (runner, grants part): a forged step result and an author's own review are refused; a - caller not in a verb's `callers`, and any caller but the holder roles and the operator of a verb with no `callers`, - are refused by the bus; a change widening a grant, and one altering the Go build module's test runner, each name it in - `widens`, computed by the running runner, and are delivered. Tests 85 and 86. - -### Health and going back - -- **The runner's events.** Each on `mesh.seat.mesh-pipeline-runner.event....`, - a branch or group name escaped as a key's name is, declared in the seat's definition and published by the runner's - account alone (ADR 0666 §24, ADR 0363 §2): - - | Event | Says | - |---|---| - | `pipeline-started`, `pipeline-ended` | a pipeline's start, and its end with every step's result, its test counts, the source revision and `widens` | - | `group-ended` | a group's one pipeline's end, on which alone its wants are written | - | `run-started` | a run on request's start, with its members at their commits | - | `step-started`, `step-ended` | each step's start and end: the step, its status in the policy, its outcome, its build-input fingerprint, its test counts, for a carried result what it was carried from, and for a rerun that it is one and the caller the runtime proved; a bypassed step too | - | `wait-held`, `wait-ended` | a step's wait: on a person (approval, code review), on a build node, on the revision view | - -- **What a session hears after its merge.** Between its `merge-pull` and the delivery, a session waits with `mesh_wait` - on the runner's `pipeline-started` and `pipeline-ended` of its module, branch and commit, and then on the status - view's `delivered` of the source revision; a failed head reaches it as `pipeline-failed` (*What holds a delivery*). -- **Nothing stands still unseen.** The watchman times each step's owed progress from `wait-held` and `step-started`, - never by run length; a step or a watched branch's head standing still five minutes is its finding `pipeline-stands`, - raised by the condition keeper and cleared on the step's end, or for a head on its `pipeline-started` (ADR 0564 §2, - §4). A step waiting on a person is said as waiting on that person (ADR 0283), never as a stall; a group waiting for - its members, and a merge behind a pending revision, are governed by their own bounds (ADR 0666 §24). At its start the - watchman seeds its open waits from the runner's `stands`, as it seeds `take-in-waits` from `indexer_pending`. -- **The runner's own health.** Its manifest declares its health check, run outside its process (ADR 0240): the runner - answers `show`, and its durable consumers of `step-ended`, `take-in.taken`, `package-published` and `decided` are - each less than five minutes behind; a failed check names which. -- **The runner waits for its view.** With no revision view it says so in `_first_views` and raises `view-waits` - after five minutes, as every part does (ADR 0656 §6). -- **Going back is one act.** A failing new version holds while the old keeps running (ADR 0656 §4); a return to an - earlier build is one value in the placement, the module's `build` in its placement key, set by a placement proposal - (ADR 0666 §24). -- **How it is checked.** Whole (runner, watchman): a step whose worker dies raises `pipeline-stands` within five minutes; - a head with no pipeline raises it and its `pipeline-started` clears it; a step waiting on the operator raises nothing; - a runner restarted mid-step takes its pipelines up again; its health check fails naming a consumer behind. Whole - (assigner): a placement's `build` delivers the earlier build. Tests 76, 77 and 88. - -### A recovery fix is an ordinary merge - -- **No recovery merge verb.** A fix that recovers the mesh is merged like any change on a watched branch, by a - session's `merge-pull`, and runs its pipeline; no trusted recovery merge verb is built (ADR 0666 §26). The shape this - design sketched for one (a verb `merge` of the seat `mesh-delivery` with `recovery-callers`) is dropped. -- **Named a recovery, said everywhere.** Its author names it a recovery by the seat `mesh-delivery`'s verb `recovery` - (the commit and why), never by a pull request's text: the gate marks the delivery record `recovery` with the caller - the runtime proves, and says `recovery-merged`, which the teller passes on to every channel (ADR 0666 §26). A widening - it carries is said in its `pipeline-ended` like any other (*Who may say what*). -- **How it is checked.** Whole (gate): a merge named a recovery is marked in its record and `recovery-merged` is said; - a recovery named by a description is not. Test 92. - -### The tools - -Every new state has a tool that reads it and every new act a tool that starts it by hand (ADR 0666 §25), against the -four lines a module's tools answer; every read tool of a store also answers its fill against its cap: - -| Part (seat) | Read everything it holds | Do by hand what it does itself | Recover without help | -|---|---|---|---| -| the runner (`mesh-pipeline-runner`) | `show` (one pipeline whole, its steps, step log and outputs), `list` (the pipelines of a module, a branch or a commit), `stands` (what stands still, since when), `why-carried` (where a step's result was carried from), `kept` (the kept results by digest) | `start` (a delivering pipeline for a watched branch's head), `run` (the run on request), `rerun` (one step again) | `accept` (a failed `optional` step, with why), `cancel` (a pipeline, dropping its asks), `ask-again` (a declined `approval`) | -| the indexer (`mesh-catalog`) | `registrations` (with each one's history); `indexer_edges` (an artifact's edges per watched branch), `indexer_order` (the order of a change, its cycles named), `indexer_catalog_difference` (two revisions); `indexer_pending` (a group with its missing members) | `register`, `policy`, `watch`, `unwatch` (each on the operator's Approve) | `indexer_seed_again` (the first registrations' ask raised again), `indexer_take_in_pending` (a group taken in as gathered), `indexer_drop_pending` (dropped) | -| the gate (`mesh-delivery`) | `source` with a branch (`gate_source`: every branch's source revision) | — | `gate_source_again` (say `source-moved` again for a branch) | -| the forge module (`git`) | `git_failed_steps` (the failed `required` steps it holds, by module and fingerprint, with the run that failed each) | — | `git_failed_steps_drop` (drop one, with why) | -| the grants part (`mesh-grants`) | `grants_callers` (the callers each verb admits, read from the seat definitions) | — | `grants_why_refused` (for an account and a verb, the grant it lacks and the definition's line that leaves it out) | -| the build seats | `steps` (the steps detected for an artifact) | `steps` with `again` (detect again) | `drop` (ADR 0664 §4) | -| the builder (`mesh-builds`) | `builder_versions` (a package's published versions) | `builder_publish_again` | — | -| the assigner (`mesh-wants`) | `assigner_why_not` (why a module is not on a machine yet: the pipeline it waits for, its hold, the placement, the node's last `running`) | — | `assigner_release` | -| the watchman | `watchman_views` (how far behind each part's view is, from each part's `view-waits` and first-view tools) | — | each part's `_first_view_again` | -| the operator-channel | `asks` (with each asker's asks held back) | — | `ask-again` (offer a held-back ask now) | -| every module that imports mesh-sdk's small object store package | `_state_objects`, `_sent_objects` | — | `_state_objects_drop`, `_sent_objects_drop` | - -Every recover tool writes its act, who and why in the hand-act log of the seat `mesh-hand-acts`. How it is checked: -each tool answers its whole-module test's case, every store's read answers its fill, and `mesh_describe` reads each -(test 93). - -### The runner's kept data, and the build capacity - -Each kept form names its section or template, its retention and its cap; a state template fixes its own size (ADR 0595 -§3), up to 64 MiB. The numbers are estimates, to be read from the fill tools once G runs: an estimated 20 merges a day -(as *The delivery record*), each starting a pipeline for about 3 modules of its repository whose fingerprint it changes, -and an estimated 2 mesh-sdk publishes a day, each rebuilding about 120 artifacts and starting about 120 pipelines: about -300 pipelines a day, of about 6 steps each. - -| Part | Kept data | Section or template | Retention | Cap and growth | -|---|---|---|---|---| -| the runner | `pipelines`: one key per pipeline, keyed by watched branch, source revision and module, its steps, statuses, outcomes, fingerprints and test counts | old `state` section | a pipeline a delivery record cites, deleted with that record (90 days); a superseded pipeline, a run on request's and one no record cites, 7 days after its end; always while it is its branch's newest for its module | 256 MiB; about 300 pipelines a day of about 4 KiB is at most about 105 MiB at 90 days, under half the cap | -| the runner | `step-log`: one entry per step's start and end, its output by name | old `streams` section | by its age, 90 days, as long as the delivery records that cite its steps | 128 MiB; about 3,600 entries a day of about 0.2 KiB is about 63 MiB at 90 days | -| the runner | `step-outputs`: a lint or test step's output | old `objects` section | 7 days | 1 GiB; about 1,200 steps run a day (the rest carried) of about 50 KiB is about 420 MiB at 7 days | -| the runner | `kept`: a package's passing result per level, by digest | old `state` section | 30 days unread | 128 MiB; a publish changes the digest of about 1,000 importing packages at two levels, so about 4,000 entries a day of about 0.3 KiB, about 36 MiB at 30 days | -| the indexer | `registrations` and its stream `registration-history` | old `state` and `streams` sections | the life of the mesh, never derived again | 64 MiB (*A module's registration*) | -| the indexer | catalog graph revisions, per watched branch | objects in the old form (ADR 0619 §2) | while a record pins it or it is its branch's current | 512 MiB, as *Two graphs, one source of truth*; a second watched branch on a few modules adds a few MiB | -| the gate | `source`: one key per watched branch | its old `state` section, as today | 64 revisions of each key; a branch's key deleted when `registration-changed` says the last registration watching it unwatched it (`unwatch`) | a few KiB | -| the forge module | `failed-steps`: failed `required` steps by module and fingerprint, with the commits each was seen at | state | an entry deleted once none of its commits is a watched branch's head or the head an open pull request names, judged on each `branch-moved` and each pull request's close | the template's 64 MiB; an estimated 50 failed steps a day of about 0.5 KiB, most gone within days, is under 1 MiB | -| every module that imports the object store package | `-objects` beside each state | objects | an object no key names, its key deleted or its value replaced, until `_state_objects_drop` on a person's word (ADR 0595 §4, ADR 0666 §16) | the template's; nothing reserved until written | -| every sender of the new form, and a foundation part by its old `objects` section | `_sent-objects` (`sent-objects`) | objects, planned by the bus module with no manifest field | 7 days, transport (*Any size*) | the objects template's cap; full is the bus module's `full` | -| the grants part, for each seat event a definition keeps | `SEAT__`, among them `SEAT_mesh-pipeline-runner_*`, `SEAT__step-ended`, `SEAT_git_branch-moved`, `SEAT_mesh-builds_package-published` and `SEAT_mesh-catalog_registration-changed` | a stream the grants part makes with its durable consumers | the seat definition's age (`keep`), 90 days unless the definition names less | the seat definition's cap (`keep`) | - -**The build capacity.** A pipeline runs a module's steps once per commit on a watched branch, carrying what did not -change, where the check ran before the merge and carried after each trunk move; a group runs one pipeline per watched -branch; a second watched branch runs the steps of the modules it carries once more. A mesh-sdk publish asks about 120 -lint steps and the test steps of the importing packages, about 240 more, the rest carried; a newer publish of the same -package supersedes the older one's rebuild pipelines, so two publishes close together run the rebuilds once. The first -pipelines after G's delivery run every module once, but carry every package whose digest the checker's kept verdicts, -taken into `kept`, already hold, so they run only what changed since. The steps go on the build seats' stream `check`, -after `delivery` and before `recheck`, within each node's build capacity (ADR 0525 §4, §5), and a run on request on the -same stream. How it is checked: live, the build nodes' time per day in the week after G, read from the build modules' -step keys and the builder's build log, against the checker's last week (test 99). - -### How milestone G itself is checked and delivered - -- **Under the clauses as they stand.** Milestone G is checked and delivered under ADR 0656 §5 and the clauses it changed - as they hold before its delivery: the acting parts (the indexer, the build modules, the assigner, the grants part, - the node-engine, and the checker, which makes G's own check) act from the milestone's heads, each first in its step, - in the order of their ordering edges; the trunk-only want, the checker and the Approve per merge as ADR 0661 leaves it - govern this delivery, no exemption is asked and no delivery goes ahead of it (ADR 0667 §2, ADR 0644 §1). -- **Its other parts as any module.** mesh-sdk's small object store package is a package published before the modules - that use it build; the manifest validator moves with the indexer; the runner is placed like any module and acts only - from the next change on; mesh-delivery's `contracts` and `sdk` move under its `modules/` folder (ADR 0667 §3). -- **Readers first** (ADR 0667 §4): an edge of kind 4 each, which the delivery plan derives: the indexer's manifest - validator for the seat definitions' new fields (`callers`, `acts`, `subject`, `keep`) before any definition using - them; on each node the node-engine that reads `form` and `catch-up` before any manifest writing them. -- **The stream maker first** (ADR 0667 §5): the grants part, which makes each kept seat stream and its durable - consumers, before the parts that hear a kept stream. -- **The bus module first** (ADR 0667 §6): the bus module, with `-objects`, the sent store and the grant of each - state's object store to its owner alone, before the modules requiring them, the grants part writing that grant from - the milestone's heads. -- **A bus restart is said first** (ADR 0667 §7): a restart of the bus its new version needs is said to the operator - before it starts. -- **A gap is built, not worked around** (ADR 0667 §8): an order the delivery plan cannot derive from the edges is - built in the delivery system within G, never a step done by hand. -- **A node-engine of the version before applies what it can read** (ADR 0667 §9): it applies every want whose - manifests use no field it does not read, and a want that uses one waits, by the reader edge above, for the new - node-engine on that node. -- **The new assigner and the new merge switch on the first registrations** (ADR 0667 §10). The new assigner, which - writes a want only from a passed pipeline, is delivered before the forge module's new `merge-pull`, which asks no - Approve, and before the runner: an edge of kind 4 from `mesh-delivery-assigner` to each, declared in their manifests' - `needs` since nothing else says it (the design's choice: without it a merge made with no Approve could reach the old - assigner, which writes wants from the trunk with no pipeline). Both switch on one fact, the first registrations - written, said as `registration-changed`: until it the new assigner keeps the trunk-only want and the new - `merge-pull` refuses every merge, naming the missing registrations. -- **Until then, the operator merges a fix at the forge** (ADR 0667 §11). Until that fact an ordinary change waits for - it, and a fix, an indexer fix included, is merged by the operator's own hand at the forge (ADR 0661 §3) and - delivered under the trunk-only want still in force; `indexer_seed_again` asks the first registrations again. Before - the milestone's delivery every merge goes as ADR 0661 has it. -- **What is removed, and when** (ADR 0667 §12). The checker's buckets and bus account and the gate's forge merge token - are removed only after the first pipeline after G's delivery has delivered a change end to end (test 63), the runner - then making every check in the checker's place (ADR 0666 §19), and only on the operator's word, asked once for all - three. The checker then leaves the manifest validator's list of foundation parts (ADR 0666 §4) and is no longer - placed, so no running module declares its buckets and they - are orphans `orphans` lists; they go through ADR 0595's `drop` on that word, after the stream snapshot `drop` takes - (ADR 0595 §4, §5, §10), kept 90 days as the delivery records are; a restore from that snapshot is tested before the - word is asked. The runner is on that list from G's delivery. -- **Told to the operator before it starts**: G's own merges are asked as ADR 0661 has them (ADR 0667 §2, §11); the one - ask of the seed registrations; the bus's restart (ADR 0667 §7); and later the one word for the checker's removal - (ADR 0667 §12). -- **How it is checked.** Tests 94 to 97, and 100 for the assigner's edge. - -### Choices this design makes under ADR 0666 and ADR 0667 - -| Choice | Why | -|---|---| -| The registrations in the indexer's old `state` section with their history on an old stream, capped at 64 MiB, kept for the life of the mesh | the indexer is a foundation part (ADR 0619 §1 to §3, ADR 0666 §4); a registration keeps every version with who and on whose Approve, and nothing derives it again | -| The runner a foundation part, its kept data in old sections, on the manifest validator's list | the bus module's own delivery waits on its pipeline (ADR 0666 §4) | -| The want's compare-and-set keyed per module and watched branch | source revisions are kept per watched branch, so two branches' revisions have no order; comparing across them would let `main` refuse `beta`'s want (ADR 0666 §9) | -| A second start of a pipeline for the same source revision and module, on `take-in.taken` and `package-published`, writes nothing, by the pipeline key's compare-and-set | the runner starts on both events (ADR 0666 §13, §15); the key it already keeps judges a start in one place, so neither producer knows of the other | -| A refused new indexer revision holds later merges on its branch until a revert lands | the validation runs after the merge and before take-in (ADR 0666 §6), so the refused revision has landed; taking later merges in past it would deliver them on a graph its own validator refused | -| Each check at its row's level, every requirement R1 to R18 keeping its named test | the record's rows name the levels; the test budget and one check per release bound what runs | -| The approval asked as the operator-channel's accepted kind `ask` on its work queue | the seat has no verb `ask`: an ask is its accepted kind, by the asker's own name (design 46 §10) | -| The gate no foundation part, its `source` in the old section it already has | the bus module's delivery waits on no act of the gate's; only the key's layout changes | -| The verbs `register`, `policy`, `watch`, `unwatch`, `registrations` and the event `registration-changed` on `mesh-catalog` | one verb per trusted act, each its own ask naming what moves; readers follow the event (ADR 0596) | -| The seed of the first registrations proposed as one ask, with the statuses the check judged until then and approval `bypass`, raised again by `indexer_seed_again` | registering is a trusted act (ADR 0666 §3), and one ask for the whole seed is how placement was adopted (ADR 0567); a declined or expired seed must not leave the pipelines stopped with no way on | -| Code review refused as `required` until forge accounts are bound to bus identities | a review is refused from its author (ADR 0666 §22), which cannot be told until then | -| The seat `git`'s read verb `branch` and event `branch-moved`, kept on its seat stream | registering reads a branch's protection through the seat `git` (ADR 0666 §3); a branch moves by a merge or an admitted push; a stream keeps a move said while the bridge is down | -| The watchman's finding `pipeline-stands` for a step or a head still five minutes, cleared by the step's end or the head's `pipeline-started` | the record's five minutes (ADR 0666 §24), one finding for both, timed from the runner's events | -| The runner's finding `pipeline-failed`, the author's for two hours, then the operator's | ADR 0666 §24 with ADR 0505 §5, §6 | -| A module's watched branch and its `build` in the placement key, set by a proposal | a placement names the branch and a return is one value in it (ADR 0666 §6, §24); every placement change goes by a proposal (ADR 0567) | -| The gate's `source.`, its verb `source` and event `source-moved` | one source revision per watched branch (ADR 0666 §6), read through the seat (G's prepare, the indexer's watch of the gate's `source`) | -| The build seats' verb `steps` and accepted kind `step` on `check`; the assigner's kind `step` on `mesh-wants`; `step-ended` with the node in its subject | steps are asked on the serving seat's work queue (ADR 0666 §7); the `check` stream already orders after `delivery`; a node's account says only its own node's ends (ADR 0363 §2) | -| The outcomes, with `accepted`, `superseded` and `cancelled`; an approval expired or refused ends `declined`, replaced `superseded` | every end a step can have is said as itself (ADR 0666 §10) | -| `approval` asked last, its `about` the module and the branch | the operator approves a commit the mesh already judged, the point ADR 0661 §3 kept in one place; one ask per module and branch, a newer commit's replacing it | -| A superseded pipeline's asks dropped by `drop`, and a pipeline superseded only when its module's fingerprint changed | a cancelled pipeline must leave no ask on a stream (ADR 0664 §4; G's prepare); a module the commit did not change has nothing newer to run (ADR 0666 §9) | -| A group's wants only on `group-ended` | a group is delivered whole or not at all (ADR 0666 §9; research 086, R5) | -| The six kinds derived from existing words, `needs` per artifact only where nothing says it | one form of each fact (ADR 0656 §6); the catalog entry's `needs` already exists from G | -| The cycle rule in the indexer's graph | the graph is the indexer's, and the checking program goes with the checker | -| The builder's seat `mesh-builds` and its event `package-published` | the record has the builder say the publication as an event of its seat (ADR 0666 §15); its waits move only when a later change gives the seat its verbs | -| Each state's object store `-objects` through mesh-sdk's small package, sent objects readable by a standing grant derived from the manifests, and the package's two tools | one object store per state, granted to its owner; the sender's declared callers and consumers read what it sends (ADR 0666 §16); only its users import it, so nothing else is rebuilt | -| The `run` ask published by the runner's account and the indexer's; the verb `run` called by the sessions and the operator only | the steps and the validation run code from the change, in the sandbox only, and each asker reads only its own step keys (ADR 0363 §2); a run publishes tagged packages, so nothing else may ask one | -| The checker's step `check` becomes `pipeline`; the checker's kept verdicts taken into `kept` | the runner is an acting part in the checker's place (ADR 0666 §19); the first pipelines then run only what changed | -| The field `callers` in a seat definition replaces the holders' trusted `callers`, a missing field admitting the holder roles and the operator only | the record makes the definition the grants part's one source (ADR 0666 §20); a field left out must open nothing | -| `widens` in `pipeline-ended`, computed by the running runner over every part serving a step, passed on by the teller | a widening is said and nothing refuses it (ADR 0666 §23, §26); a change must not compute its own | -| `merge-pull` judged from the forge module's own `failed-steps`, heard from `step-ended`, any run at the head's fingerprint counting unless a later rerun of that step passed, the protection read again on every `branch-moved` | the record has it judge from the events it consumes, never by a call, so a head merges while the runner is down (ADR 0666 §11, ADR 0596) | -| The new assigner before the new `merge-pull` and the runner, by `needs`, both switching on the first `registration-changed` | a merge with no Approve must never reach an assigner that writes wants without a pipeline (ADR 0667 §10) | -| The forge bridge's finding `branch-unprotected` | a move of a branch whose protection was removed starts no delivering pipeline and is said (ADR 0666 §6) | -| The verb `recovery` of `mesh-delivery` | a recovery is named by its author as a fact the bus keeps with who said it, never read from text (ADR 0666 §26, research 086 R10) | -| No forge status for a pipeline | the step results live on the bus (research 086 R10), shown by the runner and the delivery record; a status would be a second copy outside it | -| The runner's `pipelines` kept as long as the delivery record that cites each (90 days), a superseded, run-on-request or uncited one 7 days, its step log 90 days by age, its outputs 7, keyed by source revision | a pipeline is read back as long as the record that delivered it; one nothing delivered has no trace to serve after a week; about 300 pipelines a day must fit its caps, so they are 256 MiB and 128 MiB | -| The forge module's `failed-steps` kept until no head it was seen at is a watched branch's head or an open pull request's | an entry judges only a head that can still be merged; once neither names it, nothing can be refused by it | -| The gate's `source.` deleted when the branch's last watch goes | a branch no registration watches makes no revision, so its key would name nothing | -| The sent store kept 7 days by age, with no person's word | an object sent carries one reply or event and is transport, not kept data (ADR 0595 §4); its readers fetch it within a call's bound or a consumer's lag | -| A replaced object listed `key gone`, as a deleted key's is | no key names it, and one listing lets the drop tool take both on a person's word, as ADR 0595 §4 and ADR 0666 §16 have it | -| The checker's removal after the first end-to-end pipeline, on one word, its buckets through `drop`, the snapshot kept 90 days | ADR 0667 §12 asks one word for all three; 90 days is the delivery records' retention, the longest a trace reads back | -| The pipeline steps on the `check` stream after `delivery` | a delivery's build is never held by a pipeline, as a check never held one (ADR 0525 §4) | - ## A delivery *ADR 0239, ADR 0429 §1, ADR 0539 §17.* @@ -1110,182 +461,6 @@ compare-and-set (ADR 0406 §4). It writes a new head when the forge says one, an pull request's verdict is carried to it or a whole check is asked against it (ADR 0548 §5, §7). A running check watches that key and stops only when the head in it moves; a trunk move never ends it (ADR 0548 §1). -### The delivery record - -*ADR 0656; ADR 0595, ADR 0596, ADR 0597, ADR 0603 §7, ADR 0493 §3, §11, ADR 0633 §4, §5, ADR 0441 §1, ADR 0548 §8, -ADR 0564 §2, ADR 0363 §2.* - -From research 085's milestone the gate, holder of the seat `mesh-delivery`, keeps one **delivery record** per -milestone's delivery, a ledger instance (ADR 0595's template `ledger`, ADR 0597) it alone writes (ADR 0656). It -holds: - -- **the group's state**: the heads, the verdicts, the checks and the asks, which `merges` holds today; from milestone - G's delivery the pipelines' `step-started`, `step-ended` and `pipeline-ended` in place of the verdicts, the checks and - the asks, kept as long as the record (ADR 0666 §9); -- **the trace**: the milestone, its issues, its pull requests, their commits, and the graph revisions the delivery - moved between; -- **what happened to each entry on each node**: for every entry of the graph difference, taken in, built, checked, - composed, wanted, running healthy, held (with the hold's reason, so a reader of the record sees why an entry stands - still without asking its holder), failed (with what failed), or away (ADR 0656). - -It holds no tiers, and only the gate orders work by it, so it is no second copy of the keys, the objection research -063 had to a stored plan (research 085, Findings 10). Its fields, retention and tools are this design's choices under -ADR 0656. - -- **The outcomes arrive as events, through a durable consumer of the gate's own.** The gate's manifest `consumes` - each step event of *What each step says* (below), and `wait-held` and `wait-ended` of each holder. The consumer - resumes from the last event applied; an event applied twice changes nothing; an event is applied only when it comes - from its owner's account; and running healthy is taken from the node-engine seat's `running` event, never from a - have read across the seam (ADR 0596). -- **It ends when every present node runs its entries**, and the gate says `record-ended` on the seat `mesh-delivery` - with the record's milestone and its nodes away. It names the nodes away, each with since when, and ends without - waiting for them, as a node away holds nothing (ADR 0603 §7). -- **A record open too long is a finding.** The watchman writes the finding `record-open` for a record still open 24 - hours after its merge (a delivery of the whole mesh takes under an hour, so a day means something stands still) and - clears it on `record-ended`; the condition keeper raises it (ADR 0564 §2). The finding names the entries still held - or failed, read from the record's own events. It is written only while no other condition covers the record: while - an entry of it is held by a wait that raised `acting-part-late`, or a store that holds it raised `full`, that - condition already tells the operator why the record is open, and a second one for the same cause would only be noise. -- **A node away that wakes adds its outcomes.** When it wakes and catches up by its wants (*A change's graph - difference is its delivery*, below), its outcomes reach the record through the same consumer as any other, and the - record shows the node no longer away. -- **An Approve given holds at its heads, until G's delivery.** An Approve the operator gave for a group's heads holds while those heads - stand: a check of the same heads asked again, after a main move or for any other reason, records its verdict in - the record and asks the operator nothing again (issue 1972). The Approve is withdrawn only as ADR 0441 §1 has it, - when a member stops being mergeable, and a carried verdict is read as current (ADR 0548 §8). From G's delivery no - Approve is asked per merge; an `approval` step's answer is the runner's, kept in the record as its step's end - (ADR 0666 §10). -- **From G's delivery, a record for every landed merge.** A session merges through the seat `git` and the gate merges - nothing, so every merge is one the gate did not make: the gate opens a record for each source revision of a watched - branch the indexer takes in, a group's members in one, and `forge-made` no longer marks a record apart. A merge its - author names a recovery is marked `recovery` (*A recovery fix is an ordinary merge*). -- **A small fix has a record of its own.** A small fix is a milestone of one issue (ADR 0493 §3), so it has a - delivery record like any milestone; nothing is merged outside a released milestone (ADR 0493 §11). -- **It pins the graph revisions it points at.** The gate says, as the seat `mesh-delivery`'s events `pinned` and - `freed`, which catalog and assignment graph revisions a record starts and stops pointing at, and as - `heads-replaced` that a candidate's heads were replaced or its pull request closed. Only the gate's account may - publish them (ADR 0363 §2). The indexer and the assigner hear them through a durable consumer each, declared in - their manifests' `consumes`, which resumes from the last event applied after a restart, so a `freed` said while one - of them was down is still applied; neither reads the gate's state (ADR 0596; *Two graphs, one source of truth*, - below). -- **A record is kept for 90 days by default**, the gate's setting `record-retention`. Ninety days covers every trace - the operator has asked of a past delivery so far, which went back weeks, never months; the setting can keep records - longer. When the retention removes a record, the gate says `freed` for each revision it pinned. -- **Its size, its cap and its growth.** A record's state of 30 modules on four nodes is about 30 KiB, against the - bus's 256 KiB value limit (research 085, Findings 8). The ledger keeps every operation beside that state: 30 modules - on four nodes with seven outcomes each is about 840 outcome operations a record, at about 0.2 KiB each about 170 KiB, - so a record costs about 200 KiB with its snapshot. At an estimated 20 deliveries a day (a guess from the days of - 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 - 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` and every group in flight become - 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 - 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 - bus, backed up and restored with its delivery*). -- **The forge bridge asks the seat for a group.** It reads a group's members from the seat `mesh-delivery`'s verb - `groups`, never the gate's `merges` state, both to set the group on each merged message and to publish a group's - end again (ADR 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: - - | 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) | - | 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 (from G's delivery the runner's `show`), 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`) | - | 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 - leaves the record complete with no outcome counted twice; the events `pinned`, `freed`, `heads-replaced` and - `record-ended` are said; a `freed` from an account other than the gate's is refused by the bus; a group approved - before the switch is not asked again after it, nor after milestone G is delivered again following a revert; a record ends once every present node runs its - entries, naming the nodes away; a held and a failed entry are kept with their reason; a record open past 24 hours - raises `record-open`, cleared by `record-ended`; a node away that wakes adds its outcomes and is no longer shown - away; a group's heads approved and checked again ask the operator nothing again; a small fix's merge gets a record - of its own; a record past its retention is removed and frees its revisions; the tools read a record, list the - records with their fill, and a repair completes a record missing an outcome through the owners' read verbs. In the - forge bridge's whole-module test, a group's members are read from `groups` and its end published again from it, and - a read of `merges` by its account is refused. Live: one call of `gate_record` traces an issue of the registry - milestone to each node's running build, also after six later merges; a node away is named with since when and its - 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). - -### 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..`, 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..`. 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, its size the one its template fixes - (ADR 0595 §3), 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, until G's delivery.** 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. -- **From G's delivery the gate owes no merge, and the checker nothing.** A session calls `merge-pull` itself (ADR 0666 - §11), and a group's members land one by one, the group ending when every member has (*Groups*); the checker's `owed` - goes with the checker, and the runner owes the forge nothing, a pipeline's result living on the bus. The gate still - owes the delivery's view, a comment and the note's line, performed by the forge bridge as above. -- **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 *ADR 0539 §17.* @@ -1319,475 +494,7 @@ verdict that names the trunk's head (*A move of the trunk carries every verdict* backup hold, superseded, covered, stopped, retired and failed) and the machine steps went at release 6: a module's progress on each node is its want against its have, shown by the view (ADR 0539 §17). -**From milestone G's delivery the gate keeps no merge states.** With no check before a merge and no Approve per merge -(ADR 0666 §10, §17), nothing is `proposed`, `ready`, `rejected` or `held` before a merge: a commit's states are its -pipeline's steps, kept by the runner (*Pipeline steps and the policy*). The table, the gate's `table`, `recheck` and -`close` and the one key per pull request go with the check; `stalled` lists the acts owed to the forge past their 15 -minutes and the records `record-open` names. - -## Two graphs, one source of truth - -*ADR 0656, which supersedes ADR 0645 to ADR 0648; ADR 0595, -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.* - -From research 085's milestone. One graph answered two questions, which modules exist and which version runs where, -and one module running as several placed versions would have given one entry two shapes and one key two writers; two -graphs answer them, the second computed from the first, so there is one source of truth (ADR 0656; research 085, -Findings 11). How each is kept, read and retained is this design's choice under ADR 0656. - -``` - manifests ──► indexer (mesh-catalog) ──► catalog graph revision ──┐ - ├──► assigner (mesh-wants) ──► assignment graph revision - placements (mesh-module-assigner) ───────────────────────────────┤ │ │ - node capabilities (node-engine seat) ────────────────────────────┘ │ └─► wants, from a trunk revision only - ▼ - a change's assignment graph − the current one = its graph difference = its delivery -``` - -- **The catalog graph is the indexer's.** The indexer, holder of the seat `mesh-catalog`, keeps the modules as their - manifests declare them; it is today's module graph, and *module graph* stays its other name (ADR 0656). At each - revision it holds one entry per module: its bases, its packages, the toolchain version and recipe version of the - build module that builds it as ADR 0603 §2 has them, its provides and requires, its invokes and serves, and its - fingerprint, with the rules the seats declare (*An acting part's new version acts first*, below). -- **The assignment graph is the assigner's, computed and never written by hand.** The assigner, holder of the seats - `mesh-module-assigner` and `mesh-wants`, computes the module versions placed on nodes, with the edges between - versions, from the catalog graph, the placements and the nodes' capabilities, and nothing else writes it - (ADR 0656). Each entry is one module version on a node; its edges are provisioning, contribution, and the acting - parts' versions that are to act on it (ADR 0656), whose rules and versions come in with the catalog graph. It is - kept, but it is no stored plan: it has one writer, no part orders work by a stored plan, and any revision is computed - again from the inputs it names and compared with the one kept, by a tool (below), so a kept revision is a checked - derivation, never a second source of the kind research 063 removed (research 085, Findings 5). -- **Each graph is kept per revision, and each revision names its inputs** (ADR 0656). The indexer keeps a catalog - graph revision for each source revision it takes in; the assigner keeps an assignment graph revision for each change - of its inputs, naming the catalog graph revision, the placements and the capability readings it was computed from. - Both parts are the foundation (ADR 0619 §1), so both keep their revisions as objects declared in an `objects` - section in the old form, each with a cap it declares there, never in the new form (ADR 0619 §2), and neither waits - on the bus module to start; the manifest validator refuses either manifest that declares them in the new form - (ADR 0619 §3). An assignment graph revision is announced by an event of the seat `mesh-wants` and served by its - verbs. This replaces ADR 0603 §2's one key per module with five past values as the graph's form (ADR 0656, which - changes ADR 0603 §2); the keys are written no more, and a revert of milestone G restores them from their backup - (*Reverted*, below). -- **A revision is made by a merge, and also with no merge.** The indexer makes a catalog graph revision when it - takes a source revision in. The assigner makes an assignment graph revision on each new catalog graph revision, on - the seat `mesh-module-assigner`'s event `assignments-changed` (ADR 0567 §5, ADR 0641), and on the node-engine seat's event - `capabilities-changed`, which a node-engine says when the capabilities it states in its node record change - (ADR 0614 §4), so the assigner follows an event and never reads a node record across the seam (ADR 0596). A - placement change is traced like a merge. At its first start with no revision kept, the indexer takes in the head the - gate's source names for every repository by its catch-up path and keeps that as revision 1, and its verb `revision` - answers that it waits until then (lead-47's ruling in G's prepare: a first start has no merge to make a revision). -- **A revision is kept while a record pins it or it is current.** A revision of either graph, and the input revisions - it names, is removed when no delivery record pins it and it is not current: neither trunk's newest revision nor the - newest of an open candidate. Pins are counted per revision, so a revision two records point at stays until both - have said `freed`. The indexer and the assigner remove one only on applying `freed` or on a revision ceasing to be - current, never on a timer and never by reading the gate's state (ADR 0596; *The delivery record*, above). A trace - must read every revision it moved between, and a revision neither pinned nor current is read by nobody. -- **An unchanged entry is stored once.** A revision is kept as its list of entries' digests, and each entry as an - object of its own named by its digest, so an entry that two revisions share is stored once; an entry object is - removed when no kept revision lists it. Consecutive revisions differ by the few entries a delivery moves, so this - keeps the growth to what changes. It is chosen over a larger cap because whole revisions would grow with every - revision whatever changed, and a cap would only delay the same fill. -- **The caps and the growth** (estimates, to be read from the fill tools once the milestone runs). A whole assignment - graph revision of about 120 modules on four nodes is under the bus's 256 KiB value limit (its unit test), and a - catalog graph revision of about 120 entries about 120 KiB. A record pins the revisions before and after its - delivery, and consecutive records share one, so at an estimated 20 deliveries a day about 20 revisions of each graph - a day stay pinned. A delivery moving 5 modules on four nodes adds about 20 assignment entries of about 1 KiB and a - list of about 15 KiB, and 5 catalog entries and a list of about 4 KiB: about 0.7 MiB a day of assignment graph and - 0.2 MiB of catalog graph, about 63 MiB and 18 MiB at the records' default retention of 90 days. The caps are 512 MiB - for each, many times the steady state. Placement-only and capability-only revisions are pinned by no record and go - when they stop being current. -- **A store filling is said before it is full.** The indexer, the assigner and the gate each say their fill against - its cap in their read tools, and the event `filling` of their seat when a store passes 80 % of its cap; the watchman - writes the finding `store-filling` naming the part and the store, the condition keeper raises it (ADR 0564 §2), and - it clears when the store falls below 70 %. A full cap refuses loudly, naming the part and the store: the indexer - keeps no new revision and says the merge pending with the reason `objects full`, the assigner keeps its last - revision and writes no new want, and the gate opens no new record and holds the merge; each says it as the event - `full` of its seat, which the condition keeper raises as urgent. When a removal brings the store back below its cap, - the part says `room` of its seat, takes the refused work up again (the pending merge, the next revision, the held - record) and the condition clears; a condition that never clears would hide the next fill. Nothing is dropped to make - room: a removal is only the rule above, and the setting `record-retention` or a larger cap is the operator's. -- **What happened is not in the graph.** An entry says what is to run and what it waits on; whether it was built, - wanted or runs healthy is said by the parts as their events and kept in the delivery record (ADR 0656). -- **The want stays the one record a node reads.** The assigner writes `want..` from a trunk - revision's assignment graph only; a node-engine reads its want, never the assignment graph, and the have stays what - it runs (ADR 0656, which changes ADR 0571 §8). -- **From G's delivery, per watched branch and between artifacts.** The catalog graph is kept once per watched branch, - each revision naming its branch, and its edges run between artifact references, of the six kinds of *Dependencies - between artifacts* (ADR 0666 §6, §14). The assigner computes a node's entries from the catalog graph of the branch its - placement names, and writes a want from a revision of that branch whose `required` steps passed, in place of a trunk - revision's alone (ADR 0666 §9, which changes ADR 0656 §2). -- **Reverted.** Only the new form is written: the indexer, the assigner and the gate keep nothing of ADR 0603 §2's - keys or of `merges` and `turns` beside the new forms, since nothing reads them after milestone G. A revert of - milestone G is a change like any other, checked and delivered, and the delivery system restores what it must - (*A module's kept data on the bus, backed up and restored with its delivery*, under *A backup before the apply*). - Milestone G changes the form of these kept data, and raises their `form` (a kept data declaring none reads as form - 0, so G's own move takes their restore points): - - | 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`; 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 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 wants keep their form: their keys and values are unchanged, only what the assigner computes them from changes, - so G raises no `form` on them and a revert restores none. Restoring the wants would send nodes back to older - 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 - three keep form 0 and are never restored, so nothing decided since (a placement, a verdict, the source revision) is - 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 - -- **The difference names everything a plan named.** For a change (a pull request's heads, a delivery group's - heads, or a merge), the indexer gives its catalog graph and the assigner its assignment graph. Compared with the - current revision, the difference names the new versions, the moved edges, the touched nodes and the order, read off - the edges, and no plan is stored (ADR 0656). The assigner serves it by the seat `mesh-wants`'s verb `difference`, - for two revisions of the assignment graph or for a candidate against trunk. ADR 0603 §6's tiers, as ADR 0633 §5 - changes it, are a view worked out from that difference (ADR 0656, which changes ADR 0603 §6), read through - `difference`, with the waits and holds read through their owners' tools and the pending revisions through - `indexer_pending`. -- **The preview is a candidate's difference.** Issue 1874's plan preview of a group before its merge is its - candidate's difference, read by one call of `difference`, and needs no code of its own: a candidate's graphs are - computed for its check anyway, so the preview costs nothing more. -- **A changed fingerprint with no difference is refused by name.** When a module's fingerprint in the change - differs from the running one while the difference is empty, the assigner refuses it, naming the module, and the - check fails naming it. -- **A candidate's graphs are kept apart, and dropped with its heads.** A candidate's two graphs are computed per - check, kept apart from trunk's, and dropped on the gate's event `heads-replaced`, said when the candidate's heads - were replaced or its pull request closed. A candidate costs a computed graph per check. -- **Only a trunk revision writes wants**, whether a merge taken in or a placement or capability change made it; a - candidate's graph writes none (ADR 0656). From G's delivery a want comes from a revision of the watched branch a - placement chose whose `required` steps passed, and a candidate is a run on request's: the indexer builds it on the - runner's `run-started` and drops it on that run's `pipeline-ended`, the gate's `heads-replaced` no longer making - candidates (ADR 0666 §9, §18). -- **Each part acts on its own entries.** The builder, the build modules and the grants part each act when their own - entries in the new revision differ from what they run (ADR 0656), reading them through the seat `mesh-wants`'s verbs - and events, never its bus state (ADR 0596), and naming no other module (ADR 0656). The node-engine acts on its want - alone, as it does today: the want is the one record a node reads, and handing every node the assignment half would - have each node read every other node's placements. -- **A node asleep catches up when it wakes.** A node away holds nothing and catches up by its wants (ADR 0603 §7); - a want's new form reaches only a node-engine that says it reads it (ADR 0614 §4, ADR 0618 §2). -- **No delivery goes ahead of a change.** A change is delivered as its own difference, its acting parts' new versions - first in their own steps (ADR 0656); the one exception is the delivery before research 085's milestone (*The - bootstrap delivery, and the one milestone after it*, under *Milestones*; ADR 0644). - -### The revision view - -- **A pair, each half served by its one owner** (ADR 0656). For a trunk revision, or for a candidate's heads before - any merge, the indexer serves the catalog half by the seat `mesh-catalog`'s verb `revision`: the catalog graph, the - heads, the seat definitions, the manifests' verdicts and the fingerprints. The assigner serves the assignment half by - the seat `mesh-wants`'s verb `revision`: an assignment graph revision, named by its own revision and naming its - inputs, the catalog graph revision, the placements and the capability readings. A part's view for the current - revision is the newest assignment half and the catalog half it names. `seat-definitions` stays the seat list's verb - (ADR 0636 §4), and the catalog half carries the same definitions at its revision. -- **Every part takes a first view, then follows the events.** The checker, the builder, the grants part and the - indexer's own later passes take a first view from the two verbs and then follow the two seats' events, never a list - compiled into their build nor another module's bus state (ADR 0656, ADR 0596). The node-engine reads only the catalog - half, for the seat definitions it composes with, and its want; it never reads the assignment half (*Each part acts on - its own entries*, above). Of the view the assigner reads only the catalog half, never its own output back; its other - inputs stay the placements and the capabilities (ADR 0656). A running part acts only on a trunk revision's view; a - candidate's view is read only by the parts that judge a candidate, inside the check its manifest validator and - composer, and the indexer's candidate pass (ADR 0656, which changes ADR 0636 §4 in that the candidate pass joins - them). From G's delivery a running part acts on a revision of a watched branch as on a trunk revision, and a - candidate's view is read only by a run on request's steps and the indexer's candidate pass (ADR 0666 §6, §18). -- **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 `_first_views` and `_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; accepted); 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..` (*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 - 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 - for the catalog half as ADR 0636 §1 already has it wait for the seat list. Each answers in its runtime's first-view - 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 - (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 - waits and says so. -- **Each process knows its own build from its start.** The node-engine hands every process it starts the - fingerprint of the build it starts it with, and the process takes its own build from that, never learning it later - (ADR 0656, which changes ADR 0639 §7 from the indexer to every process). *The fingerprint handover*, below, says its - form. - -### What ADR 0656 leaves to this design - -ADR 0656 leaves how each part is built to this design, under issue 1921; these four needed a shape of their own. - -- **An acting rule's fields.** The seat's definition is where ADR 0656 has an acting part declare what it acts on. A - seat's definition gains one optional field `acts`, a list of rules, each with three fields of its own: `step`, one of `take-in`, - `validate`, `check`, `build`, `compose`, `grant` and `place`, and from G's delivery `pipeline`, the runner's, in - `check`'s place (ADR 0666 §19); `on`, either `every` (every module) or a `language` - naming the language of the modules it acts on, matched against what the manifest says its language is, as the - indexer's language map matches today; and `bound`, how long an entry waits in that step for the acting part's new - version (*An acting part's new version acts first*, below, gives each step's default). The definition format's own - schema (design 26) gains the field, and the format stays 1. The indexer reads it into the catalog graph, the assigner - into edges, and the checking program from the revision view. **Its cost in mesh-sdk:** the seat-definition reader in - mesh-sdk's runtime refuses a definition with a field it does not know or a format other than 1, so a reader built - before the field refuses every definition that carries `acts`, and a refused definition blocks new claims of that - seat only (ADR 0636 §3), never what runs. The runtime therefore learns `acts`, which rebuilds every module once - (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 - 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 format's reader itself is delivered before them, as a release of mesh-sdk's seat-definition - reader merged ahead of G's check (the operator's choice of a reader first, 2026-11-09; ADR 0667 §4). The bootstrapped - definitions every reader carries from its start (ADR 0636 §2), of which `node-backup` carries no `acts`, 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 - 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 - unknown` in its runtime tool and its journal, and the indexer acts on it as ADR 0639 §8 has it. **Its cost:** one - change of mesh-sdk's runtime, which rebuilds every module once (ADR 0656, Consequences), and one of the - node-engine; the order between them is the composing step's wait of the node-engine (*Order without a person*, - below), so a module whose runtime reads the value is composed only by a node-engine that hands it. -- **The build seat's ask that runs a program in the sandbox.** The checker asks the seat `node-build-go` for an ask - `run` on the build seats' `check` stream: one whole job on one node (ADR 0525 §3), which fetches the named heads, - builds the named program at them, runs it in the run step (ADR 0448 §2) with the input the ask names by its sha256 in - the asker's own state (the checker's `inputs`, a day), asked of the seat `mesh-delivery-checker`'s verb `input` and - checked against that digest, laid as a file, and writes the program's exit and its answer, carried whole, on the - build module's step key named by the ask's id (ADR 0525 §6). It is an accepted ask of the seat, not a request verb, because it is a - long job pulled where there is capacity, never a call to a named node. Only the checker's account may publish `run`, - and from G's delivery the runner's and the indexer's (its validation before take-in), each under its own name. - Every step key of a `run` ask starts with the asker's name (`checker.`), so the checker's read grant is fixed - in advance to its own prefix and never follows ask ids one by one (ADR 0363 §2); no other part can have a program run - or read its verdict. From milestone G the seat definition of `node-build-go` in `mesh-delivery-contracts` names it; B0 - brings the ask with its types in mesh-sdk's `go/delivery` and the grants check asks have today (*The bootstrap - delivery, and the one milestone after it*). The checking program, the acting parts and the composer a check builds - from a change all run through it (ADR 0656, ADR 0644). A program is built once per fingerprint: the build is the - builder's build of that fingerprint (ADR 0498 §1), kept like any build and reused by every later ask naming it, so two - checks of changes that leave the checking program unchanged ask one build. Only a build made in a run step that runs - nothing but the build is kept and reused: a program's own run happens in a separate run step over a copy, so a program - that rewrites its own binary while it runs changes no kept build. A candidate's build is never delivered to a node: a - want names only a trunk revision's fingerprint (*Only a trunk revision writes wants*), and a candidate's build is kept - only for checks. -- **The first tier's own bound.** A check's first tier has 20 minutes for all its builds together, inside the check's - one-hour bound of the state table and the checker's step bound (ADR 0639 §5); an acting part not built within it is - one the first tier cannot build, and the check fails naming it (ADR 0656). The verdict tells two cases apart: `waiting - for a build node` when no build node of the language took the ask within the bound, and `did not build` when one - took it and the build failed, so the operator knows whether to free a build node or fix the change. - -### Choices this design makes under ADR 0656 - -ADR 0656 decides the direction and leaves every choice made in working it out to this design, each with its reason -(ADR 0656, Consequences; the operator, 2026-11-06 20:3x). The choices, and why: - -| Choice | Why | -|---|---| -| Both graphs kept as objects in an `objects` section in the old form, each with a cap of 512 MiB | both parts are the foundation, whose new kept data goes on the old sections so neither waits on the bus module to start (ADR 0619 §1, §2); the caps are many times the estimated 90 days | -| An unchanged entry stored once, a revision being a list of its entries' digests | consecutive revisions differ by a few entries, so the stores grow by what changes; a larger cap over whole revisions would only delay the same fill | -| No old form written beside the new; a revert restores the parts' kept data on the bus from a restore point taken before they moved, then they catch up forward | only the new form is looked after (the operator, 2026-11-06 21:3x), and a revert still works, as the delivery system's capability for every change of a kept data's form | -| A module's kept data on the bus backed up before a `form` change and restored beside the live data at a revert, a missing restore point holding the revert | ADR 0404 covers only the items on a module's node, so the bus's kept data had no restore point; a restore never goes over live data, and a revert with nothing to restore must not start on the newer form unasked | -| Only kept data whose `form` changes restored, the wants never; at a revert the node-engine last on its node, and the reverted assigner and gate only after the reverted indexer took in the trunk's head | restoring anything else would set back what was decided since; restored wants, or an assigner reading an indexer not yet caught up, would send nodes to older fingerprints; the node-engine of before may not know how to restore | -| A restore point holding the consumers' positions and the catch-up tool the newer manifest declares, called after a restore | the reverted build then hears everything since as after any restart; the stream `forge` keeps 7 days, so what fell out of it is taken in from the trunk by the part's own tool | -| A revision removed when no record pins it and it is not current, pins counted per revision | a trace must read every revision it moved between, and a revision neither pinned nor current is read by nobody; counting pins keeps a revision two records share | -| The indexer and the assigner hear `pinned`, `freed` and `heads-replaced` through durable consumers | an event said while either was down is applied when it comes back, so no revision leaks and none is dropped early | -| Records kept 90 days by default, the gate's setting `record-retention`, the ledger capped at 768 MiB, a record's operations removed with it | the traces asked so far went back weeks; about 840 outcome operations make a record about 200 KiB, so 90 days at an estimated 20 a day is about 360 MiB, and the cap is twice that | -| `record-open` only when no other condition covers the record | the cause is already told once; a second condition for it is noise | -| `full` cleared by `room` when the store falls back below its cap | the refused work is taken up again, and a condition that never clears would hide the next fill | -| The switch into records keyed by milestone and heads, safe to run twice | delivering milestone G again after a revert makes no second record and asks no group again | -| A store passing 80 % of its cap said as `filling` and raised; a full cap refused as `full`, naming the part | the operator hears of a store filling while there is time, and a full store stops work loudly instead of dropping what a trace needs | -| A candidate's graphs kept apart and dropped on `heads-replaced` | a candidate must never write wants or be read by a running part, and its graphs mean nothing once its heads are gone | -| The verbs `revision`, `entry` and `difference` on the two seats | each half of the view, and the difference, is served by its one owner through its seat, never read from its state | -| The node-engine reads its want and the catalog half, never the assignment half | the want is the one record a node reads; the assignment half would have each node read every node's placements | -| Composing waits per node, held by the assigner, with no new field in the want: a node's node-engine want first, its other wants once its new node-engine runs | a node away holds only itself (ADR 0603 §7); an old node-engine reads its want as it is, so it is reached with no form it cannot read | -| Capability changes said as the node-engine seat's event `capabilities-changed` | the assigner follows an event instead of reading node records across the seam (ADR 0596) | -| The step events, their fields and their subjects, with the node in the subject of every event a node publishes | every outcome reaches the delivery record as the event of the part that did it (research 085, Findings 7), and a node's account can be granted only its own node's subjects (ADR 0363 §2) | -| A first tier of only the changed acting parts, bounded at 20 minutes, its verdict telling `waiting for a build node` from `did not build` | an ordinary change pays nothing more; a bound turns a build that never ends into a named failure, and the two words tell the operator which act frees it | -| The build seat's ask `run`, published only by the checker's account, its step keys starting with the asker's name | the program is a long job pulled where capacity is, run in the sandbox every check already uses (ADR 0448 §2), and no other part can have a program run or read its verdict | -| A program built once per fingerprint and reused, only from a run step that runs nothing but the build; a candidate's build never delivered | a check that leaves the checking program unchanged costs no build, and a program run from a change can never change a kept build or reach a node | -| Every program built from a change run with no network and no bus account | a change not yet merged is not trusted, and the sandbox already keeps the logins outside (ADR 0448 §2, §4) | -| Every change of the checking program's fingerprint named in the verdict and the Approve ask, with the rule names of the trunk's and the heads' programs compared by the running checker outside the sandbox as its detail | only the fingerprint covers a helper a rule calls; the comparison is made from the sources by a part the change did not build, so a program that drops a rule and hides it is still named; a rule widens or narrows what judges or acts on every module, so the operator sees it before approving | -| A rule matching a module with no holder for its step held by name, and its check failed | a rule nobody serves would otherwise pass in silence | -| Each step's wait held by the part that does the step, with its own read and release tools and the events `wait-held` (at the wait's start, with its bound) and `wait-ended`, timed by the watchman, whose clock starts when the new version's build is done | the part that does the step already holds its state; the watchman timing from `wait-held` still raises a wait whose holder stopped, and counting from the build done leaves a slow build to the build's own wait | -| The bound per step in the acting rule, with a default per step | the time a step's new version needs is the acting part's to know, not another module's | -| A build module's wait ends on the agreed toolchain naming the new build module | the agreed toolchain is what a fingerprint takes (ADR 0584 §1), so before it names the new build module no module could be built once by it | -| The running indexer makes a catalog graph revision with the named indexer's entry | the newer indexer can then be wanted and granted, so a revision waiting for it is never stuck behind it | -| The acting rule's field `acts` with `step`, `on` and `bound`, the definition format staying 1 | the steps and the language match are what the indexer's map and the checker's cases held in code (research 085, Findings 2); the reader refuses an unknown field, so the runtime learns it in the one rebuild the milestone makes | -| The fingerprint handed as `MESH_FINGERPRINT` at a process's start | one value every runtime reads before anything else, a service and a container alike | -| The delivery record's consumer, held and failed outcomes, end and `record-ended`, the finding `record-open`, node away and wake, switch done once, and tools | a restart must lose and double nothing; a reader sees why an entry stands still; a node asleep must not hold a delivery open; a switch run twice must ask no approved group again | -| A small fix's own record | a small fix is a milestone of one issue (ADR 0493 §3) | -| An Approve given held while its heads stand (issue 1972) | the operator approved those heads; a check of them asked again changes nothing they approved (ADR 0441 §1, ADR 0548 §8) | -| The milestone events on a subject of their own | a waiter on one member's pull request otherwise wakes on every member's | -| The issue tracker's link kinds to a decision and a research effort, and the knowledge base's link from a decision to its milestone | the trace from research to the running build is then links all the way, with no text match (research 085, Findings 7; ADR 0493 §4) | -| The view's state read and asked again by mesh-sdk's `go/views` tools `_first_views` and `_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`) | - -Each choice is checked by the tests its section names; the review by architectural domain judges them. - -### What each step says - -Each step says what it did as its own event, the event of the part that did it. A catalog graph revision kept -carries the source revision; an assignment graph revision kept and a difference worked out carry the source revision -and the assignment graph revisions; an entry taken in, built, checked, composed, wanted and running also carries the -entry's fingerprint and its node. The gate's delivery record is built from them. The seat's event comes first where -the parts follow it through a seat (ADR 0656); a holder's own event stays under its own subject, declared in its own -manifest's `streams` and published on `mesh.stream..event.` (ADR 0363 §1, §2). A seat's event is -declared in its definition and its holder's manifest claims the seat; a seat event's name has no dot, since it is read -as a subject's token, and it is kept on the stream `SEAT__`, which the grants part makes with its durable -consumers, keeping it by the age and cap the definition's `keep` names, 90 days unless it names less. **An event a node publishes carries the node in -its subject**, and the grants part grants each node-engine's account only its own node's subjects, so one node cannot -say another runs a build (ADR 0363 §2); the gate's events are granted to the gate's account alone. - -| Step | Event | Owner: the seat, then the module | Subject | Declared in | -|---|---|---|---|---| -| a catalog graph revision kept, saying whether it is a trunk revision or a candidate's and its watched branch | `catalog-revision` | `mesh-catalog`, the indexer | `mesh.seat.mesh-catalog.event.catalog-revision`, the watched branch in the subject from G's delivery | 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-delivery-contracts` (ADR 0641 §2) | -| a difference worked out | `difference` | `mesh-wants`, the assigner | `mesh.seat.mesh-wants.event.difference` | the same | -| an entry taken in | `take-in.taken`, which gains the entries | the indexer's own | `mesh.stream.mesh-delivery-indexer.event.take-in.taken` | the indexer's manifest | -| an entry built | `build.ended` | the builder's own | `mesh.stream.mesh-delivery-builder.event.build.ended` | the builder's manifest | -| an entry checked | `checked` | `mesh-delivery-checker`, the checker | `mesh.seat.mesh-delivery-checker.event.checked` | the seat's definition in `mesh-delivery-contracts` | -| an entry wanted | `wanted` | `mesh-wants`, the assigner | `mesh.seat.mesh-wants.event.wanted` | the seat's definition in `mesh-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.`, `.running..`, 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.` | 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..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..event.filling`, `.full`, `.room` | each seat's definition | -| a record pins or frees a revision; a candidate's heads replaced; a record ended | `pinned`, `freed`, `heads-replaced`, `record-ended` | `mesh-delivery`, the gate | `mesh.seat.mesh-delivery.event.` | the seat's definition in `mesh-delivery-contracts` | -| a milestone's ask asked, withdrawn and answered, until G's delivery | `milestone-asked`, `milestone-withdrawn`, `milestone-answered` | `mesh-delivery`, the gate | `mesh.seat.mesh-delivery.event.`, the milestone in the event, on the seat's family stream, apart from each delivery's `transition` | the same | -| a delivery record opened, and a merge named a recovery | `record-opened`, `recovery-merged` | `mesh-delivery`, the gate | `mesh.seat.mesh-delivery.event.` | the same | -| a pipeline, its steps, its waits and a run on request, from G's delivery | `pipeline-started`, `pipeline-ended`, `group-ended`, `run-started`, `step-started`, `step-ended`, `wait-held`, `wait-ended` | `mesh-pipeline-runner`, the runner | `mesh.seat.mesh-pipeline-runner.event....` | the seat's definition in `mesh-delivery-contracts` | -| a pipeline step ended, from G's delivery | `step-ended` | each build seat, `mesh-wants` | `mesh.seat..event.step-ended.`, the node that ran it | each seat's definition | -| a registration changed; a package published, from G's delivery | `registration-changed`; `package-published` | `mesh-catalog`, the indexer; `mesh-builds`, the builder | `mesh.seat.mesh-catalog.event.registration-changed`; `mesh.seat.mesh-builds.event.package-published` | the seats' definitions in `mesh-delivery-contracts` | - -The events, their fields, their subjects and which are a seat's are this design's choices: a seat's event where -other parts follow the step through the seat, a holder's own event where only the delivery record hears it, so that -nothing reads another module's bus state (ADR 0596). The builder's waits go on its own stream because the builder -holds no seat of its own; the watchman and the gate follow them there. How it is checked: each seat definition's -conformance fixtures name the subject of every event it gains, and a case of the holder's whole-module test matches an -event it publishes against them, as for every seat (design 26); the gate's whole-module test hears each row through -its durable consumer, with exactly the fields this section gives it; a `running` event published by one node's account -on another node's subject is refused by the bus. - -### Their tools - -| Line | The assigner | The indexer | -|---|---|---| -| read everything it holds | `assigner_revision` (one assignment graph revision whole, with the revisions of its inputs), `assigner_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) | -| 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` | - -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 -list again, the view is read and steered by the two tools mesh-sdk's `go/views` already serves every part that takes a -first view: `_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 `_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 -lines every module's tools answer (design 26), so that every state these parts keep is read and every act they do is -steered by a tool. - -**How it is checked.** Unit (assigner): a revision of the assignment graph computed again from its named inputs -equals the one kept; a fixture change with a new fingerprint and an empty difference is refused, naming its module; -one revision of about 120 modules on four nodes stays under the bus's value limit; of the view the assigner reads only -the catalog half. Unit (indexer): a catalog graph revision holds one entry per module of its source revision. Whole -(indexer): a source revision taken in gives one catalog graph revision kept as objects in an `objects` section in the -old form within the cap its manifest declares; the manifest validator refuses the indexer's or the assigner's manifest -that declares them in the new form. Whole (indexer, assigner): a revision a delivery record pins is not removed; one -two records pin stays until both free it; one neither pinned nor current is removed; a `freed` said while the part -was stopped is applied after its restart; a candidate's graphs are dropped on `heads-replaced`; a store past 80 % says -`filling` and raises `store-filling`, and a full one says `full` and refuses its next revision naming itself; for a -candidate's heads both `revision` verbs answer, the assigner's half named by its own revision and naming its inputs; a -placement change with no merge, and a `capabilities-changed`, each give a new assignment half on the same catalog half, -whose difference moves only the module concerned, and a part takes that pair as its view; after its first view a part -acts on a seat event without asking a verb again; a running part does not act on a candidate's view; a pull request -that adds a seat and a module using it is validated by the indexer's candidate pass and checked by the checker with -the same definitions; the tools of the table answer and the drop tools write the hand-act log. Whole (assigner): a -pull request's graph leaves every node's want unchanged; a placement-only revision moves the want of the module it -places; the builder and the grants part read their entries only through the seat `mesh-wants`'s verbs and events, and -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' -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.`, the forge bridge's read of the gate's `merges` and `owed`, -the checker's read of the gate's `source` and `turns`, the forge module's watch of the checker's `owed` (its `mesh/check` -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. +**From milestone G's delivery** the gate keeps no merge states: design 47 G, *The state table, from milestone G's delivery*. ## Order without a person @@ -1819,135 +526,6 @@ per module and node from the keys: 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 - -*ADR 0656, which supersedes ADR 0646; ADR 0603 §1 to §4, §8, §11, ADR 0614 §1, §3, §6, ADR 0633 -§1, ADR 0539 §7, ADR 0584 §1, §2, ADR 0564 §2.* - -From research 085's milestone. A seat's definition may carry a rule, the step its holder acts in and the modules it -acts on, and a holder of such a seat is an **acting part** (ADR 0656): the indexer taking in and validating, the -checker checking, the build modules building, the node-engine composing, the grants part granting, the assigner -placing. *What ADR 0656 leaves to this design*, above, gives the rule's fields. Adding one needs its manifest and -its seat's rule, and no code elsewhere: the indexer's map from language to build module and the checker's own module -names go, since every new acting part needed code changes elsewhere (research 085, Findings 2). - -- **The rule becomes edges between versions.** In the assignment graph the assigner gives an edge from the acting - part's version to each version its rule names, and no part names another module in its code to order by (ADR 0656). -- **Within a revision the new version acts first, a wait with a bound.** The entries an acting part acts on wait for - its new version in its own step, with the bound its rule's `bound` gives (ADR 0656), the part's own as ADR 0603 §8 - has every wait. A bound's clock starts when the new version's build is done, not when the wait begins, so a slow - build of the acting part is the build's own wait and not counted twice. When a rule names none, the step's default holds: 60 minutes for building (a build module's own - build and its spread to a majority of build nodes), 30 for composing (a node-engine's apply on one node), 10 for granting and placing (a write of one part), and the first tier's 20 for checking. A module changed with - its build module is no longer built with the running recipe and again later, and a build module's edge, a trigger no - want waited on, becomes this wait (ADR 0656, which changes ADR 0603 §1, §3 and ADR 0614 §1, §6). -- **A build module's wait ends on the agreed toolchain.** For building, an entry waits until the agreed toolchain of - its language (ADR 0584 §1) names the new build module, never merely until the new build module runs on one node: a - fingerprint names the agreed toolchain (ADR 0603 §3), so only then is the module built once, by the new one. A build - node still on the old build module builds nothing of that language until it reports the agreed one (ADR 0584 §2). - Every other step's wait ends when the acting part's new version runs healthy, as the node-engine seat's `running` - event says. -- **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 - the wants, holds a node's other wants until the node-engine seat's `running..` 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 - 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, - so a node asleep raises nothing while away. -- **A failed or late new version holds its modules, and a condition names it.** When the new version fails, or its - wait passes its bound, the entries waiting for it stay held, the modules stay on their running builds, and the - watchman writes the finding `acting-part-late` naming the acting part, its step and since when, and the condition - keeper raises it (ADR 0564 §2). The holder says `wait-held` at the start of the wait, carrying its bound, and the - watchman times it: a holder stopped in the middle of a wait still has its wait timed, so a stopped holder hides - nothing. At its own start the watchman reads the open waits from each holder's read tool, as it seeds - `take-in-waits` from `indexer_pending`, so a wait said while it was down is timed too. An entry moves on only once the new - version runs, or its holder's release tool releases it; either way the holder says `wait-ended`, and the finding and - the condition clear. The operator sees each stuck acting part as one condition. Going on with the running version - instead would build or check a change with a part it replaced, the cause of the failures of research 085, Findings - 4; stopping the whole delivery would hold modules the failed part does not act on (the operator, 2026-11-06 17:0x). -- **A wait holds only within its step, and skips the holder's own inputs** (ADR 0656). An entry waits only for its - own step's holders, so two acting parts that act on each other in different steps (the indexer taking in the - checker, the checker checking the indexer) form no cycle. Within a step a holder's own change is its first act, and - what its new version is built from or needs (a base, a package, a provider) is acted on by its running version, - never waited for: the running build module builds the shared contracts and the registry holder, then the new build - module builds the rest, so ADR 0614 §6's cycle through them stays allowed, now for that reason. -- **The 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 - cycle), counted beside the edges ADR 0614 §3 and §6 list; a cycle through an acting part's edges across two steps, or - through a holder's own inputs, is none. -- **The indexer's own steps have no wait, and a newer indexer is reached.** Taking in and validating stay as *Taken in - by the indexer it names* has them: a revision is taken in only by the indexer it names, which judges its own change - at its start, and no build waits on which indexer judged it (ADR 0603 §4, as ADR 0633 §1 changes it). So that the - named indexer can start at all, the running indexer makes, for a merged revision naming a newer indexer, a catalog - graph revision that is the previous one with only the indexer's entry replaced by the one its manifest at the merge - gives, and nothing else of the revision, so no other want moves before the named indexer takes the revision in; the assigner wants it and the grants part grants it like any module, and once it runs it takes the revision - in whole. Without that, a revision waiting for its indexer would wait for good. -- **A rule with no holder is no silent pass.** An entry a rule matches with no holder for its step is held by the - assigner, naming the missing holder as the hold's reason, and the check fails naming it. -- **An acting rule grants nothing.** A holder's bus grants come from the grants part as today (ADR 0539 §7). An - acting rule changes what a part acts on across every module it matches, so the operator's Approve ask of a change - names any acting rule it adds, and any it widens: a `step`, an `on` or a longer `bound` that now matches more - modules or holds them longer is named like an added rule. From G's delivery there is no Approve ask per merge, and - the pipeline's end names it in `widens` instead, refusing nothing (ADR 0666 §23). -- **Each step's wait is its own part's, read and released by its own tools.** The part that does a step holds its - wait, so each wait has one owner that already holds that step's state, and says `wait-held` and `wait-ended` (*What - each step says*) with the step, the acting part, its version, the entry and since when: - - | Step | Holder | Reads its waits | Releases one | - |---|---|---|---| - | building | the builder, on its build key | `builder_waits` | `builder_release` (build the entry with the running build module), beside `builder_build_again` (ADR 0603 §11) | - | placing and wanting | the assigner, on its hold | `assigner_waits` | `assigner_release` (ADR 0603 §11) | - | granting | the grants part | `grants_waits` | `grants_release` | - | composing | the assigner, holding a node's other wants until its new node-engine runs there (*Composing waits per node*) | `assigner_waits` | `assigner_release` | - | checking | the check's first tier | `checker_first_tier` | its ask-again (*The check on the change's own acting parts*) | - - Each release writes the hand-act log of the seat `mesh-hand-acts`, with who released and why. -- **How it is checked.** Whole (assigner): a fixture seat declaring a rule, with a fixture holder, gets its edges with - no code change elsewhere. Whole (assigner, builder, three build nodes): a group changing the shared contracts and the - build module that builds them, the new build module updated on the first build node first, builds no module with the - new build module while one node of three runs it, builds the contracts with the running build module, and once the - second node reports it and the agreed toolchain names it, builds each other module once, by the new one; the third - node builds nothing of the language until it reports the agreed version. Whole (assigner, builder, grants part, - watchman): a fixture acting part whose new version fails, and one whose wait passes its bound, each leave their - modules on their running builds, say `wait-held` at the wait's start with its bound, and raise `acting-part-late` - naming it; a holder stopped in the middle of a wait still raises it, and a watchman restarted mid-wait reads the - wait from the holder's read tool and times it; a bound counts from the new version's build done; each holder's release tool - moves a held entry on, says `wait-ended` and writes the hand-act log, and the condition clears; a wait ends on its - own when the new version runs; each holder's read tool lists its waits with step, acting part, version and since - when; a rule's `bound` overrides the step's default. Whole (assigner, node-engine): during a node-engine change with - one node away, the present nodes take their new node-engine and then their other wants, nothing waits on the node - away and no condition is raised for it; a node asleep since before milestone G wakes, takes its new node-engine - first, then the rest. Whole (indexer, assigner): a merged revision naming a newer indexer gives a catalog graph - revision that is the previous one with only the indexer's entry replaced, and no other want moves; the new indexer is wanted and granted, starts, - and takes the revision in, with no build waiting on which indexer judged it. Whole (assigner): a module with no - holder for its step is held by name, and the check of a change bringing it fails naming the missing holder. Unit - (graph): an acting part acting on itself, two acting parts acting on each other in different steps, and a cycle - through a build module's edge each pass the cycle check, each new version first in its own step; a cycle among - waits within one step is refused. Unit (assigner): the Approve ask of a change that adds an acting rule, and of one - that widens one, names the rule. Live: a search of the delivery parts' code finds no other module's name. - The planner's edges (*built by*, *SDK before its users*, *verb before caller*, *version skew*) and its one default, the node-engine before the controller, ordered the tiers of a plan until release 6 (ADR 0419 §3 to §5). For release 6's own switch, the last plan of release 5's controller, the version-skew edge and that @@ -2063,18 +641,7 @@ the check gates merges.* *ADR 0548 §2 to §4, §9, §10, as ADR 0551 bounds them; from research 085's milestone removed by ADR 0661 (accepted on 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 no merge waits on a check, and none on an Approve either (ADR 0666 §10): the checker is gone, and the -pipeline runs on the landed commit (*Pipelines per module*). **Its record is accepted:** ADR 0661 ends ADR 0548 §2 -to §4, §9 and §10 and ADR 0551 and changes ADR 0534 §4's judgement of `mesh/check` by the merge; until G's delivery the -rule below holds as those records have it. ADR 0662 is withdrawn; G builds ADR 0661 §1, §2 and §6, and ADR 0666 §10 -changes its §3 to §5 (the merge on the Approve alone), which G therefore builds for no merge. Beside it, ADR 0663 (accepted: the indexer answers `revision` in its own runtime to -exactly the parts that invoke it, the tool runner among them) holds the tool -runner's first view of the catalog half (*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. +**Removed at milestone G:** design 47 G, *Nothing merges into a repository under check: removed*. Until milestone G's delivery: @@ -2172,80 +739,6 @@ From its delivery, a check is this: heads in the check's first tier and composes with its own code (ADR 0656; *The check on the change's own acting parts*, below). -### The check on the change's own acting parts - -*ADR 0656, which supersedes ADR 0648, ADR 0644; ADR 0448 §2, §4, ADR 0391 §1, ADR 0603 §10, ADR 0614 §7, ADR 0633 -§6, ADR 0636 §4, ADR 0639 §5, ADR 0498 §1.* - -From research 085's milestone. ADR 0603 §10 and ADR 0614 §7 let a check pass while the part that would build or -check the change never ran: 7 of 24 failures since 2026-11-01 (research 085, Findings 4). The acting parts a change -alters, and the checking program, the rules every check applies, are built from the change's heads and check it; the -running versions never check in their place, and a check fails, naming the part, when one cannot be built or run -(ADR 0656). - -- **Two tiers on the change's assignment graph.** The first tier builds, at the change's heads, only the acting parts - whose fingerprint in the change's assignment graph differs from the running one and which are to act on a module - the check acts on; a change to an ordinary module asks no first-tier build, since building every acting part for - every check would make an ordinary change pay for builds that change nothing. The second tier runs the check's - levels with those programs and with the revision view of the change's heads (ADR 0656). This keeps ADR 0603 §10's - building of changed build modules first and widens it to every acting part. -- **The judging rules are a checking program built from the change.** Every check builds its checking program from - the change's heads and runs it with the revision view as its input; when it cannot be built or run, the check - fails naming it, and the running checker's own rules never judge in its place (ADR 0656). It is built once per - fingerprint and reused (ADR 0498 §1): checks whose heads leave the checking program unchanged ask one build between - them. -- **Every program built from a change runs only in the build seat's sandbox.** The acting parts the first tier builds - and the checking program run in the run step, with no network (ADR 0448 §2) and no bus account, the logins staying - outside (ADR 0448 §4), through the seat `node-build-go`'s ask `run` (*What ADR 0656 leaves to this design*), as - the validator, the composer and the Go build module already run; a change not yet merged is not trusted. The running - checker alone asks, reads the program's verdict, records it and publishes it. -- **A first tier that cannot build an acting part fails the check, naming it.** The verdict never passes on the - running version's word: a module whose changed build module the check cannot run is no longer composed from its - manifest (ADR 0656, which changes ADR 0603 §10 and ADR 0614 §7), and ADR 0614 §7's reason, a changed build module - invoking a verb no running holder serves, is one reason the first tier cannot run an acting part: the check fails - naming the build module and the verb. An acting part not built within the first tier's bound of 20 minutes is one - it cannot build, and the verdict says `waiting for a build node` or `did not build`. -- **A change to the checking program is named, by a part it did not build.** Every change of the checking program's - fingerprint is named in the verdict and the Approve ask, whatever changed: a helper a rule calls changes what the rule - judges as much as the rule does, and only the fingerprint covers every input. The rule-name comparison is its detail: - each checking program declares its rules by name in its source. The running checker, outside the sandbox, reads the rule names from the - trunk's sources and from the heads' and compares them; every rule removed, added or altered (its source changed) is - named in the verdict and in the operator's Approve ask. The program built from the change is never asked which rules - it has, so a program that drops a rule and hides it is still named. -- **ADR 0633 §6 stays, beside the change's own validator.** Whether the running parts can take the change in is - still checked with the trunk's manifest validator, built from the trunk (ADR 0633 §6); the change's own validator, - built in the first tier, judges the change's manifests besides (ADR 0656). A change fails if either refuses it. -- **The asking and recording are covered by the checker's whole-module test**, which starts the changed checker on a - real bus and asks one check of a fixture group end to end (ADR 0391 §1). -- **One seat list for both readers of a change's heads.** Inside every check, a lone pull request's as a group of one, - the checking program built from the heads makes one seat list from them, and the checker hands it to the manifest - validator and the composer (ADR 0644, ADR 0636 §4 with its insight of 2026-11-06); the running checker reads no - definition of the heads itself (*The bootstrap delivery, and the one milestone after it*). -- **Its tools.** The checker's read of a check names the checking program's build that judged it, its fingerprint and - the heads it was built from, and the rules named changed; `checker_first_tier` lists a check's first-tier builds, - each with its acting part, its fingerprint and its outcome (`built`, `waiting for a build node`, `did not build`), - and asks one of them again. Asking a whole check again stays the checker's existing ask-again. -- **What it costs.** A check of a change to an acting part costs one build per changed acting part, within the - checker's step bound (ADR 0639 §5); an ordinary change costs nothing more; a checking program costs one build per - fingerprint, shared by every check that uses it. -- **How it is checked.** In the checker's whole-module integration test: a fixture change whose acting part does not - build, and one whose checking program does not run, each fail their check, naming the part; a checking program that - builds but does not run fails naming it; a first-tier ask no build node takes within the bound says `waiting for a - build node`, and one that fails says `did not build`; a change that breaks a rule of the checking program fails its - own check; a change that removes a rule passes, and its verdict and the ask name the removal, also when the - program built from the change hides it; a change to a helper a rule calls, with no rule renamed, names the checking - program's new fingerprint in the verdict and the ask; a program that rewrites its own binary while it runs changes - no kept build; a fixture checking program that tries to reach the bus or the network - fails; a `run` ask published from an account other than the checker's is refused by the bus, and the checker's - account cannot read another account's step key; a fixture build module invoking a verb no running holder serves - fails naming it and the verb; a change to an ordinary module asks no first-tier build; two ordinary checks with the - same checking program ask one build of it; a group that changes the assigner's placing is checked with its own - assigner; a fixture indexer change whose manifest the trunk's validator refuses fails its check, even when its own - validator passes it; a fixture group whose heads add a seat has that seat in the list both the validator and the - composer receive; the check's read names the checking program's build, heads and changed rules; `checker_first_tier` - lists a check's first-tier builds and asks one again; the changed checker asks one check of a fixture group end to - end. Live: the registry group passes its one check with its own checker, validator and composer. - ### A try: a delivery group's check at exact commits *ADR 0637, ADR 0638; ADR 0593 §7, §9, ADR 0636 §4, ADR 0548 §5, ADR 0596 §1 to §3, ADR 0615, ADR 0639 §1 to @@ -2410,13 +903,8 @@ session merges a pull request*). assigner writes each want when its six rules hold. A merge is never refused, held or dropped once it is made. What of it is taken in waits only for the indexer its source revision names, or for the rest of its group (*Taken in by the indexer it names*, below; ADR 0633). -- **From milestone G's delivery, per watched branch.** The gate writes one source revision per watched branch, - `source.`, as a commit or a group lands there; the pipeline runs on each revision the indexer takes in, and - the wants follow a revision whose `required` steps passed, on the branch each placement chose (ADR 0666 §6, §9). -- **From research 085's milestone, the wants follow the trunk's assignment graph.** A merge taken in makes a - catalog graph revision and then an assignment graph revision; the assigner writes each want from that revision, - its rules unchanged (ADR 0656), and each acting part's new version acts first in its own step (ADR 0656; *Two - graphs, one source of truth*, above). +- **From milestone G** the source revision is kept per watched branch and the wants follow the assignment graph: + design 47 G, *After the merge, from milestone G*. - **Two merges close together are two revisions.** The second's fingerprints replace the first's in the indexer's modules; a node gets the newer fingerprint's want once its rules hold, and a fingerprint nobody wants any more is never applied. Nothing waits for a window to close. @@ -2524,12 +1012,7 @@ timer. A group's merges arrive together. `take-in.taken`: a hand take-in as any take-in does, and a hand drop naming the drop, for a merge whose wait was said pending, so the watchman's `take-in-waits` clears; a drop of a merge never said pending emits none (ADR 0633 §5, ADR 0639 §9). -- **From milestone G's delivery** (ADR 0666 §6, §13, which change ADR 0633 §1 and §3 to §6): before any take-in, on every - watched branch, the running indexer validates the revision with the manifest validator built from its heads, in the - sandbox, and a revision it refuses stays pending, as the bullets above have it, with the way back a revert; a pending - revision holds only its own watched branch; a group's member reaches it by landing, and the group ends when the gate's - group verb says every member has; `bridge_group_end_again` reads that verb; and the check's refusal below goes with the - check (*Watched branches and the catalog graph per branch*, *Groups*). +- **From milestone G's delivery:** design 47 G, *Taken in by the indexer it names, from milestone G's delivery*. - **The check refuses an indexer the running parts could not move, until G's delivery.** For a change to the indexer's own module, the check validates the new indexer's manifest, found as the manifest that claims the seat `mesh-catalog`, with the trunk's manifest validator in its sandbox and the seat definitions of the members' heads, and refuses the change @@ -2570,99 +1053,6 @@ backup holder backs up nothing, and the have says so. - **What it costs.** About 85% of data modules back up in under 30 s; the slowest measured, postgres on the home server, about 165 s (research 055, finding 5). A module that keeps no backed-up item costs nothing more. -### A module's kept data on the bus, backed up and restored with its delivery - -*ADR 0404, ADR 0235, ADR 0233, ADR 0539 §16, ADR 0595, ADR 0619 §2, ADR 0633 §1, §5, ADR 0363 §2; from research -085's milestone, this design's choice under ADR 0656.* - -**ADR 0404's backup does not cover a module's kept data on the bus.** It backs up the items a moved module keeps on -its own node (ADR 0404 §2, ADR 0233), and the bus's streams are dumped whole by the bus module on its own rhythm -(ADR 0235), not per module and not before a delivery. A key-value state, a stream or an object store a module keeps on -the bus (ADR 0595, ADR 0619 §2), and its durable consumers' positions on the streams it reads, therefore have no -restore point taken before its module moves. That is a gap of the delivery system, and milestone G builds it, because -a revert of milestone G is the first change that needs it. It is built as the delivery system's capability for every -later change of a kept data's form, not as a case of this milestone. - -- **Its form is declared.** Each kept data a manifest declares names a `form`, a number its holder raises whenever it - changes how it writes that data, or stops declaring it; a declaration naming none reads as form 0. The declaration - alone cannot tell a changed layout of the same bucket, so the holder says it. Only kept data whose `form` changes is - backed up and restored, so a part's other kept data, and every decision it holds, is never set back. -- **It is backed up before the module moves.** When a want moves a module whose new manifest declares a kept data at - another `form` than the running one, or no longer declares it, the node agent applying it first asks the seat - `node-backup` of the node holding `mesh-broker` for a restore point of that kept data, and waits for its event - `ended`, as for any backup before the apply. The bus module's account takes it, as it takes the bus's snapshots - (ADR 0235 §5). A restore point is keyed by the module, the kept data, its form and the fingerprint it was taken - before, and it holds the kept data whole, the position of each durable consumer the module reads with, and the - catch-up tool the newer manifest declares beside that kept data. A failed - backup holds that module as any failed backup does. -- **A revert restores it before the reverted build starts.** When a want takes a module back across a change of a - kept data's `form`, the node agent applying it asks that seat's verb `restore` for the restore point of that module, - kept data and form, waits for the seat's event `restored`, and only then starts the reverted build. The node agent - that restores is the one running when the revert starts. As every restore is, it is brought back beside the live data - and never over it: the live kept data of the newer form is set aside under a name of its own, and only the operator - removes it, so nothing written since is destroyed. The consumer's position is set back with it, so the reverted - build hears everything since as after any restart. -- **The order of a delivery that crosses a form change** is the module graph's (*Order without a person*), with three - edges the assigner, which writes every want, keeps: - - the new versions of the `node-backup` holder and of the bus module run before any module whose kept data's form - changes is moved, since the restore point needs both; - - at a revert, a node's node-engine goes back last on that node, after every module it restores there has said - `restored` and runs, since the node-engine of before may not know how to restore; - - the reverted assigner and gate are wanted only once the reverted indexer has taken in the trunk's head, as its - `take-in.taken` naming the current source revision says (ADR 0633 §1), since the assigner of before computes the - wants from the indexer's `modules` and would otherwise write the fingerprints of the restore point. Until then the - running assigner writes no want, and every module keeps the fingerprint it runs. -- **The restored part catches up forward, with the code it already has.** Read on main, mesh-delivery at 2d201f78 - and mesh-catalog at 1d07778c: - - **The indexer** (mesh-delivery, `modules/mesh-delivery-indexer`): its durable consumer `_` on the stream - `forge` redelivers every message since the restored position, and `handle` takes each - merge through `Indexer.Arrive` into `pending` and then into `modules` (`applyMerged`); `applySource` takes the - gate's `source.main` in, and `ApplySource` leaves a revision older than the latest it has seen. **The stream - `forge` keeps 7 days**: the forge bridge's manifest declares no age, and a stream's default is 7 days, at most 30 - (mesh-sdk `go/catalogue` `StreamDefaultDays`, `StreamMostDays`), so it does not cover the records' 90 days. A - merge older than the stream's first message is never redelivered, and the code then leaves that repository's - modules at the restore point's fingerprints. So the restore runs one forward step: once the reverted indexer - runs, the node agent that restored it calls its tool `indexer_take_in` with each repository the gate's source names - (`NewTakeInRepository`, which takes in the head the source names for a repository). The catch-up tool is declared - by the newer build's manifest, beside the kept data whose form it changes, and recorded in the restore point when - the backup is taken; the node agent takes it from the restore point, never from the manifest being applied, since - at a revert that is the manifest from before the change, which names none. So the delivery system names no - module's tool. - - **The assigner** (mesh-delivery, `modules/mesh-delivery-assigner`): it keeps nothing restored. Its pass - (`passer.wants`) writes, from what the world holds now, each node's want by the six rules from the indexer's - newest fingerprint at the trunk, and only where the value differs; so once the indexer has caught up it writes - the trunk's wants, and nothing older. - - **The gate** (mesh-catalog, `modules/mesh-delivery-gate`): `Holder.Load` reads the restored deliveries and groups - back; `readOnStart` then reads what happened while it was away: `wantForge` reads the forge's open pull requests - at the next look, `hearAsks` reads the teller's answer to every ask it still holds as pending, and - `SourceCatchUp` brings the newest merge of each repository into `source.main`, never moving a repository back. An - ask the gate of milestone G raised after the restore point is not among the pending ones, so its answer is not read - and the operator is asked again. Whether the first look clears a merge kept in the restored `merges` that the forge - merged since was not read in the code; the catch-up test below proves it with the real builds. -- **A missing restore point holds the revert, naming it.** When the restore point a revert needs does not exist, or - `restored` does not come, the node agent applies nothing of that module, keeps what runs, and writes the have phase - `held` with the reason `restore point missing` and the module, kept data and form it names; the assigner asks the - operator (hold, or start the reverted build on the live data as it is), raises the condition naming them, and on - the answer writes the node's want again naming it (ADR 0539 §16). -- **What the operator is told.** A revert across a change of a kept data's form puts that kept data back to the - moment before the change moved it: the deliveries made since stay delivered, but what the part wrote there since - (for milestone G, its delivery records and its graph revisions) is set aside and not read again; an Approve asked - and answered since is asked again, and one the gate asked before still reads its answer. The revert's Approve ask - says this in those words, naming each kept data restored. -- **Its tools.** The seat `node-backup`'s `backed-up` lists each module's restore points of its bus data, with the - kept data, the form and the fingerprint each was taken before, and the data set aside at each restore, with its - size; `restore` restores one; `discard-aside` removes data set aside by a restore, only on the operator's call, and - writes the act, who and why in the hand-act log of the seat `mesh-hand-acts`. `backed-up` and `restore` exist on - the seat today and gain the module's kept data on the bus as an item; `discard-aside` is new. -- **How it is checked.** Whole (node-engine, backup holder, bus module): a want moving a module across a `form` - change, and one moving a module whose kept data declares no `form` to one that does, each take a restore point - first, keyed by module, kept data, form and fingerprint; a want taking it back restores it beside the live data and - the consumer's position before the reverted build starts, and the data set aside is listed with its size and - removed only by `discard-aside`, which writes the hand-act log; a revert of a group holding the node-engine and a - module whose form changes restores the module before the node-engine goes back; a revert whose restore point is - missing is held, naming it, and moves on only on the operator's answer. The catch-up is proved with the real builds - of the indexer, the assigner and the gate from before milestone G, never fixtures (acceptance test 36). - ## Compositions, wants and the apply *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.* @@ -3039,153 +1429,9 @@ forge module's files of what it announced (ADR 0406 §6). `times`, `what-if`, `release`, `stop` and `retire-history` went at release 6; each is answered that it no longer exists. -From research 085's milestone the seat gains: - -| 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), 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*) | -| `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..`, 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` | until G's delivery: 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.`, the milestone in the 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`. G's delivery ends the ask and its three events with the Approve per merge (ADR 0666 §10) | -| `record-opened` | a delivery record opened, which the watchman times for `record-open` | -| `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*) | - -From milestone G's delivery the seat's `table`, `recheck` and `close` go with the merge states (*The state table*), -the milestone ask and its three events with the Approve per merge, and it gains (ADR 0666 §6, §26): - -| Verb or event | Answers or does | -|---|---| -| `source` with a watched branch | that branch's source revision; the indexer and the node-engine's catch-up read it, never the gate's state | -| `source-moved` | a new source revision of a watched branch | -| `recovery` | marks a merge its author names a recovery (the commit and why), its record marked `recovery` with the caller the runtime proves | -| `record-opened`, `recovery-merged` | a delivery record opened; a merge named a recovery, which the teller passes on to every channel | - -**The seat `mesh-pipeline-runner`**, from milestone G's delivery, defined in `mesh-delivery-contracts` with the callers -of each verb (ADR 0666 §7, §20, §25): - -| Verb | Answers or does | Callers | -|---|---|---| -| `run` | the run on request of one or more members, each a module at a named commit; delivers nothing | the sessions (the agents' bus identities the tool runner proves) and the operator, nothing else | -| `start` | a delivering pipeline for a watched branch's head, by hand | the operator, the healers | -| `show`, `list`, `stands`, `why-carried`, `kept` | one pipeline whole with its step log; the pipelines and runs of a module, a branch or a commit; what stands still; where a result was carried from; the kept results | any person, an agent session, the healers | -| `review` | a code review's result for a commit and fingerprint | the reviewers the definition names; refused from the commit's author | -| `rerun`, `accept`, `cancel`, `ask-again` | one step again; a failed `optional` step accepted with why; a pipeline ended, its asks dropped; a declined `approval` asked again | the operator, the healers (`accept` and `ask-again` the operator) | - -**The seat `mesh-catalog`** gains, from milestone G's delivery, `register`, `policy`, `watch`, `unwatch` and -`registrations`, and the event `registration-changed` (*A module's registration*), and `catalog-revision` names its -watched branch in its subject. **The build seats** gain the verb -`steps` and the accepted kind `step`, and **the seat `mesh-wants`** the kind `step`, each saying `step-ended`. **The -seat `mesh-builds`**, new and held once for the mesh, says `package-published` (*A publish rebuilds*). - -**The seats `mesh-catalog` and `mesh-wants`** gain, from research 085's milestone, `revision` on each (the two halves -of the revision view, ADR 0656), and `entry` and `difference` on `mesh-wants` (ADR 0656), with the events of *What -each step says*. - -**The seat `node-engine`**'s event `running..` carries, from research 085's milestone, the module, its -fingerprint and the digest of its build's manifest, so the node-engine of another node and the grants part decide a -seat's pass from it (ADR 0660 §2; *Who holds a seat is applied by one rule*). No verb is added. - -**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, and `merging` while the forge merges it; an unknown one answers the error kind `not-found` | the forge bridge (a merge the gate did not make; `gitea_api`), the gate (a stalled line's author) | -| `branch` | from milestone G's delivery: a branch's head, and whether a protection rule refuses a direct push and admits only merges | the indexer (`register`, `watch`), the forge bridge (a watched branch's head) | -| `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` | until G's delivery: 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). From G's delivery: merges with the forge tools' account (ADR 0398 §2) at the head the caller names, judging that it is still the pull request's head and that the branch's protection refuses a direct push, the protection read again on every `branch-moved`, and refusing a head when any run at its build-input fingerprint failed a `required` step, judged from its own state `failed-steps` heard from the runner's `step-ended`, never by a call; a head with no run yet or a passed one merges, it never waits for a run and never asks an Approve (ADR 0666 §11). A pull request already merged at that head is answered performed | until G's delivery the forge bridge alone (`gitea_merge_pull_request`); from it any session the tool runner proves, and the operator | - -| 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`) | -| `branch-moved` | from milestone G's delivery: a branch's new head, by a merge or an admitted push, from the forge's push webhook | the forge bridge | - -Each is said on `mesh.seat.git.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. From G's delivery the callers per verb are the seat definition's field `callers`, - the grants part's one source (ADR 0666 §20): `status`, `comment`, `view` and `note` the forge bridge alone, - `merge-pull` the persons and agent sessions the tool runner proves, the reads the parts that declare them. 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, and from G's delivery no Approve, only the runs at the head's fingerprint.** 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*). From G's delivery it judges no Approve either, its caller - is any session the tool runner proves, and it refuses a head when any run at its fingerprint failed a `required` step, - never waiting for one (ADR 0666 §11; *Approval is a step, and a session merges a pull request*). The reads the - gate would have needed to merge (the forge's word for a conflict, the base's required statuses, the merging account's - write access) are not added: no part of the mesh but `merge-pull` merges, and it answers git's own refusal of a merge - as refused. -- **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 - `_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 -with no text match (research 085, Findings 7). The issue tracker gains link kinds from an issue to the decision and to the research effort -it carries, made by a tool call and never by text, as ADR 0493 §4 has every link made; the knowledge base gains a -typed link from a decision to the milestone of the issue tracker that builds it, made by a tool call, which joins the -link kinds of its link-fits rule (design 55), beside the `became` link a research effort gets at its graduation -(playbook 02). How it is checked: whole (gate), one ask per milestone, withdrawn by a new head; -a waiter on one member's pull request wakes only on that member's transition. Whole (issue tracker, knowledge base): -an issue linked to a decision and to a research effort reads both back; a decision linked to its milestone reads it -back. Live: research 085's milestone's record reads back research 085 to its decisions, its milestone, its issues and -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. +From research 085's milestone and milestone G's delivery the seat gains verbs and events, and the seats +`mesh-pipeline-runner`, `mesh-catalog`, `mesh-wants`, `mesh-builds`, `node-engine` and `git` theirs: design 47 G, +*The verbs milestone G adds*. **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`, @@ -3663,7 +1909,8 @@ ADR 0667's checks, of milestone G itself: that branch passes it (whole, runner and condition keeper). 99. **The build capacity.** In the week after G, the build nodes' time per day, read from the build modules' step keys and the builder's build log, is set beside the checker's in its last week; a newer publish supersedes an older one's - rebuild pipelines, and the first pipelines after G carry what the checker's kept verdicts held (live; whole, runner). + rebuild pipelines, and the first pipelines after G run every module's tests once, `kept` starting empty, and carry + from then on (live; whole, runner). 100. **The new assigner before the new merge.** In G's delivery the delivery plan delivers the new assigner before the forge module's new `merge-pull` and before the runner, by their `needs`, and no merge made through the new `merge-pull` reaches an old assigner; until the first registrations' `registration-changed` the new assigner writes @@ -3716,27 +1963,7 @@ ADR 0667's checks, of milestone G itself: view's events instead; the assigner's comparison with the send; the node-engine's queue of whole declarations, its orders, put-backs and five-minute reconcile; the buckets of plan state; the stop of a shared plan (ADR 0299, superseded by ADR 0539 §18); and a declaration sent by hand (ADR 0526 §4, changed by ADR 0539 §10). -- At research 085's milestone's delivery: the indexer's map from language to build module, and the checker's own - module names and its cases for a change to the manifest validator and to the Go build module (ADR 0656); a build - module's edge as a trigger, with the extra build per recipe change (ADR 0603 §3, as ADR 0656 changes it); composing - from manifests a module whose changed build module the check cannot run (ADR 0603 §10 and ADR 0614 §7, as ADR 0656 - changes them); the module graph's one key per module with five past values 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 - list compiled into a part, and every read of another module's bus state the revision view replaces (ADR 0656); the - 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. -- At milestone G's delivery, from research 086 (ADR 0666, ADR 0667): the checker (`mesh-delivery-checker`), its seat, - its try with `tryevent` and the indexer's try candidates, its kept verdicts and carries (the runner's from then), the - checking program and `mesh/check`, and its buckets and bus account, removed with the gate's forge merge token only - after the first pipeline after G's delivery has delivered a change end to end and on the operator's one word, its - buckets through `drop` after a snapshot whose restore is tested (ADR 0667 §12); the bundle of steps run before a merge; the Approve per - merge, the milestone ask and its three events, and the gate's merges; the gate's merge states, one key per pull request and its verbs `table`, `recheck` and - `close`; the trunk-only want; `source.main`, for one source revision per watched branch; every fixed branch, - repository and module name in code logic; the recovery merge verb this design sketched, never built; and the holders' - trusted `callers` values, for the seat definitions' `callers`. The words **merge check**, **try**, **trunk commit** - and **merge turn** go to *Not:* lines with the as-is update after that delivery, as the glossary's entries say. +- At research 085's milestone's delivery and at milestone G's: design 47 G, *What retires at milestone G*. ## Milestones diff --git a/03-DESIGN/01-to-be/47-milestones/G.md b/03-DESIGN/01-to-be/47-milestones/G.md new file mode 100644 index 00000000..b1c606d5 --- /dev/null +++ b/03-DESIGN/01-to-be/47-milestones/G.md @@ -0,0 +1,2101 @@ +--- +layer: to-be +status: in-progress +design: 47 +milestone: G +updated: 2026-11-10 +decisions: + - "ADR 0668" + - "ADR 0667" + - "ADR 0666" + - "ADR 0664" + - "ADR 0663" + - "ADR 0662" + - "ADR 0661" + - "ADR 0660" + - "ADR 0659" + - "ADR 0656" + - "ADR 0648" + - "ADR 0646" + - "ADR 0645" + - "ADR 0644" + - "ADR 0641" + - "ADR 0639" + - "ADR 0636" + - "ADR 0635" + - "ADR 0633" + - "ADR 0625" + - "ADR 0621" + - "ADR 0619" + - "ADR 0618" + - "ADR 0615" + - "ADR 0614" + - "ADR 0603" + - "ADR 0597" + - "ADR 0596" + - "ADR 0595" + - "ADR 0593" + - "ADR 0584" + - "ADR 0573" + - "ADR 0571" + - "ADR 0567" + - "ADR 0564" + - "ADR 0563" + - "ADR 0551" + - "ADR 0548" + - "ADR 0539" + - "ADR 0534" + - "ADR 0525" + - "ADR 0505" + - "ADR 0498" + - "ADR 0493" + - "ADR 0448" + - "ADR 0443" + - "ADR 0441" + - "ADR 0437" + - "ADR 0429" + - "ADR 0421" + - "ADR 0404" + - "ADR 0398" + - "ADR 0391" + - "ADR 0363" + - "ADR 0283" + - "ADR 0240" + - "ADR 0235" + - "ADR 0233" +--- +# 47, milestone G — every line milestone G builds + +This is milestone G's part of [design 47](../47-delivery-from-commit-to-delivered.md): the pipelines per module of +research 086 and the two graphs of research 085, one milestone (ADR 0667 §1). The main file keeps the purpose, the +whole shape, the acceptance tests and the milestones; every line milestone G builds is here, moved whole from the main +file on 2026-11-10, and is cited as "design 47 G §n". A sentence that holds a delivered line and G's change together +stayed in the main file, and G builds what it says from G's delivery. A section named in italics is in this part, or, +when it is not here, in the main file. + +## Pipelines per module + +*ADR 0666, ADR 0667; ADR 0595, ADR 0596, ADR 0448 §2, §4, ADR 0548 §5, ADR 0564 §2, §4, ADR 0283, ADR 0656 §4, §6, ADR 0633 §5, +ADR 0664 §4, ADR 0398 §2, ADR 0593 §9; research 086, Direction.* + +§1 From milestone G's delivery. A change of any module, the delivery system's own parts included, goes from a commit to +the machines through that module's **pipeline**: the pipeline steps its **policy** names, run for each commit or group +on each of the module's **watched branches** by the seat `mesh-pipeline-runner`, ordered by the catalog graph's edges +between artifacts, with no hand act (ADR 0666 §1). Milestone G is the one milestone that builds it, beside the two +graphs, the revision view and the delivery record (ADR 0667 §1). Until G's delivery the sections this one replaces +(*Checks*, *A try*, *The Approve and the merge*, the state table and the trunk-only want) hold as written, and they +check and deliver milestone G itself (ADR 0667 §2); each of them says so in a line of its own. + +``` + a session ──merge-pull (seat git)──► forge ──commit on a watched branch──► forge bridge ──► indexer (mesh-catalog) + │ registrations; a catalog graph + │ per watched branch; the revision + │ validated before take-in + ▼ take-in.taken + pipeline runner (mesh-pipeline-runner) ── asks each pipeline step on the serving seat's work queue, hears step-ended: + │ lint, unit tests, integration tests ──► the build seats (node-build-go, node-build-node, node-build-image) + │ composition ──────────────────────────► the assigner (mesh-wants) + │ code review ──────────────────────────► the runner's own verb `review`, from the reviewer's bus account + │ approval ─────────────────────────────► operator-channel: accepted kind ask, then decided + ▼ pipeline-ended (every step's result), keyed by source revision + assigner ──► wants from a revision whose required steps passed, on the watched branch a placement chose + gate ──► the delivery record keeps the step and pipeline events +``` + +### A module's registration + +- §2 **What it holds.** The seat `mesh-catalog` keeps each module's **registration**: its git origin, the path of its + manifest, its watched branches and its policy, on the bus, every version with who changed it and the warrant of the + operator's Approve (ADR 0666 §2). The indexer is a foundation part, so the registrations are kept in its old sections + (ADR 0619 §1 to §3, ADR 0666 §4): one key per module in its old `state` section `registrations`, and every version on + its old `streams` section's stream `registration-history`, kept with no age limit. + The catalog graph is derived from the registrations and the manifests they point to; the mesh knows modules, and a + repository only as a module's git origin. +- §3 **Changing one is a trusted act.** The seat's verbs `register` (a module whole), `policy` (one module's step + statuses, per artifact), `watch` and `unwatch` (add or remove a watched branch) each raise an authorising ask of tier + approve through the seat `operator-channel` (design 46 §10), naming every value the change moves, one line each + ("`mesh-grants:program` unit tests: `required` → `bypass`"), and write the version only on its warrant; a Decline or + an expiry writes nothing (ADR 0666 §2). Until a record binds each forge account to its bus identity, `register` and + `policy` refuse code review as a `required` step, naming why, so no review gates while its author cannot be told + (ADR 0666 §22; issue 1966, note 157). A manifest moved to another path is the one manifest change that changes the + registration; any other manifest change is a commit, judged at its revision. +- §4 **Said and read.** Each written change is said as the seat's event `registration-changed` (the module, the version, + what moved); the verb `registrations` answers every registration, or one with its history. The indexer derives the + modules it keeps from them, and the forge bridge its watched branches, each by a first view of `registrations` and + then that event, never by reading the ledger (ADR 0666 §3, ADR 0596). +- §5 **An unprotected branch is refused.** `register` and `watch` read a branch's protection through the seat `git`'s read + verb `branch` (its head, and whether a rule refuses a direct push and admits only merges), and refuse a watched branch + the forge does not protect, naming it (ADR 0666 §3). +- §6 **The foundation parts are the manifest validator's list.** The manifest validator's list (ADR 0619 §3) holds + exactly the foundation parts, ADR 0619 §1's and the runner, which joins them (ADR 0666 §4); the checker leaves the + list when it is removed (*How milestone G itself is checked and delivered*). A registration holds no foundation + value. How it is checked: a unit test of the manifest validator refuses a template in the manifest of every part on + its list, the runner's included, and judges every other part's manifest as any part's. +- §7 **No part fixes a name.** Every branch, repository and module name a part needs is read from the registrations and the + catalog graph; the lint step refuses such a name in a string, a constant or a table of code logic, a Go import path + not being code logic (ADR 0666 §5). About 39 such names in 9 parts were found on 2026-11-09 (research 086, Findings); + milestone G removes them. +- §8 **The first registrations are one ask.** At its first start on G's build the indexer, holding no registration, + proposes one registration for every module its trunk revision holds, from what it took in (the origin and path of + each), its watched branch the repository's default branch read through the seat `git`, and the statuses the check + judged until then: lint, unit tests, integration tests and composition `required`, code review `optional`, approval + `bypass`, and `bypass` for every step the artifact's build seat's `steps` does not answer at the seed, so no module + is held by a `required` step it has nothing for (the design's choice under ADR 0666 §7, 2026-11-10); it raises them as one ask naming every registration, as the seat `mesh-module-assigner`'s `adopt` proposes + placement whole (ADR 0567). Until that Approve the runner starts no delivering pipeline and says why, so the + operator is told of this one ask before G's delivery starts. A Decline or an expiry leaves the seed unwritten and + says so; the indexer's tool `indexer_seed_again` raises the ask again, recorded in the hand-act log. +- §9 **Kept for the life of the mesh**, never derived again (research 086, choice 25): the history stream's cap is 64 MiB. + About 120 registrations of about 1 KiB, and an estimated change a week each (a guess, not a measure), grow about 6 MiB + a year, so the cap holds about ten years; past 80 % the indexer says `filling`, as every store of *Two graphs, one + source of truth* does. +- §10 **How it is checked.** Whole (indexer): an unprotected watched branch is refused, naming it; a policy change without + the warrant writes nothing, and a declined one writes nothing; a change from `required` to `bypass` asks, showing + that line; `registration-changed` is said and `registrations` answers the history; the first start proposes the seed + as one ask, and `indexer_seed_again` asks it again after a Decline and after an expiry; a policy making code review + `required` is refused. Unit (the Go build module's lint step): a module name in a string, a constant and a table is + refused, an import path is not. Tests 75, 68 and 83. + +### Watched branches and the catalog graph per branch + +- §11 **Only a watched branch starts a pipeline.** The forge bridge hears every commit of every watched branch the + registrations name, through the seat `git`'s event `branch-moved` (a branch's new head, from the forge's push + webhook, which a merge and an admitted push alike say), and takes the commit from the forge's own record by the seat's + verb `branch`, never from the event's body (ADR 0666 §6). One event for every way a branch moves, because a merge is + not the only one. `branch-moved` is kept on the seat's stream `SEAT_git_branch-moved`, which the bridge hears through + a durable consumer, so a move said while the bridge is down is heard when it starts; at its start it also reads each + watched branch's head the same way. +- §12 **A head with no pipeline is a finding.** A watched branch's head that starts no pipeline within five minutes is the + watchman's finding `pipeline-stands`, naming the branch and its head, raised by the condition keeper (ADR 0564 §2), + unless it waits as progress not owed: a member of a gathered group is governed by ADR 0633 §5's 30-minute bound, and + a merge behind a pending revision of the same branch by its 60-minute bound (ADR 0666 §24). The finding clears on the + runner's `pipeline-started` for that head. +- §13 **The catalog graph per watched branch.** The indexer keeps the catalog graph once per watched branch, from that + branch's manifests at each source revision (ADR 0666 §6): each revision names its branch, and the stores, caps and + pins of *Two graphs, one source of truth* hold per branch. +- §14 **A placement names the branch.** Each module of a placement key names the watched branch its node runs, by default the + registration's first, set by a placement proposal like every other placement change (ADR 0567, ADR 0666 §6). The + assigner computes each node's entries from the catalog graph of the branch its placement names, so a module watched on + `main` and `beta` runs `beta` only where a placement chose it. +- §15 **A source revision per watched branch.** The gate keeps one source revision per watched branch, `source.`, + in place of `source.main` (ADR 0429 §11 to §13 as ADR 0666 §6 changes them), in the old `state` section `source` + already holds, its key's layout being the only change. The gate is no foundation part: the bus module's delivery + waits on no act of the gate's, since the indexer takes a revision in from the forge bridge's stream and the assigner + writes wants from the runner's events, so the gate's other kept data stay in ADR 0595's templates (ADR 0666 §4), and serves it by the seat + `mesh-delivery`'s verb `source` with the branch, saying `source-moved` on each new revision; the indexer and the + node-engine's catch-up read it there, never the gate's state (ADR 0596). Each want names a build-input fingerprint + computed at one such revision. +- §16 **Validated before any take-in, on every branch.** Before it takes a revision in, on every watched branch, the running + indexer asks the manifest validator built from the revision's heads to judge it in the build seat's sandbox (the + ask `run`, *What ADR 0656 leaves to this design*). A revision it refuses stays pending under ADR 0633 §5's + 60-minute bound, its hand acts and its condition `take-in-waits`; the way back is a revert, an ordinary merge + (ADR 0666 §6, §26). A revision on the branch the indexer's own placement chose is taken in only by the indexer it + names (ADR 0633 §1). This validation is no pipeline step and waits on no pipeline, so every delivering pipeline runs + on a revision already taken in. +- §17 **A branch whose protection was removed starts nothing.** On every `branch-moved` the forge bridge reads the + branch's protection again; a move of a watched branch whose protection was removed starts no delivering pipeline, and + the forge bridge writes the finding `branch-unprotected`, naming the branch, which the condition keeper raises and + clears once the protection is back (ADR 0666 §6). +- §18 **A pending revision holds its own branch only.** A merge waits behind a pending revision only on the same watched + branch; other branches move on (ADR 0666 §6, which changes ADR 0633 §3). +- §19 **A refused new indexer holds its branch until a revert lands.** A merge of a new indexer whose own validator refuses + its revision has already landed when it is refused, since the validation runs before take-in and after the merge + (ADR 0666 §6). It stays pending, and every later merge on that watched branch waits behind it, said by + `take-in-waits` at the 60-minute bound, until a revert, an ordinary merge through its pipeline (ADR 0666 §26), lands + and is taken in; nothing takes a later merge in past it. This is the cost of validating every revision with the + validator built from its own heads, the design's reading of ADR 0666 §6, and the operator is told it with the + condition, which names the pending revision and the revert as the way on. +- §20 **How it is checked.** Whole (forge bridge): a commit of a branch no registration names starts nothing; a commit on a + watched branch is taken from the seat's `branch` read, not the event; a head missed while the bridge was stopped is + read at its start. Whole (indexer, assigner): a commit on `beta` gives a revision of the `beta` graph only and moves + only the want of the node whose placement chose `beta`; a revision whose own validator refuses it stays pending and + holds `beta` while `main` moves on. Whole (watchman): a head with no pipeline for five minutes raises + `pipeline-stands`, cleared by `pipeline-started` for that head, and a gathered member does not; a move said while the + bridge was stopped is heard from the seat's stream. Tests 64, 68, 76, 78 and 82. + +### Pipeline steps and the policy + +- §21 **The runner.** The seat `mesh-pipeline-runner`, held once for the mesh by the module `mesh-delivery-pipeline`, + runs each pipeline (ADR 0666 §7). It is a foundation part, since the bus module's own delivery waits on its pipeline + (ADR 0666 §4): its kept data are in old sections (ADR 0619 §2), it waits on no bus module process to start, and it + joins the manifest validator's list of foundation parts, which refuses its manifest asking a template (ADR 0666 §4, + which changes ADR 0619 §1 and §3). It reads the policy from the registrations, asks each step that is not `bypass` of + the seat that serves it, and says each step's start and end and the pipeline's end (*Health and going back*, below). +- §22 **The steps and who serves them.** Lint, unit tests and integration tests are the build seats' (`node-build-go`, + `node-build-node`, `node-build-image`): each gains the verb `steps`, which answers which pipeline steps an artifact + can run by its language's convention (as *The check from release 4* says the tests are found), and the accepted kind + `step` on its stream `check`, which runs one. Composition is the assigner's, an accepted kind `step` of the seat + `mesh-wants`. Code review comes in through the runner's own verb `review`. Approval is asked as the seat + `operator-channel`'s accepted kind `ask`, on its work queue by the runner's name (design 46 §10, *Asks, warrants and answers on the bus*; + the seat has no verb `ask`), and heard on its event `decided` (ADR 0666 §7, §10). A step with nothing to do ends at once as + `nothing to run`, never as passed. +- §23 **The policy.** Each step's status, per module and per artifact, is `required` (runs; holds the delivery until it + passes), `optional` (runs; a failure is shown and may be accepted) or `bypass` (nothing runs; said as bypassed), + kept in the registration and never in a manifest: the manifest validator refuses a manifest that names a status + (ADR 0666 §7; research 086, R3). A `required` step that ends `nothing to run` holds the delivery and names the step. +- §24 **Asked on a work queue, ended by an event.** The runner asks each step on the serving seat's work queue and hears + its end as that seat's event `step-ended` (the record's `step ended`), on + `mesh.seat..event.step-ended.`, the node that ran it in the subject and each holder's account granted only + its own node's subject, through a durable consumer of its own, so a step outlives a restart of either side (ADR 0666 + §7, ADR 0363 §2). A build seat's holder restarted mid-step gets the step again from its work queue and finishes it + (ADR 0664 §1). A unit or integration test step says its test counts in `step-ended`, and `pipeline-ended` names any + repository over 50 integration or 500 unit tests, and any catalog module over them (ADR 0666 §8; the test budget). A step's outcome is one of `passed`, `failed`, `nothing to run`, + `bypassed`, `carried` (with the pipeline it was carried from), `could not run` (naming the part not heard), + `waiting on `, `accepted` (a failed `optional` step a person accepted, with who and why), `superseded` and + `cancelled`. +- §25 **Carried, not run.** A step whose build-input fingerprint and policy did not change is carried by its package + digests, as ADR 0548 §5 holds, the runner making the carry instead of the checker: a test step runs only the packages + with no kept result for their digest, and a run on request's results are reused when the merged commit's inputs match + (ADR 0666 §8; research 086, choice 24). An `approval` step is never carried. +- §26 **Approval comes last.** The runner asks the `approval` step only once every other `required` step of the pipeline + passed, so the operator approves a commit the mesh already judged, the one place ADR 0661 §3 had the check gate the + ask. A failure after an approval is said, as a failed `optional` step is, and the approval stays. +- §27 **Kept on the bus, in old sections.** The runner keeps each pipeline's state in its old `state` section `pipelines`, + one key per pipeline keyed by its watched branch, source revision and module, written by compare-and-set so a holder + replaced mid-pipeline and its successor never both write one; its step log on its old `streams` section's stream + `step-log`; each step's output in its old `objects` section `step-outputs`, named in the log; and each package's + passing result per level in its old `state` section `kept`, under the digest of what its tests read (ADR 0666 §4, §8; + *The runner's kept data*, below). `kept` starts empty: the runner takes no verdict of the checker's, since a step's + result is taken only from the bus account of that step's seat holder (ADR 0666 §21), so the first pipelines after G + run each package's tests once and carry from then on (the design's choice, 2026-11-10). +- §28 **How it is checked.** Whole (runner): a step with unchanged fingerprint and policy is carried and says from where, + and an `approval` step is not; a module with no integration tests shows `nothing to run`, and a `required` unit-test + step on a module with no tests holds its delivery; a bypassed step is said; a runner restarted mid-step hears the + step's end and finishes the pipeline; two runners writing one pipeline key, one loses by compare-and-set; a test step's + counts are in `step-ended` and a repository over budget is named in `pipeline-ended`. Whole (Go build module): `steps` + answers the steps of a fixture artifact, a `step` ask ends with `step-ended` on its own node's subject, one on another + node's subject is refused by the bus, and a build module restarted mid-step finishes it. Unit (manifest validator): a manifest naming a status is refused. Tests 65, 66, 73 + and 88. + +### What holds a delivery + +- §29 **The assigner writes a want only from a passed pipeline.** The runner says each pipeline's end as `pipeline-ended` + (the record's `pipeline ended`), keyed by source revision, with every step's result. The assigner consumes it, and + writes a want only from a source revision whose every `required` step passed for the modules it moves, on the watched + branch a placement chose, by compare-and-set on a newer revision, so an older revision ending after a newer one + writes nothing (ADR 0666 §9). The compare-and-set is keyed per module and watched branch: it compares a revision only + with the last one written for the same module on the same watched branch, so a revision of `beta` ending after a + newer one of `main` writes its own want and refuses neither (the design's choice under ADR 0666 §9: source + revisions are kept per watched branch, `source.`, and two branches' revisions have no order between them). This is one more rule beside the assigner's others (ADR 0429 §6), checked per module. + From G's delivery it replaces the trunk-only want (ADR 0656 §2 as ADR 0666 §9 changes it). For a group's source + revision the runner says one `group-ended` once every member's modules have ended, and the assigner writes the + group's wants only on it: a member's own `pipeline-ended` writes nothing (ADR 0666 §9). +- §30 **A failed `optional` step holds nothing.** It is shown in `pipeline-ended`, in the delivery record and in the runner's + `show`; a person may accept it by the runner's verb `accept`, recorded in the hand-act log with who and why. +- §31 **A newer commit supersedes an older pipeline of a module whose fingerprint it changed.** On a newer commit of the + same watched branch the runner ends a module's older running pipeline as `superseded` only when the newer commit + changed that module's build-input fingerprint (ADR 0666 §9); a module the commit leaves as it was finishes its + pipeline. A newer publish of a package likewise supersedes the rebuild pipelines an older publish of it started. A + superseded pipeline's waiting asks are dropped by each build seat's `drop` (ADR 0664 §4), naming + the newer commit as the cause, so a cancelled pipeline leaves no ask on a stream (a gap G's prepare found: a cancelled + build withdrew only the builder's wait). +- §32 **A step nothing starts ends its pipeline.** A step whose prerequisite nothing starts (a seat with no holder, a + prerequisite step `bypass`) ends the pipeline refused within five minutes, naming the step and what it waits for, + never as a silent wait (research 086, R5); a step whose seat has no holder ends its pipeline failed, naming the seat + (ADR 0666 §17). +- §33 **A failed head is said to its author, then to the operator.** A `required` step that failed, or ended `could not + run`, on a watched branch's head is the runner's finding `pipeline-failed`, naming the module, the branch, the commit + and the step; the condition keeper raises it as the commit's author's for two hours and then the operator's, as ADR + 0505 §5 and §6 have a delivery whose cure is its author's new head, and clears it when a newer revision of that branch + passes that step (ADR 0666 §24). The author is the forge's record of the commit, read through the seat `git`. +- §34 **The delivery record keeps every step.** The gate's delivery record consumes the step and pipeline events and keeps + them as long as the record (ADR 0666 §9; *The delivery record*). +- §35 **How it is checked.** Whole (assigner): a failed `required` step writes no want; a failed `optional` step holds + nothing; an older revision's `pipeline-ended` after a newer one's writes nothing, and a revision of one watched branch + ending after a newer one of another writes its own want; a group with one member passed and + another still running writes no want until `group-ended`. Whole (runner): a newer commit that changed a module's + fingerprint supersedes its older pipeline and drops its asks, and one that left it unchanged lets it finish; a step + with no holder ends the pipeline naming the seat within five minutes; a failed `required` step on a head raises + `pipeline-failed`, the author's for two hours and then the operator's, cleared by a newer passing revision. Tests 66, + 67, 87, 89 and 98. + +### Approval is a step, and a session merges a pull request + +- §36 **No Approve per merge.** The operator's approval is the pipeline step `approval`, its status in each module's policy; + no Approve is asked per merge, and the delivery gate's merge turns and its Approve per merge go (ADR 0666 §10, which + changes ADR 0661 §3 to §5). The operator is asked only where a module's policy says `approval`, and for registrations + and policy changes. +- §37 **The approval is an ask of the runner's.** The runner raises an authorising ask of tier approve as the seat + `operator-channel`'s accepted kind `ask`, under its own name, its `about` the module and the watched branch only, so a newer commit's ask + replaces the older one's (design 46 §10). The warrant ends the step passed; an ask that is declined, expires or is + refused ends it `declined`, and one that is replaced ends it `superseded`. Only a declined `approval` step is asked + again, by the runner's verb `ask-again` (ADR 0666 §10). While it waits the runner + says `wait-held` waiting on the operator, never a stall (ADR 0283). +- §38 **A session merges a pull request.** Any session the tool runner proves, and the operator, merges by calling the seat + `git`'s verb `merge-pull` over the mesh, which merges with the forge tools' account (ADR 0398 §2) at the head the + caller names. It judges that this is still the pull request's head and that the branch's protection refuses a direct + push, the protection read again on every `branch-moved` of the branch, and it judges the head's runs by its modules' + policies: it refuses a head when any run at its build-input fingerprint failed a step a policy marks `required`, and + merges a head whose `required` steps passed or that has no run yet, a failed `optional` or a `bypass` step refusing + nothing; it never waits for a run and never asks an Approve (ADR 0666 §11). The forge keeps only its branch protection. +- §39 **Judged from its own state, never by a call.** The holder of the seat `git` consumes the runner's `step-ended` + through a durable consumer of its own and keeps, in its own state `failed-steps`, each failed `required` step by + module and build-input fingerprint, with the commits it was seen at and the run that failed it, until none of those + commits is a watched branch's head or the head an open pull request names (*The runner's kept data*); so a head + merges while the runner is down, judged on what it already heard (ADR 0666 §11, ADR 0596). A head's fingerprints are + those its runs named for its commit; a step that failed at that fingerprint in any run, a group's or another commit's + of the same content included, refuses it, unless a later run of that same step at that fingerprint, asked again by + the operator or the healers (the runner's `rerun`), passed: that pass clears the failure from `failed-steps` (ADR 0666 + §11). The runner's `step-ended` says that the step was a rerun and the caller the runtime proved, and the forge module + clears a failure only for a rerun whose caller is the operator or a healer; a plain pass, or a rerun asked by anyone + else, clears nothing. A run still running is judged by the steps it has ended, since the merge never waits. A refusal names the run, the module and the step, so the session knows what to fix. The gate merges nothing, and its forge merge token is + removed with the checker's buckets and bus account, after the first pipeline after G's delivery has delivered a change + end to end and on the operator's word (ADR 0667 §12; *How milestone G itself is checked and delivered*); the forge bridge hears the landed commit as it hears every commit of a watched + branch. +- §40 **The operator-channel hides no ask.** It keeps design 46's three open asks per asker, never holds the newest back, + and replaces an open ask by the same asker's ask with the same `about` (ADR 0666 §12; design 46 §6). +- §41 **How it is checked.** Whole (forge module, forge bridge): a session's `merge-pull` at its head merges with no run yet, + and with a passed one, and asks no Approve; with the runner stopped a head merges; a head at whose fingerprint any + run failed a `required` step, a head that moved and a branch whose protection was removed since its last move are + refused, each naming why; a failed `optional` step refuses nothing. Whole (runner): an `approval` step is asked last, + a Decline and an expiry each end it `declined` and `ask-again` asks it once more, and a newer commit's ask replaces the + older and ends its step `superseded`. + Live: a declined approval and a fourth ask each reach the operator. Tests 71 and 91. + +### Groups + +- §42 **Formed from the branch name.** The gate forms a group from a shared branch name carrying its issue number, as it + does today without the fixed list of trunk names (ADR 0666 §13). +- §43 **A member reaches its group by landing.** A member has reached its group when its commit lands on its modules' + watched branch. The forge bridge sets the group on each landed member's commit, reading the members from the seat + `mesh-delivery`'s verb `groups`, and publishes `forge.group.merged` when that verb says every member has (ADR 0666 §13, + which changes ADR 0633 §4). +- §44 **One source revision, one pipeline per branch.** The indexer keeps landed members pending until the group's end and + takes them in together as one source revision of that watched branch, saying `take-in.taken`; the runner starts the + group's one pipeline per watched branch on that event, and a member of a gathered group starts no pipeline of its own + (ADR 0666 §13). + When one member's `required` step fails, none of the group's modules is delivered (research 086, R5). +- §45 **A group that never completes is said.** By ADR 0633 §5's 30-minute bound and its condition; `bridge_group_end_again` + says a group's end again from the gate's group verb, never the gate's `merges` state (ADR 0666 §13, which changes ADR + 0633 §5). +- §46 **How it is checked.** Whole (indexer, gate, forge bridge): a group of three repositories, its own packages included, + is one source revision and one pipeline; one member's failed `required` step delivers none; a group with a member that + never lands raises `take-in-waits` at 30 minutes. Tests 67 and 81. + +### Dependencies between artifacts + +- §47 **Six kinds of edge between artifact references.** The catalog graph's edges run between **artifact references**, + `:`, such as `mesh-grants:program`, of six kinds (ADR 0666 §14): + + | Kind | B before A | Derived from | + |---|---|---| + | 1 | B published before A builds | a package A's build source imports (ADR 0573 §3) | + | 2 | B published before A delivers | an artifact A's manifest fetches by reference at its start | + | 3 | B delivered before A builds | a build module A is built by, and the toolchain its agreed version names (ADR 0584 §1) | + | 4 | B delivered before A delivers | a provision A requires and B provides, bus state among them (ADR 0614 §5), and a format's reader (below) | + | 5 | B has acted for A's new version | a seat's acting rule (*What ADR 0656 leaves to this design*): a grant, a credential, a verdict, bus state | + | 6 | B runs a version that serves A | a verb or a manifest word A uses and B serves or reads (ADR 0614 §2, §4), the build seats' `kept-artifact` among them | + + Each kind is derived from what manifests and seat definitions already say, and declared per artifact in the manifest's + artifact entry, its field `needs`, only where nothing else says it. Today's edges run between modules, and only a + package edge names an artifact; at module level the tool runner and the grants part looked like a cycle, per artifact + they are a chain (`mesh-grants:program`, then `node-tools:runtime`, then `mesh-grants:tools`). +- §48 **Removal runs the other way.** When something goes away the order is reversed: a seat moved to a new holder has its + old holder released before the new one claims (ADR 0666 §14). +- §49 **The edges alone order.** The build and the delivery order by these edges alone; a cycle of delivery edges (kinds 2, + 4, 5, 6) is delivered as one step, and a cycle of build edges (kinds 1 and 3) is refused, naming every artifact on it + (ADR 0666 §14; research 086, R17). The cycle rule is the indexer's, in the catalog graph it keeps, so the checking + program's cycle rule goes with the checker. +- §50 **A format's reader first.** A format a running reader cannot read is preceded by its reader, an edge of kind 4 on + every watched branch (ADR 0666 §14): the indexer's manifest validator for a new field of a seat definition or a + manifest, and on each node the node-engine that reads a manifest's new fields before any manifest that writes them + (ADR 0667 §4). +- §51 **How it is checked.** Unit (indexer's graph): a chain per artifact where modules would cycle; two programs needing + each other's new verb are one step; two artifacts each needing the other's new package to build are refused, naming + both; a seat moved to a new holder releases the old first. Live: the tool runner and the grants part delivered in + the order `mesh-grants:program`, `node-tools:runtime`, `mesh-grants:tools`. Test 79. + +### A publish rebuilds + +- §52 **Numbered at publication.** The builder numbers a package's version when it is published, never only when a build + is claimed, and says the publication as the event `package-published` of its seat `mesh-builds` (ADR 0666 §15; design + 51, *The versions*). The seat is new, held once for the mesh, defined in `mesh-delivery-contracts`; the builder held + none until now, and its waits stay on its own stream in this milestone. +- §53 **Every dependent is rebuilt against it.** On `package-published` every artifact with a kind-1 edge to the package is + rebuilt against the new version, and the runner, which consumes the event, starts its pipeline; nothing else is + rebuilt, and a change to tests alone publishes nothing (ADR 0666 §15; research 086, R18). +- §54 **A second start writes nothing.** The runner starts a pipeline on two events, the indexer's `take-in.taken` (ADR + 0666 §13) and `package-published` (ADR 0666 §15). When both reach it for the same source revision and module, the + second start writes nothing: the runner writes a pipeline's key (watched branch, source revision and module, *The + runner's kept data*) by compare-and-set on its absence, so one revision and module has one pipeline. The design's + choice under ADR 0666 §13 and §15: the key the runner already keeps is the one place a start is judged, so neither + event's producer needs to know of the other. +- §55 **Unread packages refuse.** A build that cannot read the published packages refuses and names the unread state + (ADR 0666 §15). +- §56 **How it is checked.** Whole (builder, indexer): a mesh-sdk merge changing one package publishes one version, and only + the artifacts importing that package rebuild; a merge changing only tests rebuilds nothing; a build whose packages + cannot be read refuses naming the state. Whole (runner): a `take-in.taken` and a `package-published` for the same + source revision and module start one pipeline, the second writing nothing. Tests 70, 80 and 101. + +### Any size + +- §57 **A value over the limit is an object.** mesh-sdk's own small object store package (ADR 0595 §9) puts a value over + the bus's per-value limit in the object store beside its state and keeps the object's name in the key; a verb's reply or an event over the + per-message limit carries the object's name (ADR 0666 §16). A replace writes the new object and sets the key by + compare-and-set; the object it replaced stays, as one whose key was deleted does, listed as `key gone` since no key + names it, and only the drop tool removes either, on a person's word: the mesh removes kept data only through `drop` + and `recreate`, each on a person's word (ADR 0595 §4; ADR 0666 §16). +- §58 **One object store per state, granted to its owner.** Each state asked by the template `state` gets its object store + beside it, `-objects`, a template form of ADR 0595 that the bus module provides and the grants part grants to + the state's owner alone (ADR 0666 §16); a foundation part's large values go in an old `objects` section of its own. + Its size is the template's (ADR 0595 §3). An object store holds no space until a value is written to it, so the many + it adds reserve nothing; the few values over the limit (a delivery record, a catalog graph revision list, a test's + output) are estimated, as a guess, at under 1 GiB across the mesh. +- §59 **An object sent is readable by the modules it is for.** A reply's or an event's object is written to the sender's + **sent store**, `_sent-objects`: the bus module plans it, with no manifest field, for every module of the new + form that serves a verb or emits an event, and a foundation part declares it as an old `objects` section + `sent-objects` (ADR 0619 §2). Its cap is the objects template's (ADR 0595 §3), and it keeps an object 7 days, after + which the bus expires it. That age is transport, not kept data: an object sent exists only to carry one reply or one + event, read within its call's bound or its consumer's lag, so its expiry is not a removal of kept data that ADR 0595 + §4 holds to a person's word (the design's choice; 7 days is a guess at the longest a consumer lags, read from the + fill tools once G runs). A full sent store is the bus module's `full` and its condition (ADR 0595 §6), and the sender + then refuses the large reply or event loudly, naming the store. The grants part derives from the manifests a standing grant to read them: the + callers its seat definition names for the verbs it serves, and the consumers whose `consumes` declare its events; + no other module may read them (ADR 0666 §16). The grant follows the manifests, so it is written when they change, + never per object. A consumer's reader of + the form is delivered before its producer writes it, an edge of kind 4. +- §60 **Its tools come with the package.** The package serves each module that imports it `_state_objects` (the + objects of each state, with their size, the key that names each or `key gone`, and the fill against its cap), + `_state_objects_drop` (drop the objects whose key is gone, on a person's word as ADR 0595 §4 removes kept + data), `_sent_objects` (each sent object, its size, when it was sent and to which verb or event, its age + against the store's and the fill against its cap) and `_sent_objects_drop` (drop sent objects older than an + age a person names); each drop names who asked and is recorded in the hand-act log. +- §61 **Its cost.** Only the modules that import the package are built with it, so no other module is rebuilt for it: a + package published before its users build (ADR 0573 §2, ADR 0667 §3). +- §62 **How it is checked.** Whole (mesh-sdk, against the real bus): values of one, ten and a hundred times the per-value + limit stored, sent as a reply and as an event, and read back whole by a caller and a consumer the manifests declare, + and refused to a module that declares neither; a replaced large value leaves its old object listed `key gone` beside + the new one, and a key deleted leaves its object listed `key gone`, each removed by the drop tool and by nothing else; + a sent object is readable within its 7 + days and expired after; each drop without who asked is refused. Tests 69 and 90. + +### The pipeline makes the check, and the checker goes + +- §63 **Every step runs on parts built from the change.** Every pipeline step that runs a change's code runs on parts built + from the change's own heads, in the build seat's sandbox, with no network and no bus account (ADR 0666 §17, ADR 0448 + §2, §4): the composition step composes each machine's declaration with the composer built from the heads and refuses + a change in which two modules own one path; the build seats' steps run lint and tests. A step whose serving part the + change alters runs from the change's build of it, built within 20 minutes or ending `waiting for a build node` or + `did not build`, the first tier of *The check on the change's own acting parts* made the runner's. +- §64 **The run on request.** The runner's verb `run` takes one or more members, each a module at a named commit, runs them + through their pipelines and delivers nothing, replacing the checker's try (ADR 0666 §18). Its callers are the + sessions, as the agents' bus identities the tool runner proves, and the operator, and nothing else, since a run of a + group builds and publishes its packages' tagged versions (design 51). The runner says `run-started`, the indexer builds + the run's candidate from it, and the candidate's composition step writes no want (ADR 0656 §9); the candidate is + dropped on that run's `pipeline-ended`. A step that could not run ends `could not run`, never as passed. A + composition step for a node that sleeps passes it with a warning (ADR 0593 §9). +- §65 **The runner is an acting part in the checker's place.** The acting rule's step `check` becomes the runner's step + `pipeline` (*What ADR 0656 leaves to this design*): its own change runs on its own new version, a failing new runner + holds while the old one runs pipelines (ADR 0656 §4), and the pipelines in flight when its holder is replaced are + taken up again from its kept state (ADR 0666 §19). +- §66 **What the checker did, and where it goes.** + + | The checker's | From G's delivery | + |---|---| + | the merge check, one status `mesh/check` | the pipeline, its result in `pipeline-ended`, the runner's `show` and the delivery record; no status on the forge | + | the try | the run on request | + | the composition check | the composition step, the assigner's | + | the kept verdicts and the carry | the runner's `kept`, which starts empty, and its carry (ADR 0548 §5); the checker's verdicts go with its buckets | + | the checking program: the manifest validator at the heads, the cycle rule, the composer, the rule names | the indexer's validation before take-in; the indexer's cycle rule; the composition step; `widens` in the pipeline's end | + | the `run` ask, published by the checker's account | published by the runner's account and the indexer's (its validation), each with step keys under its own name | + | its buckets and bus account | removed with the gate's forge merge token after the first pipeline after G's delivery has delivered a change end to end, on the operator's one word, the buckets through `drop` after its snapshot, whose restore is tested first (ADR 0667 §12) | + +- §67 **How it is checked.** Whole (runner, assigner): a run on request of `feature/1966-x` delivers nothing, and a call of + `run` from another account is refused; a composition step refuses two modules owning one path; a step whose part + cannot be heard ends `could not run`; a node asleep passes with a warning; a runner stopped mid-step takes its + pipelines up again. Live: once the checker is removed no module claims the seat `mesh-delivery-checker`. Tests 64, + 84 and 88. + +### Who may say what + +- §68 **Callers per verb, in the seat's definition.** Each seat definition names, per verb, the callers allowed to call it, + in its field `callers` (holder roles, modules, the operator, the healers), which the grants part reads as its one + source of caller limits; the runner's verbs are the first (ADR 0666 §20). A verb whose definition names no `callers` + admits only the seat's holder roles and the operator, so a field left out opens nothing. It replaces the holder's + trusted config value `callers` of the seat `git` and the package seats (design 51), which no holder set for most + verbs. A format its running reader cannot read, so its reader is delivered first (ADR 0667 §4). +- §69 **A step's result from its holder only.** The runner takes a step's result only from the bus account of that step's + seat holder, naming the commit and the build-input fingerprint; a result from another account, or naming another + commit or fingerprint, is refused and said (ADR 0666 §21). +- §70 **A review gates, once it can.** A code review's result is taken through the verb `review` from the reviewer's bus + account and refused from the commit's author, so a review gates where a policy says `required` (ADR 0666 §22, which + changes ADR 0659 §2). Until a record binds each forge account to its bus identity no policy may say it (*A module's + registration*; issue 1966, note 157). +- §71 **A widening is said, never refused.** A change that alters any part serving a step (the runner, step detection, the + lint rule, a build seat's test runner, the composer), or widens an acting rule, a grant or a credential, says so in + its `pipeline-ended`, its field `widens` naming each. The running runner computes it, from the sources of the change + against those of the watched branch, never the runner built from the change, so a change cannot hide its own + widening; nothing refuses it for that (ADR 0666 §23, the operator, 2026-11-10). The teller passes `widens` on to every + channel, as it does `recovery-merged`. This is what replaces ADR 0656 §8's naming in the Approve ask. +- §72 **How it is checked.** Whole (runner, grants part): a forged step result and an author's own review are refused; a + caller not in a verb's `callers`, and any caller but the holder roles and the operator of a verb with no `callers`, + are refused by the bus; a change widening a grant, and one altering the Go build module's test runner, each name it in + `widens`, computed by the running runner, and are delivered. Tests 85 and 86. + +### Health and going back + +- §73 **The runner's events.** Each on `mesh.seat.mesh-pipeline-runner.event....`, + a branch or group name escaped as a key's name is, declared in the seat's definition and published by the runner's + account alone (ADR 0666 §24, ADR 0363 §2): + + | Event | Says | + |---|---| + | `pipeline-started`, `pipeline-ended` | a pipeline's start, and its end with every step's result, its test counts, the source revision and `widens` | + | `group-ended` | a group's one pipeline's end, on which alone its wants are written | + | `run-started` | a run on request's start, with its members at their commits | + | `step-started`, `step-ended` | each step's start and end: the step, its status in the policy, its outcome, its build-input fingerprint, its test counts, for a carried result what it was carried from, and for a rerun that it is one and the caller the runtime proved; a bypassed step too | + | `wait-held`, `wait-ended` | a step's wait: on a person (approval, code review), on a build node, on the revision view | + +- §74 **What a session hears after its merge.** Between its `merge-pull` and the delivery, a session waits with `mesh_wait` + on the runner's `pipeline-started` and `pipeline-ended` of its module, branch and commit, and then on the status + view's `delivered` of the source revision; a failed head reaches it as `pipeline-failed` (*What holds a delivery*). +- §75 **Nothing stands still unseen.** The watchman times each step's owed progress from `wait-held` and `step-started`, + never by run length; a step or a watched branch's head standing still five minutes is its finding `pipeline-stands`, + raised by the condition keeper and cleared on the step's end, or for a head on its `pipeline-started` (ADR 0564 §2, + §4). A step waiting on a person is said as waiting on that person (ADR 0283), never as a stall; a group waiting for + its members, and a merge behind a pending revision, are governed by their own bounds (ADR 0666 §24). At its start the + watchman seeds its open waits from the runner's `stands`, as it seeds `take-in-waits` from `indexer_pending`. +- §76 **The runner's own health.** Its manifest declares its health check, run outside its process (ADR 0240): the runner + answers `show`, and its durable consumers of `step-ended`, `take-in.taken`, `package-published` and `decided` are + each less than five minutes behind; a failed check names which. +- §77 **The runner waits for its view.** With no revision view it says so in `_first_views` and raises `view-waits` + after five minutes, as every part does (ADR 0656 §6). +- §78 **Going back is one act.** A failing new version holds while the old keeps running (ADR 0656 §4); a return to an + earlier build is one value in the placement, the module's `build` in its placement key, set by a placement proposal + (ADR 0666 §24). +- §79 **How it is checked.** Whole (runner, watchman): a step whose worker dies raises `pipeline-stands` within five minutes; + a head with no pipeline raises it and its `pipeline-started` clears it; a step waiting on the operator raises nothing; + a runner restarted mid-step takes its pipelines up again; its health check fails naming a consumer behind. Whole + (assigner): a placement's `build` delivers the earlier build. Tests 76, 77 and 88. + +### A recovery fix is an ordinary merge + +- §80 **No recovery merge verb.** A fix that recovers the mesh is merged like any change on a watched branch, by a + session's `merge-pull`, and runs its pipeline; no trusted recovery merge verb is built (ADR 0666 §26). The shape this + design sketched for one (a verb `merge` of the seat `mesh-delivery` with `recovery-callers`) is dropped. +- §81 **Named a recovery, said everywhere.** Its author names it a recovery by the seat `mesh-delivery`'s verb `recovery` + (the commit and why), never by a pull request's text: the gate marks the delivery record `recovery` with the caller + the runtime proves, and says `recovery-merged`, which the teller passes on to every channel (ADR 0666 §26). A widening + it carries is said in its `pipeline-ended` like any other (*Who may say what*). +- §82 **How it is checked.** Whole (gate): a merge named a recovery is marked in its record and `recovery-merged` is said; + a recovery named by a description is not. Test 92. + +### The tools + +§83 Every new state has a tool that reads it and every new act a tool that starts it by hand (ADR 0666 §25), against the +four lines a module's tools answer; every read tool of a store also answers its fill against its cap: + +| Part (seat) | Read everything it holds | Do by hand what it does itself | Recover without help | +|---|---|---|---| +| the runner (`mesh-pipeline-runner`) | `show` (one pipeline whole, its steps, step log and outputs), `list` (the pipelines of a module, a branch or a commit), `stands` (what stands still, since when), `why-carried` (where a step's result was carried from), `kept` (the kept results by digest) | `start` (a delivering pipeline for a watched branch's head), `run` (the run on request), `rerun` (one step again) | `accept` (a failed `optional` step, with why), `cancel` (a pipeline, dropping its asks), `ask-again` (a declined `approval`) | +| the indexer (`mesh-catalog`) | `registrations` (with each one's history); `indexer_edges` (an artifact's edges per watched branch), `indexer_order` (the order of a change, its cycles named), `indexer_catalog_difference` (two revisions); `indexer_pending` (a group with its missing members) | `register`, `policy`, `watch`, `unwatch` (each on the operator's Approve) | `indexer_seed_again` (the first registrations' ask raised again), `indexer_take_in_pending` (a group taken in as gathered), `indexer_drop_pending` (dropped) | +| the gate (`mesh-delivery`) | `source` with a branch (`gate_source`: every branch's source revision) | — | `gate_source_again` (say `source-moved` again for a branch) | +| the forge module (`git`) | `git_failed_steps` (the failed `required` steps it holds, by module and fingerprint, with the run that failed each) | — | `git_failed_steps_drop` (drop one, with why) | +| the grants part (`mesh-grants`) | `grants_callers` (the callers each verb admits, read from the seat definitions) | — | `grants_why_refused` (for an account and a verb, the grant it lacks and the definition's line that leaves it out) | +| the build seats | `steps` (the steps detected for an artifact) | `steps` with `again` (detect again) | `drop` (ADR 0664 §4) | +| the builder (`mesh-builds`) | `builder_versions` (a package's published versions) | `builder_publish_again` | — | +| the assigner (`mesh-wants`) | `assigner_why_not` (why a module is not on a machine yet: the pipeline it waits for, its hold, the placement, the node's last `running`) | — | `assigner_release` | +| the watchman | `watchman_views` (how far behind each part's view is, from each part's `view-waits` and first-view tools) | — | each part's `_first_view_again` | +| the operator-channel | `asks` (with each asker's asks held back) | — | `ask-again` (offer a held-back ask now) | +| every module that imports mesh-sdk's small object store package | `_state_objects`, `_sent_objects` | — | `_state_objects_drop`, `_sent_objects_drop` | + +§84 Every recover tool writes its act, who and why in the hand-act log of the seat `mesh-hand-acts`. How it is checked: +each tool answers its whole-module test's case, every store's read answers its fill, and `mesh_describe` reads each +(test 93). + +### The runner's kept data, and the build capacity + +§85 Each kept form names its section or template, its retention and its cap; a state template fixes its own size (ADR 0595 +§3), up to 64 MiB. The numbers are estimates, to be read from the fill tools once G runs: an estimated 20 merges a day +(as *The delivery record*), each starting a pipeline for about 3 modules of its repository whose fingerprint it changes, +and an estimated 2 mesh-sdk publishes a day, each rebuilding about 120 artifacts and starting about 120 pipelines: about +300 pipelines a day, of about 6 steps each. + +| Part | Kept data | Section or template | Retention | Cap and growth | +|---|---|---|---|---| +| the runner | `pipelines`: one key per pipeline, keyed by watched branch, source revision and module, its steps, statuses, outcomes, fingerprints and test counts | old `state` section | a pipeline a delivery record cites, deleted with that record (90 days); a superseded pipeline, a run on request's and one no record cites, 7 days after its end; always while it is its branch's newest for its module | 256 MiB; about 300 pipelines a day of about 4 KiB is at most about 105 MiB at 90 days, under half the cap | +| the runner | `step-log`: one entry per step's start and end, its output by name | old `streams` section | by its age, 90 days, as long as the delivery records that cite its steps | 128 MiB; about 3,600 entries a day of about 0.2 KiB is about 63 MiB at 90 days | +| the runner | `step-outputs`: a lint or test step's output | old `objects` section | 7 days | 1 GiB; about 1,200 steps run a day (the rest carried) of about 50 KiB is about 420 MiB at 7 days | +| the runner | `kept`: a package's passing result per level, by digest | old `state` section | 30 days unread | 128 MiB; a publish changes the digest of about 1,000 importing packages at two levels, so about 4,000 entries a day of about 0.3 KiB, about 36 MiB at 30 days | +| the indexer | `registrations` and its stream `registration-history` | old `state` and `streams` sections | the life of the mesh, never derived again | 64 MiB (*A module's registration*) | +| the indexer | catalog graph revisions, per watched branch | objects in the old form (ADR 0619 §2) | while a record pins it or it is its branch's current | 512 MiB, as *Two graphs, one source of truth*; a second watched branch on a few modules adds a few MiB | +| the gate | `source`: one key per watched branch | its old `state` section, as today | 64 revisions of each key; a branch's key deleted when `registration-changed` says the last registration watching it unwatched it (`unwatch`) | a few KiB | +| the forge module | `failed-steps`: failed `required` steps by module and fingerprint, with the commits each was seen at | state | an entry deleted once none of its commits is a watched branch's head or the head an open pull request names, judged on each `branch-moved` and each pull request's close | the template's 64 MiB; an estimated 50 failed steps a day of about 0.5 KiB, most gone within days, is under 1 MiB | +| every module that imports the object store package | `-objects` beside each state | objects | an object no key names, its key deleted or its value replaced, until `_state_objects_drop` on a person's word (ADR 0595 §4, ADR 0666 §16) | the template's; nothing reserved until written | +| every sender of the new form, and a foundation part by its old `objects` section | `_sent-objects` (`sent-objects`) | objects, planned by the bus module with no manifest field | 7 days, transport (*Any size*) | the objects template's cap; full is the bus module's `full` | +| the grants part, for each seat event a definition keeps | `SEAT__`, among them `SEAT_mesh-pipeline-runner_*`, `SEAT__step-ended`, `SEAT_git_branch-moved`, `SEAT_mesh-builds_package-published` and `SEAT_mesh-catalog_registration-changed` | a stream the grants part makes with its durable consumers | the seat definition's age (`keep`), 90 days unless the definition names less | the seat definition's cap (`keep`) | + +§86 **The build capacity.** A pipeline runs a module's steps once per commit on a watched branch, carrying what did not +change, where the check ran before the merge and carried after each trunk move; a group runs one pipeline per watched +branch; a second watched branch runs the steps of the modules it carries once more. A mesh-sdk publish asks about 120 +lint steps and the test steps of the importing packages, about 240 more, the rest carried; a newer publish of the same +package supersedes the older one's rebuild pipelines, so two publishes close together run the rebuilds once. The first +pipelines after G's delivery run every module's lint and tests once, since `kept` starts empty (ADR 0666 §21): about +120 modules, one round of the build capacity, taken in the `check` stream's order; from then they run only what +changed. The steps go on the build seats' stream `check`, +after `delivery` and before `recheck`, within each node's build capacity (ADR 0525 §4, §5), and a run on request on the +same stream. How it is checked: live, the build nodes' time per day in the week after G, read from the build modules' +step keys and the builder's build log, against the checker's last week (test 99). + +### How milestone G itself is checked and delivered + +- §87 **Under the clauses as they stand.** Milestone G is checked and delivered under ADR 0656 §5 and the clauses it changed + as they hold before its delivery: the acting parts (the indexer, the build modules, the assigner, the grants part, + the node-engine, and the checker, which makes G's own check) act from the milestone's heads, each first in its step, + in the order of their ordering edges; the trunk-only want, the checker and the Approve per merge as ADR 0661 leaves it + govern this delivery, no exemption is asked and no delivery goes ahead of it (ADR 0667 §2, ADR 0644 §1). +- §88 **Its other parts as any module.** mesh-sdk's small object store package is a package published before the modules + that use it build; the manifest validator moves with the indexer; the runner is placed like any module and acts only + from the next change on; mesh-delivery's `contracts` and `sdk` move under its `modules/` folder (ADR 0667 §3). +- §89 **Readers first** (ADR 0667 §4): an edge of kind 4 each, which the delivery plan derives: the indexer's manifest + validator for the seat definitions' new fields (`callers`, `acts`, `subject`, `keep`) before any definition using + them; on each node the node-engine that reads `form` and `catch-up` before any manifest writing them. +- §90 **The stream maker first** (ADR 0667 §5): the grants part, which makes each kept seat stream and its durable + consumers, before the parts that hear a kept stream. +- §91 **The bus module first** (ADR 0667 §6): the bus module, with `-objects`, the sent store and the grant of each + state's object store to its owner alone, before the modules requiring them, the grants part writing that grant from + the milestone's heads. +- §92 **A bus restart is said first** (ADR 0667 §7): a restart of the bus its new version needs is said to the operator + before it starts. +- §93 **A gap is built, not worked around** (ADR 0667 §8): an order the delivery plan cannot derive from the edges is + built in the delivery system within G, never a step done by hand. +- §94 **A node-engine of the version before applies what it can read** (ADR 0667 §9): it applies every want whose + manifests use no field it does not read, and a want that uses one waits, by the reader edge above, for the new + node-engine on that node. +- §95 **The new assigner and the new merge switch on the first registrations** (ADR 0667 §10). The new assigner, which + writes a want only from a passed pipeline, is delivered before the forge module's new `merge-pull`, which asks no + Approve, and before the runner: an edge of kind 4 from `mesh-delivery-assigner` to each, declared in their manifests' + `needs` since nothing else says it (the design's choice: without it a merge made with no Approve could reach the old + assigner, which writes wants from the trunk with no pipeline). Both switch on one fact, the first registrations + written, said as `registration-changed`: until it the new assigner keeps the trunk-only want and the new + `merge-pull` refuses every merge, naming the missing registrations. +- §96 **Until then, the operator merges a fix at the forge** (ADR 0667 §11). Until that fact an ordinary change waits for + it, and a fix, an indexer fix included, is merged by the operator's own hand at the forge (ADR 0661 §3) and + delivered under the trunk-only want still in force; `indexer_seed_again` asks the first registrations again. Before + the milestone's delivery every merge goes as ADR 0661 has it. +- §97 **What is removed, and when** (ADR 0667 §12). The checker's buckets and bus account and the gate's forge merge token + are removed only after the first pipeline after G's delivery has delivered a change end to end (test 63), the runner + then making every check in the checker's place (ADR 0666 §19), and only on the operator's word, asked once for all + three. The checker then leaves the manifest validator's list of foundation parts (ADR 0666 §4) and is no longer + placed, so no running module declares its buckets and they + are orphans `orphans` lists; they go through ADR 0595's `drop` on that word, after the stream snapshot `drop` takes + (ADR 0595 §4, §5, §10), kept 90 days as the delivery records are; a restore from that snapshot is tested before the + word is asked. The runner is on that list from G's delivery. +- §98 **Told to the operator before it starts**: G's own merges are asked as ADR 0661 has them (ADR 0667 §2, §11); the one + ask of the seed registrations; the bus's restart (ADR 0667 §7); and later the one word for the checker's removal + (ADR 0667 §12). +- §99 **How it is checked.** Tests 94 to 97, and 100 for the assigner's edge. + +### Choices this design makes under ADR 0666 and ADR 0667 + +| Choice | Why | +|---|---| +| §100 The registrations in the indexer's old `state` section with their history on an old stream, capped at 64 MiB, kept for the life of the mesh | the indexer is a foundation part (ADR 0619 §1 to §3, ADR 0666 §4); a registration keeps every version with who and on whose Approve, and nothing derives it again | +| §101 The runner a foundation part, its kept data in old sections, on the manifest validator's list | the bus module's own delivery waits on its pipeline (ADR 0666 §4) | +| §102 The want's compare-and-set keyed per module and watched branch | source revisions are kept per watched branch, so two branches' revisions have no order; comparing across them would let `main` refuse `beta`'s want (ADR 0666 §9) | +| §103 A second start of a pipeline for the same source revision and module, on `take-in.taken` and `package-published`, writes nothing, by the pipeline key's compare-and-set | the runner starts on both events (ADR 0666 §13, §15); the key it already keeps judges a start in one place, so neither producer knows of the other | +| §104 A refused new indexer revision holds later merges on its branch until a revert lands | the validation runs after the merge and before take-in (ADR 0666 §6), so the refused revision has landed; taking later merges in past it would deliver them on a graph its own validator refused | +| §105 Each check at its row's level, every requirement R1 to R18 keeping its named test | the record's rows name the levels; the test budget and one check per release bound what runs | +| §106 The approval asked as the operator-channel's accepted kind `ask` on its work queue | the seat has no verb `ask`: an ask is its accepted kind, by the asker's own name (design 46 §10) | +| §107 The gate no foundation part, its `source` in the old section it already has | the bus module's delivery waits on no act of the gate's; only the key's layout changes | +| §108 The verbs `register`, `policy`, `watch`, `unwatch`, `registrations` and the event `registration-changed` on `mesh-catalog` | one verb per trusted act, each its own ask naming what moves; readers follow the event (ADR 0596) | +| §109 The seed of the first registrations proposed as one ask, with the statuses the check judged until then and approval `bypass`, raised again by `indexer_seed_again` | registering is a trusted act (ADR 0666 §3), and one ask for the whole seed is how placement was adopted (ADR 0567); a declined or expired seed must not leave the pipelines stopped with no way on | +| §110 Code review refused as `required` until forge accounts are bound to bus identities | a review is refused from its author (ADR 0666 §22), which cannot be told until then | +| §111 The seat `git`'s read verb `branch` and event `branch-moved`, kept on its seat stream | registering reads a branch's protection through the seat `git` (ADR 0666 §3); a branch moves by a merge or an admitted push; a stream keeps a move said while the bridge is down | +| §112 The watchman's finding `pipeline-stands` for a step or a head still five minutes, cleared by the step's end or the head's `pipeline-started` | the record's five minutes (ADR 0666 §24), one finding for both, timed from the runner's events | +| §113 The runner's finding `pipeline-failed`, the author's for two hours, then the operator's | ADR 0666 §24 with ADR 0505 §5, §6 | +| §114 A module's watched branch and its `build` in the placement key, set by a proposal | a placement names the branch and a return is one value in it (ADR 0666 §6, §24); every placement change goes by a proposal (ADR 0567) | +| §115 The gate's `source.`, its verb `source` and event `source-moved` | one source revision per watched branch (ADR 0666 §6), read through the seat (G's prepare, the indexer's watch of the gate's `source`) | +| §116 The build seats' verb `steps` and accepted kind `step` on `check`; the assigner's kind `step` on `mesh-wants`; `step-ended` with the node in its subject | steps are asked on the serving seat's work queue (ADR 0666 §7); the `check` stream already orders after `delivery`; a node's account says only its own node's ends (ADR 0363 §2) | +| §117 The outcomes, with `accepted`, `superseded` and `cancelled`; an approval expired or refused ends `declined`, replaced `superseded` | every end a step can have is said as itself (ADR 0666 §10) | +| §118 `approval` asked last, its `about` the module and the branch | the operator approves a commit the mesh already judged, the point ADR 0661 §3 kept in one place; one ask per module and branch, a newer commit's replacing it | +| §119 A superseded pipeline's asks dropped by `drop`, and a pipeline superseded only when its module's fingerprint changed | a cancelled pipeline must leave no ask on a stream (ADR 0664 §4; G's prepare); a module the commit did not change has nothing newer to run (ADR 0666 §9) | +| §120 A group's wants only on `group-ended` | a group is delivered whole or not at all (ADR 0666 §9; research 086, R5) | +| §121 The six kinds derived from existing words, `needs` per artifact only where nothing says it | one form of each fact (ADR 0656 §6); the catalog entry's `needs` already exists from G | +| §122 The cycle rule in the indexer's graph | the graph is the indexer's, and the checking program goes with the checker | +| §123 The builder's seat `mesh-builds` and its event `package-published` | the record has the builder say the publication as an event of its seat (ADR 0666 §15); its waits move only when a later change gives the seat its verbs | +| §124 Each state's object store `-objects` through mesh-sdk's small package, sent objects readable by a standing grant derived from the manifests, and the package's two tools | one object store per state, granted to its owner; the sender's declared callers and consumers read what it sends (ADR 0666 §16); only its users import it, so nothing else is rebuilt | +| §125 The `run` ask published by the runner's account and the indexer's; the verb `run` called by the sessions and the operator only | the steps and the validation run code from the change, in the sandbox only, and each asker reads only its own step keys (ADR 0363 §2); a run publishes tagged packages, so nothing else may ask one | +| §126 The checker's step `check` becomes `pipeline`; `kept` starts empty | the runner is an acting part in the checker's place (ADR 0666 §19); a step's result is taken only from its seat holder (ADR 0666 §21), so no verdict of the checker's is taken in, at the cost of one round of every module's tests | +| §127 The field `callers` in a seat definition replaces the holders' trusted `callers`, a missing field admitting the holder roles and the operator only | the record makes the definition the grants part's one source (ADR 0666 §20); a field left out must open nothing | +| §128 `widens` in `pipeline-ended`, computed by the running runner over every part serving a step, passed on by the teller | a widening is said and nothing refuses it (ADR 0666 §23, §26); a change must not compute its own | +| §129 `merge-pull` judged from the forge module's own `failed-steps`, heard from `step-ended`, any run at the head's fingerprint counting unless a later rerun of that step passed, the protection read again on every `branch-moved` | the record has it judge from the events it consumes, never by a call, so a head merges while the runner is down (ADR 0666 §11, ADR 0596) | +| §130 The new assigner before the new `merge-pull` and the runner, by `needs`, both switching on the first `registration-changed` | a merge with no Approve must never reach an assigner that writes wants without a pipeline (ADR 0667 §10) | +| §131 The forge bridge's finding `branch-unprotected` | a move of a branch whose protection was removed starts no delivering pipeline and is said (ADR 0666 §6) | +| §132 The verb `recovery` of `mesh-delivery` | a recovery is named by its author as a fact the bus keeps with who said it, never read from text (ADR 0666 §26, research 086 R10) | +| §133 No forge status for a pipeline | the step results live on the bus (research 086 R10), shown by the runner and the delivery record; a status would be a second copy outside it | +| §134 The runner's `pipelines` kept as long as the delivery record that cites each (90 days), a superseded, run-on-request or uncited one 7 days, its step log 90 days by age, its outputs 7, keyed by source revision | a pipeline is read back as long as the record that delivered it; one nothing delivered has no trace to serve after a week; about 300 pipelines a day must fit its caps, so they are 256 MiB and 128 MiB | +| §135 The forge module's `failed-steps` kept until no head it was seen at is a watched branch's head or an open pull request's | an entry judges only a head that can still be merged; once neither names it, nothing can be refused by it | +| §136 The gate's `source.` deleted when the branch's last watch goes | a branch no registration watches makes no revision, so its key would name nothing | +| §137 The sent store kept 7 days by age, with no person's word | an object sent carries one reply or event and is transport, not kept data (ADR 0595 §4); its readers fetch it within a call's bound or a consumer's lag | +| §138 A replaced object listed `key gone`, as a deleted key's is | no key names it, and one listing lets the drop tool take both on a person's word, as ADR 0595 §4 and ADR 0666 §16 have it | +| §139 The checker's removal after the first end-to-end pipeline, on one word, its buckets through `drop`, the snapshot kept 90 days | ADR 0667 §12 asks one word for all three; 90 days is the delivery records' retention, the longest a trace reads back | +| §140 The pipeline steps on the `check` stream after `delivery` | a delivery's build is never held by a pipeline, as a check never held one (ADR 0525 §4) | + +## The delivery record, and what the gate owes the forge + +### The delivery record + +*ADR 0656; ADR 0595, ADR 0596, ADR 0597, ADR 0603 §7, ADR 0493 §3, §11, ADR 0633 §4, §5, ADR 0441 §1, ADR 0548 §8, +ADR 0564 §2, ADR 0363 §2.* + +§141 From research 085's milestone the gate, holder of the seat `mesh-delivery`, keeps one **delivery record** per +milestone's delivery, a ledger instance (ADR 0595's template `ledger`, ADR 0597) it alone writes (ADR 0656). It +holds: + +- §142 **the group's state**: the heads, the verdicts, the checks and the asks, which `merges` holds today; from milestone + G's delivery the pipelines' `step-started`, `step-ended` and `pipeline-ended` in place of the verdicts, the checks and + the asks, kept as long as the record (ADR 0666 §9); +- §143 **the trace**: the milestone, its issues, its pull requests, their commits, and the graph revisions the delivery + moved between; +- §144 **what happened to each entry on each node**: for every entry of the graph difference, taken in, built, checked, + composed, wanted, running healthy, held (with the hold's reason, so a reader of the record sees why an entry stands + still without asking its holder), failed (with what failed), or away (ADR 0656). + +§145 It holds no tiers, and only the gate orders work by it, so it is no second copy of the keys, the objection research +063 had to a stored plan (research 085, Findings 10). Its fields, retention and tools are this design's choices under +ADR 0656. + +- §146 **The outcomes arrive as events, through a durable consumer of the gate's own.** The gate's manifest `consumes` + each step event of *What each step says* (below), and `wait-held` and `wait-ended` of each holder. The consumer + resumes from the last event applied; an event applied twice changes nothing; an event is applied only when it comes + from its owner's account; and running healthy is taken from the node-engine seat's `running` event, never from a + have read across the seam (ADR 0596). +- §147 **It ends when every present node runs its entries**, and the gate says `record-ended` on the seat `mesh-delivery` + with the record's milestone and its nodes away. It names the nodes away, each with since when, and ends without + waiting for them, as a node away holds nothing (ADR 0603 §7). +- §148 **A record open too long is a finding.** The watchman writes the finding `record-open` for a record still open 24 + hours after its merge (a delivery of the whole mesh takes under an hour, so a day means something stands still) and + clears it on `record-ended`; the condition keeper raises it (ADR 0564 §2). The finding names the entries still held + or failed, read from the record's own events. It is written only while no other condition covers the record: while + an entry of it is held by a wait that raised `acting-part-late`, or a store that holds it raised `full`, that + condition already tells the operator why the record is open, and a second one for the same cause would only be noise. +- §149 **A node away that wakes adds its outcomes.** When it wakes and catches up by its wants (*A change's graph + difference is its delivery*, below), its outcomes reach the record through the same consumer as any other, and the + record shows the node no longer away. +- §150 **An Approve given holds at its heads, until G's delivery.** An Approve the operator gave for a group's heads holds while those heads + stand: a check of the same heads asked again, after a main move or for any other reason, records its verdict in + the record and asks the operator nothing again (issue 1972). The Approve is withdrawn only as ADR 0441 §1 has it, + when a member stops being mergeable, and a carried verdict is read as current (ADR 0548 §8). From G's delivery no + Approve is asked per merge; an `approval` step's answer is the runner's, kept in the record as its step's end + (ADR 0666 §10). +- §151 **From G's delivery, a record for every landed merge.** A session merges through the seat `git` and the gate merges + nothing, so every merge is one the gate did not make: the gate opens a record for each source revision of a watched + branch the indexer takes in, a group's members in one, and `forge-made` no longer marks a record apart. A merge its + author names a recovery is marked `recovery` (*A recovery fix is an ordinary merge*). +- §152 **A small fix has a record of its own.** A small fix is a milestone of one issue (ADR 0493 §3), so it has a + delivery record like any milestone; nothing is merged outside a released milestone (ADR 0493 §11). +- §153 **It pins the graph revisions it points at.** The gate says, as the seat `mesh-delivery`'s events `pinned` and + `freed`, which catalog and assignment graph revisions a record starts and stops pointing at, and as + `heads-replaced` that a candidate's heads were replaced or its pull request closed. Only the gate's account may + publish them (ADR 0363 §2). The indexer and the assigner hear them through a durable consumer each, declared in + their manifests' `consumes`, which resumes from the last event applied after a restart, so a `freed` said while one + of them was down is still applied; neither reads the gate's state (ADR 0596; *Two graphs, one source of truth*, + below). +- §154 **A record is kept for 90 days by default**, the gate's setting `record-retention`. Ninety days covers every trace + the operator has asked of a past delivery so far, which went back weeks, never months; the setting can keep records + longer. When the retention removes a record, the gate says `freed` for each revision it pinned. +- §155 **Its size, its cap and its growth.** A record's state of 30 modules on four nodes is about 30 KiB, against the + bus's 256 KiB value limit (research 085, Findings 8). The ledger keeps every operation beside that state: 30 modules + on four nodes with seven outcomes each is about 840 outcome operations a record, at about 0.2 KiB each about 170 KiB, + so a record costs about 200 KiB with its snapshot. At an estimated 20 deliveries a day (a guess from the days of + 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 + operations and its snapshot with it, so the ledger's size follows the retention, not the mesh's age. +- §156 **The switch carries today's state in, once.** At the new gate's start, `merges` and every group in flight become + 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 + 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 + bus, backed up and restored with its delivery*). +- §157 **The forge bridge asks the seat for a group.** It reads a group's members from the seat `mesh-delivery`'s verb + `groups`, never the gate's `merges` state, both to set the group on each merged message and to publish a group's + end again (ADR 0656, which changes ADR 0633 §4 and §5; ADR 0596). Its account holds no grant to read `merges`. +- §158 **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). +- §159 **Its tools**, against the four lines a module's tools answer: + + | Line | The gate | + |---|---| + | read everything it holds | `gate_record` (one record whole: the group's state, the trace, each entry's outcome per node, the nodes away), `gate_records` (every record with its fill against the value limit, 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 (from G's delivery the runner's `show`), 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`) | + | one seat, many tools | the seat `mesh-delivery`'s verbs, with `groups` answering a group's members and the acts said for it | + +- §160 **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 + `record-ended` are said; a `freed` from an account other than the gate's is refused by the bus; a group approved + before the switch is not asked again after it, nor after milestone G is delivered again following a revert; a record ends once every present node runs its + entries, naming the nodes away; a held and a failed entry are kept with their reason; a record open past 24 hours + raises `record-open`, cleared by `record-ended`; a node away that wakes adds its outcomes and is no longer shown + away; a group's heads approved and checked again ask the operator nothing again; a small fix's merge gets a record + of its own; a record past its retention is removed and frees its revisions; the tools read a record, list the + records with their fill, and a repair completes a record missing an outcome through the owners' read verbs. In the + forge bridge's whole-module test, a group's members are read from `groups` and its end published again from it, and + a read of `merges` by its account is refused. Live: one call of `gate_record` traces an issue of the registry + milestone to each node's running build, also after six later merges; a node away is named with since when and its + 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). + +### 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.* + +§161 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: + +- §162 **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..`, 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..`. 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). +- §163 **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, its size the one its template fixes + (ADR 0595 §3), is therefore a + saving and a read, never what keeps an act from happening twice. +- §164 **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. +- §165 **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. +- §166 **A group's merges follow one another, until G's delivery.** 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. +- §167 **From G's delivery the gate owes no merge, and the checker nothing.** A session calls `merge-pull` itself (ADR 0666 + §11), and a group's members land one by one, the group ending when every member has (*Groups*); the checker's `owed` + goes with the checker, and the runner owes the forge nothing, a pipeline's result living on the bus. The gate still + owes the delivery's view, a comment and the note's line, performed by the forge bridge as above. +- §168 **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`). +- §169 **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. +- §170 **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"). +- §171 **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, from milestone G's delivery + +§172 **From milestone G's delivery the gate keeps no merge states.** With no check before a merge and no Approve per merge +(ADR 0666 §10, §17), nothing is `proposed`, `ready`, `rejected` or `held` before a merge: a commit's states are its +pipeline's steps, kept by the runner (*Pipeline steps and the policy*). The table, the gate's `table`, `recheck` and +`close` and the one key per pull request go with the check; `stalled` lists the acts owed to the forge past their 15 +minutes and the records `record-open` names. + +## Two graphs, one source of truth + +*ADR 0656, which supersedes ADR 0645 to ADR 0648; ADR 0595, +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.* + +§173 From research 085's milestone. One graph answered two questions, which modules exist and which version runs where, +and one module running as several placed versions would have given one entry two shapes and one key two writers; two +graphs answer them, the second computed from the first, so there is one source of truth (ADR 0656; research 085, +Findings 11). How each is kept, read and retained is this design's choice under ADR 0656. + +``` + manifests ──► indexer (mesh-catalog) ──► catalog graph revision ──┐ + ├──► assigner (mesh-wants) ──► assignment graph revision + placements (mesh-module-assigner) ───────────────────────────────┤ │ │ + node capabilities (node-engine seat) ────────────────────────────┘ │ └─► wants, from a trunk revision only + ▼ + a change's assignment graph − the current one = its graph difference = its delivery +``` + +- §174 **The catalog graph is the indexer's.** The indexer, holder of the seat `mesh-catalog`, keeps the modules as their + manifests declare them; it is today's module graph, and *module graph* stays its other name (ADR 0656). At each + revision it holds one entry per module: its bases, its packages, the toolchain version and recipe version of the + build module that builds it as ADR 0603 §2 has them, its provides and requires, its invokes and serves, and its + fingerprint, with the rules the seats declare (*An acting part's new version acts first*, below). +- §175 **The assignment graph is the assigner's, computed and never written by hand.** The assigner, holder of the seats + `mesh-module-assigner` and `mesh-wants`, computes the module versions placed on nodes, with the edges between + versions, from the catalog graph, the placements and the nodes' capabilities, and nothing else writes it + (ADR 0656). Each entry is one module version on a node; its edges are provisioning, contribution, and the acting + parts' versions that are to act on it (ADR 0656), whose rules and versions come in with the catalog graph. It is + kept, but it is no stored plan: it has one writer, no part orders work by a stored plan, and any revision is computed + again from the inputs it names and compared with the one kept, by a tool (below), so a kept revision is a checked + derivation, never a second source of the kind research 063 removed (research 085, Findings 5). +- §176 **Each graph is kept per revision, and each revision names its inputs** (ADR 0656). The indexer keeps a catalog + graph revision for each source revision it takes in; the assigner keeps an assignment graph revision for each change + of its inputs, naming the catalog graph revision, the placements and the capability readings it was computed from. + Both parts are the foundation (ADR 0619 §1), so both keep their revisions as objects declared in an `objects` + section in the old form, each with a cap it declares there, never in the new form (ADR 0619 §2), and neither waits + on the bus module to start; the manifest validator refuses either manifest that declares them in the new form + (ADR 0619 §3). An assignment graph revision is announced by an event of the seat `mesh-wants` and served by its + verbs. This replaces ADR 0603 §2's one key per module with five past values as the graph's form (ADR 0656, which + changes ADR 0603 §2); the keys are written no more, and a revert of milestone G restores them from their backup + (*Reverted*, below). +- §177 **A revision is made by a merge, and also with no merge.** The indexer makes a catalog graph revision when it + takes a source revision in. The assigner makes an assignment graph revision on each new catalog graph revision, on + the seat `mesh-module-assigner`'s event `assignments-changed` (ADR 0567 §5, ADR 0641), and on the node-engine seat's event + `capabilities-changed`, which a node-engine says when the capabilities it states in its node record change + (ADR 0614 §4), so the assigner follows an event and never reads a node record across the seam (ADR 0596). A + placement change is traced like a merge. At its first start with no revision kept, the indexer takes in the head the + gate's source names for every repository by its catch-up path and keeps that as revision 1, and its verb `revision` + answers that it waits until then (lead-47's ruling in G's prepare: a first start has no merge to make a revision). +- §178 **A revision is kept while a record pins it or it is current.** A revision of either graph, and the input revisions + it names, is removed when no delivery record pins it and it is not current: neither trunk's newest revision nor the + newest of an open candidate. Pins are counted per revision, so a revision two records point at stays until both + have said `freed`. The indexer and the assigner remove one only on applying `freed` or on a revision ceasing to be + current, never on a timer and never by reading the gate's state (ADR 0596; *The delivery record*, above). A trace + must read every revision it moved between, and a revision neither pinned nor current is read by nobody. +- §179 **An unchanged entry is stored once.** A revision is kept as its list of entries' digests, and each entry as an + object of its own named by its digest, so an entry that two revisions share is stored once; an entry object is + removed when no kept revision lists it. Consecutive revisions differ by the few entries a delivery moves, so this + keeps the growth to what changes. It is chosen over a larger cap because whole revisions would grow with every + revision whatever changed, and a cap would only delay the same fill. +- §180 **The caps and the growth** (estimates, to be read from the fill tools once the milestone runs). A whole assignment + graph revision of about 120 modules on four nodes is under the bus's 256 KiB value limit (its unit test), and a + catalog graph revision of about 120 entries about 120 KiB. A record pins the revisions before and after its + delivery, and consecutive records share one, so at an estimated 20 deliveries a day about 20 revisions of each graph + a day stay pinned. A delivery moving 5 modules on four nodes adds about 20 assignment entries of about 1 KiB and a + list of about 15 KiB, and 5 catalog entries and a list of about 4 KiB: about 0.7 MiB a day of assignment graph and + 0.2 MiB of catalog graph, about 63 MiB and 18 MiB at the records' default retention of 90 days. The caps are 512 MiB + for each, many times the steady state. Placement-only and capability-only revisions are pinned by no record and go + when they stop being current. +- §181 **A store filling is said before it is full.** The indexer, the assigner and the gate each say their fill against + its cap in their read tools, and the event `filling` of their seat when a store passes 80 % of its cap; the watchman + writes the finding `store-filling` naming the part and the store, the condition keeper raises it (ADR 0564 §2), and + it clears when the store falls below 70 %. A full cap refuses loudly, naming the part and the store: the indexer + keeps no new revision and says the merge pending with the reason `objects full`, the assigner keeps its last + revision and writes no new want, and the gate opens no new record and holds the merge; each says it as the event + `full` of its seat, which the condition keeper raises as urgent. When a removal brings the store back below its cap, + the part says `room` of its seat, takes the refused work up again (the pending merge, the next revision, the held + record) and the condition clears; a condition that never clears would hide the next fill. Nothing is dropped to make + room: a removal is only the rule above, and the setting `record-retention` or a larger cap is the operator's. +- §182 **What happened is not in the graph.** An entry says what is to run and what it waits on; whether it was built, + wanted or runs healthy is said by the parts as their events and kept in the delivery record (ADR 0656). +- §183 **The want stays the one record a node reads.** The assigner writes `want..` from a trunk + revision's assignment graph only; a node-engine reads its want, never the assignment graph, and the have stays what + it runs (ADR 0656, which changes ADR 0571 §8). +- §184 **From G's delivery, per watched branch and between artifacts.** The catalog graph is kept once per watched branch, + each revision naming its branch, and its edges run between artifact references, of the six kinds of *Dependencies + between artifacts* (ADR 0666 §6, §14). The assigner computes a node's entries from the catalog graph of the branch its + placement names, and writes a want from a revision of that branch whose `required` steps passed, in place of a trunk + revision's alone (ADR 0666 §9, which changes ADR 0656 §2). +- §185 **Reverted.** Only the new form is written: the indexer, the assigner and the gate keep nothing of ADR 0603 §2's + keys or of `merges` and `turns` beside the new forms, since nothing reads them after milestone G. A revert of + milestone G is a change like any other, checked and delivered, and the delivery system restores what it must + (*A module's kept data on the bus, backed up and restored with its delivery*, under *A backup before the apply*). + Milestone G changes the form of these kept data, and raises their `form` (a kept data declaring none reads as form + 0, so G's own move takes their restore points): + + | 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`; 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 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 wants keep their form: their keys and values are unchanged, only what the assigner computes them from changes, + so G raises no `form` on them and a revert restores none. Restoring the wants would send nodes back to older + 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 + three keep form 0 and are never restored, so nothing decided since (a placement, a verdict, the source revision) is + 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 + +- §186 **The difference names everything a plan named.** For a change (a pull request's heads, a delivery group's + heads, or a merge), the indexer gives its catalog graph and the assigner its assignment graph. Compared with the + current revision, the difference names the new versions, the moved edges, the touched nodes and the order, read off + the edges, and no plan is stored (ADR 0656). The assigner serves it by the seat `mesh-wants`'s verb `difference`, + for two revisions of the assignment graph or for a candidate against trunk. ADR 0603 §6's tiers, as ADR 0633 §5 + changes it, are a view worked out from that difference (ADR 0656, which changes ADR 0603 §6), read through + `difference`, with the waits and holds read through their owners' tools and the pending revisions through + `indexer_pending`. +- §187 **The preview is a candidate's difference.** Issue 1874's plan preview of a group before its merge is its + candidate's difference, read by one call of `difference`, and needs no code of its own: a candidate's graphs are + computed for its check anyway, so the preview costs nothing more. +- §188 **A changed fingerprint with no difference is refused by name.** When a module's fingerprint in the change + differs from the running one while the difference is empty, the assigner refuses it, naming the module, and the + check fails naming it. +- §189 **A candidate's graphs are kept apart, and dropped with its heads.** A candidate's two graphs are computed per + check, kept apart from trunk's, and dropped on the gate's event `heads-replaced`, said when the candidate's heads + were replaced or its pull request closed. A candidate costs a computed graph per check. +- §190 **Only a trunk revision writes wants**, whether a merge taken in or a placement or capability change made it; a + candidate's graph writes none (ADR 0656). From G's delivery a want comes from a revision of the watched branch a + placement chose whose `required` steps passed, and a candidate is a run on request's: the indexer builds it on the + runner's `run-started` and drops it on that run's `pipeline-ended`, the gate's `heads-replaced` no longer making + candidates (ADR 0666 §9, §18). +- §191 **Each part acts on its own entries.** The builder, the build modules and the grants part each act when their own + entries in the new revision differ from what they run (ADR 0656), reading them through the seat `mesh-wants`'s verbs + and events, never its bus state (ADR 0596), and naming no other module (ADR 0656). The node-engine acts on its want + alone, as it does today: the want is the one record a node reads, and handing every node the assignment half would + have each node read every other node's placements. +- §192 **A node asleep catches up when it wakes.** A node away holds nothing and catches up by its wants (ADR 0603 §7); + a want's new form reaches only a node-engine that says it reads it (ADR 0614 §4, ADR 0618 §2). +- §193 **No delivery goes ahead of a change.** A change is delivered as its own difference, its acting parts' new versions + first in their own steps (ADR 0656); the one exception is the delivery before research 085's milestone (*The + bootstrap delivery, and the one milestone after it*, under *Milestones*; ADR 0644). + +### The revision view + +- §194 **A pair, each half served by its one owner** (ADR 0656). For a trunk revision, or for a candidate's heads before + any merge, the indexer serves the catalog half by the seat `mesh-catalog`'s verb `revision`: the catalog graph, the + heads, the seat definitions, the manifests' verdicts and the fingerprints. The assigner serves the assignment half by + the seat `mesh-wants`'s verb `revision`: an assignment graph revision, named by its own revision and naming its + inputs, the catalog graph revision, the placements and the capability readings. A part's view for the current + revision is the newest assignment half and the catalog half it names. `seat-definitions` stays the seat list's verb + (ADR 0636 §4), and the catalog half carries the same definitions at its revision. +- §195 **Every part takes a first view, then follows the events.** The checker, the builder, the grants part and the + indexer's own later passes take a first view from the two verbs and then follow the two seats' events, never a list + compiled into their build nor another module's bus state (ADR 0656, ADR 0596). The node-engine reads only the catalog + half, for the seat definitions it composes with, and its want; it never reads the assignment half (*Each part acts on + its own entries*, above). Of the view the assigner reads only the catalog half, never its own output back; its other + inputs stay the placements and the capabilities (ADR 0656). A running part acts only on a trunk revision's view; a + candidate's view is read only by the parts that judge a candidate, inside the check its manifest validator and + composer, and the indexer's candidate pass (ADR 0656, which changes ADR 0636 §4 in that the candidate pass joins + them). From G's delivery a running part acts on a revision of a watched branch as on a trunk revision, and a + candidate's view is read only by a run on request's steps and the indexer's candidate pass (ADR 0666 §6, §18). +- §196 **Every other reader of which modules exist reads the catalog half, in the same milestone.** From milestone G the + indexer declares no state `modules` and serves neither its tool `indexer_read_modules` nor a view of it (*Reverted*, + above), so every module that learns from it which modules exist moves in milestone G, not after: the watchman (its + manifest findings), the status view (`view_reach`), the forge module (which repositories its account writes), the + holders of the seats `mesh-config`, `mesh-provisioner` and `mesh-self-check`, the claude-code module and the tool + runner. Each takes a first view of the catalog half by the seat `mesh-catalog`'s verb `revision` and follows its + 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 `_first_views` and `_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; accepted); 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). +- §197 **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*). +- §198 **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. +- §199 **Who holds a seat is applied by one rule, from what each node runs.** The node-engine and the grants part decide a + seat's pass by mesh-sdk's `SeatsToPassOn` (ADR 0660 §3), reading the manifest of the build each assignment runs + (ADR 0660 §2). What each node runs is heard, never asked: each part keeps it from the node-engine seat's events + `running..` (*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. +- §200 **A part with no view says it waits.** It names the revision it has no view for, acts on nothing new, and keeps + running what it runs, as ADR 0636 §1 has a reader of the seat list do; the checker, the builder and the grants part + wait too, and wait for the view, not only the seat list (ADR 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 in its runtime's first-view + 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 + (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 + waits and says so. +- §201 **Each process knows its own build from its start.** The node-engine hands every process it starts the + fingerprint of the build it starts it with, and the process takes its own build from that, never learning it later + (ADR 0656, which changes ADR 0639 §7 from the indexer to every process). *The fingerprint handover*, below, says its + form. + +### What ADR 0656 leaves to this design + +§202 ADR 0656 leaves how each part is built to this design, under issue 1921; these four needed a shape of their own. + +- §203 **An acting rule's fields.** The seat's definition is where ADR 0656 has an acting part declare what it acts on. A + seat's definition gains one optional field `acts`, a list of rules, each with three fields of its own: `step`, one of `take-in`, + `validate`, `check`, `build`, `compose`, `grant` and `place`, and from G's delivery `pipeline`, the runner's, in + `check`'s place (ADR 0666 §19); `on`, either `every` (every module) or a `language` + naming the language of the modules it acts on, matched against what the manifest says its language is, as the + indexer's language map matches today; and `bound`, how long an entry waits in that step for the acting part's new + version (*An acting part's new version acts first*, below, gives each step's default). The definition format's own + schema (design 26) gains the field, and the format stays 1. The indexer reads it into the catalog graph, the assigner + into edges, and the checking program from the revision view. **Its cost in mesh-sdk:** the seat-definition reader in + mesh-sdk's runtime refuses a definition with a field it does not know or a format other than 1, so a reader built + before the field refuses every definition that carries `acts`, and a refused definition blocks new claims of that + seat only (ADR 0636 §3), never what runs. The runtime therefore learns `acts`, which rebuilds every module once + (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 + 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 format's reader itself is delivered before them, as a release of mesh-sdk's seat-definition + reader merged ahead of G's check (the operator's choice of a reader first, 2026-11-09; ADR 0667 §4). The bootstrapped + definitions every reader carries from its start (ADR 0636 §2), of which `node-backup` carries no `acts`, 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. +- §204 **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. +- §205 **The fingerprint handover.** The node-engine starts each process, a service or a container alike, with the + environment value `MESH_FINGERPRINT`, the fingerprint of the want it applies; mesh-sdk's runtime reads it once at the + process's start and holds it as the process's own build (ADR 0656). A process started with no value says `own build + unknown` in its runtime tool and its journal, and the indexer acts on it as ADR 0639 §8 has it. **Its cost:** one + change of mesh-sdk's runtime, which rebuilds every module once (ADR 0656, Consequences), and one of the + node-engine; the order between them is the composing step's wait of the node-engine (*Order without a person*, + below), so a module whose runtime reads the value is composed only by a node-engine that hands it. +- §206 **The build seat's ask that runs a program in the sandbox.** The checker asks the seat `node-build-go` for an ask + `run` on the build seats' `check` stream: one whole job on one node (ADR 0525 §3), which fetches the named heads, + builds the named program at them, runs it in the run step (ADR 0448 §2) with the input the ask names by its sha256 in + the asker's own state (the checker's `inputs`, a day), asked of the seat `mesh-delivery-checker`'s verb `input` and + checked against that digest, laid as a file, and writes the program's exit and its answer, carried whole, on the + build module's step key named by the ask's id (ADR 0525 §6). It is an accepted ask of the seat, not a request verb, because it is a + long job pulled where there is capacity, never a call to a named node. Only the checker's account may publish `run`, + and from G's delivery the runner's and the indexer's (its validation before take-in), each under its own name. + Every step key of a `run` ask starts with the asker's name (`checker.`), so the checker's read grant is fixed + in advance to its own prefix and never follows ask ids one by one (ADR 0363 §2); no other part can have a program run + or read its verdict. From milestone G the seat definition of `node-build-go` in `mesh-delivery-contracts` names it; B0 + brings the ask with its types in mesh-sdk's `go/delivery` and the grants check asks have today (*The bootstrap + delivery, and the one milestone after it*). The checking program, the acting parts and the composer a check builds + from a change all run through it (ADR 0656, ADR 0644). A program is built once per fingerprint: the build is the + builder's build of that fingerprint (ADR 0498 §1), kept like any build and reused by every later ask naming it, so two + checks of changes that leave the checking program unchanged ask one build. Only a build made in a run step that runs + nothing but the build is kept and reused: a program's own run happens in a separate run step over a copy, so a program + that rewrites its own binary while it runs changes no kept build. A candidate's build is never delivered to a node: a + want names only a trunk revision's fingerprint (*Only a trunk revision writes wants*), and a candidate's build is kept + only for checks. +- §207 **The first tier's own bound.** A check's first tier has 20 minutes for all its builds together, inside the check's + one-hour bound of the state table and the checker's step bound (ADR 0639 §5); an acting part not built within it is + one the first tier cannot build, and the check fails naming it (ADR 0656). The verdict tells two cases apart: `waiting + for a build node` when no build node of the language took the ask within the bound, and `did not build` when one + took it and the build failed, so the operator knows whether to free a build node or fix the change. + +### Choices this design makes under ADR 0656 + +§208 ADR 0656 decides the direction and leaves every choice made in working it out to this design, each with its reason +(ADR 0656, Consequences; the operator, 2026-11-06 20:3x). The choices, and why: + +| Choice | Why | +|---|---| +| §209 Both graphs kept as objects in an `objects` section in the old form, each with a cap of 512 MiB | both parts are the foundation, whose new kept data goes on the old sections so neither waits on the bus module to start (ADR 0619 §1, §2); the caps are many times the estimated 90 days | +| §210 An unchanged entry stored once, a revision being a list of its entries' digests | consecutive revisions differ by a few entries, so the stores grow by what changes; a larger cap over whole revisions would only delay the same fill | +| §211 No old form written beside the new; a revert restores the parts' kept data on the bus from a restore point taken before they moved, then they catch up forward | only the new form is looked after (the operator, 2026-11-06 21:3x), and a revert still works, as the delivery system's capability for every change of a kept data's form | +| §212 A module's kept data on the bus backed up before a `form` change and restored beside the live data at a revert, a missing restore point holding the revert | ADR 0404 covers only the items on a module's node, so the bus's kept data had no restore point; a restore never goes over live data, and a revert with nothing to restore must not start on the newer form unasked | +| §213 Only kept data whose `form` changes restored, the wants never; at a revert the node-engine last on its node, and the reverted assigner and gate only after the reverted indexer took in the trunk's head | restoring anything else would set back what was decided since; restored wants, or an assigner reading an indexer not yet caught up, would send nodes to older fingerprints; the node-engine of before may not know how to restore | +| §214 A restore point holding the consumers' positions and the catch-up tool the newer manifest declares, called after a restore | the reverted build then hears everything since as after any restart; the stream `forge` keeps 7 days, so what fell out of it is taken in from the trunk by the part's own tool | +| §215 A revision removed when no record pins it and it is not current, pins counted per revision | a trace must read every revision it moved between, and a revision neither pinned nor current is read by nobody; counting pins keeps a revision two records share | +| §216 The indexer and the assigner hear `pinned`, `freed` and `heads-replaced` through durable consumers | an event said while either was down is applied when it comes back, so no revision leaks and none is dropped early | +| §217 Records kept 90 days by default, the gate's setting `record-retention`, the ledger capped at 768 MiB, a record's operations removed with it | the traces asked so far went back weeks; about 840 outcome operations make a record about 200 KiB, so 90 days at an estimated 20 a day is about 360 MiB, and the cap is twice that | +| §218 `record-open` only when no other condition covers the record | the cause is already told once; a second condition for it is noise | +| §219 `full` cleared by `room` when the store falls back below its cap | the refused work is taken up again, and a condition that never clears would hide the next fill | +| §220 The switch into records keyed by milestone and heads, safe to run twice | delivering milestone G again after a revert makes no second record and asks no group again | +| §221 A store passing 80 % of its cap said as `filling` and raised; a full cap refused as `full`, naming the part | the operator hears of a store filling while there is time, and a full store stops work loudly instead of dropping what a trace needs | +| §222 A candidate's graphs kept apart and dropped on `heads-replaced` | a candidate must never write wants or be read by a running part, and its graphs mean nothing once its heads are gone | +| §223 The verbs `revision`, `entry` and `difference` on the two seats | each half of the view, and the difference, is served by its one owner through its seat, never read from its state | +| §224 The node-engine reads its want and the catalog half, never the assignment half | the want is the one record a node reads; the assignment half would have each node read every node's placements | +| §225 Composing waits per node, held by the assigner, with no new field in the want: a node's node-engine want first, its other wants once its new node-engine runs | a node away holds only itself (ADR 0603 §7); an old node-engine reads its want as it is, so it is reached with no form it cannot read | +| §226 Capability changes said as the node-engine seat's event `capabilities-changed` | the assigner follows an event instead of reading node records across the seam (ADR 0596) | +| §227 The step events, their fields and their subjects, with the node in the subject of every event a node publishes | every outcome reaches the delivery record as the event of the part that did it (research 085, Findings 7), and a node's account can be granted only its own node's subjects (ADR 0363 §2) | +| §228 A first tier of only the changed acting parts, bounded at 20 minutes, its verdict telling `waiting for a build node` from `did not build` | an ordinary change pays nothing more; a bound turns a build that never ends into a named failure, and the two words tell the operator which act frees it | +| §229 The build seat's ask `run`, published only by the checker's account, its step keys starting with the asker's name | the program is a long job pulled where capacity is, run in the sandbox every check already uses (ADR 0448 §2), and no other part can have a program run or read its verdict | +| §230 A program built once per fingerprint and reused, only from a run step that runs nothing but the build; a candidate's build never delivered | a check that leaves the checking program unchanged costs no build, and a program run from a change can never change a kept build or reach a node | +| §231 Every program built from a change run with no network and no bus account | a change not yet merged is not trusted, and the sandbox already keeps the logins outside (ADR 0448 §2, §4) | +| §232 Every change of the checking program's fingerprint named in the verdict and the Approve ask, with the rule names of the trunk's and the heads' programs compared by the running checker outside the sandbox as its detail | only the fingerprint covers a helper a rule calls; the comparison is made from the sources by a part the change did not build, so a program that drops a rule and hides it is still named; a rule widens or narrows what judges or acts on every module, so the operator sees it before approving | +| §233 A rule matching a module with no holder for its step held by name, and its check failed | a rule nobody serves would otherwise pass in silence | +| §234 Each step's wait held by the part that does the step, with its own read and release tools and the events `wait-held` (at the wait's start, with its bound) and `wait-ended`, timed by the watchman, whose clock starts when the new version's build is done | the part that does the step already holds its state; the watchman timing from `wait-held` still raises a wait whose holder stopped, and counting from the build done leaves a slow build to the build's own wait | +| §235 The bound per step in the acting rule, with a default per step | the time a step's new version needs is the acting part's to know, not another module's | +| §236 A build module's wait ends on the agreed toolchain naming the new build module | the agreed toolchain is what a fingerprint takes (ADR 0584 §1), so before it names the new build module no module could be built once by it | +| §237 The running indexer makes a catalog graph revision with the named indexer's entry | the newer indexer can then be wanted and granted, so a revision waiting for it is never stuck behind it | +| §238 The acting rule's field `acts` with `step`, `on` and `bound`, the definition format staying 1 | the steps and the language match are what the indexer's map and the checker's cases held in code (research 085, Findings 2); the reader refuses an unknown field, so the runtime learns it in the one rebuild the milestone makes | +| §239 The fingerprint handed as `MESH_FINGERPRINT` at a process's start | one value every runtime reads before anything else, a service and a container alike | +| §240 The delivery record's consumer, held and failed outcomes, end and `record-ended`, the finding `record-open`, node away and wake, switch done once, and tools | a restart must lose and double nothing; a reader sees why an entry stands still; a node asleep must not hold a delivery open; a switch run twice must ask no approved group again | +| §241 A small fix's own record | a small fix is a milestone of one issue (ADR 0493 §3) | +| §242 An Approve given held while its heads stand (issue 1972) | the operator approved those heads; a check of them asked again changes nothing they approved (ADR 0441 §1, ADR 0548 §8) | +| §243 The milestone events on a subject of their own | a waiter on one member's pull request otherwise wakes on every member's | +| §244 The issue tracker's link kinds to a decision and a research effort, and the knowledge base's link from a decision to its milestone | the trace from research to the running build is then links all the way, with no text match (research 085, Findings 7; ADR 0493 §4) | +| §245 The view's state read and asked again by mesh-sdk's `go/views` tools `_first_views` and `_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 | +| §246 The seat list's reader and its two tools wired once by mesh-sdk's runtime | ADR 0636 §7 puts them in the runtime bundle; four hand-wired copies would each learn `acts` apart | +| §247 The trunk's heads from the catalog half, and nothing read of the gate by the checker | ADR 0596 §2; with the hold and turns removed nothing of the gate is left for the checker to read | +| §248 The indexer reads every contracts trunk's definitions at its start, before it judges | a definition merged while it was down is never judged against a list that lacks it (ADR 0636 §1) | +| §249 Another node's running build kept from the node-engine seat's `running` events by a durable consumer, the event carrying the fingerprint and the manifest's digest, the trunk's manifest for a node that said nothing | ADR 0660 §2 reads the manifest of the build each node runs; an event kept by a durable consumer answers while a node is away, where a call would wait on it; one fallback in the one function keeps the two parts agreed (ADR 0660 §3) | +| §250 What the gate and the checker owe the forge said as the event `owed` per repository and pull request, each act safe to repeat at the forge, each outcome said as `owed.ended` and recorded, an unanswered act said again at the gate's start and stalled after 15 minutes | ADR 0596 §1, §2 end the watches of the gate's and the checker's keys; an act safe to repeat cannot be lost between the act and its record, where an id recorded first could; an outcome said and recorded leaves no act unseen | +| §251 A merge made at the forge opens a `forge-made` delivery record | its trace and outcomes are kept like every delivery's, and no later merge waits behind a merge the gate never heard | +| §252 Every delivery part and the gate reach the forge only through the seat `git`'s verbs and events, the act verbs granted by the holder's trusted `callers` to the forge bridge alone, a failed read answered as an error | the delivery parts name no other module (ADR 0656 §1, acceptance test 27); the forge's answers are typed in the seat's contract instead of guessed in each caller; the bridge stays the one part that acts on the forge; an error read as an empty answer would hide a forge down | +| §253 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) | +| §254 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) | +| §255 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 | +| §256 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 | +| §257 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 | +| §258 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`) | + +§259 Each choice is checked by the tests its section names; the review by architectural domain judges them. + +### What each step says + +§260 Each step says what it did as its own event, the event of the part that did it. A catalog graph revision kept +carries the source revision; an assignment graph revision kept and a difference worked out carry the source revision +and the assignment graph revisions; an entry taken in, built, checked, composed, wanted and running also carries the +entry's fingerprint and its node. The gate's delivery record is built from them. The seat's event comes first where +the parts follow it through a seat (ADR 0656); a holder's own event stays under its own subject, declared in its own +manifest's `streams` and published on `mesh.stream..event.` (ADR 0363 §1, §2). A seat's event is +declared in its definition and its holder's manifest claims the seat; a seat event's name has no dot, since it is read +as a subject's token, and it is kept on the stream `SEAT__`, which the grants part makes with its durable +consumers, keeping it by the age and cap the definition's `keep` names, 90 days unless it names less. **An event a node publishes carries the node in +its subject**, and the grants part grants each node-engine's account only its own node's subjects, so one node cannot +say another runs a build (ADR 0363 §2); the gate's events are granted to the gate's account alone. + +| Step | Event | Owner: the seat, then the module | Subject | Declared in | +|---|---|---|---|---| +| a catalog graph revision kept, saying whether it is a trunk revision or a candidate's and its watched branch | `catalog-revision` | `mesh-catalog`, the indexer | `mesh.seat.mesh-catalog.event.catalog-revision`, the watched branch in the subject from G's delivery | 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-delivery-contracts` (ADR 0641 §2) | +| a difference worked out | `difference` | `mesh-wants`, the assigner | `mesh.seat.mesh-wants.event.difference` | the same | +| an entry taken in | `take-in.taken`, which gains the entries | the indexer's own | `mesh.stream.mesh-delivery-indexer.event.take-in.taken` | the indexer's manifest | +| an entry built | `build.ended` | the builder's own | `mesh.stream.mesh-delivery-builder.event.build.ended` | the builder's manifest | +| an entry checked | `checked` | `mesh-delivery-checker`, the checker | `mesh.seat.mesh-delivery-checker.event.checked` | the seat's definition in `mesh-delivery-contracts` | +| an entry wanted | `wanted` | `mesh-wants`, the assigner | `mesh.seat.mesh-wants.event.wanted` | the seat's definition in `mesh-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.`, `.running..`, 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.` | 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..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..event.filling`, `.full`, `.room` | each seat's definition | +| a record pins or frees a revision; a candidate's heads replaced; a record ended | `pinned`, `freed`, `heads-replaced`, `record-ended` | `mesh-delivery`, the gate | `mesh.seat.mesh-delivery.event.` | the seat's definition in `mesh-delivery-contracts` | +| a milestone's ask asked, withdrawn and answered, until G's delivery | `milestone-asked`, `milestone-withdrawn`, `milestone-answered` | `mesh-delivery`, the gate | `mesh.seat.mesh-delivery.event.`, the milestone in the event, on the seat's family stream, apart from each delivery's `transition` | the same | +| a delivery record opened, and a merge named a recovery | `record-opened`, `recovery-merged` | `mesh-delivery`, the gate | `mesh.seat.mesh-delivery.event.` | the same | +| a pipeline, its steps, its waits and a run on request, from G's delivery | `pipeline-started`, `pipeline-ended`, `group-ended`, `run-started`, `step-started`, `step-ended`, `wait-held`, `wait-ended` | `mesh-pipeline-runner`, the runner | `mesh.seat.mesh-pipeline-runner.event....` | the seat's definition in `mesh-delivery-contracts` | +| a pipeline step ended, from G's delivery | `step-ended` | each build seat, `mesh-wants` | `mesh.seat..event.step-ended.`, the node that ran it | each seat's definition | +| a registration changed; a package published, from G's delivery | `registration-changed`; `package-published` | `mesh-catalog`, the indexer; `mesh-builds`, the builder | `mesh.seat.mesh-catalog.event.registration-changed`; `mesh.seat.mesh-builds.event.package-published` | the seats' definitions in `mesh-delivery-contracts` | + +§261 The events, their fields, their subjects and which are a seat's are this design's choices: a seat's event where +other parts follow the step through the seat, a holder's own event where only the delivery record hears it, so that +nothing reads another module's bus state (ADR 0596). The builder's waits go on its own stream because the builder +holds no seat of its own; the watchman and the gate follow them there. How it is checked: each seat definition's +conformance fixtures name the subject of every event it gains, and a case of the holder's whole-module test matches an +event it publishes against them, as for every seat (design 26); the gate's whole-module test hears each row through +its durable consumer, with exactly the fields this section gives it; a `running` event published by one node's account +on another node's subject is refused by the bus. + +### Their tools + +| Line | The assigner | The indexer | +|---|---|---| +| read everything it holds | `assigner_revision` (one assignment graph revision whole, with the revisions of its inputs), `assigner_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) | +| 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` | + +§262 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 +list again, the view is read and steered by the two tools mesh-sdk's `go/views` already serves every part that takes a +first view: `_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 `_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 +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. + +§263 **How it is checked.** Unit (assigner): a revision of the assignment graph computed again from its named inputs +equals the one kept; a fixture change with a new fingerprint and an empty difference is refused, naming its module; +one revision of about 120 modules on four nodes stays under the bus's value limit; of the view the assigner reads only +the catalog half. Unit (indexer): a catalog graph revision holds one entry per module of its source revision. Whole +(indexer): a source revision taken in gives one catalog graph revision kept as objects in an `objects` section in the +old form within the cap its manifest declares; the manifest validator refuses the indexer's or the assigner's manifest +that declares them in the new form. Whole (indexer, assigner): a revision a delivery record pins is not removed; one +two records pin stays until both free it; one neither pinned nor current is removed; a `freed` said while the part +was stopped is applied after its restart; a candidate's graphs are dropped on `heads-replaced`; a store past 80 % says +`filling` and raises `store-filling`, and a full one says `full` and refuses its next revision naming itself; for a +candidate's heads both `revision` verbs answer, the assigner's half named by its own revision and naming its inputs; a +placement change with no merge, and a `capabilities-changed`, each give a new assignment half on the same catalog half, +whose difference moves only the module concerned, and a part takes that pair as its view; after its first view a part +acts on a seat event without asking a verb again; a running part does not act on a candidate's view; a pull request +that adds a seat and a module using it is validated by the indexer's candidate pass and checked by the checker with +the same definitions; the tools of the table answer and the drop tools write the hand-act log. Whole (assigner): a +pull request's graph leaves every node's want unchanged; a placement-only revision moves the want of the module it +places; the builder and the grants part read their entries only through the seat `mesh-wants`'s verbs and events, and +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' +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.`, the forge bridge's read of the gate's `merges` and `owed`, +the checker's read of the gate's `source` and `turns`, the forge module's watch of the checker's `owed` (its `mesh/check` +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: the acting parts + +### An acting part's new version acts first, a wait with a bound + +*ADR 0656, which supersedes ADR 0646; ADR 0603 §1 to §4, §8, §11, ADR 0614 §1, §3, §6, ADR 0633 +§1, ADR 0539 §7, ADR 0584 §1, §2, ADR 0564 §2.* + +§264 From research 085's milestone. A seat's definition may carry a rule, the step its holder acts in and the modules it +acts on, and a holder of such a seat is an **acting part** (ADR 0656): the indexer taking in and validating, the +checker checking, the build modules building, the node-engine composing, the grants part granting, the assigner +placing. *What ADR 0656 leaves to this design*, above, gives the rule's fields. Adding one needs its manifest and +its seat's rule, and no code elsewhere: the indexer's map from language to build module and the checker's own module +names go, since every new acting part needed code changes elsewhere (research 085, Findings 2). + +- §265 **The rule becomes edges between versions.** In the assignment graph the assigner gives an edge from the acting + part's version to each version its rule names, and no part names another module in its code to order by (ADR 0656). +- §266 **Within a revision the new version acts first, a wait with a bound.** The entries an acting part acts on wait for + its new version in its own step, with the bound its rule's `bound` gives (ADR 0656), the part's own as ADR 0603 §8 + has every wait. A bound's clock starts when the new version's build is done, not when the wait begins, so a slow + build of the acting part is the build's own wait and not counted twice. When a rule names none, the step's default holds: 60 minutes for building (a build module's own + build and its spread to a majority of build nodes), 30 for composing (a node-engine's apply on one node), 10 for granting and placing (a write of one part), and the first tier's 20 for checking; from G's delivery 30 for the runner's `pipeline`, whose wait ends when the new runner runs healthy, one module's apply on one node as composing's is (the design's choice under ADR 0666 §19, 2026-11-10). A module changed with + its build module is no longer built with the running recipe and again later, and a build module's edge, a trigger no + want waited on, becomes this wait (ADR 0656, which changes ADR 0603 §1, §3 and ADR 0614 §1, §6). +- §267 **A build module's wait ends on the agreed toolchain.** For building, an entry waits until the agreed toolchain of + its language (ADR 0584 §1) names the new build module, never merely until the new build module runs on one node: a + fingerprint names the agreed toolchain (ADR 0603 §3), so only then is the module built once, by the new one. A build + node still on the old build module builds nothing of that language until it reports the agreed one (ADR 0584 §2). + Every other step's wait ends when the acting part's new version runs healthy, as the node-engine seat's `running` + event says. +- §268 **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 + the wants, holds a node's other wants until the node-engine seat's `running..` 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 + 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, + so a node asleep raises nothing while away. +- §269 **A failed or late new version holds its modules, and a condition names it.** When the new version fails, or its + wait passes its bound, the entries waiting for it stay held, the modules stay on their running builds, and the + watchman writes the finding `acting-part-late` naming the acting part, its step and since when, and the condition + keeper raises it (ADR 0564 §2). The holder says `wait-held` at the start of the wait, carrying its bound, and the + watchman times it: a holder stopped in the middle of a wait still has its wait timed, so a stopped holder hides + nothing. At its own start the watchman reads the open waits from each holder's read tool, as it seeds + `take-in-waits` from `indexer_pending`, so a wait said while it was down is timed too. An entry moves on only once the new + version runs, or its holder's release tool releases it; either way the holder says `wait-ended`, and the finding and + the condition clear. The operator sees each stuck acting part as one condition. Going on with the running version + instead would build or check a change with a part it replaced, the cause of the failures of research 085, Findings + 4; stopping the whole delivery would hold modules the failed part does not act on (the operator, 2026-11-06 17:0x). +- §270 **A wait holds only within its step, and skips the holder's own inputs** (ADR 0656). An entry waits only for its + own step's holders, so two acting parts that act on each other in different steps (the indexer taking in the + checker, the checker checking the indexer) form no cycle. Within a step a holder's own change is its first act, and + what its new version is built from or needs (a base, a package, a provider) is acted on by its running version, + never waited for: the running build module builds the shared contracts and the registry holder, then the new build + module builds the rest, so ADR 0614 §6's cycle through them stays allowed, now for that reason. +- §271 **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 the reply's object in the build module's sent store `_sent-objects` (*Any size*), never in + a value, since an artifact is over the bus's value limit; the build module is no foundation part, so it keeps no + old `objects` section, its kept data being in ADR 0595's templates (ADR 0666 §4), and the build itself stays among + its kept builds on its node (the design's choice, 2026-11-10, correcting the old form this line named); 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. +- §272 **The check refuses a cycle among the waits within one step** (ADR 0656, which changes ADR 0603 §2's refusal of a + cycle), counted beside the edges ADR 0614 §3 and §6 list; a cycle through an acting part's edges across two steps, or + through a holder's own inputs, is none. +- §273 **The indexer's own steps have no wait, and a newer indexer is reached.** Taking in and validating stay as *Taken in + by the indexer it names* has them: a revision is taken in only by the indexer it names, which judges its own change + at its start, and no build waits on which indexer judged it (ADR 0603 §4, as ADR 0633 §1 changes it). So that the + named indexer can start at all, the running indexer makes, for a merged revision naming a newer indexer, a catalog + graph revision that is the previous one with only the indexer's entry replaced by the one its manifest at the merge + gives, and nothing else of the revision, so no other want moves before the named indexer takes the revision in; the assigner wants it and the grants part grants it like any module, and once it runs it takes the revision + in whole. Without that, a revision waiting for its indexer would wait for good. +- §274 **A rule with no holder is no silent pass.** An entry a rule matches with no holder for its step is held by the + assigner, naming the missing holder as the hold's reason, and the check fails naming it. +- §275 **An acting rule grants nothing.** A holder's bus grants come from the grants part as today (ADR 0539 §7). An + acting rule changes what a part acts on across every module it matches, so the operator's Approve ask of a change + names any acting rule it adds, and any it widens: a `step`, an `on` or a longer `bound` that now matches more + modules or holds them longer is named like an added rule. From G's delivery there is no Approve ask per merge, and + the pipeline's end names it in `widens` instead, refusing nothing (ADR 0666 §23). +- §276 **Each step's wait is its own part's, read and released by its own tools.** The part that does a step holds its + wait, so each wait has one owner that already holds that step's state, and says `wait-held` and `wait-ended` (*What + each step says*) with the step, the acting part, its version, the entry and since when: + + | Step | Holder | Reads its waits | Releases one | + |---|---|---|---| + | building | the builder, on its build key | `builder_waits` | `builder_release` (build the entry with the running build module), beside `builder_build_again` (ADR 0603 §11) | + | placing and wanting | the assigner, on its hold | `assigner_waits` | `assigner_release` (ADR 0603 §11) | + | granting | the grants part | `grants_waits` | `grants_release` | + | composing | the assigner, holding a node's other wants until its new node-engine runs there (*Composing waits per node*) | `assigner_waits` | `assigner_release` | + | checking | the check's first tier | `checker_first_tier` | its ask-again (*The check on the change's own acting parts*) | + + Each release writes the hand-act log of the seat `mesh-hand-acts`, with who released and why. +- §277 **How it is checked.** Whole (assigner): a fixture seat declaring a rule, with a fixture holder, gets its edges with + no code change elsewhere. Whole (assigner, builder, three build nodes): a group changing the shared contracts and the + build module that builds them, the new build module updated on the first build node first, builds no module with the + new build module while one node of three runs it, builds the contracts with the running build module, and once the + second node reports it and the agreed toolchain names it, builds each other module once, by the new one; the third + node builds nothing of the language until it reports the agreed version. Whole (assigner, builder, grants part, + watchman): a fixture acting part whose new version fails, and one whose wait passes its bound, each leave their + modules on their running builds, say `wait-held` at the wait's start with its bound, and raise `acting-part-late` + naming it; a holder stopped in the middle of a wait still raises it, and a watchman restarted mid-wait reads the + wait from the holder's read tool and times it; a bound counts from the new version's build done; each holder's release tool + moves a held entry on, says `wait-ended` and writes the hand-act log, and the condition clears; a wait ends on its + own when the new version runs; each holder's read tool lists its waits with step, acting part, version and since + when; a rule's `bound` overrides the step's default. Whole (assigner, node-engine): during a node-engine change with + one node away, the present nodes take their new node-engine and then their other wants, nothing waits on the node + away and no condition is raised for it; a node asleep since before milestone G wakes, takes its new node-engine + first, then the rest. Whole (indexer, assigner): a merged revision naming a newer indexer gives a catalog graph + revision that is the previous one with only the indexer's entry replaced, and no other want moves; the new indexer is wanted and granted, starts, + and takes the revision in, with no build waiting on which indexer judged it. Whole (assigner): a module with no + holder for its step is held by name, and the check of a change bringing it fails naming the missing holder. Unit + (graph): an acting part acting on itself, two acting parts acting on each other in different steps, and a cycle + through a build module's edge each pass the cycle check, each new version first in its own step; a cycle among + waits within one step is refused. Unit (assigner): the Approve ask of a change that adds an acting rule, and of one + that widens one, names the rule. Live: a search of the delivery parts' code finds no other module's name. + +## Nothing merges into a repository under check: removed + +§278 **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 no merge waits on a check, and none on an Approve either (ADR 0666 §10): the checker is gone, and the +pipeline runs on the landed commit (*Pipelines per module*). **Its record is accepted:** ADR 0661 ends ADR 0548 §2 +to §4, §9 and §10 and ADR 0551 and changes ADR 0534 §4's judgement of `mesh/check` by the merge; until G's delivery the +rule below holds as those records have it. ADR 0662 is withdrawn; G builds ADR 0661 §1, §2 and §6, and ADR 0666 §10 +changes its §3 to §5 (the merge on the Approve alone), which G therefore builds for no merge. Beside it, ADR 0663 (accepted: the indexer answers `revision` in its own runtime to +exactly the parts that invoke it, the tool runner among them) holds the tool +runner's first view of the catalog half (*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. + +## Checks: the check on the change's own acting parts + +### The check on the change's own acting parts + +*ADR 0656, which supersedes ADR 0648, ADR 0644; ADR 0448 §2, §4, ADR 0391 §1, ADR 0603 §10, ADR 0614 §7, ADR 0633 +§6, ADR 0636 §4, ADR 0639 §5, ADR 0498 §1.* + +§279 From research 085's milestone. ADR 0603 §10 and ADR 0614 §7 let a check pass while the part that would build or +check the change never ran: 7 of 24 failures since 2026-11-01 (research 085, Findings 4). The acting parts a change +alters, and the checking program, the rules every check applies, are built from the change's heads and check it; the +running versions never check in their place, and a check fails, naming the part, when one cannot be built or run +(ADR 0656). + +- §280 **Two tiers on the change's assignment graph.** The first tier builds, at the change's heads, only the acting parts + whose fingerprint in the change's assignment graph differs from the running one and which are to act on a module + the check acts on; a change to an ordinary module asks no first-tier build, since building every acting part for + every check would make an ordinary change pay for builds that change nothing. The second tier runs the check's + levels with those programs and with the revision view of the change's heads (ADR 0656). This keeps ADR 0603 §10's + building of changed build modules first and widens it to every acting part. +- §281 **The judging rules are a checking program built from the change.** Every check builds its checking program from + the change's heads and runs it with the revision view as its input; when it cannot be built or run, the check + fails naming it, and the running checker's own rules never judge in its place (ADR 0656). It is built once per + fingerprint and reused (ADR 0498 §1): checks whose heads leave the checking program unchanged ask one build between + them. +- §282 **Every program built from a change runs only in the build seat's sandbox.** The acting parts the first tier builds + and the checking program run in the run step, with no network (ADR 0448 §2) and no bus account, the logins staying + outside (ADR 0448 §4), through the seat `node-build-go`'s ask `run` (*What ADR 0656 leaves to this design*), as + the validator, the composer and the Go build module already run; a change not yet merged is not trusted. The running + checker alone asks, reads the program's verdict, records it and publishes it. +- §283 **A first tier that cannot build an acting part fails the check, naming it.** The verdict never passes on the + running version's word: a module whose changed build module the check cannot run is no longer composed from its + manifest (ADR 0656, which changes ADR 0603 §10 and ADR 0614 §7), and ADR 0614 §7's reason, a changed build module + invoking a verb no running holder serves, is one reason the first tier cannot run an acting part: the check fails + naming the build module and the verb. An acting part not built within the first tier's bound of 20 minutes is one + it cannot build, and the verdict says `waiting for a build node` or `did not build`. +- §284 **A change to the checking program is named, by a part it did not build.** Every change of the checking program's + fingerprint is named in the verdict and the Approve ask, whatever changed: a helper a rule calls changes what the rule + judges as much as the rule does, and only the fingerprint covers every input. The rule-name comparison is its detail: + each checking program declares its rules by name in its source. The running checker, outside the sandbox, reads the rule names from the + trunk's sources and from the heads' and compares them; every rule removed, added or altered (its source changed) is + named in the verdict and in the operator's Approve ask. The program built from the change is never asked which rules + it has, so a program that drops a rule and hides it is still named. +- §285 **ADR 0633 §6 stays, beside the change's own validator.** Whether the running parts can take the change in is + still checked with the trunk's manifest validator, built from the trunk (ADR 0633 §6); the change's own validator, + built in the first tier, judges the change's manifests besides (ADR 0656). A change fails if either refuses it. +- §286 **The asking and recording are covered by the checker's whole-module test**, which starts the changed checker on a + real bus and asks one check of a fixture group end to end (ADR 0391 §1). +- §287 **One seat list for both readers of a change's heads.** Inside every check, a lone pull request's as a group of one, + the checking program built from the heads makes one seat list from them, and the checker hands it to the manifest + validator and the composer (ADR 0644, ADR 0636 §4 with its insight of 2026-11-06); the running checker reads no + definition of the heads itself (*The bootstrap delivery, and the one milestone after it*). +- §288 **Its tools.** The checker's read of a check names the checking program's build that judged it, its fingerprint and + the heads it was built from, and the rules named changed; `checker_first_tier` lists a check's first-tier builds, + each with its acting part, its fingerprint and its outcome (`built`, `waiting for a build node`, `did not build`), + and asks one of them again. Asking a whole check again stays the checker's existing ask-again. +- §289 **What it costs.** A check of a change to an acting part costs one build per changed acting part, within the + checker's step bound (ADR 0639 §5); an ordinary change costs nothing more; a checking program costs one build per + fingerprint, shared by every check that uses it. +- §290 **How it is checked.** In the checker's whole-module integration test: a fixture change whose acting part does not + build, and one whose checking program does not run, each fail their check, naming the part; a checking program that + builds but does not run fails naming it; a first-tier ask no build node takes within the bound says `waiting for a + build node`, and one that fails says `did not build`; a change that breaks a rule of the checking program fails its + own check; a change that removes a rule passes, and its verdict and the ask name the removal, also when the + program built from the change hides it; a change to a helper a rule calls, with no rule renamed, names the checking + program's new fingerprint in the verdict and the ask; a program that rewrites its own binary while it runs changes + no kept build; a fixture checking program that tries to reach the bus or the network + fails; a `run` ask published from an account other than the checker's is refused by the bus, and the checker's + account cannot read another account's step key; a fixture build module invoking a verb no running holder serves + fails naming it and the verb; a change to an ordinary module asks no first-tier build; two ordinary checks with the + same checking program ask one build of it; a group that changes the assigner's placing is checked with its own + assigner; a fixture indexer change whose manifest the trunk's validator refuses fails its check, even when its own + validator passes it; a fixture group whose heads add a seat has that seat in the list both the validator and the + composer receive; the check's read names the checking program's build, heads and changed rules; `checker_first_tier` + lists a check's first-tier builds and asks one again; the changed checker asks one check of a fixture group end to + end. Live: the registry group passes its one check with its own checker, validator and composer. + +## After the merge, from milestone G + +- §291 **From milestone G's delivery, per watched branch.** The gate writes one source revision per watched branch, + `source.`, as a commit or a group lands there; the pipeline runs on each revision the indexer takes in, and + the wants follow a revision whose `required` steps passed, on the branch each placement chose (ADR 0666 §6, §9). +- §292 **From research 085's milestone, the wants follow the trunk's assignment graph.** A merge taken in makes a + catalog graph revision and then an assignment graph revision; the assigner writes each want from that revision, + its rules unchanged (ADR 0656), and each acting part's new version acts first in its own step (ADR 0656; *Two + graphs, one source of truth*, above). + +## Taken in by the indexer it names, from milestone G's delivery + +- §293 **From milestone G's delivery** (ADR 0666 §6, §13, which change ADR 0633 §1 and §3 to §6): before any take-in, on every + watched branch, the running indexer validates the revision with the manifest validator built from its heads, in the + sandbox, and a revision it refuses stays pending, as the bullets above have it, with the way back a revert; a pending + revision holds only its own watched branch; a group's member reaches it by landing, and the group ends when the gate's + group verb says every member has; `bridge_group_end_again` reads that verb; and the check's refusal below goes with the + check (*Watched branches and the catalog graph per branch*, *Groups*). + +## A backup before the apply: kept data on the bus + +### A module's kept data on the bus, backed up and restored with its delivery + +*ADR 0404, ADR 0235, ADR 0233, ADR 0539 §16, ADR 0595, ADR 0619 §2, ADR 0633 §1, §5, ADR 0363 §2; from research +085's milestone, this design's choice under ADR 0656.* + +§294 **ADR 0404's backup does not cover a module's kept data on the bus.** It backs up the items a moved module keeps on +its own node (ADR 0404 §2, ADR 0233), and the bus's streams are dumped whole by the bus module on its own rhythm +(ADR 0235), not per module and not before a delivery. A key-value state, a stream or an object store a module keeps on +the bus (ADR 0595, ADR 0619 §2), and its durable consumers' positions on the streams it reads, therefore have no +restore point taken before its module moves. That is a gap of the delivery system, and milestone G builds it, because +a revert of milestone G is the first change that needs it. It is built as the delivery system's capability for every +later change of a kept data's form, not as a case of this milestone. + +- §295 **Its form is declared.** Each kept data a manifest declares names a `form`, a number its holder raises whenever it + changes how it writes that data, or stops declaring it; a declaration naming none reads as form 0. The declaration + alone cannot tell a changed layout of the same bucket, so the holder says it. Only kept data whose `form` changes is + backed up and restored, so a part's other kept data, and every decision it holds, is never set back. +- §296 **It is backed up before the module moves.** When a want moves a module whose new manifest declares a kept data at + another `form` than the running one, or no longer declares it, the node agent applying it first asks the seat + `node-backup` of the node holding `mesh-broker` for a restore point of that kept data, and waits for its event + `ended`, as for any backup before the apply. The bus module's account takes it, as it takes the bus's snapshots + (ADR 0235 §5). A restore point is keyed by the module, the kept data, its form and the fingerprint it was taken + before, and it holds the kept data whole, the position of each durable consumer the module reads with, and the + catch-up tool the newer manifest declares beside that kept data. A failed + backup holds that module as any failed backup does. +- §297 **A revert restores it before the reverted build starts.** When a want takes a module back across a change of a + kept data's `form`, the node agent applying it asks that seat's verb `restore` for the restore point of that module, + kept data and form, waits for the seat's event `restored`, and only then starts the reverted build. The node agent + that restores is the one running when the revert starts. As every restore is, it is brought back beside the live data + and never over it: the live kept data of the newer form is set aside under a name of its own, and only the operator + removes it, so nothing written since is destroyed. The consumer's position is set back with it, so the reverted + build hears everything since as after any restart. +- §298 **The order of a delivery that crosses a form change** is the module graph's (*Order without a person*), with three + edges the assigner, which writes every want, keeps: + - the new versions of the `node-backup` holder and of the bus module run before any module whose kept data's form + changes is moved, since the restore point needs both; + - at a revert, a node's node-engine goes back last on that node, after every module it restores there has said + `restored` and runs, since the node-engine of before may not know how to restore; + - the reverted assigner and gate are wanted only once the reverted indexer has taken in the trunk's head, as its + `take-in.taken` naming the current source revision says (ADR 0633 §1), since the assigner of before computes the + wants from the indexer's `modules` and would otherwise write the fingerprints of the restore point. Until then the + running assigner writes no want, and every module keeps the fingerprint it runs. +- §299 **The restored part catches up forward, with the code it already has.** Read on main, mesh-delivery at 2d201f78 + and mesh-catalog at 1d07778c: + - **The indexer** (mesh-delivery, `modules/mesh-delivery-indexer`): its durable consumer `_` on the stream + `forge` redelivers every message since the restored position, and `handle` takes each + merge through `Indexer.Arrive` into `pending` and then into `modules` (`applyMerged`); `applySource` takes the + gate's `source.main` in, and `ApplySource` leaves a revision older than the latest it has seen. **The stream + `forge` keeps 7 days**: the forge bridge's manifest declares no age, and a stream's default is 7 days, at most 30 + (mesh-sdk `go/catalogue` `StreamDefaultDays`, `StreamMostDays`), so it does not cover the records' 90 days. A + merge older than the stream's first message is never redelivered, and the code then leaves that repository's + modules at the restore point's fingerprints. So the restore runs one forward step: once the reverted indexer + runs, the node agent that restored it calls its tool `indexer_take_in` with each repository the gate's source names + (`NewTakeInRepository`, which takes in the head the source names for a repository). The catch-up tool is declared + by the newer build's manifest, beside the kept data whose form it changes, and recorded in the restore point when + the backup is taken; the node agent takes it from the restore point, never from the manifest being applied, since + at a revert that is the manifest from before the change, which names none. So the delivery system names no + module's tool. + - **The assigner** (mesh-delivery, `modules/mesh-delivery-assigner`): it keeps nothing restored. Its pass + (`passer.wants`) writes, from what the world holds now, each node's want by the six rules from the indexer's + newest fingerprint at the trunk, and only where the value differs; so once the indexer has caught up it writes + the trunk's wants, and nothing older. + - **The gate** (mesh-catalog, `modules/mesh-delivery-gate`): `Holder.Load` reads the restored deliveries and groups + back; `readOnStart` then reads what happened while it was away: `wantForge` reads the forge's open pull requests + at the next look, `hearAsks` reads the teller's answer to every ask it still holds as pending, and + `SourceCatchUp` brings the newest merge of each repository into `source.main`, never moving a repository back. An + ask the gate of milestone G raised after the restore point is not among the pending ones, so its answer is not read + and the operator is asked again. Whether the first look clears a merge kept in the restored `merges` that the forge + merged since was not read in the code; the catch-up test below proves it with the real builds. +- §300 **A missing restore point holds the revert, naming it.** When the restore point a revert needs does not exist, or + `restored` does not come, the node agent applies nothing of that module, keeps what runs, and writes the have phase + `held` with the reason `restore point missing` and the module, kept data and form it names; the assigner asks the + operator (hold, or start the reverted build on the live data as it is), raises the condition naming them, and on + the answer writes the node's want again naming it (ADR 0539 §16). +- §301 **What the operator is told.** A revert across a change of a kept data's form puts that kept data back to the + moment before the change moved it: the deliveries made since stay delivered, but what the part wrote there since + (for milestone G, its delivery records and its graph revisions) is set aside and not read again; an Approve asked + and answered since is asked again, and one the gate asked before still reads its answer. The revert's Approve ask + says this in those words, naming each kept data restored. +- §302 **Its tools.** The seat `node-backup`'s `backed-up` lists each module's restore points of its bus data, with the + kept data, the form and the fingerprint each was taken before, and the data set aside at each restore, with its + size; `restore` restores one; `discard-aside` removes data set aside by a restore, only on the operator's call, and + writes the act, who and why in the hand-act log of the seat `mesh-hand-acts`. `backed-up` and `restore` exist on + the seat today and gain the module's kept data on the bus as an item; `discard-aside` is new. +- §303 **How it is checked.** Whole (node-engine, backup holder, bus module): a want moving a module across a `form` + change, and one moving a module whose kept data declares no `form` to one that does, each take a restore point + first, keyed by module, kept data, form and fingerprint; a want taking it back restores it beside the live data and + the consumer's position before the reverted build starts, and the data set aside is listed with its size and + removed only by `discard-aside`, which writes the hand-act log; a revert of a group holding the node-engine and a + module whose form changes restores the module before the node-engine goes back; a revert whose restore point is + missing is held, naming it, and moves on only on the operator's answer. The catch-up is proved with the real builds + of the indexer, the assigner and the gate from before milestone G, never fixtures (acceptance test 36). + +## The verbs milestone G adds + +§304 From research 085's milestone the seat gains: + +| Verb or event | Answers or does | +|---|---| +| `groups` with a group | that group's members, which the forge bridge reads in place of the gate's `merges` state (ADR 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*) | +| `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..`, 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` | until G's delivery: 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.`, the milestone in the 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`. G's delivery ends the ask and its three events with the Approve per merge (ADR 0666 §10) | +| `record-opened` | a delivery record opened, which the watchman times for `record-open` | +| `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*) | + +§305 From milestone G's delivery the seat's `table`, `recheck` and `close` go with the merge states (*The state table*), +the milestone ask and its three events with the Approve per merge, and it gains (ADR 0666 §6, §26): + +| Verb or event | Answers or does | +|---|---| +| `source` with a watched branch | that branch's source revision; the indexer and the node-engine's catch-up read it, never the gate's state | +| `source-moved` | a new source revision of a watched branch | +| `recovery` | marks a merge its author names a recovery (the commit and why), its record marked `recovery` with the caller the runtime proves | +| `record-opened`, `recovery-merged` | a delivery record opened; a merge named a recovery, which the teller passes on to every channel | + +§306 **The seat `mesh-pipeline-runner`**, from milestone G's delivery, defined in `mesh-delivery-contracts` with the callers +of each verb (ADR 0666 §7, §20, §25): + +| Verb | Answers or does | Callers | +|---|---|---| +| `run` | the run on request of one or more members, each a module at a named commit; delivers nothing | the sessions (the agents' bus identities the tool runner proves) and the operator, nothing else | +| `start` | a delivering pipeline for a watched branch's head, by hand | the operator, the healers | +| `show`, `list`, `stands`, `why-carried`, `kept` | one pipeline whole with its step log; the pipelines and runs of a module, a branch or a commit; what stands still; where a result was carried from; the kept results | any person, an agent session, the healers | +| `review` | a code review's result for a commit and fingerprint | the reviewers the definition names; refused from the commit's author | +| `rerun`, `accept`, `cancel`, `ask-again` | one step again; a failed `optional` step accepted with why; a pipeline ended, its asks dropped; a declined `approval` asked again | the operator, the healers (`accept` and `ask-again` the operator) | + +§307 **The seat `mesh-catalog`** gains, from milestone G's delivery, `register`, `policy`, `watch`, `unwatch` and +`registrations`, and the event `registration-changed` (*A module's registration*), and `catalog-revision` names its +watched branch in its subject. **The build seats** gain the verb +`steps` and the accepted kind `step`, and **the seat `mesh-wants`** the kind `step`, each saying `step-ended`. **The +seat `mesh-builds`**, new and held once for the mesh, says `package-published` (*A publish rebuilds*). + +§308 **The seats `mesh-catalog` and `mesh-wants`** gain, from research 085's milestone, `revision` on each (the two halves +of the revision view, ADR 0656), and `entry` and `difference` on `mesh-wants` (ADR 0656), with the events of *What +each step says*. + +§309 **The seat `node-engine`**'s event `running..` carries, from research 085's milestone, the module, its +fingerprint and the digest of its build's manifest, so the node-engine of another node and the grants part decide a +seat's pass from it (ADR 0660 §2; *Who holds a seat is applied by one rule*). No verb is added. + +§310 **The seat `git`.** The seat `git` (design 26, *The git seat*), of the Delivery domain, defined in +`mesh-delivery-contracts`, holds no verb today, and the delivery parts and the gate reach the forge by naming the forge +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, and `merging` while the forge merges it; an unknown one answers the error kind `not-found` | the forge bridge (a merge the gate did not make; `gitea_api`), the gate (a stalled line's author) | +| `branch` | from milestone G's delivery: a branch's head, and whether a protection rule refuses a direct push and admits only merges | the indexer (`register`, `watch`), the forge bridge (a watched branch's head) | +| `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` | until G's delivery: 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). From G's delivery: merges with the forge tools' account (ADR 0398 §2) at the head the caller names, judging that it is still the pull request's head and that the branch's protection refuses a direct push, the protection read again on every `branch-moved`, and refusing a head when any run at its build-input fingerprint failed a `required` step, judged from its own state `failed-steps` heard from the runner's `step-ended`, never by a call; a head with no run yet or a passed one merges, it never waits for a run and never asks an Approve (ADR 0666 §11). A pull request already merged at that head is answered performed | until G's delivery the forge bridge alone (`gitea_merge_pull_request`); from it any session the tool runner proves, and the operator | + +| 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`) | +| `branch-moved` | from milestone G's delivery: a branch's new head, by a merge or an admitted push, from the forge's push webhook | the forge bridge | + +§311 Each is said on `mesh.seat.git.event.`, declared in the seat's definition, and heard through the hearer's +`consumes` of the seat. + +- §312 **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). +- §313 **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. From G's delivery the callers per verb are the seat definition's field `callers`, + the grants part's one source (ADR 0666 §20): `status`, `comment`, `view` and `note` the forge bridge alone, + `merge-pull` the persons and agent sessions the tool runner proves, the reads the parts that declare them. 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. +- §314 **`merge-pull` judges no check, and from G's delivery no Approve, only the runs at the head's fingerprint.** 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*). From G's delivery it judges no Approve either, its caller + is any session the tool runner proves, and it refuses a head when any run at its fingerprint failed a `required` step, + never waiting for one (ADR 0666 §11; *Approval is a step, and a session merges a pull request*). The reads the + gate would have needed to merge (the forge's word for a conflict, the base's required statuses, the merging account's + write access) are not added: no part of the mesh but `merge-pull` merges, and it answers git's own refusal of a merge + as refused. +- §315 **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*). +- §316 **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 + `_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. +- §317 **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. + +§318 **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 +with no text match (research 085, Findings 7). The issue tracker gains link kinds from an issue to the decision and to the research effort +it carries, made by a tool call and never by text, as ADR 0493 §4 has every link made; the knowledge base gains a +typed link from a decision to the milestone of the issue tracker that builds it, made by a tool call, which joins the +link kinds of its link-fits rule (design 55), beside the `became` link a research effort gets at its graduation +(playbook 02). How it is checked: whole (gate), one ask per milestone, withdrawn by a new head; +a waiter on one member's pull request wakes only on that member's transition. Whole (issue tracker, knowledge base): +an issue linked to a decision and to a research effort reads both back; a decision linked to its milestone reads it +back. Live: research 085's milestone's record reads back research 085 to its decisions, its milestone, its issues and +its pull requests with no text match. + +§319 **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. + +## What retires at milestone G + +- §320 At research 085's milestone's delivery: the indexer's map from language to build module, and the checker's own + module names and its cases for a change to the manifest validator and to the Go build module (ADR 0656); a build + module's edge as a trigger, with the extra build per recipe change (ADR 0603 §3, as ADR 0656 changes it); composing + from manifests a module whose changed build module the check cannot run (ADR 0603 §10 and ADR 0614 §7, as ADR 0656 + changes them); the module graph's one key per module with five past values 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 + list compiled into a part, and every read of another module's bus state the revision view replaces (ADR 0656); the + 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. +- §321 At milestone G's delivery, from research 086 (ADR 0666, ADR 0667): the checker (`mesh-delivery-checker`), its seat, + its try with `tryevent` and the indexer's try candidates, its kept verdicts and carries (the runner's from then), the + checking program and `mesh/check`, and its buckets and bus account, removed with the gate's forge merge token only + after the first pipeline after G's delivery has delivered a change end to end and on the operator's one word, its + buckets through `drop` after a snapshot whose restore is tested (ADR 0667 §12); the bundle of steps run before a merge; the Approve per + merge, the milestone ask and its three events, and the gate's merges; the gate's merge states, one key per pull request and its verbs `table`, `recheck` and + `close`; the trunk-only want; `source.main`, for one source revision per watched branch; every fixed branch, + repository and module name in code logic; the recovery merge verb this design sketched, never built; and the holders' + trusted `callers` values, for the seat definitions' `callers`. The words **merge check**, **try**, **trunk commit** + and **merge turn** go to *Not:* lines with the as-is update after that delivery, as the glossary's entries say. + +## What milestone G's builders found open, answered by this design (2026-11-10) + +*ADR 0666, ADR 0667, ADR 0668; ADR 0656, ADR 0596, ADR 0595 §4, §9, ADR 0619 §1, §2, ADR 0563, ADR 0564 §2, ADR 0625 +§1, §4, ADR 0635 §4, ADR 0548 §5, ADR 0363 §2; design 27, *Which module answers*. The operator, 2026-11-10: a small +choice within what a record decides is the design's own, written here with its reason and reviewed by the reviewers +by architectural domain.* + +§322 Milestone G's prepare and develop met these questions (issue 1966). Each line is the design's choice, with the +record it follows from, and replaces the builder's own choice where one was made. + +### The runner and its steps + +- §323 **A step's build seat is read from the artifact's language.** The catalog graph entry names each artifact's + `language`, as its manifest's artifact entry says it and as the indexer's language map matches today; the runner + reads it from the catalog half of its revision view and asks lint and the test steps of the build seat whose + definition's acting rule `build` has `on` naming that language. With no such seat, or no holder of it, the pipeline + ends failed, naming the seat (ADR 0666 §18). Why: the language is already in the manifest and the catalog half is + the runner's one view (ADR 0666 §24, ADR 0596). How it is checked: whole (runner), a Go and a TypeScript fixture + module each ask their own build seat, and one with no holder ends failed naming the seat. +- §324 **An acting rule's `on` may name an artifact kind.** Beside `every` and a language, `on` may be `kind: image`, + matched against the manifest's artifact entry's kind; the seat `node-build-image`'s rule says `kind: image`. Why: an + image has no language, and the rule's fields are this design's (*What ADR 0656 leaves to this design*). How it is + checked: a unit row of the definition reader accepts `kind: image` and refuses another kind. +- §325 **An approval never asked ends `not asked`.** When a `required` step failed before the `approval` step was asked, + the `approval` step ends `not asked`, naming the failed step, never as passed; a `rerun` that passes the failed step + asks it then. `not asked` joins the outcomes of *Pipeline steps and the policy*. Why: approval comes last (above), + and every end a step can have is said as itself (ADR 0666 §10). How it is checked: whole (runner), a failed unit + step leaves the approval `not asked`, and its passing rerun asks it. +- §326 **A build seat keeps its `steps` answer.** The build module keeps each artifact's detected steps in its state + `steps`, from the template `state`, one key per artifact and build-input fingerprint, written at the first + detection and replaced by `steps` with `again`; the module deletes a key unread for 30 days at its next detection. + Why: ADR 0666 §25 asks a tool for "the steps detected for an artifact and detect again", which a reply computed + anew each time would not need; a build module is no foundation part, so the template form (ADR 0666 §4). How it is + checked: whole (Go build module), `steps` answers from the key, and `again` replaces it. +- §327 **The step code lives in the domain SDK.** The step run and the fetch-and-release code the three build modules + share move, in this milestone, into a build-step package of `mesh-delivery-sdk`, which the Go, TypeScript and image + build modules import; none keeps a copy. Why: code shared between modules lives in an SDK, and the delivery + domain's shared code is `mesh-delivery-sdk`'s (ADR 0635 §4); the copies were met in develop. How it is checked: a + search of the three build modules finds no fetch, release or step-run function of their own. +- §328 **Lint per language.** Go's lint step is the Go build module's linter with the fixed-names rule; TypeScript's is the + type-check with the fixed-names rule; an image's lint is the fixed-names rule over its build files; + an image has no unit or integration test step, so `steps` answers none for it and the seed has those `bypass` + (*A module's registration*). Why: ADR 0666 §5 has the lint step refuse fixed names in every language, and §7 lets a + build seat answer only the steps an artifact can run. How it is checked: whole (TypeScript and image build modules), + a fixture naming a module in code fails lint. +- §329 **What the fixed-names rule exempts.** It exempts a Go import path, a comment and a test file (`_test.go`, + `*.test.ts`), never a struct tag or any other string of code. Why: none of the three is code logic (ADR 0666 §5), + and a test fixture names modules. How it is checked: unit (lint rule), a name in a comment and in a test file + passes, in a struct tag fails. +- §330 **The runner's own kept data age by its own deletes.** The runner deletes its own `pipelines` keys, `kept` entries + and `step-outputs` objects by the retentions of *The runner's kept data*, at each step's end, for those past their + retention; a foundation part's sent store (`sent-objects`) is aged the same way by its owner at each send. Nothing + waits on a timer, and nothing but the owner deletes. Why: an old section cannot declare an age, and deleting one's + own entries is the owner's act, not the removal of a store ADR 0595 §4 holds to a person's word. How it is checked: + whole (runner), an output 7 days old is gone after the next step's end. +- §331 **The kept event streams' caps.** On the seat `mesh-pipeline-runner`, each kept 90 days: `pipeline-started` 32 MiB, + `pipeline-ended` 128 MiB, `group-ended` 64 MiB, `run-started` 16 MiB, `step-started` and `step-ended` 128 MiB each, + `wait-held` and `wait-ended` 32 MiB each; the seat `git`'s `branch-moved` 64 MiB, 90 days. Why: about 300 pipelines + a day of about 6 steps (*The runner's kept data*) say about 1,800 step events a day of about 0.5 KiB, about 80 MiB in + 90 days, and about 300 pipeline ends of about 4 KiB, about 105 MiB; estimates, read from the fill tools once G runs. + How it is checked: each seat definition's fixtures name each stream's `keep`. +- §332 **A group's end is said under the group.** `group-ended` is said on + `mesh.seat.mesh-pipeline-runner.event.group-ended..`, with no module part, since a group spans + modules. Why: every other runner event names one module (*Health and going back*). How it is checked: the seat's + fixtures. +- §333 **The runner hears the indexer's own event.** The runner's manifest `consumes` the indexer's own event + `take-in.taken` (ADR 0666 §13), which ADR 0596 §1 lets any module subscribe to; the indexer's name stands in that + manifest only, never in the runner's code. Why: ADR 0666 §13, in force, names that event. How it is checked: a search + of the runner's code finds no module name (lint). +- §334 **A publication's pipelines and their key.** `package-published` carries the package's artifact reference + (`:`, from the catalog entry), its version and digest, the watched branch and the source revision + its build was made from. The runner reads the dependents from that revision's catalog graph, the artifacts with a + kind-1 edge to the package, and starts each one's pipeline keyed by that branch, that source revision and the + dependent module, the version in the pipeline's state; a `take-in.taken` of the same revision and module is the + same pipeline (*A second start writes nothing*). Why: a pipeline's key is branch, source revision and module (above), + and the publication is made from a revision of a watched branch (ADR 0666 §15). How it is checked: whole (builder, + runner), a publish starts one pipeline per dependent, keyed by the publishing revision. +- §335 **What the teller says of a widening.** Each entry of `widens` names what widens (`acting-rule`, `grant`, + `credential` or `serving-part`), its name, the module and the commit. The teller says one message per + `pipeline-ended` that carries any, on every channel, once per module, watched branch and commit. Why: ADR 0666 §23 + says a widening in the pipeline's end, and the teller passes it on (*Who may say what*). How it is checked: whole + (teller), a `pipeline-ended` said twice with the same `widens` gives one message. + +### Callers + +- §336 **The forms of `callers`.** A verb's or an accepted kind's `callers` is a list whose entries are: a holder role (a + seat's name), a module, `operator`, `healers`, `persons` (any person the tool runner proves), `sessions` (an agent + session the tool runner proves), `invokers` (every module whose manifest declares the verb in `invokes`), and + `holder:@same-node` (the holder of that seat on the node of the verb's holder). A definition whose `callers` + today is text is given a list in this milestone: "any caller whose role grants it" becomes `invokers`, "a person" + `persons`, and every other text the names the design gives that verb. Why: ADR 0666 §20 makes the definition the + grants part's one source of caller limits, in a form it reads. How it is checked: unit (definition reader), each + form accepted and any other entry refused; the grants part's table test grants each form. +- §337 **The bus module's restore points.** The verbs the holder of `node-backup` on the bus module's node calls to take + and restore a module's kept data on the bus name `holder:node-backup@same-node`. Why: only that holder takes them + (*A backup before the apply: kept data on the bus*). How it is checked: a call from another node's `node-backup` + holder is refused by the bus. +- §338 **Callers on accepted kinds.** An accepted kind of a work queue carries `callers` as a verb does, and the grants part + grants publish on its subject to them alone: the build seats' `step` the runner; `run` the runner, the indexer and + the assigner, and the checker until it goes; `mesh-wants`'s `step` the runner. Why: a step's result is taken only + from its seat holder (ADR 0666 §21), so the ask side is limited too. How it is checked: a `step` published by another + account is refused by the bus. +- §339 **The contract generator reads `callers` and makes nothing of it.** The generated contracts carry no caller check; + the grants part reads `callers` from the definition, and the generator refuses a definition whose entry is no form + above. Why: one source of caller limits (ADR 0666 §20). How it is checked: the generator's test refuses an unknown + entry. +- §340 **The reader release first.** mesh-sdk's seat-definition reader released before G's check reads `callers` as text + or as a list; G's own reader refuses text. Why: readers first (ADR 0667 §4), and every definition is a list from G. + How it is checked: unit rows for both forms in the release, and for the refusal in G. +- §341 **TypeScript contracts as JavaScript.** The generator emits each seat's TypeScript contract as `index.js` with its + `index.d.ts`, so a TypeScript module imports it with no build step of its own. Why: a seat's contract is generated + from its definition (ADR 0625 §1), and a gap of the build system is built in it. How it is checked: a TypeScript + module builds against a generated contract with no `tsc` of the contract. + +### The catalog, the builder and the assigner + +- §342 **A module not watched on a branch.** A watched branch's catalog graph takes each module not watched on that branch + from the registration's first watched branch. `register` names a module's watched branches; with none named it takes + the repository's default branch, read through the seat `git`. Why: a placement's default is the registration's first + branch (ADR 0666 §6). How it is checked: whole (indexer), a `beta` revision holds a `main`-only module at `main`'s + head. +- §343 **Branch names the indexer's keys use.** `register` and `watch` refuse a watched branch named `candidate` or + `entry`, naming why, since the catalog keeps its revisions under `.` beside those two key forms. + How it is checked: whole (indexer), each is refused. +- §344 **The bus module plans a sent store from what a manifest already says.** It plans `_sent-objects` for a + module of the new form whose accepted manifest claims a seat whose definition has a verb or an event, or declares an + event of its own, read from the manifest and the seat list; the indexer's event carries no field `sends`. Why: no + manifest field (*Any size*). How it is checked: whole (bus module), a module claiming a seat with a verb gets a sent + store, one with neither gets none. +- §345 **A large value reaches the tool runner in chunks.** A bundle's put of a value over the bus's per-message limit is + sent to the tool runner in chunks under that limit, in order, each acknowledged, and written as one object through + the object store's own chunking; a put not sealed within the call's bound is dropped by the tool runner. No value is + split over objects. Why: one object per value (ADR 0666 §16), through the tool runner (ADR 0595 §9). How it is + checked: whole (mesh-sdk), a value of a hundred times the limit is read back whole. +- §346 **One object store package.** The assigner's and the indexer's object store code is mesh-sdk's small object store + package, with no copy in either. Why: ADR 0595 §9. How it is checked: a search finds no second copy. +- §347 **Reading sent objects is a bus state call.** mesh-sdk lists the call that reads a sent object under its existing + bus state capability. Why: ADR 0595 §9 puts the calls in that package. How it is checked: the package's table test. +- §348 **The builder reads the catalog through its seat.** The builder reads the registrations' watched branches through + `mesh-catalog`'s `registrations` and `registration-changed`, and a build seat's holder from the seat list; the + manifests, the packages, each package's name in its ecosystem (the Go module path, the npm name, which the catalog + graph entry's packages carry) and a run's candidate from the catalog half of its revision view, never the indexer's + state. With no holder of a build seat, a build ends `could not run`, naming the seat, and is asked again on the seat + list's change. Why: ADR 0596 §2. How it is checked: the builder's account holds no grant to the indexer's state. +- §349 **`package-published` is heard by the indexer.** The indexer keeps its package state from `package-published` for + every package, and from the builder's `version.numbered` only for images, bundles and archives. Why: the + publication is the seat's event (ADR 0666 §15). How it is checked: whole (indexer), a published package's version is + in its state. +- §350 **A superseded build's drop is a kept call.** The runner ends a superseded build's step `superseded` at once, and + asks the build seat's `drop` as a kept call (ADR 0668 §1, §2), so it is asked again through every transport fault + and said `call-unanswered` after five minutes. How it is checked: whole (runner), a drop unanswered is asked again. +- §351 **One rule for asking again.** mesh-sdk's kept-call form (ADR 0668 §7) asks an ask again only while it is open and + not replaced, and every asker and every hand ask-again tool uses it. How it is checked: unit (mesh-sdk), a replaced + ask is not asked again. +- §352 **The assigner's newer-revision check reads the want.** Each want names its source revision and watched branch, and + the assigner writes a want only by compare-and-set over a want of an older revision of that branch (*What holds a + delivery*). How it is checked: whole (assigner), an older revision ending after a newer one writes nothing. +- §353 **The assigner follows the registrations.** `mesh-delivery-contracts`' client `meshcatalogclient` carries a typed + follower of `registrations`, a first view then `registration-changed`, built on `go/views`; the assigner and the + forge module's merge switch on its first registrations (ADR 0667 §10). How it is checked: whole (assigner), it keeps + the trunk-only want until the first `registration-changed`. +- §354 **The assigner's composition step runs the composer in the sandbox.** It asks the seat `node-build-go` the ask `run` + (*What ADR 0656 leaves to this design*), its step keys under `assigner.`, and serves the ask's input by its seat + `mesh-wants`' verb `input`, kept a day in its state `inputs`, as the checker's seat does today; the indexer does the + same for its validation by `mesh-catalog`'s `input`. The Go build module reads no revision verb. Why: the + composition step runs on parts built from the heads, in the sandbox (ADR 0666 §17). How it is checked: whole + (assigner), a composition step's `run` is answered and its input read by digest. +- §355 **The assigner says an unanswered `manifest-reads`.** The assigner, the one caller of the node-engine's + `manifest-reads` from G, writes `call-unanswered` into its own findings state, and the condition keeper's reads gain + it in the same change (ADR 0668 §3). How it is checked: whole (assigner), a node-engine that never answers raises it + after five minutes. +- §356 **Two acting parts in different steps make no cycle.** The assigner's cycle check counts waits within one step only + (*A wait holds only within its step*). How it is checked: the unit rows there. +- §357 **Which provider a requirement points to.** In the assignment graph, by design 27's order: the named seat's + holder, a pin, the provider on the consumer's node, the only provider; otherwise the entry is held, naming the + candidates, and nothing is guessed. A contribution edge runs from a consumer's entry to the provider its requirement + resolves to, wherever that requirement carries values the consumer contributes. How it is checked: unit + (assignment graph), each step of the order and a hold. +- §358 **The catalog's shared view takes a branch.** The client's view of the catalog half is per watched branch, named by + its caller. How it is checked: unit (client), two branches give two views. +- §359 **`difference` names its revisions.** `difference` with none of `from`, `to` and `group` is refused, naming the + missing argument. How it is checked: a unit row. +- §360 **An approved ask binds the placement.** What an approved ask binds to includes the placement's watched branch and + its `build`, beside the fingerprint. How it is checked: whole (assigner), a placement changed after the Approve asks + again. +- §361 **A placement's `build` is a held put.** A placement's `build` is written as a held put of that build, released when + the placement drops it; a put a person wrote is never released by a placement change. How it is checked: whole + (assigner). +- §362 **The indexer's first-start catch-up runs apart from its source handler.** At its first start the indexer takes in + the heads the gate's source names by its catch-up path before it starts its handler of `source-moved`. How it is + checked: whole (indexer). +- §363 **A stale ask is dropped, backups included.** The assigner drops an ask it raised once the want it asked for is + replaced, a backup ask among them (built in mesh-delivery #200). Why: ADR 0596 and ADR 0668 §2. How it is checked: + whole (assigner). + +### The condition keeper and the node-engine + +- §364 **The node-engine claims its seat.** The node-engine's manifest claims the node seat `node-engine` (ADR 0563), and + the indexer and the node-engine's own guard read its holder from the seat list, keeping no module name. How it is + checked: lint finds no module name in either. +- §365 **The condition keeper reads its sources from the catalog.** The catalog graph entry carries each kept data a + manifest declares (its name and its section or template); the keeper takes a first view of the catalog half and + reads a module's `findings` wherever its entry declares a state `findings`, and the node-engine's holder from the + seat list. It joins the readers of *Every other reader of which modules exist*. Why: no fixed names (ADR 0666 §5), + and the keeper reads findings (ADR 0564 §2). How it is checked: whole (keeper), a fixture module declaring `findings` + is read with no code change.