Keep the controller and node-engine at the build a machine was last sent over an older record (hq issue 201) #273

Merged
mesh-admin merged 6 commits from fix/201-a-push-never-downgrades-the-core into main 2026-10-12 18:52:05 +00:00
Contributor

What

Every send but a person's push (every send through sendToEach: plans, releases, healers, rotations, secrets given) composes mesh-controller and mesh-host at the build the machine was last sent when the mesh's record of it is older by the builds' registration order (issue 219), and carries everything else. Nothing is refused and nothing is retried. A plan whose own build is the older one finds its gate superseded by the kept build (issue 352) and ends.

Exceptions: a gate's own put-back carries its modules back (sendScope.puttingBack, set in gateFailed and sendRollbacks). A sent build that failed its gate is never kept, so when a put-back's own send was refused, the next automatic send completes the put-back.

A warning condition core.<component>.<machine>.core-downgrade-kept says it. It names the two ways out: push <node> takes the older build, and a newer merge or rebuild <module> moves the record forward. It is cleared after any send that carries the record or does not carry the module, a person's push included (overTheBus.declare).

If the kept build's manifest is no longer in the build records, the send to that machine is refused and says why, as for a recorded module (ADR 0245). The other machines are still sent.

Why

On 2026-10-02 a plan sent the control node a controller older than the one running there, and the mesh went quiet for ten minutes. ADR 0185 took the outage out of it, and the race stayed open. The decision of 2026-10-11 on issue 201 closes the class without pinning the trigger. Review 90: the first version refused the whole send, and that wedged a machine after a gate put-back whose own send was refused.

Design limits chosen

  • "Runs" is read as "was last sent" (node.sent_builds), as the gate and ADR 0236's checks read it.
  • Order is the asked time, read from the module's 50 newest builds. A retry or rebuild of an old commit is asked anew and counts as newer, as registration does, so the guard does not stop that move. A build missing from the records is not proved older.
  • Only the controller and the node-engine are kept, not the node tools.
  • The node-engine half of the decision (record what each core resource was told) is issue 234's send record.

How it was tested

  • TestACoreModuleIsKeptOverAnOlderRecord (no store): the order, a failed gate, the put-back scope, unknown builds.
  • TestReplay201 (store): a plan's judged send goes, keeps c2 and composes its manifest, and raises the condition. The put-back carries it back. A send that carried c2 leaves the condition open, and a send carrying the record clears it. It fails with the keep disabled.
  • TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend (store): the gate failed c2 and the record is back at c1. A healer's send goes and keeps nothing. It fails without the failed-gate rule.
  • sh merge-check.sh against a throwaway postgres 17: exit 0.
  • The two store tests are not yet listed in testdata/store-tests, because open PR #266 changes that file.

Fixes issue 201

What Every send but a person's push (every send through sendToEach: plans, releases, healers, rotations, secrets given) composes mesh-controller and mesh-host at the build the machine was last sent when the mesh's record of it is older by the builds' registration order (issue 219), and carries everything else. Nothing is refused and nothing is retried. A plan whose own build is the older one finds its gate superseded by the kept build (issue 352) and ends. Exceptions: a gate's own put-back carries its modules back (sendScope.puttingBack, set in gateFailed and sendRollbacks). A sent build that failed its gate is never kept, so when a put-back's own send was refused, the next automatic send completes the put-back. A warning condition `core.<component>.<machine>.core-downgrade-kept` says it. It names the two ways out: `push <node>` takes the older build, and a newer merge or `rebuild <module>` moves the record forward. It is cleared after any send that carries the record or does not carry the module, a person's push included (overTheBus.declare). If the kept build's manifest is no longer in the build records, the send to that machine is refused and says why, as for a recorded module (ADR 0245). The other machines are still sent. Why On 2026-10-02 a plan sent the control node a controller older than the one running there, and the mesh went quiet for ten minutes. ADR 0185 took the outage out of it, and the race stayed open. The decision of 2026-10-11 on issue 201 closes the class without pinning the trigger. Review 90: the first version refused the whole send, and that wedged a machine after a gate put-back whose own send was refused. Design limits chosen - "Runs" is read as "was last sent" (node.sent_builds), as the gate and ADR 0236's checks read it. - Order is the asked time, read from the module's 50 newest builds. A retry or rebuild of an old commit is asked anew and counts as newer, as registration does, so the guard does not stop that move. A build missing from the records is not proved older. - Only the controller and the node-engine are kept, not the node tools. - The node-engine half of the decision (record what each core resource was told) is issue 234's send record. How it was tested - TestACoreModuleIsKeptOverAnOlderRecord (no store): the order, a failed gate, the put-back scope, unknown builds. - TestReplay201 (store): a plan's judged send goes, keeps c2 and composes its manifest, and raises the condition. The put-back carries it back. A send that carried c2 leaves the condition open, and a send carrying the record clears it. It fails with the keep disabled. - TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend (store): the gate failed c2 and the record is back at c1. A healer's send goes and keeps nothing. It fails without the failed-gate rule. - `sh merge-check.sh` against a throwaway postgres 17: exit 0. - The two store tests are not yet listed in testdata/store-tests, because open PR #266 changes that file. Fixes issue 201
mesh-admin added 1 commit 2026-10-12 16:21:29 +00:00
Refuse a send that puts the controller or node-engine behind its machine's build (issue 201)
mesh/merge-gate out of date: judged against trunk f10aedac5880, the trunk is now f8daec01d3f0; judged again on a recheck or when it is merged
mesh/repo-check out of date: judged against trunk f10aedac5880, the trunk is now f8daec01d3f0; judged again on a recheck or when it is merged
mesh/delivery superseded: a newer head of the same pull request
9038d4b0d3
On 2026-10-02 a plan sent the control node a controller older than the one
running there, whose seat row the newer build had widened; the older binary
refused the row and the mesh went quiet for ten minutes. ADR 0185 took the
outage out of it, and the race stayed open.

Every send but a person's push now refuses a move of mesh-controller or
mesh-host to a build asked before the one its machine was last sent (the
builds' registration order, issue 219), whatever composed it — gated or not.
A gate's own put-back is the one exception, for the modules it puts back,
and says so in its send's scope. The refusal is the send's error, which the
plan keeps as its note, and a warning condition on the machine, cleared by
the next send there that carries no such move.
Author
Contributor

Delivery novox/mesh-controller@b3787e4d8eb2 — delivered since 2026-10-12T18:57:32Z

Delivery plan — builds mesh-controller → novox; no bus step

  • tier 0: mesh-controller
  • novox: receives mesh-controller

Machines

  • mesh-controller on novox: passed — healthy 3 times over 3m42s
  • mesh-controller on the rest running it: sent

Transitions

  • 2026-10-12 18:39 (new) → proposed (announced): novox/mesh-controller#273's head announced
  • 2026-10-12 18:46 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
  • 2026-10-12 18:46 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
  • 2026-10-12 18:52 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
  • 2026-10-12 18:52 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 — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit
  • 2026-10-12 18:57 delivering → delivered (done): its walk is done, carrying its own commit: 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@b3787e4d8eb2` — **delivered** since 2026-10-12T18:57:32Z **Delivery plan** — builds mesh-controller → novox; no bus step - tier 0: mesh-controller - novox: receives mesh-controller **Machines** - mesh-controller on novox: passed — healthy 3 times over 3m42s - mesh-controller on the rest running it: sent **Transitions** - 2026-10-12 18:39 (new) → proposed (announced): novox/mesh-controller#273's head announced - 2026-10-12 18:46 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit - 2026-10-12 18:46 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail - 2026-10-12 18:52 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move - 2026-10-12 18:52 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 — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit - 2026-10-12 18:57 delivering → delivered (done): its walk is done, carrying its own commit: 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`.
Author
Contributor

Merge check at 9038d4b0
Judged: head 9038d4b0d317 merged into trunk f10aedac5880; read beside it: mesh-catalog 23ea0f431faf, mesh-controller-main f10aedac5880, mesh-host a1f9856b3957, mesh-tools 954e1a53eef9

  • mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: mesh-controller)
  • mesh/repo-check: PASS — its merge-check.sh passed

Delivery plan — builds mesh-controller → novox; no bus step

  • tier 0: mesh-controller
  • novox: receives mesh-controller
  • read by no module's build: cmd/mesh-controller/issue201_test.go

