Design 47 and the as-is delivery after release 6: acceptance tests on wants, as-is 04 and 13 as the mesh runs now (issue 1130) #477

Merged
mesh-tools merged 3 commits from fix/1130-after-r6 into main 2026-10-26 00:39:22 +00:00
3 changed files with 179 additions and 92 deletions
+97 -49
View File
@@ -1,12 +1,11 @@
---
layer: as-is
status: implemented
code: [mesh-controller, mesh-delivery, mesh-catalog modules/gitea, mesh-catalog modules/mesh-build-go]
updated: 2026-10-24
code: [mesh-delivery, mesh-catalog modules/mesh-delivery-gate, mesh-catalog modules/gitea, mesh-catalog modules/mesh-build-go, mesh-catalog modules/messenger, mesh-catalog modules/mesh-issues, mesh-controller, mesh-host, mesh-sdk]
updated: 2026-10-26
decisions:
- "ADR 0239"
- "ADR 0267"
- "ADR 0276"
- "ADR 0282"
- "ADR 0289"
- "ADR 0304"
@@ -17,71 +16,120 @@ decisions:
- "ADR 0382"
- "ADR 0395"
- "ADR 0398"
- "ADR 0429"
- "ADR 0524"
- "ADR 0525"
- "ADR 0527"
- "ADR 0528"
- "ADR 0529"
- "ADR 0539"
- "ADR 0546"
- "ADR 0547"
---
# Delivery — from a merge to the nodes, as it runs
What runs on 2026-10-24, after the delivery of release 4 and release 5's first half (milestone R4g, design 47),
read from the live controller (`mesh-controller.modules`, `.seats`, `.plans`), the delivery checker's `checker_status`
and the machines' module lists. It is what [to-be 47](../01-to-be/47-delivery-from-commit-to-delivered.md) has not yet
finished: the node agent applying wants and the deletion of plans are release 6, and the controller still plans,
orders and sends a delivery's builds to the machines. Until 2026-10-23 this document described the pipeline with the
build agent, the build queue and the two statuses `mesh/merge-gate` and `mesh/repo-check`, which no longer run.
What runs on 2026-10-26, after the delivery of release 6 (milestone R6 of
[to-be 47](../01-to-be/47-delivery-from-commit-to-delivered.md), ADR 0539), read from the code on each repository's
main (`mesh-delivery`, the gate in `mesh-catalog`, the node agent in `mesh-host`, `mesh-controller`) and from the live
mesh: the controller's seat verbs, `mesh-controller.modules`, the gate's `table`, and the view's `assigner_wants` and
`node_haves`. Until 2026-10-26 this document described release 5, in which the controller still made a delivery plan
for each merge, ordered it in tiers and sent whole declarations to the machines; none of that runs any more.
## Who does what
- **The parts of `mesh-delivery`** are modules of one repository, each a process with its own bus credential that
watches keys and writes keys (design 47, ADR 0429). Running now: the forge bridge (`mesh-delivery-forge-bridge`),
the indexer, the checker, the gate (`mesh-delivery-gate`, which holds the seat `mesh-delivery`), the teller and
the watchman on the control-node; the builder (`mesh-delivery-builder`) and the status view on the workstation;
and the assigner (`mesh-delivery-assigner`) on the home server (ADR 0524, ADR 0528).
- **The forge bridge** turns the forge's events into stream messages and is the only part that calls the forge. The
forge module (`gitea`, on the control-node) still announces them through the forge's system webhook.
- **The indexer** computes each module's fingerprint at the merge preview; **the builder** claims a build once per
fingerprint and orders it as an ask on the stream of the artifact's language.
- **The build modules** (`mesh-build-go` and `mesh-build-node` on three machines, `mesh-build-image` on one; ADR 0525) hold the
node seats `node-build-go`, `node-build-node` and `node-build-image`. Each pulls asks from the bus's work-queue
streams (deliveries first, then checks, then re-checks) while its node has a free slot of build capacity; no part
chooses the node. The seat `node-build-agent` and the module `build-agent` have no holder any more, and the seat
`mesh-build-machine` has none either.
- **The checker** (`mesh-delivery-checker`) runs the merge check: a change's tests through the build module of each
language, running only packages whose inputs changed, and writes the one status `mesh/check`. It also serves a
**try** (`checker_try`, `checker_try_read`): the same check on a pushed branch, before a pull request. `checker_status`
shows the steps in flight by node and the candidates still without a verdict.
- **The gate** merges a delivery group's pull requests once the check, the review and the operator's Approve agree on
the same heads. The forge requires no status on any repository (ADR 0534). The scripts `merge-check.sh` are gone from every repository (ADR 0529).
- **The assigner** composes the machines a change touches (the composition check the checker reads) and writes which
fingerprint each node should want, by its six rules; it only compares wants with what the controller sends.
- **The controller** (`mesh-controller`, on the control-node) plans, orders, sends and judges. It computes a delivery plan for the
files a merge changes, moves only modules whose build source changed with their build dependents, and writes the
chain's links it owns. On 2026-10-24 the seat still lists 64 verbs, `queue` and `replay` among them; whether
those still do work was not read here, and the build agent they served has no holder.
watches keys and writes keys (ADR 0429). Running now: the forge bridge, the indexer, the checker, the teller and the
watchman on the control-node; the builder and the status view (`mesh-delivery-view`) on the workstation; and the
assigner on the home server. The gate (`mesh-delivery-gate`, holding the seat `mesh-delivery`) is a module of
`mesh-catalog` and runs on the control-node.
- **The forge bridge** turns the forge's events into stream messages and is the only part that calls the forge; the
forge module (`gitea`) still announces them through the forge's system webhook.
- **The indexer** writes each module's fingerprint at the merge preview and at a trunk merge; **the builder** claims a
build once per fingerprint and orders it as an ask on the stream of the artifact's language.
- **The build modules** (`mesh-build-go` on all four machines, `mesh-build-node` on three, `mesh-build-image` on one;
ADR 0525) hold the node seats `node-build-go`, `node-build-node` and `node-build-image` and pull asks from the bus's
work-queue streams (deliveries first, then checks, then re-checks) while their node has a free slot of build
capacity.
- **The checker** runs the merge check and writes the one status `mesh/check`, and serves a **try** on a pushed
branch. The forge requires no status on any repository (ADR 0534), and no repository holds a `merge-check.sh`
(ADR 0529).
- **The gate** keeps one key per pull request and the merge's states only: `proposed`, `ready`, `rejected`, `held`,
`merged` and `closed`, read from its `table` verb. On the operator's Approve it merges a delivery group's pull
requests in one pass and writes their merged heads as one revision of `source.main`. It sends nothing to a
machine and asks the controller nothing.
- **The controller** (`mesh-controller`, on the control-node) keeps registration, placement in its assignments
bucket and every node's inputs, and composes: on events it writes each module's signed composition for each node at
each fingerprint into the node's bucket `composed-<node>`, with its digest and its judgement of the move in
`mesh-controller_composed`, and it issues a module's credential and grant when its build is done. It plans,
orders and sends nothing: of its seat's 65 verbs, 20 are refused by name with their replacement, among them
`plans`, `plan`, `push`, `deliver`, `delivery-stop`, `delivery-order` and `delivery-walks` (read 2026-10-26 01:20).
- **The assigner** writes each node's want of each module, `want.<node>.<module>`, naming a fingerprint and the
digest of the one composition it allows, when its seven rules hold: the build is done, the fingerprint is not
held, the node is the module's canary or the canary runs it healthy, at most `step` others ahead, every provider
runs healthy, the grant exists and the composition exists. In the code the canary is the first of the module's
nodes by name that is online (one ring), and rule 4 always holds, because the mesh keeps no `step`. It also runs
the composition check the checker reads. Its differences bucket, from release 5's comparison with what the
controller sent, is no longer written.
- **Two ways around the rules, both by hand.** A **put** (ADR 0546), written by the assigner's tool `assigner_put`,
puts one version of a module on one node: while a put owns a node's want of a module, from its ask until it ends,
the rules pass over that want. And the operator's credential may write a want itself, with a composition the
operator signed and wrote through mesh-sdk's `mesh-hand-compose` (ADR 0539 §10).
- **The node agent**, a process of the node-engine (`mesh-host`) on every node, watches its node's wants and its
bucket of compositions, and applies a module only when the want's fingerprint or digest differs from what runs,
and only the composition whose digest the want names, after checking its signature. It asks its node's
`node-backup` seat to back up a data module first and waits for the backup's end. It writes the have,
`have.<node>.<module>` in `node-engine_have`, with the fingerprint, the composition's digest, the phase and the
health. A failed apply is retried by the next change of the want or the composition; an apply that failed only
because the bus did not answer for a moment is retried with a bounded backoff, and at once when the bus is back.
- **The watchman** mirrors every want as a pulse owed by that node's agent until its have names the want's
fingerprint, so a node that does not move shows as a stall.
- **The status view** derives from `source.main`, the wants and the haves whether the source revision is
delivered, and says the event `delivered` once per revision, and `moving`, `settled` and `stuck` once for a
module on a node at one composition. The messenger holds the operator's notices on those events, and the issue
tracker hears `delivered`.
- **The grants part** (`mesh-grants`, on the control-node; ADR 0547) publishes each assignment's membership on the
assignments stream when it differs from the one last published. The bus's user list, assertions and grants it
composes only in its own state, compared with what the bus holds, and they take no effect; the controller still
composes the user list the bus loads.
## From a merge to a delivery plan
## From a merge to the nodes
- A pull request's head is built and checked as it comes in. One status, `mesh/check`, carries the verdict; a delivery
group has one verdict for every member. A move of the trunk asks the checks again, and a running check stops itself
when its head or trunk commit moves.
- A merge is made by the gate on the operator's Approve; the controller then makes a delivery plan, tiered along the
module graph, and sends it. `mesh-controller.plans` lists the plans and the delivery plans' tiers; a plan that
fails on a node says so and is retried by hand.
- A pull request's head is built and checked as it comes in; one status, `mesh/check`, carries the verdict, and a
delivery group has one verdict for every member. A move of the trunk asks the checks again, and a running check
stops itself when its head or trunk commit moves.
- The gate merges on the operator's Approve and moves the source revision in one write. Nothing collects merges or
waits for others: the indexer writes the new fingerprints, the builder claims each new one once, the controller
composes and grants on the done build, and the assigner writes each want once its rules hold, the canary first.
- Each node applies its own wants one module at a time and writes its haves; the source revision is delivered when
every want equals its module's fingerprint and every have equals its want, running and healthy. Read on
2026-10-26 at 01:20: 303 wants, every one equal to its node's have in fingerprint and composition digest, and 12
fingerprints held.
- **hq** builds no module: the checker runs hq's Go tests (`go test ./...`) as its check (ADR 0527).
## Where the record of what runs lives
Fingerprints, builds, verdicts and wants are keys in the bus's key-value buckets of the parts; builds' files are in
the artifact store by digest; packages are versions in the package registry. Plans, rollouts with their tiers,
assignments and settings are still rows in the controller's store. An assignment names its module and node but not
the build, artifact or plan that put it there.
Fingerprints, builds, verdicts, wants and haves are keys in the parts' buckets on the bus; compositions are in each
node's `composed-<node>` bucket, readable only by that node, with a file over 64 KiB in the object store; builds'
files are in the artifact store by digest; packages are versions in the package registry. The controller
still records every build it takes in, in its builds bucket (`RecordBuild` in `cmd/mesh-controller/key_takein.go`); its
assignments bucket keeps placement alone, and its rollouts bucket keeps the record of releases 1 to 5 read-only, and
nothing writes it now.
## What is not covered
The node agent does not yet apply wants: a node runs what the controller sent. The checker's left-running keys of
build modules that stopped (`checker_status`'s `left_running`) are listed and hold no place. The integration tests run
in each repository's check; there are no end-to-end tests of delivery yet, and the lab is not used (the operator,
2026-10-16).
Nothing checks the delivery budget: the over-budget condition and the gate's `times` went with release 6, and no
reader of the view's `settled` and `delivered` events measures it yet (issue 1945, note 10). The bus's own move stays
a person's step through the controller's `bus` verb (ADR 0539 §15). The checker's left-running keys of build modules
that stopped (`checker_status`'s `left_running`) are listed and hold no place. There are no end-to-end tests of
delivery, and the lab is not used (the operator, 2026-10-16).
## How it is checked
- `mesh-delivery-view.assigner_wants` and `mesh-delivery-view.node_haves`: each want beside its have; `indexer_modules`
and `builder_builds` for the fingerprints and builds they name.
- `mesh-delivery.table`: the gate's states and transitions; `mesh-delivery.deliveries` and `show` for one delivery.
- `mesh-controller.seats` and `mesh_overview`: the controller's verbs, and which are refused by name.
- The code: `mesh-delivery` (`modules/mesh-delivery-assigner/internal/assign`, `modules/mesh-delivery-view/internal/view`,
`modules/mesh-delivery-watchman/internal/watch`, `modules/mesh-grants`), `mesh-host` (`internal/agent`,
`cmd/mesh-host/nodeagent.go`), and the gate in `mesh-catalog` (`modules/mesh-delivery-gate`).
+16 -9
View File
@@ -2,8 +2,10 @@
layer: as-is
status: implemented
code: [mesh-tools, mesh-host, mesh-controller]
updated: 2026-10-24
updated: 2026-10-26
decisions:
- "ADR 0539"
- "ADR 0360"
- "ADR 0524"
- "ADR 0525"
- "ADR 0152"
@@ -21,17 +23,20 @@ decisions:
through `mesh_overview`, `mesh_machine`, `mesh_runtimes` and `mesh_describe`. Checked: the
catalogue (`mesh-catalog`) carries no module named `mesh-console` any more — the name survives only
in the glossary's retired-words list and in a test fixture — and none of the four nodes answers a
module of that name.
module of that name. How the tool runner reaches a node, its count of modules and tools and the
controller's verbs were read again on 2026-10-26, after the delivery of release 6 (ADR 0539).
## What it is now
**The tool runner is one of the mesh's core components**, named `node-tools` beside
`mesh-controller`, `mesh-host` (the node-engine) and `nats` (the bus) — the mesh's own repositories'
check treats the four the same way, as the core whose health the mesh itself defines rather than a
module's own. `mesh-host` and `mesh-controller` supervise, compose and account for it as a core
process rather than as an ordinary assignment (`ComponentNodeTools`/`BusNodeTools` in both, the
witness and lease code that restarts and rolls it back, the account named `<node>.node-tools` on
the bus).
module's own. Since release 6 it reaches each node the way every module does: the controller composes
and signs its composition for that node, the assigner writes the node's want of it, and the
node-engine's node agent applies it and writes its have. What stays particular to it is the account
named `<node>.node-tools` on the bus (`BusNodeTools` in `mesh-controller`) and the node-engine's
witness and lease code that puts back a tool runner that does not come up (`ComponentNodeTools` in
`mesh-host`, ADR 0360 §9).
**It still carries a manifest, `node-tools/module.json` in `mesh-tools`,** and that manifest is
where its grants live: `invokes` names `*`, so its account may call every tool on the mesh;
@@ -60,7 +65,7 @@ body per request, no session and no event stream (`node-tools/internal/console/m
`mesh_machine`, `mesh_search`, `mesh_describe`, `mesh_call`, `mesh_runtimes` and `mesh_wait`. The
handshake's `instructions` text names all seven and the four address forms. `mesh_overview` is
where the mesh-wide count of modules and tools is read live — a number copied into this document
would drift; asked on 2026-10-17 it answered 103 modules and 645 tools across the whole mesh, with
would drift; asked on 2026-10-26 it answered 115 modules and 714 tools across the whole mesh, with
two module instances (`route-proxy` on two of the nodes) named as not answering rather than silently
absent.
@@ -94,8 +99,10 @@ command, not inline, because one call blocks until it answers or times out.
**These already answer directly, not as a stated future.** Beside every assigned module's tools,
the tool runner asks the `mesh-controller` seat for its own verbs the same way (ADR 0154): measured
live, the mesh-controller runtime is one instance, mesh-wide, and it answers 64 verbs for that one
seat (`status`, `push`, `assign`, `build`, `artifacts` and the rest), and the `mesh-controller`
live on 2026-10-26, the mesh-controller runtime is one instance, mesh-wide, and it answers 65 verbs for
that one seat (`status`, `assign`, `modules`, `artifacts` and the rest), of which 20 are refused by
name with what replaces them: the delivery verbs release 6 removed (`plans`, `plan`, `push`,
`deliver` among them) and the build verbs of release 4 (`build`, `queue` among them). The `mesh-controller`
*module* answers none of its own — it serves no module tools, only its seat's, exactly as design 33
described while it was still only designed. The 56-to-93 seat-verb counts each node's tool runner
answers (below) are a different thing: the tool runner serves the verbs of whichever node-scoped
@@ -2,7 +2,7 @@
layer: to-be
status: in-progress
code: [mesh-controller, mesh-catalog modules/mesh-delivery-gate, mesh-delivery, mesh-host, mesh-sdk, hq 00-META/checks]
updated: 2026-10-24
updated: 2026-10-26
decisions:
- "ADR 0539"
- "ADR 0536"
@@ -172,8 +172,8 @@ It lands in six releases, each leaving the mesh working, each one milestone belo
with one switch-over and no rehearsal (ADR 0524 §1). Until the
release that replaces it is delivered, each section from here to *The bootstrap* stays this design and its rule
(ADR 0429 §21); each is rewritten when the release that replaces it is prepared (issue 1130). Release 6's were
rewritten when it was prepared, from ADR 0539: until its delivery the plans of release 5 run, as the as-is
design says, and ADR 0539's clauses hold from that delivery (ADR 0539 §20).
rewritten when it was prepared, from ADR 0539, and its acceptance tests restated after its delivery; release 6
is delivered, so ADR 0539's clauses hold (ADR 0539 §20), and the as-is design describes the delivery as it runs.
## The parts
@@ -740,23 +740,22 @@ the operator for the bus node's want (ADR 0539 §15).
- **A build before its want.** The controller takes every module, the builder's own and the build modules among
them, from the builder's done key whose artifacts all name a reference; a module whose key is not yet done
waits under the assigner's first rule and fails nothing (ADR 0524 §7, ADR 0539 §18).
- **The switch to release 6 is one plan, release 5's last.** Release 5's controller runs the group's plan with
the new node-engine and the new controller in one tier (issue 1942), so every node's last declaration names
the new node-engine and carries the operator's public key, and the control-node's names the new controller
too. Each node applies it with the node-engine it runs; the new controller writes every composition at its
start, and the assigner's wants equal what runs. For that plan one machine at a time yields: each new
node-engine is judged by its launcher, and the new controller by the node-engine's witness. A node away during
- **The switch to release 6 was one plan, release 5's last** (history: it is delivered). Release 5's controller ran
the group's plan with the new node-engine and the new controller in one tier (issue 1942), so every node's last
declaration named the new node-engine and carried the operator's public key, and the control-node's named the new
controller too. Each node applied it with the node-engine it ran; the new controller wrote every composition at
its start, and the assigner's wants equalled what ran. For that plan one machine at a time yielded: each new
node-engine was judged by its launcher, and the new controller by the node-engine's witness. A node away during
the switch finds its last declaration on the bus's stream of declarations when it returns; the controller
deletes that stream and the nodes' consumers only once every node's have names the new node-engine. The
merge waits until every node is present (ADR 0539 §11). The switch works only because the bus's user list that
release 5's controller composes already grants what release 6 uses: the controller writing compositions and
deletes that stream and the nodes' consumers only once every node's have names the new node-engine. The merge
waited until every node was present (ADR 0539 §11). The switch worked only because the bus's user list that
release 5's controller composed already granted what release 6 uses: the controller writing compositions and
their digests, each node-engine reading its own compositions and wants, asking its backup holder and hearing the
backup's end, the assigner reading the digests, and the operator's account writing the hand path. That grant is
delivered first by release 5's controller, like issue 1942, as issue 1945's fix before the switch. The
node-engine's setting `operator-signers` must hold the operator's public key before the switch, or no operator
key is trusted and the hand path cannot work (ADR 0539 §3). At its first start the new controller deletes the
buckets of plan state (the merge window's, the silent sends' and the building plan's hold) and says each
deletion as its event (ADR 0539 §13).
backup's end, the assigner reading the digests, and the operator's account writing the hand path; that grant was
delivered first, as issue 1945's fix before the switch. The node-engine's setting `operator-signers` holds the
operator's public key, or no operator key is trusted and the hand path cannot work (ADR 0539 §3). At its first
start the new controller deleted the buckets of plan state (the merge window's, the silent sends' and the
building plan's hold) and said each deletion as its event (ADR 0539 §13).
### Delivering the controller, the builder or a build module without the builder
@@ -790,28 +789,60 @@ way is written down before the switch (ADR 0526, which ADR 0522 §6 asked of R4g
What the build proves before this design is implemented (research 055's direction):
1. A feature across the controller and the catalogue with a new seat verb is delivered as one group, with no
`after:` line, one composed check, one Approve and one delivery plan: its merges are one batch, each module is
built once and sent once, its commits are carried by that one plan, and the plan names the edge that placed
each tier.
`after:` line, one composed check and one Approve: its merges move one source revision, each module it changes
is built once, and every want naming one of those fingerprints is written by the assigner's seven rules, with
no order written by anyone.
2. An SDK change and a Go module using it are delivered as one group.
3. A data module is backed up before a delivery moves it, and a failed backup holds the delivery.
3. A data module is backed up by its node's backup seat before the node agent applies a new fingerprint of it,
and a failed backup holds that module on that node, its have in phase `held`, while every other want moves.
4. A build on any builder uses the installed toolchain with no container, and a toolchain update rebuilds only
modules of that language when its version changes.
5. Two merges into one repository within a minute leave each open pull request with one queued check, by the
stream's rule.
6. The operator's Approve is asked within seconds of the event of a pull request's checks passing, with no ready
mark, label or comment written by anyone.
7. A controller replaced in the middle of a rollout resumes it with no step lost or repeated.
8. The merge window closes by its key's expiry.
9. A hotfix to a module the running feature's delivery does not touch reaches the machines in minutes, beside it.
10. For any module on any node, one read of its assignment names the commit, build, artifact or package and the
rollout that put it there, and one read of that rollout lists every assignment it changed.
11. Two merges into one repository while a delivery of that repository runs are both delivered by the next plan,
with no person's release and nothing held in mesh-delivery.
12. No table in the controller's store holds builds, rollouts or assignments.
7. A controller, an assigner or a node agent replaced while a source revision is being delivered carries on from
its keys: no composition, want or have is lost, and no module is applied again whose have already equals its
want.
8. Nothing collects merges: a merge moves the source revision in one write, and the assigner writes the wants it
allows with no window, no key's expiry and no timer between them.
9. A hotfix to a module that the source revision being delivered does not touch reaches the machines in minutes,
beside it: its wants move on its own build, canary and providers.
10. For any module on any node, one read of its have names the fingerprint and composition it runs, one read of
its want the same or what it should run, and the fingerprint names the source revision, the build and its
artifact or package.
11. Two merges into one repository while its modules are moving are two source revisions: a node is wanted the
newer fingerprint once its rules hold, a fingerprint nobody wants any more is never applied, and nothing is
released by a person or held in the gate.
12. No table in the controller's store holds builds, deliveries or assignments: builds are the builder's keys,
wants the assigner's, haves the node agents', and placement the controller's assignments bucket.
Tests 1, 3, 7, 8, 9, 10 and 11 were proved by the milestones that built them, on the plans and rollouts of their
time; from release 6, tests 18 and 19 prove what of them still holds without a plan.
Tests 1 to 12 are stated as they hold from release 6. Tests 1, 3, 7, 8, 9, 10 and 11 were first proved by
milestones 1 to 5 in the shape of their time, the controller's plans and what it sent (the milestones table keeps
it). Restated, each has its own proof, or says it has none yet:
- **Tests 1 and 8, and the assigner's half of test 7:** test 18 (scenario A, three repositories through the keys
alone; scenario D, the assigner replaced, in the assigner's integration test
`TestTheAssignerReplacedResumesWithNothingLostOrRepeated`). **Tests 8 and 12:** test 19 (the window, the batches,
the plans and their verbs deleted from the code).
- **Test 3:** the node-engine's integration test `TestNatsADataModuleAsksItsBackupFirstAndIsHeldWhenItFails`
(`cmd/mesh-host/nodeagent_integration_test.go`, R6-A AC5) proves the backup first and the hold with phase `held`.
That every other want moves meanwhile is not yet proved by a test; it shows on the live mesh at the first failed
backup, in the view's wants beside the haves.
- **Test 7, the node agent's and the controller's halves:** a node agent restarted on its own haves applies nothing
(`internal/agent/agent_test.go`, `TestStartingOnItsOwnHaveAppliesNothing`, at the unit level), and a controller
writes a composition once and again only when it changes (`composed_writer_test.go`,
`TestACompositionIsWrittenOnceAndAgainOnlyWhenItChanges`). A controller replaced while a source revision is being
delivered is not yet proved; it shows at the next delivery of the controller, in the view.
- **Test 9:** not yet proved under release 6. Each rule holding a want back on its own is a unit test of the assigner
(`internal/assign/wants_test.go`, `TestEachRuleHoldsTheWantBack`); the hotfix beside a moving source revision shows
live at the first such pair, read in the view's wants and haves.
- **Test 10:** a live read on 2026-10-26 at 01:20: one node's have of `avahi` named its fingerprint and composition digest,
its want named the same, and the builder's build of that fingerprint (`builder_build`) named its artifact by digest.
In all, 303 wants equalled their haves in fingerprint and digest.
- **Test 11:** half proved. The node agent applies only the composition its current want names
(`internal/agent/agent_test.go`, `TestTheRevisionAWantNamesIsAppliedFromHistory`); two merges of one repository
while its modules move are not yet proved live, and show at the first such pair in the view.
From ADR 0429 (research 063's done-when, and the live proof each of its releases names):
@@ -821,8 +852,9 @@ From ADR 0429 (research 063's done-when, and the live proof each of its releases
15. A group of two repositories merges as one source revision, and every module's fingerprint the indexer
writes equals the controller's source fingerprint.
16. A merge builds nothing its check built, and a hotfix's build waits for no other build.
17. A day of deliveries shows no difference between the assigner's wants and what the controller sent that the
six rules do not explain.
17. A day of deliveries in release 5 showed no difference between the assigner's wants and what the controller
sent that the six rules then in force did not explain. That was proved in R4g; the differences bucket is kept
read-only as its evidence (ADR 0539 §8).
18. On the live mesh a milestone of three repositories reaches every node through the keys alone (research 063's
scenario A), and the assigner replaced in the middle of it resumes with nothing lost or repeated (scenario
D, once).