hq issue 356 (hq pull request named in the thread once open); the engine's side is mesh-host #74, the catalogue's check mesh-catalog #165. A module's condition told the operator to run the node-engine's hand-over at the machine, as root (issue 339), the mesh had no channel for it, and the engine on the machine's PATH was a build from before the subcommand (the engine's PR fixes that).
Reviewers' checklist
Validate every caller value.handOverLine (cmd/mesh-controller/nodes.go) takes exactly a node and a path: the node a name (not a flag, not empty) the inventory knows (NodeByName); the path absolute and filepath.Clean(path) == path — no .., no doubled or trailing separator — before anything is asked. The engine judges the same values again and is the one that acts (mesh-host #74). AskHandOver (internal/link/handover.go) refuses an answer that is neither a record nor a refusal, and an unreadable one.
Trust-changing acts terminal-only.node hand-over is a node subcommand that is not in nodeReads, so terminalOnly refuses it through every verb and ordinaryLine through mesh-cli outside the terminal — no new rule, and TestAHandOverIsRefusedThroughEveryVerb holds it four ways (terminalOnly, the generic command verb's composition, the ordinary mesh-cli line, the node verb's composition). The ask goes on mesh.node.<node>.ask.hand-over: the controller's mesh.node.> publish grant, and the node's grant gains exactly its own subject and the right to answer what it was asked (AllowResponses for KindNode; a person still has none). The golden composition (internal/broker/testdata/composed.conf) changed by exactly those two lines.
Every test fails with its check removed.TestAHandOverLineIsJudgedBeforeItIsAsked (ten refusals, the one acceptance), TestAHandOverNamesWhoAsked, TestAHandOverIsRefusedThroughEveryVerb, TestTheUsedAsFoundConditionNamesTheOperatorsLine (the module's health names nox node hand-over <node> <directory> on the control-node, never the engine's binary, never a path; the condition's words are plain under conditions.PlainWords) (cmd/mesh-controller); TestTheHandOverAskAndAnswerKeepTheirFieldNames (held by the engine's twin), TestAHandOverIsAskedOfTheMachineAndItsAnswerComesBack (over a bus: the record and the refusal come back whole, a machine with no engine listening is said as not answering, an empty answer is refused, no bus is refused), TestAMachineHearsItsOwnHandOverAskAndMayAnswerIt (internal/link); TestOnlyWhatCanBeAskedMayAnswer now holds that a node answers its one ask and a person answers nothing (internal/broker).
Fail closed. A refusal from the engine is the command's error (" refused: … nothing was handed over"); no engine answering is an error naming the node-engine; a timeout says the outcome is not known and where to look (the module's condition); nothing is recorded on the controller's side at all.
What changes
node hand-over <node> <directory>: judges the line, asks the node's engine with who asked (MESH_CALLER, as every verb's caller is recorded — " through mesh-cli on " — or "the controller's terminal"), prints the engine's answer and that push <node> applies it now.
broker.AskHandOverSubject, the node's subscribe grant and AllowResponses; link.AskHandOver with the field names the engine holds.
Words (ADR 0272, the operator's rule of 2026-10-09): the module's wait says the nox line with the machine; the condition's "needs" line is plain (the line and the directory are in the summary and the evidence); nox-mesh-host overlay take and enrol in the network command's and the lab's texts use the binary's real name (install-time acts, at the machine).
Checks.merge-check.sh passed locally on the merge result (this branch on top of main at 1c7c385, after #184 and #185 merged): gofmt, vet, go test -race ./..., 26 packages ok. Not merged.
Order. This first — it composes the node's grant; then mesh-host #74. The catalogue's and hq's PRs in any order. Live, after both: nox node hand-over <control-node> <the messenger's data directory> on the control-node, then its next apply clears the messenger's condition.
hq issue 356 (hq pull request named in the thread once open); the engine's side is mesh-host #74, the catalogue's check mesh-catalog #165. A module's condition told the operator to run the node-engine's `hand-over` at the machine, as root (issue 339), the mesh had no channel for it, and the engine on the machine's PATH was a build from before the subcommand (the engine's PR fixes that).
**Reviewers' checklist**
- **Validate every caller value.** `handOverLine` (`cmd/mesh-controller/nodes.go`) takes exactly a node and a path: the node a name (not a flag, not empty) the inventory knows (`NodeByName`); the path absolute and `filepath.Clean(path) == path` — no `..`, no doubled or trailing separator — before anything is asked. The engine judges the same values again and is the one that acts (mesh-host #74). `AskHandOver` (`internal/link/handover.go`) refuses an answer that is neither a record nor a refusal, and an unreadable one.
- **Trust-changing acts terminal-only.** `node hand-over` is a `node` subcommand that is not in `nodeReads`, so `terminalOnly` refuses it through every verb and `ordinaryLine` through mesh-cli outside the terminal — no new rule, and `TestAHandOverIsRefusedThroughEveryVerb` holds it four ways (`terminalOnly`, the generic command verb's composition, the ordinary mesh-cli line, the `node` verb's composition). The ask goes on `mesh.node.<node>.ask.hand-over`: the controller's `mesh.node.>` publish grant, and the node's grant gains exactly its own subject and the right to answer what it was asked (`AllowResponses` for `KindNode`; a person still has none). The golden composition (`internal/broker/testdata/composed.conf`) changed by exactly those two lines.
- **Every test fails with its check removed.** `TestAHandOverLineIsJudgedBeforeItIsAsked` (ten refusals, the one acceptance), `TestAHandOverNamesWhoAsked`, `TestAHandOverIsRefusedThroughEveryVerb`, `TestTheUsedAsFoundConditionNamesTheOperatorsLine` (the module's health names `nox node hand-over <node> <directory>` on the control-node, never the engine's binary, never a path; the condition's words are plain under `conditions.PlainWords`) (`cmd/mesh-controller`); `TestTheHandOverAskAndAnswerKeepTheirFieldNames` (held by the engine's twin), `TestAHandOverIsAskedOfTheMachineAndItsAnswerComesBack` (over a bus: the record and the refusal come back whole, a machine with no engine listening is said as not answering, an empty answer is refused, no bus is refused), `TestAMachineHearsItsOwnHandOverAskAndMayAnswerIt` (`internal/link`); `TestOnlyWhatCanBeAskedMayAnswer` now holds that a node answers its one ask and a person answers nothing (`internal/broker`).
- **Fail closed.** A refusal from the engine is the command's error ("<node> refused: … nothing was handed over"); no engine answering is an error naming the node-engine; a timeout says the outcome is not known and where to look (the module's condition); nothing is recorded on the controller's side at all.
**What changes**
- `node hand-over <node> <directory>`: judges the line, asks the node's engine with who asked (`MESH_CALLER`, as every verb's caller is recorded — "<account> through mesh-cli on <node>" — or "the controller's terminal"), prints the engine's answer and that `push <node>` applies it now.
- `broker.AskHandOverSubject`, the node's subscribe grant and `AllowResponses`; `link.AskHandOver` with the field names the engine holds.
- Words (ADR 0272, the operator's rule of 2026-10-09): the module's wait says the `nox` line with the machine; the condition's "needs" line is plain (the line and the directory are in the summary and the evidence); `nox-mesh-host overlay take` and `enrol` in the network command's and the lab's texts use the binary's real name (install-time acts, at the machine).
**Checks.** `merge-check.sh` passed locally on the merge result (this branch on top of main at 1c7c385, after #184 and #185 merged): gofmt, vet, `go test -race ./...`, 26 packages ok. Not merged.
**Order.** This first — it composes the node's grant; then mesh-host #74. The catalogue's and hq's PRs in any order. Live, after both: `nox node hand-over <control-node> <the messenger's data directory>` on the control-node, then its next apply clears the messenger's condition.
build-agent keeps data (ADR 0233): what it holds is backed up before it moves
route-proxy provides route: its consumers are sent again after it
route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Machines
mesh-controller on novox: passed — healthy 3 times over 3m39s
mesh-controller on the rest running it: sent
build-agent on ace: passed — healthy 3 times over 3m14s
build-agent on the rest running it: sent
route-proxy on ace: passed — healthy 3 times over 3m30s
route-proxy on the rest running it: sent
Transitions
2026-10-09 17:47 (new) → proposed (announced): novox/mesh-controller#187's head announced
2026-10-09 17:53 proposed → checked (checked): the verdict names this commit
2026-10-09 17:53 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-09 17:57 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
2026-10-09 17:57 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path
2026-10-09 18:13 delivering → delivered (done): its walk is done: every machine of its deploy plan passed, or was left as its policy says
The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-controller@081d9244d6dd` — **delivered** since 2026-10-09T18:13:21Z
**Delivery plan** — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- tier 2: route-proxy
- ace: receives build-agent, route-proxy
- g14: receives build-agent
- novox: receives mesh-controller, build-agent, route-proxy
- shanks: receives build-agent
- build-agent keeps data (ADR 0233): what it holds is backed up before it moves
- route-proxy provides route: its consumers are sent again after it
- route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
**Machines**
- mesh-controller on novox: passed — healthy 3 times over 3m39s
- mesh-controller on the rest running it: sent
- build-agent on ace: passed — healthy 3 times over 3m14s
- build-agent on the rest running it: sent
- route-proxy on ace: passed — healthy 3 times over 3m30s
- route-proxy on the rest running it: sent
**Transitions**
- 2026-10-09 17:47 (new) → proposed (announced): novox/mesh-controller#187's head announced
- 2026-10-09 17:53 proposed → checked (checked): the verdict names this commit
- 2026-10-09 17:53 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-09 17:57 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
- 2026-10-09 17:57 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path
- 2026-10-09 18:13 delivering → delivered (done): its walk is done: every machine of its deploy plan passed, or was left as its policy says
The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
A module's condition told the operator to run the node-engine's hand-over at the machine, as root (issue 339), and the mesh had no channel for it. Now node hand-over <node> <path> is the controller's terminal's — a node subcommand that is not a read, so every verb and mesh-cli outside the terminal refuse it — and asks that node's engine on mesh.node.<node>.ask.hand-over, a request only the controller may publish and only that node's engine may hear and answer (its grant gains the subject and the right to answer what it was asked). The line's node and path are judged before anything is asked; the engine's answer is printed, a refusal as a refusal. Every text addressed to the operator names the nox line (ADR 0272); the condition's words stay plain.
build-agent keeps data (ADR 0233): what it holds is backed up before it moves
route-proxy provides route: its consumers are sent again after it
route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on ace as build-1791563824735966092 (builds --log build-1791563824735966092).
--- the gate: build-agent, mesh-controller, route-proxy
mesh-controller: ok, 54 tool(s); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
files asking for a setting without saying whether it is trusted: 0
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-09T16:31:14Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-09T16:31:14Z
modules the change moves:
- mesh-controller (changed)
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 3 module(s) in 3 tier(s): build-agent, mesh-controller, route-proxy
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.038s
ok github.com/novox/mesh-controller/cmd/mesh-controller 190.264s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.012s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.017s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.012s
ok github.com/novox/mesh-controller/examples/route-proxy 1.119s
ok github.com/novox/mesh-controller/internal/artifacts 1.123s
ok github.com/novox/mesh-controller/internal/broker 2.651s
ok github.com/novox/mesh-controller/internal/builder 1.948s
ok github.com/novox/mesh-controller/internal/catalogue 4.411s
ok github.com/novox/mesh-controller/internal/conditions 2.447s
ok github.com/novox/mesh-controller/internal/envfile 1.086s
ok github.com/novox/mesh-controller/internal/facts 1.047s
ok github.com/novox/mesh-controller/internal/identity 4.144s
ok github.com/novox/mesh-controller/internal/inventory 73.932s
ok github.com/novox/mesh-controller/internal/lease 17.689s
ok github.com/novox/mesh-controller/internal/licences 3.784s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.043s
ok github.com/novox/mesh-controller/internal/link 51.633s
ok github.com/novox/mesh-controller/internal/lint 2.025s
ok github.com/novox/mesh-controller/internal/outward 1.111s
ok github.com/novox/mesh-controller/internal/overlay 1.060s
ok github.com/novox/mesh-controller/internal/secrets 1.474s
ok github.com/novox/mesh-controller/internal/store 3.367s
ok github.com/novox/mesh-controller/internal/testbus 1.253s
ok github.com/novox/mesh-controller/internal/token 1.016s
**Merge check** at `7ba32744`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller, route-proxy)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed
**Delivery plan** — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- tier 2: route-proxy
- ace: receives build-agent, route-proxy
- g14: receives build-agent
- novox: receives mesh-controller, build-agent, route-proxy
- shanks: receives build-agent
- build-agent keeps data (ADR 0233): what it holds is backed up before it moves
- route-proxy provides route: its consumers are sent again after it
- route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on ace as `build-1791563824735966092` (`builds --log build-1791563824735966092`).
```
--- the gate: build-agent, mesh-controller, route-proxy
mesh-controller: ok, 54 tool(s); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
files asking for a setting without saying whether it is trusted: 0
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-09T16:31:14Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-09T16:31:14Z
modules the change moves:
- mesh-controller (changed)
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 3 module(s) in 3 tier(s): build-agent, mesh-controller, route-proxy
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.038s
ok github.com/novox/mesh-controller/cmd/mesh-controller 190.264s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.012s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.017s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.012s
ok github.com/novox/mesh-controller/examples/route-proxy 1.119s
ok github.com/novox/mesh-controller/internal/artifacts 1.123s
ok github.com/novox/mesh-controller/internal/broker 2.651s
ok github.com/novox/mesh-controller/internal/builder 1.948s
ok github.com/novox/mesh-controller/internal/catalogue 4.411s
ok github.com/novox/mesh-controller/internal/conditions 2.447s
ok github.com/novox/mesh-controller/internal/envfile 1.086s
ok github.com/novox/mesh-controller/internal/facts 1.047s
ok github.com/novox/mesh-controller/internal/identity 4.144s
ok github.com/novox/mesh-controller/internal/inventory 73.932s
ok github.com/novox/mesh-controller/internal/lease 17.689s
ok github.com/novox/mesh-controller/internal/licences 3.784s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.043s
ok github.com/novox/mesh-controller/internal/link 51.633s
ok github.com/novox/mesh-controller/internal/lint 2.025s
ok github.com/novox/mesh-controller/internal/outward 1.111s
ok github.com/novox/mesh-controller/internal/overlay 1.060s
ok github.com/novox/mesh-controller/internal/secrets 1.474s
ok github.com/novox/mesh-controller/internal/store 3.367s
ok github.com/novox/mesh-controller/internal/testbus 1.253s
ok github.com/novox/mesh-controller/internal/token 1.016s
```
build-agent keeps data (ADR 0233): what it holds is backed up before it moves
route-proxy provides route: its consumers are sent again after it
route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on novox as build-1791563916409013292 (builds --log build-1791563916409013292).
--- the gate: build-agent, mesh-controller, route-proxy
mesh-controller: ok, 54 tool(s); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
files asking for a setting without saying whether it is trusted: 0
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-09T16:31:14Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-09T16:31:14Z
modules the change moves:
- mesh-controller (changed)
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 3 module(s) in 3 tier(s): build-agent, mesh-controller, route-proxy
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.053s
ok github.com/novox/mesh-controller/cmd/mesh-controller 248.389s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.020s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.034s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.021s
ok github.com/novox/mesh-controller/examples/route-proxy 1.137s
ok github.com/novox/mesh-controller/internal/artifacts 1.072s
ok github.com/novox/mesh-controller/internal/broker 6.343s
ok github.com/novox/mesh-controller/internal/builder 10.909s
ok github.com/novox/mesh-controller/internal/catalogue 5.019s
ok github.com/novox/mesh-controller/internal/conditions 2.892s
ok github.com/novox/mesh-controller/internal/envfile 1.030s
ok github.com/novox/mesh-controller/internal/facts 1.036s
ok github.com/novox/mesh-controller/internal/identity 10.058s
ok github.com/novox/mesh-controller/internal/inventory 99.239s
ok github.com/novox/mesh-controller/internal/lease 18.091s
ok github.com/novox/mesh-controller/internal/licences 9.597s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.010s
ok github.com/novox/mesh-controller/internal/link 57.244s
ok github.com/novox/mesh-controller/internal/lint 2.169s
ok github.com/novox/mesh-controller/internal/outward 1.036s
ok github.com/novox/mesh-controller/internal/overlay 1.025s
ok github.com/novox/mesh-controller/internal/secrets 1.482s
ok github.com/novox/mesh-controller/internal/store 5.810s
ok github.com/novox/mesh-controller/internal/testbus 1.179s
ok github.com/novox/mesh-controller/internal/token 1.017s
**Merge check** at `9006c823`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller, route-proxy)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed
**Delivery plan** — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- tier 2: route-proxy
- ace: receives build-agent, route-proxy
- g14: receives build-agent
- novox: receives mesh-controller, build-agent, route-proxy
- shanks: receives build-agent
- build-agent keeps data (ADR 0233): what it holds is backed up before it moves
- route-proxy provides route: its consumers are sent again after it
- route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on novox as `build-1791563916409013292` (`builds --log build-1791563916409013292`).
```
--- the gate: build-agent, mesh-controller, route-proxy
mesh-controller: ok, 54 tool(s); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
files asking for a setting without saying whether it is trusted: 0
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-09T16:31:14Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-09T16:31:14Z
modules the change moves:
- mesh-controller (changed)
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 3 module(s) in 3 tier(s): build-agent, mesh-controller, route-proxy
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.053s
ok github.com/novox/mesh-controller/cmd/mesh-controller 248.389s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.020s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.034s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.021s
ok github.com/novox/mesh-controller/examples/route-proxy 1.137s
ok github.com/novox/mesh-controller/internal/artifacts 1.072s
ok github.com/novox/mesh-controller/internal/broker 6.343s
ok github.com/novox/mesh-controller/internal/builder 10.909s
ok github.com/novox/mesh-controller/internal/catalogue 5.019s
ok github.com/novox/mesh-controller/internal/conditions 2.892s
ok github.com/novox/mesh-controller/internal/envfile 1.030s
ok github.com/novox/mesh-controller/internal/facts 1.036s
ok github.com/novox/mesh-controller/internal/identity 10.058s
ok github.com/novox/mesh-controller/internal/inventory 99.239s
ok github.com/novox/mesh-controller/internal/lease 18.091s
ok github.com/novox/mesh-controller/internal/licences 9.597s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.010s
ok github.com/novox/mesh-controller/internal/link 57.244s
ok github.com/novox/mesh-controller/internal/lint 2.169s
ok github.com/novox/mesh-controller/internal/outward 1.036s
ok github.com/novox/mesh-controller/internal/overlay 1.025s
ok github.com/novox/mesh-controller/internal/secrets 1.482s
ok github.com/novox/mesh-controller/internal/store 5.810s
ok github.com/novox/mesh-controller/internal/testbus 1.179s
ok github.com/novox/mesh-controller/internal/token 1.017s
```
The subject proved nothing: the bus lets any principal allowed to answer reply to a message it received on the reply subject that message named, so a tool server — the operator's account, every agent — could deliver a hand-over to an engine. The controller now signs the ask with the mesh's key over a fixed context (node, path, who asked, a minute's expiry, a fresh nonce), as declarations are signed, and the engine verifies it. The writers table gains the row for mesh.node.*.ask.hand-over; the subject's comment no longer claims who the engine hears. The line's known-node check and the refusal branch are tested; every check was removed in turn and a test failed.
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
Forgeable ask (blocking).link.SignHandOver signs the ask with the mesh's identity key (open.Identity, the key declarations are signed with) over HandOverContext ("novox-mesh hand-over v1\n") + the ask's bytes, so the signature is never a declaration's. The ask is {node, path, by, expires (now+1m), nonce (16 random bytes, hex)}, sent as SignedHandOver{ask, signature}. The engine verifies before reading (mesh-host #74). Writers table. New row "a hand-over asked of a machine", mesh.node.*.ask.hand-over, Writes: isController (and designRows; to-be 45 §1 gains the row in hq #256). The false comment on AskHandOverSubject now says the subject bounds who is granted the publish and the signature who is believed. KindNode AllowResponses. Kept: the request/reply needs it, and it is bounded — the node is its machine's engine (root there already), it is delivered only its own subjects (declare, ask.report, ask.hand-over, its _DELIVER), max 1 / 1m, and the controller records nothing from the answer. Narrowing per subject is not something the server's permissions express. Test gaps.handOverAsked is the line with its two acts given: TestAHandOverAsksOnlyAKnownNodeAndFailsOnARefusal (unknown node → nothing asked; a refused line → nothing asked; the engine's refusal → error, nothing printed; a record → printed with nox push; a failing ask → error). TestAHandOverIsSignedWithAContextANonceAndAnExpiry, TestAHandOverAskHasOnePublisher (node, node tools, module refused at composition; the controller allowed). Mutations (each check removed, a test failed): sign context, nonce, expiry, no signer, signed body sent, neither-answer, known node, refusal-fails, line clean/abs/node, writers row, node subscribes, node answers — 14 of 14 killed. merge-check.sh on the merge result 081d924: exit 0 (gofmt, vet, go test -race ./...).
Review addressed — head 081d924 (b55a38c, merged with main at 7477346).
**Forgeable ask (blocking).** `link.SignHandOver` signs the ask with the mesh's identity key (`open.Identity`, the key declarations are signed with) over `HandOverContext` ("novox-mesh hand-over v1\n") + the ask's bytes, so the signature is never a declaration's. The ask is `{node, path, by, expires (now+1m), nonce (16 random bytes, hex)}`, sent as `SignedHandOver{ask, signature}`. The engine verifies before reading (mesh-host #74).
**Writers table.** New row "a hand-over asked of a machine", `mesh.node.*.ask.hand-over`, `Writes: isController` (and `designRows`; to-be 45 §1 gains the row in hq #256). The false comment on `AskHandOverSubject` now says the subject bounds who is granted the publish and the signature who is believed.
**KindNode AllowResponses.** Kept: the request/reply needs it, and it is bounded — the node is its machine's engine (root there already), it is delivered only its own subjects (declare, ask.report, ask.hand-over, its _DELIVER), max 1 / 1m, and the controller records nothing from the answer. Narrowing per subject is not something the server's permissions express.
**Test gaps.** `handOverAsked` is the line with its two acts given: `TestAHandOverAsksOnlyAKnownNodeAndFailsOnARefusal` (unknown node → nothing asked; a refused line → nothing asked; the engine's refusal → error, nothing printed; a record → printed with `nox push`; a failing ask → error). `TestAHandOverIsSignedWithAContextANonceAndAnExpiry`, `TestAHandOverAskHasOnePublisher` (node, node tools, module refused at composition; the controller allowed).
**Mutations** (each check removed, a test failed): sign context, nonce, expiry, no signer, signed body sent, neither-answer, known node, refusal-fails, line clean/abs/node, writers row, node subscribes, node answers — 14 of 14 killed.
**merge-check.sh** on the merge result 081d924: exit 0 (gofmt, vet, `go test -race ./...`).
build-agent keeps data (ADR 0233): what it holds is backed up before it moves
route-proxy provides route: its consumers are sent again after it
route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on g14 as build-1791568027361874825 (builds --log build-1791568027361874825).
--- the gate: build-agent, mesh-controller, route-proxy
mesh-controller: ok, 54 tool(s); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
files asking for a setting without saying whether it is trusted: 0
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-09T17:45:02Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-09T17:45:02Z
modules the change moves:
- mesh-controller (changed)
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 3 module(s) in 3 tier(s): build-agent, mesh-controller, route-proxy
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.029s
ok github.com/novox/mesh-controller/cmd/mesh-controller 208.791s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.022s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.029s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.022s
ok github.com/novox/mesh-controller/examples/route-proxy 1.213s
ok github.com/novox/mesh-controller/internal/artifacts 1.048s
ok github.com/novox/mesh-controller/internal/broker 2.561s
ok github.com/novox/mesh-controller/internal/builder 1.747s
ok github.com/novox/mesh-controller/internal/catalogue 4.330s
ok github.com/novox/mesh-controller/internal/conditions 2.338s
ok github.com/novox/mesh-controller/internal/envfile 1.026s
ok github.com/novox/mesh-controller/internal/facts 1.030s
ok github.com/novox/mesh-controller/internal/identity 3.950s
ok github.com/novox/mesh-controller/internal/inventory 70.010s
ok github.com/novox/mesh-controller/internal/lease 17.685s
ok github.com/novox/mesh-controller/internal/licences 3.511s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.008s
ok github.com/novox/mesh-controller/internal/link 50.732s
ok github.com/novox/mesh-controller/internal/lint 1.885s
ok github.com/novox/mesh-controller/internal/outward 1.030s
ok github.com/novox/mesh-controller/internal/overlay 1.023s
ok github.com/novox/mesh-controller/internal/secrets 1.376s
ok github.com/novox/mesh-controller/internal/store 3.126s
ok github.com/novox/mesh-controller/internal/testbus 1.172s
ok github.com/novox/mesh-controller/internal/token 1.011s
**Merge check** at `081d9244`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller, route-proxy)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed
**Delivery plan** — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- tier 2: route-proxy
- ace: receives build-agent, route-proxy
- g14: receives build-agent
- novox: receives mesh-controller, build-agent, route-proxy
- shanks: receives build-agent
- build-agent keeps data (ADR 0233): what it holds is backed up before it moves
- route-proxy provides route: its consumers are sent again after it
- route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on g14 as `build-1791568027361874825` (`builds --log build-1791568027361874825`).
```
--- the gate: build-agent, mesh-controller, route-proxy
mesh-controller: ok, 54 tool(s); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
files asking for a setting without saying whether it is trusted: 0
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-09T17:45:02Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-09T17:45:02Z
modules the change moves:
- mesh-controller (changed)
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 3 module(s) in 3 tier(s): build-agent, mesh-controller, route-proxy
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.029s
ok github.com/novox/mesh-controller/cmd/mesh-controller 208.791s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.022s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.029s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.022s
ok github.com/novox/mesh-controller/examples/route-proxy 1.213s
ok github.com/novox/mesh-controller/internal/artifacts 1.048s
ok github.com/novox/mesh-controller/internal/broker 2.561s
ok github.com/novox/mesh-controller/internal/builder 1.747s
ok github.com/novox/mesh-controller/internal/catalogue 4.330s
ok github.com/novox/mesh-controller/internal/conditions 2.338s
ok github.com/novox/mesh-controller/internal/envfile 1.026s
ok github.com/novox/mesh-controller/internal/facts 1.030s
ok github.com/novox/mesh-controller/internal/identity 3.950s
ok github.com/novox/mesh-controller/internal/inventory 70.010s
ok github.com/novox/mesh-controller/internal/lease 17.685s
ok github.com/novox/mesh-controller/internal/licences 3.511s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.008s
ok github.com/novox/mesh-controller/internal/link 50.732s
ok github.com/novox/mesh-controller/internal/lint 1.885s
ok github.com/novox/mesh-controller/internal/outward 1.030s
ok github.com/novox/mesh-controller/internal/overlay 1.023s
ok github.com/novox/mesh-controller/internal/secrets 1.376s
ok github.com/novox/mesh-controller/internal/store 3.126s
ok github.com/novox/mesh-controller/internal/testbus 1.172s
ok github.com/novox/mesh-controller/internal/token 1.011s
```
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
hq issue 356 (hq pull request named in the thread once open); the engine's side is mesh-host #74, the catalogue's check mesh-catalog #165. A module's condition told the operator to run the node-engine's
hand-overat the machine, as root (issue 339), the mesh had no channel for it, and the engine on the machine's PATH was a build from before the subcommand (the engine's PR fixes that).Reviewers' checklist
handOverLine(cmd/mesh-controller/nodes.go) takes exactly a node and a path: the node a name (not a flag, not empty) the inventory knows (NodeByName); the path absolute andfilepath.Clean(path) == path— no.., no doubled or trailing separator — before anything is asked. The engine judges the same values again and is the one that acts (mesh-host #74).AskHandOver(internal/link/handover.go) refuses an answer that is neither a record nor a refusal, and an unreadable one.node hand-overis anodesubcommand that is not innodeReads, soterminalOnlyrefuses it through every verb andordinaryLinethrough mesh-cli outside the terminal — no new rule, andTestAHandOverIsRefusedThroughEveryVerbholds it four ways (terminalOnly, the generic command verb's composition, the ordinary mesh-cli line, thenodeverb's composition). The ask goes onmesh.node.<node>.ask.hand-over: the controller'smesh.node.>publish grant, and the node's grant gains exactly its own subject and the right to answer what it was asked (AllowResponsesforKindNode; a person still has none). The golden composition (internal/broker/testdata/composed.conf) changed by exactly those two lines.TestAHandOverLineIsJudgedBeforeItIsAsked(ten refusals, the one acceptance),TestAHandOverNamesWhoAsked,TestAHandOverIsRefusedThroughEveryVerb,TestTheUsedAsFoundConditionNamesTheOperatorsLine(the module's health namesnox node hand-over <node> <directory>on the control-node, never the engine's binary, never a path; the condition's words are plain underconditions.PlainWords) (cmd/mesh-controller);TestTheHandOverAskAndAnswerKeepTheirFieldNames(held by the engine's twin),TestAHandOverIsAskedOfTheMachineAndItsAnswerComesBack(over a bus: the record and the refusal come back whole, a machine with no engine listening is said as not answering, an empty answer is refused, no bus is refused),TestAMachineHearsItsOwnHandOverAskAndMayAnswerIt(internal/link);TestOnlyWhatCanBeAskedMayAnswernow holds that a node answers its one ask and a person answers nothing (internal/broker).What changes
node hand-over <node> <directory>: judges the line, asks the node's engine with who asked (MESH_CALLER, as every verb's caller is recorded — " through mesh-cli on " — or "the controller's terminal"), prints the engine's answer and thatpush <node>applies it now.broker.AskHandOverSubject, the node's subscribe grant andAllowResponses;link.AskHandOverwith the field names the engine holds.noxline with the machine; the condition's "needs" line is plain (the line and the directory are in the summary and the evidence);nox-mesh-host overlay takeandenrolin the network command's and the lab's texts use the binary's real name (install-time acts, at the machine).Checks.
merge-check.shpassed locally on the merge result (this branch on top of main at1c7c385, after #184 and #185 merged): gofmt, vet,go test -race ./..., 26 packages ok. Not merged.Order. This first — it composes the node's grant; then mesh-host #74. The catalogue's and hq's PRs in any order. Live, after both:
nox node hand-over <control-node> <the messenger's data directory>on the control-node, then its next apply clears the messenger's condition.Delivery
novox/mesh-controller@081d9244d6dd— delivered since 2026-10-09T18:13:21ZDelivery plan — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
Machines
Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.The record: hq #256 (issue 356). The engine's side is mesh-host #74 (merge after this one), the catalogue's check mesh-catalog #165.
7ba3274408to9006c82393Merge check at
7ba32744mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller, route-proxy)mesh/repo-check: PASS — its merge-check.sh passedDelivery plan — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
Run by the build seat on ace as
build-1791563824735966092(builds --log build-1791563824735966092).Merge check at
9006c823mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller, route-proxy)mesh/repo-check: PASS — its merge-check.sh passedDelivery plan — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
Run by the build seat on novox as
build-1791563916409013292(builds --log build-1791563916409013292).Review addressed — head
081d924(b55a38c, merged with main at7477346).Forgeable ask (blocking).
link.SignHandOversigns the ask with the mesh's identity key (open.Identity, the key declarations are signed with) overHandOverContext("novox-mesh hand-over v1\n") + the ask's bytes, so the signature is never a declaration's. The ask is{node, path, by, expires (now+1m), nonce (16 random bytes, hex)}, sent asSignedHandOver{ask, signature}. The engine verifies before reading (mesh-host #74).Writers table. New row "a hand-over asked of a machine",
mesh.node.*.ask.hand-over,Writes: isController(anddesignRows; to-be 45 §1 gains the row in hq #256). The false comment onAskHandOverSubjectnow says the subject bounds who is granted the publish and the signature who is believed.KindNode AllowResponses. Kept: the request/reply needs it, and it is bounded — the node is its machine's engine (root there already), it is delivered only its own subjects (declare, ask.report, ask.hand-over, its _DELIVER), max 1 / 1m, and the controller records nothing from the answer. Narrowing per subject is not something the server's permissions express.
Test gaps.
handOverAskedis the line with its two acts given:TestAHandOverAsksOnlyAKnownNodeAndFailsOnARefusal(unknown node → nothing asked; a refused line → nothing asked; the engine's refusal → error, nothing printed; a record → printed withnox push; a failing ask → error).TestAHandOverIsSignedWithAContextANonceAndAnExpiry,TestAHandOverAskHasOnePublisher(node, node tools, module refused at composition; the controller allowed).Mutations (each check removed, a test failed): sign context, nonce, expiry, no signer, signed body sent, neither-answer, known node, refusal-fails, line clean/abs/node, writers row, node subscribes, node answers — 14 of 14 killed.
merge-check.sh on the merge result
081d924: exit 0 (gofmt, vet,go test -race ./...).Merge check at
081d9244mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller, route-proxy)mesh/repo-check: PASS — its merge-check.sh passedDelivery plan — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
Run by the build seat on g14 as
build-1791568027361874825(builds --log build-1791568027361874825).