Run by the build seat on ace as build-1791822107369334674 (builds --log build-1791822107369334674).

--- the gate: mesh-controller
mesh-controller: ok, 58 tool(s); WARNING: merge-window ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); 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: 1
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-12T16:17:25Z 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-12T16:17:25Z

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 2 module(s) in 2 tier(s): build-agent, mesh-controller
--- its merge-check.sh (go toolchain)
ok  	github.com/novox/mesh-controller/cmd/mesh-builder	1.049s
ok  	github.com/novox/mesh-controller/cmd/mesh-controller	242.027s
ok  	github.com/novox/mesh-controller/examples/objectstore-provisioner	1.014s
ok  	github.com/novox/mesh-controller/examples/postgres-provisioner	1.019s
ok  	github.com/novox/mesh-controller/examples/redis-provisioner	1.013s
ok  	github.com/novox/mesh-controller/examples/route-proxy	1.124s
ok  	github.com/novox/mesh-controller/internal/artifacts	1.059s
?   	github.com/novox/mesh-controller/internal/beside	[no test files]
ok  	github.com/novox/mesh-controller/internal/broker	3.915s
ok  	github.com/novox/mesh-controller/internal/builder	35.190s
ok  	github.com/novox/mesh-controller/internal/catalogue	7.337s
ok  	github.com/novox/mesh-controller/internal/conditions	2.569s
ok  	github.com/novox/mesh-controller/internal/envfile	1.059s
ok  	github.com/novox/mesh-controller/internal/facts	1.068s
ok  	github.com/novox/mesh-controller/internal/identity	4.314s
ok  	github.com/novox/mesh-controller/internal/inventory	89.508s
ok  	github.com/novox/mesh-controller/internal/lease	17.701s
ok  	github.com/novox/mesh-controller/internal/licences	3.894s
ok  	github.com/novox/mesh-controller/internal/licences/adapters	1.055s
ok  	github.com/novox/mesh-controller/internal/link	59.452s
ok  	github.com/novox/mesh-controller/internal/lint	2.244s
ok  	github.com/novox/mesh-controller/internal/outward	1.084s
ok  	github.com/novox/mesh-controller/internal/overlay	1.072s
ok  	github.com/novox/mesh-controller/internal/secrets	1.448s
ok  	github.com/novox/mesh-controller/internal/store	3.371s
ok  	github.com/novox/mesh-controller/internal/testbus	1.216s
ok  	github.com/novox/mesh-controller/internal/token	1.016s
store tests, each run against the store:
  ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.37s)
  ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.38s)
  ./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.38s)
  ./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.36s)
  ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.37s)
  ./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.32s)
  ./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.40s)
  ./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.28s)
  ./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.46s)
  ./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.45s)
  ./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.39s)
  ./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.40s)
  ./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.44s)
  ./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.40s)
  ./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.42s)
  ./cmd/mesh-controller --- PASS: TestReplay237 (0.39s)
  ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.34s)
  ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.35s)
  ./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.37s)
  ./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.43s)
  ./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.45s)
  ./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.45s)
  ./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.24s)
  ./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.24s)
  ./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.23s)
  ./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.22s)
  ./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.23s)
  ./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.24s)
**Merge check** at `9038d4b0` Judged: head `9038d4b0d317` merged into trunk `f10aedac5880`; read beside it: mesh-catalog `23ea0f431faf`, mesh-controller-main `f10aedac5880`, mesh-host `a1f9856b3957`, mesh-tools `954e1a53eef9` - `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: mesh-controller) - `mesh/repo-check`: **PASS** — its merge-check.sh passed **Delivery plan** — builds mesh-controller → novox; no bus step - tier 0: mesh-controller - novox: receives mesh-controller - read by no module's build: cmd/mesh-controller/issue201_test.go Run by the build seat on ace as `build-1791822107369334674` (`builds --log build-1791822107369334674`). ``` --- the gate: mesh-controller mesh-controller: ok, 58 tool(s); WARNING: merge-window ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); 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: 1 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-12T16:17:25Z 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-12T16:17:25Z 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 2 module(s) in 2 tier(s): build-agent, mesh-controller --- its merge-check.sh (go toolchain) ok github.com/novox/mesh-controller/cmd/mesh-builder 1.049s ok github.com/novox/mesh-controller/cmd/mesh-controller 242.027s ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.014s ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.019s ok github.com/novox/mesh-controller/examples/redis-provisioner 1.013s ok github.com/novox/mesh-controller/examples/route-proxy 1.124s ok github.com/novox/mesh-controller/internal/artifacts 1.059s ? github.com/novox/mesh-controller/internal/beside [no test files] ok github.com/novox/mesh-controller/internal/broker 3.915s ok github.com/novox/mesh-controller/internal/builder 35.190s ok github.com/novox/mesh-controller/internal/catalogue 7.337s ok github.com/novox/mesh-controller/internal/conditions 2.569s ok github.com/novox/mesh-controller/internal/envfile 1.059s ok github.com/novox/mesh-controller/internal/facts 1.068s ok github.com/novox/mesh-controller/internal/identity 4.314s ok github.com/novox/mesh-controller/internal/inventory 89.508s ok github.com/novox/mesh-controller/internal/lease 17.701s ok github.com/novox/mesh-controller/internal/licences 3.894s ok github.com/novox/mesh-controller/internal/licences/adapters 1.055s ok github.com/novox/mesh-controller/internal/link 59.452s ok github.com/novox/mesh-controller/internal/lint 2.244s ok github.com/novox/mesh-controller/internal/outward 1.084s ok github.com/novox/mesh-controller/internal/overlay 1.072s ok github.com/novox/mesh-controller/internal/secrets 1.448s ok github.com/novox/mesh-controller/internal/store 3.371s ok github.com/novox/mesh-controller/internal/testbus 1.216s ok github.com/novox/mesh-controller/internal/token 1.016s store tests, each run against the store: ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.37s) ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.38s) ./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.38s) ./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.36s) ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.37s) ./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.32s) ./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.40s) ./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.28s) ./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.46s) ./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.45s) ./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.39s) ./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.40s) ./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.44s) ./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.40s) ./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.42s) ./cmd/mesh-controller --- PASS: TestReplay237 (0.39s) ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.34s) ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.35s) ./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.37s) ./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.43s) ./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.45s) ./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.45s) ./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.24s) ./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.24s) ./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.23s) ./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.22s) ./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.23s) ./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.24s) ```
mesh-admin left a comment
Author
Contributor

Verdict: request changes at 9038d4b0d3

Independent review for hq issue 201 (a push recreated the controller at a digest older than its seat row). The guard is well placed and its tests are good, but it wedges a machine in one state that the code itself produces, and the condition does not clear when a person acts. Details below.

What I ran (head 9038d4b, local clone; also merges cleanly onto main f10aeda)

  • go vet ./...: clean.
  • go test -race -count=1 -run 'TestReplay201|TestACoreModule|TestARefusedCoreDowngrade' -v ./cmd/mesh-controller/ against a throwaway Postgres 18 (MESH_TEST_POSTGRES): all 3 PASS, and TestReplay201 ran against the store (0.18s).
  • I disabled the guard (refuseCoreDowngrades returned nil, nil at once), and TestReplay201 FAILED with "a plan's send of the older controller to the machine running the newer is refused: ". So the test proves the guard.
  • sh merge-check.sh with MESH_TEST_POSTGRES: exit 0, with no FAIL and no NOT RUN lines.
  • Statuses on the head: mesh/merge-gate success ("head 9038d4b0d3 merged into trunk f10aedac58 — pass … every machine composes"), mesh/repo-check success, mesh/delivery success ("ready"). The forge says it is mergeable. There are no reviews before this one.

Checklist

1. Legitimate rollbacks.

  • A gate's put-back (gateFailed, sendRollbacks, and through them failCarried/putBackBroken) carries puttingBack together with its modules. It is exempt only for the modules it puts back. That is correct.
  • A person's push (pushCommand) does not go through sendToEach/ungatedIn. The bus step returns early on scope.person. Neither is touched.
  • A revert merge is a new commit with a new build that is asked after the merge. buildAsked returns the newest recorded build of the commit, so the revert is judged newer. Issue 280's "standing build" registers the old artifacts at the new commit, so it is still judged newer.
  • The release backlog re-release goes through gatedSend with judged set, so the guard applies to it. See finding A.

2. Wedging (finding A, blocking). errCoreDowngrade is an ordinary step error, and advanceHeld keeps it as the plan's note with "— tried again" on every tick, without a bound. Only three things end it: a newer registered build, a person's push, or the machine's sent record changing.

The trouble is that the guard cannot tell the 201 race apart from a gate's put-back that was registered and then not sent. In gateFailed, RestoreModule(previous) runs first and the send follows. If that send is refused, the record is at the older build while the machine was sent the failed, newer-asked one. notBack says this already. The send can be refused because of errUngated from another build registered during the gate window (two merges a minute apart is exactly the 201 setting), errBusWaits, or a send error. TestReplay201's fixture is exactly this state: the record is restored to the build before, and the machine was sent the newer one.

Before this PR, the next automated send to that machine finished the put-back, because the older build is gated. After it, every non-person send to that machine is refused whole: the plans' first and rest sends, release plans, healers, rotations, secrets given, and the hub send. Each walk retries forever. Because only one walk runs at a time (ADR 0276), the open walk holds every other walk too. Nothing but a person or a new merge ends it.

Suggested fix: a build that failed its gate is never "ahead". Do not count a move as a downgrade when its From build has a recorded failed gate (inv.GateFailed on that build's id, or the gate record's rollback state NotRolledBack/RollingBack with previous == To). Add a test for that: gate failed, put-back send refused, then a healer send goes through.

3. Order (no blocking finding). The comparison uses asked time (or recorded time), which is the same order RegisterModule uses (built_asked <=). The two orders differ only for builds that are recorded but not registered. Off-trunk builds have distinct commits. Failed-gate builds lead to finding A. Builds outside the 50-newest window, or with no record, leave the move unproved and let it pass (fail open), which is the right direction.

I found no case where a genuinely newer trunk build is judged older. A plan retry or a rebuild of an old commit is asked anew, so it becomes "newer" by this order. That matches registration and the decision's wording ("by the build's registration order"), but it means the guard does not stop that kind of downgrade. A comment should say so.

Minor: "the build its machine runs" is implemented as the build it was last sent (SentBuilds), not the one it reports running. That is fine as a choice, but the doc comment and the condition should say "was sent".

4. Condition (finding B, should fix, plus wording).

  • B: the condition is cleared only inside ungatedIn, and ungatedIn is never reached by a person's act: pushCommand bypasses sendToEach, and scope.person returns before the check. So after the person does what the condition asks, the warning stays until some later automated send reaches that machine, which could be hours on a quiet machine. Clear it on the person's path as well, for example by running refuseCoreDowngrades' clear for the pushed machine(s) when the push carries no downgrade, or by clearing on any successful send to the node.
  • Wording: "Needs: decide which build of the controller the mesh should hold; the details say which." does not name an act. Name the two ways out. push <node> accepts the older build, because it sends the record. A newer merge or rebuild mesh-controller moves the record forward. Also consider saying in the explanation that every automated send to that machine is held until then (that is what the operator will notice), and whether Warning is the right severity for that.

5. Tests and checks: they pass, as listed above.

6. Statuses: all three are green and read.

Other notes (not blocking)

  • Switching ungatedIn to machineMoves(..., true) and then skipping f.gated(mv.Module, mv.To) gives the same waiting list as before. I checked this against moves().
  • When the bus holder is added only for its user list and would be downgraded, it is skipped with a log line and the condition is raised. That is consistent.
  • The node-tools runtime (ComponentNodeTools) is not guarded. That matches the decision, which names only the controller and the node-engine.
Verdict: request changes at 9038d4b0d317d27be0183354b3d4b73cd3b89b9c Independent review for hq issue 201 (a push recreated the controller at a digest older than its seat row). The guard is well placed and its tests are good, but it wedges a machine in one state that the code itself produces, and the condition does not clear when a person acts. Details below. ## What I ran (head 9038d4b, local clone; also merges cleanly onto main f10aeda) - `go vet ./...`: clean. - `go test -race -count=1 -run 'TestReplay201|TestACoreModule|TestARefusedCoreDowngrade' -v ./cmd/mesh-controller/` against a throwaway Postgres 18 (MESH_TEST_POSTGRES): all 3 PASS, and TestReplay201 ran against the store (0.18s). - I disabled the guard (`refuseCoreDowngrades` returned nil, nil at once), and TestReplay201 FAILED with "a plan's send of the older controller to the machine running the newer is refused: <nil>". So the test proves the guard. - `sh merge-check.sh` with MESH_TEST_POSTGRES: exit 0, with no FAIL and no NOT RUN lines. - Statuses on the head: mesh/merge-gate success ("head 9038d4b0d317 merged into trunk f10aedac5880 — pass … every machine composes"), mesh/repo-check success, mesh/delivery success ("ready"). The forge says it is mergeable. There are no reviews before this one. ## Checklist **1. Legitimate rollbacks.** - A gate's put-back (`gateFailed`, `sendRollbacks`, and through them `failCarried`/`putBackBroken`) carries `puttingBack` together with its modules. It is exempt only for the modules it puts back. That is correct. - A person's push (`pushCommand`) does not go through `sendToEach`/`ungatedIn`. The bus step returns early on `scope.person`. Neither is touched. - A revert merge is a new commit with a new build that is asked after the merge. `buildAsked` returns the newest recorded build of the commit, so the revert is judged newer. Issue 280's "standing build" registers the old artifacts at the new commit, so it is still judged newer. - The release backlog re-release goes through `gatedSend` with `judged` set, so the guard applies to it. See finding A. **2. Wedging (finding A, blocking).** `errCoreDowngrade` is an ordinary step error, and `advanceHeld` keeps it as the plan's note with "— tried again" on every tick, without a bound. Only three things end it: a newer registered build, a person's push, or the machine's sent record changing. The trouble is that the guard cannot tell the 201 race apart from **a gate's put-back that was registered and then not sent**. In `gateFailed`, `RestoreModule(previous)` runs first and the send follows. If that send is refused, the record is at the older build while the machine was sent the failed, newer-asked one. `notBack` says this already. The send can be refused because of `errUngated` from another build registered during the gate window (two merges a minute apart is exactly the 201 setting), `errBusWaits`, or a send error. TestReplay201's fixture is exactly this state: the record is restored to the build before, and the machine was sent the newer one. Before this PR, the next automated send to that machine finished the put-back, because the older build is gated. After it, every non-person send to that machine is refused whole: the plans' first and rest sends, release plans, healers, rotations, secrets given, and the hub send. Each walk retries forever. Because only one walk runs at a time (ADR 0276), the open walk holds every other walk too. Nothing but a person or a new merge ends it. Suggested fix: a build that failed its gate is never "ahead". Do not count a move as a downgrade when its From build has a recorded failed gate (`inv.GateFailed` on that build's id, or the gate record's rollback state NotRolledBack/RollingBack with `previous == To`). Add a test for that: gate failed, put-back send refused, then a healer send goes through. **3. Order (no blocking finding).** The comparison uses asked time (or recorded time), which is the same order `RegisterModule` uses (`built_asked <=`). The two orders differ only for builds that are recorded but not registered. Off-trunk builds have distinct commits. Failed-gate builds lead to finding A. Builds outside the 50-newest window, or with no record, leave the move unproved and let it pass (fail open), which is the right direction. I found no case where a genuinely newer trunk build is judged older. A plan retry or a `rebuild` of an old commit is asked anew, so it becomes "newer" by this order. That matches registration and the decision's wording ("by the build's registration order"), but it means the guard does not stop that kind of downgrade. A comment should say so. Minor: "the build its machine runs" is implemented as the build it was last **sent** (`SentBuilds`), not the one it reports running. That is fine as a choice, but the doc comment and the condition should say "was sent". **4. Condition (finding B, should fix, plus wording).** - B: the condition is cleared only inside `ungatedIn`, and `ungatedIn` is never reached by a person's act: `pushCommand` bypasses `sendToEach`, and `scope.person` returns before the check. So after the person does what the condition asks, the warning stays until some later automated send reaches that machine, which could be hours on a quiet machine. Clear it on the person's path as well, for example by running `refuseCoreDowngrades`' clear for the pushed machine(s) when the push carries no downgrade, or by clearing on any successful send to the node. - Wording: "Needs: decide which build of the controller the mesh should hold; the details say which." does not name an act. Name the two ways out. `push <node>` accepts the older build, because it sends the record. A newer merge or `rebuild mesh-controller` moves the record forward. Also consider saying in the explanation that every automated send to that machine is held until then (that is what the operator will notice), and whether Warning is the right severity for that. **5. Tests and checks:** they pass, as listed above. **6. Statuses:** all three are green and read. ## Other notes (not blocking) - Switching `ungatedIn` to `machineMoves(..., true)` and then skipping `f.gated(mv.Module, mv.To)` gives the same `waiting` list as before. I checked this against `moves()`. - When the bus holder is added only for its user list and would be downgraded, it is skipped with a log line and the condition is raised. That is consistent. - The node-tools runtime (ComponentNodeTools) is not guarded. That matches the decision, which names only the controller and the node-engine.
jschoubben added 2 commits 2026-10-12 16:51:19 +00:00
Keep the core over an older record instead of refusing the send (issue 201, review 90)
mesh/merge-gate out of date: judged against trunk f8daec01d3f0, the trunk is now ba685b17f5e1; judged again on a recheck or when it is merged
mesh/repo-check out of date: judged against trunk f8daec01d3f0, the trunk is now ba685b17f5e1; judged again on a recheck or when it is merged
mesh/delivery superseded: a newer head of the same pull request
d170491256
Refusing the whole send wedged a machine whose gate put back the
controller and whose put-back send was refused: every later automatic
send there was refused, retried each tick, and held up every other walk.

A send now composes the controller and the node-engine at the build the
machine was last sent when the mesh's record is older, and carries the
rest; nothing is refused or retried, and a plan whose own build is the
older one ends with its gate superseded. A sent build that failed its
gate is never kept, so the next send completes a put-back. The condition
names the two ways out and clears on any send that carries the record,
a person's push included.
mesh-admin changed title from Refuse a send that puts the controller or node-engine behind its machine's build (hq issue 201) to Keep the controller and node-engine at the build a machine was last sent over an older record (hq issue 201) 2026-10-12 16:51:30 +00:00
Author
Contributor

Merge check at d1704912
Judged: head d17049125655 merged into trunk f8daec01d3f0; read beside it: mesh-catalog 23ea0f431faf, mesh-controller-main f8daec01d3f0, mesh-host a1f9856b3957, mesh-tools 954e1a53eef9

  • mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: mesh-controller)
  • mesh/repo-check: PASS — its merge-check.sh passed

Delivery plan — builds mesh-controller → novox; no bus step

  • tier 0: mesh-controller
  • novox: receives mesh-controller
  • read by no module's build: cmd/mesh-controller/issue201_test.go

Run by the build seat on g14 as build-1791823881989317567 (builds --log build-1791823881989317567).

--- the gate: mesh-controller
mesh-controller: ok, 58 tool(s); WARNING: merge-window ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); 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: 1
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-12T16:48: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-12T16:48: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 1 module(s) in 1 tier(s): mesh-controller

notes:
  - cmd/mesh-controller/issue201_test.go read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok  	github.com/novox/mesh-controller/cmd/mesh-builder	1.036s
ok  	github.com/novox/mesh-controller/cmd/mesh-controller	250.902s
ok  	github.com/novox/mesh-controller/examples/objectstore-provisioner	1.017s
ok  	github.com/novox/mesh-controller/examples/postgres-provisioner	1.026s
ok  	github.com/novox/mesh-controller/examples/redis-provisioner	1.015s
ok  	github.com/novox/mesh-controller/examples/route-proxy	1.155s
ok  	github.com/novox/mesh-controller/internal/artifacts	1.054s
?   	github.com/novox/mesh-controller/internal/beside	[no test files]
ok  	github.com/novox/mesh-controller/internal/broker	4.000s
ok  	github.com/novox/mesh-controller/internal/builder	29.799s
ok  	github.com/novox/mesh-controller/internal/catalogue	7.125s
ok  	github.com/novox/mesh-controller/internal/conditions	2.435s
ok  	github.com/novox/mesh-controller/internal/envfile	1.030s
ok  	github.com/novox/mesh-controller/internal/facts	1.035s
ok  	github.com/novox/mesh-controller/internal/identity	4.241s
ok  	github.com/novox/mesh-controller/internal/inventory	82.260s
ok  	github.com/novox/mesh-controller/internal/lease	17.701s
ok  	github.com/novox/mesh-controller/internal/licences	3.885s
ok  	github.com/novox/mesh-controller/internal/licences/adapters	1.012s
ok  	github.com/novox/mesh-controller/internal/link	58.193s
ok  	github.com/novox/mesh-controller/internal/lint	2.197s
ok  	github.com/novox/mesh-controller/internal/outward	1.039s
ok  	github.com/novox/mesh-controller/internal/overlay	1.026s
ok  	github.com/novox/mesh-controller/internal/secrets	1.423s
ok  	github.com/novox/mesh-controller/internal/store	3.268s
ok  	github.com/novox/mesh-controller/internal/testbus	1.189s
ok  	github.com/novox/mesh-controller/internal/token	1.018s
store tests, each run against the store:
  ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.35s)
  ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.37s)
  ./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.35s)
  ./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.33s)
  ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.33s)
  ./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.31s)
  ./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.35s)
  ./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.26s)
  ./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.39s)
  ./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.39s)
  ./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.34s)
  ./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.36s)
  ./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.43s)
  ./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.36s)
  ./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.56s)
  ./cmd/mesh-controller --- PASS: TestReplay237 (0.33s)
  ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.36s)
  ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.34s)
  ./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.35s)
  ./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.37s)
  ./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.42s)
  ./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.38s)
  ./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.21s)
  ./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.20s)
  ./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.30s)
  ./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.21s)
  ./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.21s)
  ./internal/inventory --- PASS: TestAPlanIdHoldingAQuoteIsReadAsAPlainId (0.20s)
  ./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.20s)
**Merge check** at `d1704912` Judged: head `d17049125655` merged into trunk `f8daec01d3f0`; read beside it: mesh-catalog `23ea0f431faf`, mesh-controller-main `f8daec01d3f0`, mesh-host `a1f9856b3957`, mesh-tools `954e1a53eef9` - `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: mesh-controller) - `mesh/repo-check`: **PASS** — its merge-check.sh passed **Delivery plan** — builds mesh-controller → novox; no bus step - tier 0: mesh-controller - novox: receives mesh-controller - read by no module's build: cmd/mesh-controller/issue201_test.go Run by the build seat on g14 as `build-1791823881989317567` (`builds --log build-1791823881989317567`). ``` --- the gate: mesh-controller mesh-controller: ok, 58 tool(s); WARNING: merge-window ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); 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: 1 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-12T16:48: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-12T16:48: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 1 module(s) in 1 tier(s): mesh-controller notes: - cmd/mesh-controller/issue201_test.go read by no module's build, and rebuild nothing (issue 280) --- its merge-check.sh (go toolchain) ok github.com/novox/mesh-controller/cmd/mesh-builder 1.036s ok github.com/novox/mesh-controller/cmd/mesh-controller 250.902s ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.017s ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.026s ok github.com/novox/mesh-controller/examples/redis-provisioner 1.015s ok github.com/novox/mesh-controller/examples/route-proxy 1.155s ok github.com/novox/mesh-controller/internal/artifacts 1.054s ? github.com/novox/mesh-controller/internal/beside [no test files] ok github.com/novox/mesh-controller/internal/broker 4.000s ok github.com/novox/mesh-controller/internal/builder 29.799s ok github.com/novox/mesh-controller/internal/catalogue 7.125s ok github.com/novox/mesh-controller/internal/conditions 2.435s ok github.com/novox/mesh-controller/internal/envfile 1.030s ok github.com/novox/mesh-controller/internal/facts 1.035s ok github.com/novox/mesh-controller/internal/identity 4.241s ok github.com/novox/mesh-controller/internal/inventory 82.260s ok github.com/novox/mesh-controller/internal/lease 17.701s ok github.com/novox/mesh-controller/internal/licences 3.885s ok github.com/novox/mesh-controller/internal/licences/adapters 1.012s ok github.com/novox/mesh-controller/internal/link 58.193s ok github.com/novox/mesh-controller/internal/lint 2.197s ok github.com/novox/mesh-controller/internal/outward 1.039s ok github.com/novox/mesh-controller/internal/overlay 1.026s ok github.com/novox/mesh-controller/internal/secrets 1.423s ok github.com/novox/mesh-controller/internal/store 3.268s ok github.com/novox/mesh-controller/internal/testbus 1.189s ok github.com/novox/mesh-controller/internal/token 1.018s store tests, each run against the store: ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.35s) ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.37s) ./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.35s) ./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.33s) ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.33s) ./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.31s) ./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.35s) ./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.26s) ./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.39s) ./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.39s) ./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.34s) ./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.36s) ./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.43s) ./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.36s) ./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.56s) ./cmd/mesh-controller --- PASS: TestReplay237 (0.33s) ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.36s) ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.34s) ./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.35s) ./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.37s) ./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.42s) ./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.38s) ./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.21s) ./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.20s) ./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.30s) ./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.21s) ./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.21s) ./internal/inventory --- PASS: TestAPlanIdHoldingAQuoteIsReadAsAPlainId (0.20s) ./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.20s) ```
mesh-admin left a comment
Author
Contributor

Verdict: request changes at d170491256

Re-review against review 90. Keeping the core module instead of refusing the send fixes what review 90 raised: a send is no longer blocked, and a build that failed its gate is no longer kept. But a send that keeps the core module while carrying a gate now lets that gate be superseded at once, so the machine's other new builds go unjudged. Details below.

What I ran (head d170491, throwaway Postgres 18)

  • go vet ./...: clean.
  • go test -race on TestReplay201, TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend and TestACoreModuleIsKeptOverAnOlderRecord: all PASS against the store.
  • I removed the from.failedGate exemption, and TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend FAILED ("the failed controller was kept over the build put back"). I made coreKept return nothing, and TestReplay201 FAILED. So both tests prove their guard.
  • sh merge-check.sh with MESH_TEST_POSTGRES: exit 0, with no FAIL and no NOT RUN lines.
  • Statuses on the head: mesh/merge-gate success (head merged into trunk f8daec0), mesh/repo-check success, mesh/delivery success ("ready"). The forge says it is mergeable.

Review 90's findings

  • A (machine blocked): fixed. A send keeps the core module and carries everything else. The only refusal left is a kept build whose manifest is missing, and it applies per machine. A sent build that failed its gate is never kept, so the next healer's send finishes a rollback whose send was refused. The new test proves it.
  • B (condition not cleared): fixed. settleCoreDowngrades runs in overTheBus.declare, which both a person's push (push.go:664) and every other send go through. A send that carries the mesh's record clears the condition.
  • Wording: fixed. The needs line names both ways out.

What ends a keep

I confirmed what moves a kept machine forward. A newer merge or rebuild registers a build asked later than the one the machine was last sent, so coreDowngrades stops finding it and the next send carries the record. A person's push <node> takes the older build. Nothing keeps a machine at the old build silently: the warning stays raised for the whole time.

New finding C (blocking): a send that keeps the core module supersedes its own gate

gatedSend takes its carried moves from machineMoves(..., true), which is computed from the record. Unlike ungatedIn, it does not leave out the moves the send keeps. So on a kept machine, the gate carries mesh-controller c2→c1 while the declaration keeps c2. After the send, SentBuilds says c2, and in judgeGate supersededOn(mesh-controller, node) is true, which settles the whole gate as GateSuperseded at once ("nothing judged, nothing put back").

I proved it on the store with the core201 fixture and a throwaway test, which I did not commit:

gatedSend's carried moves: [{Module:mesh-controller Node:anchor From:c2bbbbbbbbbb To:c1aaaaaaaaaa}]
kept: map[mesh-controller:c2bbbbbbbbbb]
superseded=true: anchor was sent mesh-controller c2bbbbbb after this gate's c1aaaaaa: the build judged no longer runs there, and this judging is superseded by that send's

The consequence is the 201 scenario itself. The node-engine's plan sends its first machine (the control node, which keeps the newer controller) the new node-engine. The gate is superseded without judging anything, the new node-engine stays there unjudged, and the plan ends superseded instead of walking the rest. The same happens to every release plan's gated send and every plan whose first machine is the kept one, for as long as the record stays older. The comment "A plan whose own build is the older one finds its gate superseded … and ends" covers only the plan whose own build is the older controller. Every other module's gate on that machine is skipped as well, which goes against ADR 0236 (no build moves on a machine without a gate).

Fix: in gatedSend, leave out of moves each move the send keeps, with the same filter ungatedIn uses (recordedKept(keepingRecorded(ctx), …), matched on module and From). Then the gate judges only what the declaration changes. Test: on core201, add a rolling-out module move on anchor, run a gated send, and check that the carried moves leave out mesh-controller and that the gate is not superseded.

Minor

  • TestReplay201 and TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend need the store but are not listed in testdata/store-tests. Without a store they skip unseen, which is what issue 459 guards against. Please add both lines.
  • The bus step (a person's word for the bus) also keeps the core modules now, because sendKeeps applies to it too. That is fine, but the doc comment says "No send but a person's push".
Verdict: request changes at d17049125655568a90396626c682df23f25e58bd Re-review against review 90. Keeping the core module instead of refusing the send fixes what review 90 raised: a send is no longer blocked, and a build that failed its gate is no longer kept. But a send that keeps the core module while carrying a gate now lets that gate be superseded at once, so the machine's other new builds go unjudged. Details below. ## What I ran (head d170491, throwaway Postgres 18) - `go vet ./...`: clean. - `go test -race` on TestReplay201, TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend and TestACoreModuleIsKeptOverAnOlderRecord: all PASS against the store. - I removed the `from.failedGate` exemption, and TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend FAILED ("the failed controller was kept over the build put back"). I made `coreKept` return nothing, and TestReplay201 FAILED. So both tests prove their guard. - `sh merge-check.sh` with MESH_TEST_POSTGRES: exit 0, with no FAIL and no NOT RUN lines. - Statuses on the head: mesh/merge-gate success (head merged into trunk f8daec0), mesh/repo-check success, mesh/delivery success ("ready"). The forge says it is mergeable. ## Review 90's findings - A (machine blocked): **fixed.** A send keeps the core module and carries everything else. The only refusal left is a kept build whose manifest is missing, and it applies per machine. A sent build that failed its gate is never kept, so the next healer's send finishes a rollback whose send was refused. The new test proves it. - B (condition not cleared): **fixed.** `settleCoreDowngrades` runs in `overTheBus.declare`, which both a person's push (push.go:664) and every other send go through. A send that carries the mesh's record clears the condition. - Wording: **fixed.** The needs line names both ways out. ## What ends a keep I confirmed what moves a kept machine forward. A newer merge or `rebuild` registers a build asked later than the one the machine was last sent, so `coreDowngrades` stops finding it and the next send carries the record. A person's `push <node>` takes the older build. Nothing keeps a machine at the old build silently: the warning stays raised for the whole time. ## New finding C (blocking): a send that keeps the core module supersedes its own gate `gatedSend` takes its carried moves from `machineMoves(..., true)`, which is computed from the record. Unlike `ungatedIn`, it does not leave out the moves the send keeps. So on a kept machine, the gate carries `mesh-controller c2→c1` while the declaration keeps c2. After the send, `SentBuilds` says c2, and in `judgeGate` `supersededOn(mesh-controller, node)` is true, which settles the **whole** gate as `GateSuperseded` at once ("nothing judged, nothing put back"). I proved it on the store with the `core201` fixture and a throwaway test, which I did not commit: ``` gatedSend's carried moves: [{Module:mesh-controller Node:anchor From:c2bbbbbbbbbb To:c1aaaaaaaaaa}] kept: map[mesh-controller:c2bbbbbbbbbb] superseded=true: anchor was sent mesh-controller c2bbbbbb after this gate's c1aaaaaa: the build judged no longer runs there, and this judging is superseded by that send's ``` The consequence is the 201 scenario itself. The node-engine's plan sends its first machine (the control node, which keeps the newer controller) the new node-engine. The gate is superseded without judging anything, the new node-engine stays there unjudged, and the plan ends `superseded` instead of walking the rest. The same happens to every release plan's gated send and every plan whose first machine is the kept one, for as long as the record stays older. The comment "A plan whose own build is the older one finds its gate superseded … and ends" covers only the plan whose own build is the older controller. Every other module's gate on that machine is skipped as well, which goes against ADR 0236 (no build moves on a machine without a gate). Fix: in `gatedSend`, leave out of `moves` each move the send keeps, with the same filter `ungatedIn` uses (`recordedKept(keepingRecorded(ctx), …)`, matched on module and `From`). Then the gate judges only what the declaration changes. Test: on `core201`, add a rolling-out module move on anchor, run a gated send, and check that the carried moves leave out mesh-controller and that the gate is not superseded. ## Minor - TestReplay201 and TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend need the store but are not listed in `testdata/store-tests`. Without a store they skip unseen, which is what issue 459 guards against. Please add both lines. - The bus step (a person's word for the bus) also keeps the core modules now, because `sendKeeps` applies to it too. That is fine, but the doc comment says "No send but a person's push".
jschoubben added 2 commits 2026-10-12 17:16:30 +00:00
Leave a kept core move out of what a gate judges (issue 201, review 91)
mesh/merge-gate head f0fd7fe8868e merged into trunk a681227af373 — fail: builds mesh-controller → novox; no bus step; head f0fd7fe8868e does not merge clea…
mesh/repo-check head f0fd7fe8868e merged into trunk a681227af373 — fail: head f0fd7fe8868e does not merge cleanly into trunk a681227af373: in conflict test…
mesh/delivery superseded: a newer head of the same pull request
f0fd7fe886
gatedSend took its judged moves from the record, so on a machine kept at
a newer controller the gate judged the controller moving back to the
record, read its own send's kept controller as a later build there, and
was superseded with nothing judged. The kept moves are now left out
there as in ungatedIn (withoutKept). The doc says the bus step keeps
too, and the three store tests are listed.
Author
Contributor

Merge check at f0fd7fe8
Judged: head f0fd7fe8868e merged into trunk ba685b17f5e1; read beside it: mesh-catalog 23ea0f431faf, mesh-controller-main ba685b17f5e1, mesh-host a1f9856b3957, mesh-tools 954e1a53eef9

  • mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: mesh-controller)
  • mesh/repo-check: PASS — its merge-check.sh passed

Delivery plan — builds mesh-controller → novox; no bus step

  • tier 0: mesh-controller
  • novox: receives mesh-controller
  • read by no module's build: cmd/mesh-controller/issue201_test.go, testdata/store-tests

Run by the build seat on shanks as build-1791825418229347732 (builds --log build-1791825418229347732).

--- the gate: mesh-controller
mesh-controller: ok, 58 tool(s); WARNING: merge-window ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); 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: 1
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-12T17:09:24Z 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-12T17:09:24Z

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 2 module(s) in 2 tier(s): build-agent, mesh-controller
--- its merge-check.sh (go toolchain)
ok  	github.com/novox/mesh-controller/cmd/mesh-builder	1.039s
ok  	github.com/novox/mesh-controller/cmd/mesh-controller	288.409s
ok  	github.com/novox/mesh-controller/examples/objectstore-provisioner	1.045s
ok  	github.com/novox/mesh-controller/examples/postgres-provisioner	1.063s
ok  	github.com/novox/mesh-controller/examples/redis-provisioner	1.051s
ok  	github.com/novox/mesh-controller/examples/route-proxy	1.246s
ok  	github.com/novox/mesh-controller/internal/artifacts	1.090s
?   	github.com/novox/mesh-controller/internal/beside	[no test files]
ok  	github.com/novox/mesh-controller/internal/broker	4.542s
ok  	github.com/novox/mesh-controller/internal/builder	53.062s
ok  	github.com/novox/mesh-controller/internal/catalogue	7.826s
ok  	github.com/novox/mesh-controller/internal/conditions	2.636s
ok  	github.com/novox/mesh-controller/internal/envfile	1.049s
ok  	github.com/novox/mesh-controller/internal/facts	1.059s
ok  	github.com/novox/mesh-controller/internal/identity	5.349s
ok  	github.com/novox/mesh-controller/internal/inventory	111.875s
ok  	github.com/novox/mesh-controller/internal/lease	17.716s
ok  	github.com/novox/mesh-controller/internal/licences	4.856s
ok  	github.com/novox/mesh-controller/internal/licences/adapters	1.052s
ok  	github.com/novox/mesh-controller/internal/link	66.548s
ok  	github.com/novox/mesh-controller/internal/lint	2.385s
ok  	github.com/novox/mesh-controller/internal/outward	1.087s
ok  	github.com/novox/mesh-controller/internal/overlay	1.077s
ok  	github.com/novox/mesh-controller/internal/secrets	1.542s
ok  	github.com/novox/mesh-controller/internal/store	3.598s
ok  	github.com/novox/mesh-controller/internal/testbus	1.267s
ok  	github.com/novox/mesh-controller/internal/token	1.014s
store tests, each run against the store:
  ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.42s)
  ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.43s)
  ./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.43s)
  ./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.41s)
  ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.41s)
  ./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.38s)
  ./cmd/mesh-controller --- PASS: TestAPlanFollowedFromTheStoreAnswersWhenItMoves (4.39s)
  ./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.45s)
  ./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.31s)
  ./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.50s)
  ./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.61s)
  ./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.48s)
  ./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.43s)
  ./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.49s)
  ./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.44s)
  ./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.47s)
  ./cmd/mesh-controller --- PASS: TestReplay237 (0.43s)
  ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.41s)
  ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.41s)
  ./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.40s)
  ./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.44s)
  ./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.49s)
  ./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.48s)
  ./cmd/mesh-controller --- PASS: TestReplay201 (0.37s)
  ./cmd/mesh-controller --- PASS: TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend (0.36s)
  ./cmd/mesh-controller --- PASS: TestAGateJudgesTheOtherMovesBesideAKeptCore (0.38s)
  ./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.27s)
  ./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.28s)
  ./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.35s)
  ./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.28s)
  ./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.26s)
  ./internal/inventory --- PASS: TestAPlanIdHoldingAQuoteIsReadAsAPlainId (0.26s)
  ./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.26s)
**Merge check** at `f0fd7fe8` Judged: head `f0fd7fe8868e` merged into trunk `ba685b17f5e1`; read beside it: mesh-catalog `23ea0f431faf`, mesh-controller-main `ba685b17f5e1`, mesh-host `a1f9856b3957`, mesh-tools `954e1a53eef9` - `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: mesh-controller) - `mesh/repo-check`: **PASS** — its merge-check.sh passed **Delivery plan** — builds mesh-controller → novox; no bus step - tier 0: mesh-controller - novox: receives mesh-controller - read by no module's build: cmd/mesh-controller/issue201_test.go, testdata/store-tests Run by the build seat on shanks as `build-1791825418229347732` (`builds --log build-1791825418229347732`). ``` --- the gate: mesh-controller mesh-controller: ok, 58 tool(s); WARNING: merge-window ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); 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: 1 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-12T17:09:24Z 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-12T17:09:24Z 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 2 module(s) in 2 tier(s): build-agent, mesh-controller --- its merge-check.sh (go toolchain) ok github.com/novox/mesh-controller/cmd/mesh-builder 1.039s ok github.com/novox/mesh-controller/cmd/mesh-controller 288.409s ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.045s ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.063s ok github.com/novox/mesh-controller/examples/redis-provisioner 1.051s ok github.com/novox/mesh-controller/examples/route-proxy 1.246s ok github.com/novox/mesh-controller/internal/artifacts 1.090s ? github.com/novox/mesh-controller/internal/beside [no test files] ok github.com/novox/mesh-controller/internal/broker 4.542s ok github.com/novox/mesh-controller/internal/builder 53.062s ok github.com/novox/mesh-controller/internal/catalogue 7.826s ok github.com/novox/mesh-controller/internal/conditions 2.636s ok github.com/novox/mesh-controller/internal/envfile 1.049s ok github.com/novox/mesh-controller/internal/facts 1.059s ok github.com/novox/mesh-controller/internal/identity 5.349s ok github.com/novox/mesh-controller/internal/inventory 111.875s ok github.com/novox/mesh-controller/internal/lease 17.716s ok github.com/novox/mesh-controller/internal/licences 4.856s ok github.com/novox/mesh-controller/internal/licences/adapters 1.052s ok github.com/novox/mesh-controller/internal/link 66.548s ok github.com/novox/mesh-controller/internal/lint 2.385s ok github.com/novox/mesh-controller/internal/outward 1.087s ok github.com/novox/mesh-controller/internal/overlay 1.077s ok github.com/novox/mesh-controller/internal/secrets 1.542s ok github.com/novox/mesh-controller/internal/store 3.598s ok github.com/novox/mesh-controller/internal/testbus 1.267s ok github.com/novox/mesh-controller/internal/token 1.014s store tests, each run against the store: ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.42s) ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.43s) ./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.43s) ./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.41s) ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.41s) ./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.38s) ./cmd/mesh-controller --- PASS: TestAPlanFollowedFromTheStoreAnswersWhenItMoves (4.39s) ./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.45s) ./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.31s) ./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.50s) ./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.61s) ./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.48s) ./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.43s) ./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.49s) ./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.44s) ./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.47s) ./cmd/mesh-controller --- PASS: TestReplay237 (0.43s) ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.41s) ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.41s) ./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.40s) ./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.44s) ./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.49s) ./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.48s) ./cmd/mesh-controller --- PASS: TestReplay201 (0.37s) ./cmd/mesh-controller --- PASS: TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend (0.36s) ./cmd/mesh-controller --- PASS: TestAGateJudgesTheOtherMovesBesideAKeptCore (0.38s) ./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.27s) ./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.28s) ./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.35s) ./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.28s) ./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.26s) ./internal/inventory --- PASS: TestAPlanIdHoldingAQuoteIsReadAsAPlainId (0.26s) ./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.26s) ```
mesh-admin left a comment
Author
Contributor

Verdict: approve at f0fd7fe886

Re-review against review 91. Finding C (a send that keeps the core module superseded its own gate) is fixed, and the minor points are fixed too.

What I checked

  • C is fixed. withoutKept is used by both ungatedIn and gatedSend. It leaves out a move when the send keeps it at the build the machine was last sent (matched on module and From). Its keep context is the same one the send composes under (keepingRecorded, unless the context already keeps). A gate on a kept machine now judges only the other moves.
  • The plan whose own build is the older core. owns adds that move back, so its gate is superseded and the plan ends, which is the documented outcome.
  • ungatedIn. It now leaves out every kept move, not only those the grants step keeps. moves() lists only modules that roll out, and recordedKept skips those unless every build is kept, so the only extra moves left out are the kept core modules. Nothing else in the send changes.
  • The new test proves the fix. I removed the withoutKept call from gatedSend, and TestAGateJudgesTheOtherMovesBesideAKeptCore FAILED: the gate's moves included mesh-controller c2→c1 beside the app's move. With the call in place it passes.
  • Minor points from review 91. All three store tests are now listed in testdata/store-tests. The doc comment now says that the bus step keeps the core modules too.

Runs (head f0fd7fe, throwaway Postgres 18)

  • go vet ./...: clean.
  • go test -race on TestReplay201, TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend, TestAGateJudgesTheOtherMovesBesideAKeptCore and TestACoreModuleIsKeptOverAnOlderRecord: all PASS.
  • sh merge-check.sh with MESH_TEST_POSTGRES: exit 0, with no FAIL and no NOT RUN lines. Its list of store tests shows all three issue 201 tests as PASS.
  • Statuses on the head: mesh/merge-gate success (head merged into trunk ba685b1, every machine composes), mesh/repo-check success, mesh/delivery success ("ready"). The forge says it is mergeable.

The findings from reviews 90 and 91 are all addressed: no machine is blocked, a rollback whose send was refused is finished by the next send, the warning clears on a person's push, and the gate's judging is intact.

Verdict: approve at f0fd7fe8868e01035286bb9a282c2aa9f30969e8 Re-review against review 91. Finding C (a send that keeps the core module superseded its own gate) is fixed, and the minor points are fixed too. ## What I checked - **C is fixed.** `withoutKept` is used by both `ungatedIn` and `gatedSend`. It leaves out a move when the send keeps it at the build the machine was last sent (matched on module and `From`). Its keep context is the same one the send composes under (`keepingRecorded`, unless the context already keeps). A gate on a kept machine now judges only the other moves. - **The plan whose own build is the older core.** `owns` adds that move back, so its gate is superseded and the plan ends, which is the documented outcome. - **`ungatedIn`.** It now leaves out every kept move, not only those the grants step keeps. `moves()` lists only modules that roll out, and `recordedKept` skips those unless every build is kept, so the only extra moves left out are the kept core modules. Nothing else in the send changes. - **The new test proves the fix.** I removed the `withoutKept` call from `gatedSend`, and TestAGateJudgesTheOtherMovesBesideAKeptCore FAILED: the gate's moves included `mesh-controller c2→c1` beside the app's move. With the call in place it passes. - **Minor points from review 91.** All three store tests are now listed in `testdata/store-tests`. The doc comment now says that the bus step keeps the core modules too. ## Runs (head f0fd7fe, throwaway Postgres 18) - `go vet ./...`: clean. - `go test -race` on TestReplay201, TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend, TestAGateJudgesTheOtherMovesBesideAKeptCore and TestACoreModuleIsKeptOverAnOlderRecord: all PASS. - `sh merge-check.sh` with MESH_TEST_POSTGRES: exit 0, with no FAIL and no NOT RUN lines. Its list of store tests shows all three issue 201 tests as PASS. - Statuses on the head: mesh/merge-gate success (head merged into trunk ba685b1, every machine composes), mesh/repo-check success, mesh/delivery success ("ready"). The forge says it is mergeable. The findings from reviews 90 and 91 are all addressed: no machine is blocked, a rollback whose send was refused is finished by the next send, the warning clears on a person's push, and the gate's judging is intact.
Author
Contributor

Merge check at f0fd7fe8
Judged: head f0fd7fe8868e merged into trunk a681227af373

  • mesh/merge-gate: FAIL — head f0fd7fe886 does not merge cleanly into trunk a681227af3: in conflict testdata/store-tests (modules: mesh-controller)
  • mesh/repo-check: FAIL — head f0fd7fe886 does not merge cleanly into trunk a681227af3: in conflict testdata/store-tests

Delivery plan — builds mesh-controller → novox; no bus step

  • tier 0: mesh-controller
  • novox: receives mesh-controller
  • read by no module's build: cmd/mesh-controller/issue201_test.go, testdata/store-tests

Run by the build seat on shanks as build-1791829341724108644 (builds --log build-1791829341724108644).

head f0fd7fe8868e does not merge cleanly into trunk a681227af373: in conflict testdata/store-tests
**Merge check** at `f0fd7fe8` Judged: head `f0fd7fe8868e` merged into trunk `a681227af373` - `mesh/merge-gate`: **FAIL** — head f0fd7fe8868e does not merge cleanly into trunk a681227af373: in conflict testdata/store-tests (modules: mesh-controller) - `mesh/repo-check`: **FAIL** — head f0fd7fe8868e does not merge cleanly into trunk a681227af373: in conflict testdata/store-tests **Delivery plan** — builds mesh-controller → novox; no bus step - tier 0: mesh-controller - novox: receives mesh-controller - read by no module's build: cmd/mesh-controller/issue201_test.go, testdata/store-tests Run by the build seat on shanks as `build-1791829341724108644` (`builds --log build-1791829341724108644`). ``` head f0fd7fe8868e does not merge cleanly into trunk a681227af373: in conflict testdata/store-tests ```
jschoubben added 1 commit 2026-10-12 18:39:33 +00:00
Merge origin/main into fix/201-a-push-never-downgrades-the-core
mesh/merge-gate head b3787e4d8eb2 merged into trunk a681227af373 — pass: builds mesh-controller → novox; no bus step; every machine composes with the chang…
mesh/repo-check head b3787e4d8eb2 merged into trunk a681227af373 — pass: its merge-check.sh passed
mesh/delivery delivered
b3787e4d8e
# Conflicts:
#	testdata/store-tests
Author
Contributor

Re-check at b3787e4d8e (merge of main a681227a into the approved f0fd7fe8): the PR's own diff against main is line-for-line the approved diff (diff of git diff merge-base..f0fd7fe8 and git diff a681227a..b3787e4d shows no differing +/- lines); only testdata/store-tests context moved. Review 94's approval carries to this head.

Re-check at b3787e4d8eb2226909ceebac414ea5b78ae8fbda (merge of main a681227a into the approved f0fd7fe8): the PR's own diff against main is line-for-line the approved diff (diff of `git diff merge-base..f0fd7fe8` and `git diff a681227a..b3787e4d` shows no differing +/- lines); only testdata/store-tests context moved. Review 94's approval carries to this head.
Author
Contributor

Merge check at b3787e4d
Judged: head b3787e4d8eb2 merged into trunk a681227af373; read beside it: mesh-catalog 22071dabfc7b, mesh-controller-main a681227af373, mesh-host 303d4037e84e, mesh-tools 954e1a53eef9

  • mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: mesh-controller)
  • mesh/repo-check: PASS — its merge-check.sh passed

Delivery plan — builds mesh-controller → novox; no bus step

  • tier 0: mesh-controller
  • novox: receives mesh-controller
  • read by no module's build: cmd/mesh-controller/issue201_test.go, testdata/store-tests

Run by the build seat on ace as build-1791830393099375212 (builds --log build-1791830393099375212).

--- the gate: mesh-controller
mesh-controller: ok, 58 tool(s); WARNING: merge-window ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); 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: 1
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-12T18:27:33Z 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-12T18:27:33Z

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 1 module(s) in 1 tier(s): mesh-controller

notes:
  - cmd/mesh-controller/issue201_test.go and testdata/store-tests read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok  	github.com/novox/mesh-controller/cmd/mesh-builder	1.036s
ok  	github.com/novox/mesh-controller/cmd/mesh-controller	245.167s
ok  	github.com/novox/mesh-controller/examples/objectstore-provisioner	1.043s
ok  	github.com/novox/mesh-controller/examples/postgres-provisioner	1.048s
ok  	github.com/novox/mesh-controller/examples/redis-provisioner	1.038s
ok  	github.com/novox/mesh-controller/examples/route-proxy	1.168s
ok  	github.com/novox/mesh-controller/internal/artifacts	1.085s
?   	github.com/novox/mesh-controller/internal/beside	[no test files]
ok  	github.com/novox/mesh-controller/internal/broker	3.969s
ok  	github.com/novox/mesh-controller/internal/builder	32.836s
ok  	github.com/novox/mesh-controller/internal/catalogue	7.298s
ok  	github.com/novox/mesh-controller/internal/conditions	2.586s
ok  	github.com/novox/mesh-controller/internal/envfile	1.049s
ok  	github.com/novox/mesh-controller/internal/facts	1.043s
ok  	github.com/novox/mesh-controller/internal/identity	4.506s
ok  	github.com/novox/mesh-controller/internal/inventory	88.062s
ok  	github.com/novox/mesh-controller/internal/lease	17.699s
ok  	github.com/novox/mesh-controller/internal/licences	4.012s
ok  	github.com/novox/mesh-controller/internal/licences/adapters	1.043s
ok  	github.com/novox/mesh-controller/internal/link	59.998s
ok  	github.com/novox/mesh-controller/internal/lint	2.243s
ok  	github.com/novox/mesh-controller/internal/outward	1.096s
ok  	github.com/novox/mesh-controller/internal/overlay	1.077s
ok  	github.com/novox/mesh-controller/internal/secrets	1.461s
ok  	github.com/novox/mesh-controller/internal/store	3.507s
ok  	github.com/novox/mesh-controller/internal/testbus	1.199s
ok  	github.com/novox/mesh-controller/internal/token	1.017s
store tests, each run against the store:
  ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.37s)
  ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.39s)
  ./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.40s)
  ./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.38s)
  ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.37s)
  ./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.34s)
  ./cmd/mesh-controller --- PASS: TestAPlanFollowedFromTheStoreAnswersWhenItMoves (4.33s)
  ./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.39s)
  ./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.27s)
  ./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.41s)
  ./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.42s)
  ./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.37s)
  ./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.37s)
  ./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.44s)
  ./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.37s)
  ./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.42s)
  ./cmd/mesh-controller --- PASS: TestReplay237 (0.38s)
  ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.36s)
  ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.37s)
  ./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.38s)
  ./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.40s)
  ./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.44s)
  ./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.42s)
  ./cmd/mesh-controller --- PASS: TestReplay201 (0.31s)
  ./cmd/mesh-controller --- PASS: TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend (0.31s)
  ./cmd/mesh-controller --- PASS: TestAGateJudgesTheOtherMovesBesideAKeptCore (0.31s)
  ./cmd/mesh-controller --- PASS: TestReplay401 (0.47s)
  ./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.24s)
  ./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.23s)
  ./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.23s)
  ./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.23s)
  ./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.23s)
  ./internal/inventory --- PASS: TestAPlanIdHoldingAQuoteIsReadAsAPlainId (0.22s)
  ./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.23s)
**Merge check** at `b3787e4d` Judged: head `b3787e4d8eb2` merged into trunk `a681227af373`; read beside it: mesh-catalog `22071dabfc7b`, mesh-controller-main `a681227af373`, mesh-host `303d4037e84e`, mesh-tools `954e1a53eef9` - `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: mesh-controller) - `mesh/repo-check`: **PASS** — its merge-check.sh passed **Delivery plan** — builds mesh-controller → novox; no bus step - tier 0: mesh-controller - novox: receives mesh-controller - read by no module's build: cmd/mesh-controller/issue201_test.go, testdata/store-tests Run by the build seat on ace as `build-1791830393099375212` (`builds --log build-1791830393099375212`). ``` --- the gate: mesh-controller mesh-controller: ok, 58 tool(s); WARNING: merge-window ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); 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: 1 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-12T18:27:33Z 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-12T18:27:33Z 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 1 module(s) in 1 tier(s): mesh-controller notes: - cmd/mesh-controller/issue201_test.go and testdata/store-tests read by no module's build, and rebuild nothing (issue 280) --- its merge-check.sh (go toolchain) ok github.com/novox/mesh-controller/cmd/mesh-builder 1.036s ok github.com/novox/mesh-controller/cmd/mesh-controller 245.167s ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.043s ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.048s ok github.com/novox/mesh-controller/examples/redis-provisioner 1.038s ok github.com/novox/mesh-controller/examples/route-proxy 1.168s ok github.com/novox/mesh-controller/internal/artifacts 1.085s ? github.com/novox/mesh-controller/internal/beside [no test files] ok github.com/novox/mesh-controller/internal/broker 3.969s ok github.com/novox/mesh-controller/internal/builder 32.836s ok github.com/novox/mesh-controller/internal/catalogue 7.298s ok github.com/novox/mesh-controller/internal/conditions 2.586s ok github.com/novox/mesh-controller/internal/envfile 1.049s ok github.com/novox/mesh-controller/internal/facts 1.043s ok github.com/novox/mesh-controller/internal/identity 4.506s ok github.com/novox/mesh-controller/internal/inventory 88.062s ok github.com/novox/mesh-controller/internal/lease 17.699s ok github.com/novox/mesh-controller/internal/licences 4.012s ok github.com/novox/mesh-controller/internal/licences/adapters 1.043s ok github.com/novox/mesh-controller/internal/link 59.998s ok github.com/novox/mesh-controller/internal/lint 2.243s ok github.com/novox/mesh-controller/internal/outward 1.096s ok github.com/novox/mesh-controller/internal/overlay 1.077s ok github.com/novox/mesh-controller/internal/secrets 1.461s ok github.com/novox/mesh-controller/internal/store 3.507s ok github.com/novox/mesh-controller/internal/testbus 1.199s ok github.com/novox/mesh-controller/internal/token 1.017s store tests, each run against the store: ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.37s) ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.39s) ./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.40s) ./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.38s) ./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.37s) ./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.34s) ./cmd/mesh-controller --- PASS: TestAPlanFollowedFromTheStoreAnswersWhenItMoves (4.33s) ./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.39s) ./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.27s) ./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.41s) ./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.42s) ./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.37s) ./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.37s) ./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.44s) ./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.37s) ./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.42s) ./cmd/mesh-controller --- PASS: TestReplay237 (0.38s) ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.36s) ./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.37s) ./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.38s) ./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.40s) ./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.44s) ./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.42s) ./cmd/mesh-controller --- PASS: TestReplay201 (0.31s) ./cmd/mesh-controller --- PASS: TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend (0.31s) ./cmd/mesh-controller --- PASS: TestAGateJudgesTheOtherMovesBesideAKeptCore (0.31s) ./cmd/mesh-controller --- PASS: TestReplay401 (0.47s) ./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.24s) ./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.23s) ./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.23s) ./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.23s) ./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.23s) ./internal/inventory --- PASS: TestAPlanIdHoldingAQuoteIsReadAsAPlainId (0.22s) ./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.23s) ```
mesh-admin merged commit 84deb530ee into main 2026-10-12 18:52:05 +00:00
mesh-admin deleted branch fix/201-a-push-never-downgrades-the-core 2026-10-12 18:52:05 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/mesh-controller#273