TestAPlanIsWhatTheChangeTouchedAndWhatIsBuiltOnIt: a table of 33 merges over reachOfMerge, each with its exact plan (the moved set and the tier order). It covers A and B changed with C untouched and D on A, E on B (a,b | d,e); a transitive chain; each edge kind alone for widening and for ordering (stands-on, declared, packages, built-by, worker-of); the two cycles the kinds resolve (the runtime and the builder, the builder and the controller); two repositories, including a directory of the same name in the other one; diamonds; a cycle guard; and files no build reads.
TestASharedRepositoryMovesWhatPackagesItAsItDoesToday: the controller is built from its repository's root, and route-proxy and build-agent package that repository. This documents current behaviour. hq issue 338 and the decision pending on it would change these rows. A README in the controller's repository plans mesh-controller | build-agent | route-proxy (the live three tiers, including the worker-of order).
TestAPlanIsTheTouchedModulesAndWhatIsReachableAlongTheWideningEdges: a seeded property over 500 random cycle-free catalogues (1 to 3 repositories, mixed edge kinds, overlapping directory names, some modules built from the root). It checks three things. The moved set is exactly the touched modules plus everything reachable along stands-on, declared and packages. Every ordering edge (stands-on, declared, built-by, worker-of) with both ends in the plan has the depended-on module in an earlier tier. No cycle is reported.
cmd/mesh-controller/planner_records_test.go (needs the test store)
TestASharedRepositoryIsPlannedFromTheRecordsAsItIsToday: modules are registered and builds recorded (built against, build.on, read), so the edges are derived by inventory.Dependencies and not written by hand. It pins those derived edges to the hand-written ones above. It shows the issue 338 behaviour: a change to C alone, or to a README, moves P, which packages C's repository.
hasCycle reports a cycle where there is none. It counts any edge between two modules of the last tier, including a packages edge, and a packages edge puts both modules in the same tier by rule. So the merge handler logs the last tier depends on itself … built together, in no order for any plan whose last tier holds a module and its packager. ADR 0162 says a cycle is put in one last tier and reported, so a cycle reported where there is none breaks the rule. Three table rows and 19 of 500 property cases fail on this. They are marked [BUG: hasCycle counts a packages edge], and the expectations were left as they are. mesh/repo-check will be red until hasCycle is fixed. Every other row and every other invariant passes.
A second, related point. TestAMergeIsPlannedInTiersAlongTheThreeKindsOfDependency (release_plan_test.go, the controller case) expects builder and then controller, proxy. Its fixture has no worker-of edge, so that test predates issue 206 and does not match the live plan. I did not change it. The worker-of row here gives the real order.
Do not merge before the hasCycle fix lands, or merge the fix first.
Tests only, no planner code changed.
## What
- `cmd/mesh-controller/planner_rules_test.go`
- **TestAPlanIsWhatTheChangeTouchedAndWhatIsBuiltOnIt**: a table of 33 merges over reachOfMerge, each with its exact plan (the moved set and the tier order). It covers A and B changed with C untouched and D on A, E on B (`a,b | d,e`); a transitive chain; each edge kind alone for widening and for ordering (stands-on, declared, packages, built-by, worker-of); the two cycles the kinds resolve (the runtime and the builder, the builder and the controller); two repositories, including a directory of the same name in the other one; diamonds; a cycle guard; and files no build reads.
- **TestASharedRepositoryMovesWhatPackagesItAsItDoesToday**: the controller is built from its repository's root, and route-proxy and build-agent package that repository. **This documents current behaviour.** hq issue 338 and the decision pending on it would change these rows. A README in the controller's repository plans `mesh-controller | build-agent | route-proxy` (the live three tiers, including the worker-of order).
- **TestAPlanIsTheTouchedModulesAndWhatIsReachableAlongTheWideningEdges**: a seeded property over 500 random cycle-free catalogues (1 to 3 repositories, mixed edge kinds, overlapping directory names, some modules built from the root). It checks three things. The moved set is exactly the touched modules plus everything reachable along stands-on, declared and packages. Every ordering edge (stands-on, declared, built-by, worker-of) with both ends in the plan has the depended-on module in an earlier tier. No cycle is reported.
- `cmd/mesh-controller/planner_records_test.go` (needs the test store)
- **TestASharedRepositoryIsPlannedFromTheRecordsAsItIsToday**: modules are registered and builds recorded (built against, build.on, read), so the edges are derived by inventory.Dependencies and not written by hand. It pins those derived edges to the hand-written ones above. It shows the issue 338 behaviour: a change to C alone, or to a README, moves P, which packages C's repository.
## A bug these tests found on main (8170fc5)
**hasCycle reports a cycle where there is none.** It counts any edge between two modules of the last tier, including a packages edge, and a packages edge puts both modules in the same tier by rule. So the merge handler logs `the last tier depends on itself … built together, in no order` for any plan whose last tier holds a module and its packager. ADR 0162 says a cycle is put in one last tier and reported, so a cycle reported where there is none breaks the rule. Three table rows and 19 of 500 property cases fail on this. They are marked `[BUG: hasCycle counts a packages edge]`, and the expectations were left as they are. **mesh/repo-check will be red until hasCycle is fixed.** Every other row and every other invariant passes.
A second, related point. TestAMergeIsPlannedInTiersAlongTheThreeKindsOfDependency (release_plan_test.go, the controller case) expects `builder` and then `controller, proxy`. Its fixture has no worker-of edge, so that test predates issue 206 and does not match the live plan. I did not change it. The worker-of row here gives the real order.
Do not merge before the hasCycle fix lands, or merge the fix first.
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
A table of merges (two repositories, every edge kind, a diamond, a cycle,
files no build reads) and a seeded property over 500 random catalogues pin
what a merge moves and in which tiers, per ADR 0162 and ADR 0238 §3. The
shared-repository rows document today's behaviour that issue 338 would
change, once with hand edges and once with edges derived from the store.
The cycle check fails on main: hasCycle reads a packages edge between two
modules of the last tier as a cycle, so a plan with none is said to have
one. Left failing, marked BUG, for the planner's fix.
build-agent keeps data (ADR 0233): what it holds is backed up before it moves
route-proxy provides route: its consumers are sent again after it
route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Machines
mesh-controller on novox: passed — healthy 3 times over 3m39s
mesh-controller on the rest running it: sent
build-agent on ace: passed — healthy 3 times over 3m39s
build-agent on the rest running it: sent
route-proxy on ace: passed — healthy 3 times over 3m44s
route-proxy on the rest running it: sent
Transitions
2026-10-08 20:26 (new) → proposed (announced): novox/mesh-controller#167's head announced
2026-10-08 20:32 proposed → checked (checked): the verdict names this commit
2026-10-08 20:32 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-08 20:41 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
2026-10-08 20:41 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path
2026-10-08 20:56 delivering → delivered (done): its walk is done: every machine of its deploy plan passed, or was left as its policy says
The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-controller@758537dd4ea2` — **delivered** since 2026-10-08T20:56:07Z
**Delivery plan** — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- tier 2: route-proxy
- ace: receives build-agent, route-proxy
- g14: receives build-agent
- novox: receives mesh-controller, build-agent, route-proxy
- shanks: receives build-agent
- build-agent keeps data (ADR 0233): what it holds is backed up before it moves
- route-proxy provides route: its consumers are sent again after it
- route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
**Machines**
- mesh-controller on novox: passed — healthy 3 times over 3m39s
- mesh-controller on the rest running it: sent
- build-agent on ace: passed — healthy 3 times over 3m39s
- build-agent on the rest running it: sent
- route-proxy on ace: passed — healthy 3 times over 3m44s
- route-proxy on the rest running it: sent
**Transitions**
- 2026-10-08 20:26 (new) → proposed (announced): novox/mesh-controller#167's head announced
- 2026-10-08 20:32 proposed → checked (checked): the verdict names this commit
- 2026-10-08 20:32 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-08 20:41 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
- 2026-10-08 20:41 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path
- 2026-10-08 20:56 delivering → delivered (done): its walk is done: every machine of its deploy plan passed, or was left as its policy says
The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
build-agent keeps data (ADR 0233): what it holds is backed up before it moves
route-proxy provides route: its consumers are sent again after it
route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on ace as build-1791490542277087585 (builds --log build-1791490542277087585).
ace: ace is paused
could not read what is assigned, so the build is asked of node-build-agent: this process has neither MESH_STORE_INVENTORY nor MESH_STORE_INVENTORY_FILE, so it was not granted the inventory store. A context reaches only the store it exclusively owns (novox/hq ADR 0008), so this is either the wrong context or a missing grant — it is never something to work around by reusing another context's connection
g14: nothing on g14 answers node-build-agent.resume: its holder is not running, or is older than the verb
plan-rollout: tier 0 done; asking tier 1: b
tier 1: plan-own: done — novox/a at c0ffee, 1 tier(s)
build-at-commit was built at commit 01234567; a rebuild asks what a follows now, main — `replay build-at-commit` builds that commit
rebuild asked as build-1791490767806834341
could not read what is assigned, so the build is asked of node-build-agent: this process has neither MESH_STORE_INVENTORY nor MESH_STORE_INVENTORY_FILE, so it was not granted the inventory store. A context reaches only the store it exclusively owns (novox/hq ADR 0008), so this is either the wrong context or a missing grant — it is never something to work around by reusing another context's connection
build-1791487174598413738: the build seat did not say whether c1111111 is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487175598413738: the build seat did not say whether c1111111 is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487234598413738: the build seat did not say whether c2222222 is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487235598413738: the build seat did not say whether c2222222 is on its repository's trunk (it predates ADR 0238); registered as before
plan-1: mesh-controller settled from the build records as built (build-2)
plan-3: postgres settled from the build records as built (build-mine)
plan-2: x settled from the build records as failed (b)
release-1791490775612380855: 2 build(s) wait for a gate on anchor, laptop; one machine at a time, each judged
release-1791490775612380855: sent anchor 1 build(s) that waited for a gate; judging them there
release-1791490775612380855: sent laptop 2 build(s) that waited for a gate; judging them there
release-1791490776055195623: 2 build(s) wait for a gate on anchor, laptop; one machine at a time, each judged
release-1791490776055195623: sent anchor 1 build(s) that waited for a gate; judging them there
app's build c2 failed its gate on anchor and was put back to c1: anchor failed what it was sent
release-1791490776055195623: failed its gate on anchor: anchor failed what it was sent — app failed its gate on anchor in tier 0: anchor failed what it was sent; put back app to c1 on anchor, in one send
this act by hand could NOT be recorded in the hand-act log, and is done anyway: this control plane has no MESH_BUS_NATS, so it cannot reach the mesh's bus
release-1791490776135598645: 1 build(s) wait for a gate on laptop; one machine at a time, each judged
release-1791490776135598645 releases it; `plans release-1791490776135598645` says where it is
release-1791490776135598645: sent laptop 1 build(s) that waited for a gate; judging them there
release-1791490776543513493: 3 build(s) wait for a gate on laptop, workstation; one machine at a time, each judged
release-1791490776543513493: sent laptop 3 build(s) that waited for a gate; judging them there
release-1791490776543513493: sent workstation 3 build(s) that waited for a gate; judging them there
modules/sensors is a new module in novox/mesh-catalog: build b-modules/sensors asked at main; registered when it lands, assigned nowhere
novox/mesh-catalog merged into main (5e450125); it changed no module the mesh holds, and adds modules/sensors: built, registered when the build lands, and sent nowhere
b-modules/sensors: the build seat did not say whether 5e450125 is on its repository's trunk (it predates ADR 0238); registered as before
b-modules/sensors: sensors 1 registered, built on anchor from 5e450125
sensors rolls out on build: the machines running it are sent this now, one machine at a time — `upgrade sensors record` first if something must move before it does
b-modules/sensors: laptop is assigned sensors: build b-modules/sensors registered it (pending since 2026-10-08 20:19:37 UTC); `push laptop` sends it
plan-1: dunst passed its gate on laptop in tier 0 (healthy 3 times over 2m5s) and is kept; its walk stopped after: laptop did not report it applied within 30m0s; workstation left as it was
plan-tier: tier 0 built; sent 2 module(s) to anchor first in one send (m01, m02), the rest once its gate passes
plan-tier: tier 0 built; sent m01, m02 to laptop, one send each
plan-tier: done — novox/mesh-catalog at c2, 1 tier(s)
plan-crashloop: tier 0 built; sent 1 module(s) to anchor first in one send (app), the rest once its gate passes
app's build c2 failed its gate on anchor and was put back to c1: not healthy within -1s of its apply: its container app.server on anchor keeps restarting (2 restart(s) counted)
plan-crashloop: app failed its gate on anchor in tier 0: not healthy within -1s of its apply: its container app.server on anchor keeps restarting (2 restart(s) counted); put back app to c1 on anchor, in one send; none reported left as it was
novox/mesh-catalog merged into main (3ad22356); plan plan-1791490781025383183, 1 module(s) in 1 tier(s)
0: app
tier 0: modules/systemd-resolved is a new module in novox/mesh-catalog: build build-modules/systemd-resolved asked at main; registered when it lands, assigned nowhere
novox/mesh-catalog merged into main (3da80a4b); it changed no module the mesh holds, and adds modules/systemd-resolved: built, registered when the build lands, and sent nowhere
build-1791487182208527468: the build seat did not say whether c1111111 is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487242208527468: the build seat did not say whether c2222222 is on its repository's trunk (it predates ADR 0238); registered as before
recorded as act-1791490782308259102-2 in the hand-act log: a push of recorded builds (resolver from c1111111 → c2222222) by an unnamed account at a shell on Ace, because "operator's yes: the resolver's new build on anchor" — the person's word their upgrade policy asks for, which no healer is wanted for
recorded as act-1791490782352751160-3 in the hand-act log: a push of recorded builds (resolver from c1111111 → c2222222) by an unnamed account at a shell on Ace, because "operator's yes: the resolver's new build on laptop" — the person's word their upgrade policy asks for, which no healer is wanted for
laptop is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
laptop is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
build-1791487184911473374: the build seat did not say whether c1aaaaaa is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487244911473374: the build seat did not say whether c2bbbbbb is on its repository's trunk (it predates ADR 0238); registered as before
app at c2bbbbbb was made from the source build-1791487184911473374 was: registered with its artifacts, no move
build-1791487304911473374: the build seat did not say whether c3cccccc is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487364911473374: the build seat did not say whether c4dddddd is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487185282725968: the build seat did not say whether n1111111 is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487245282725968: the build seat did not say whether n2222222 is on its repository's trunk (it predates ADR 0238); registered as before
nats at n2222222 was made from the source build-1791487185282725968 was: registered with its artifacts, no move
every machine running nats runs the build the mesh holds (n2222222): nothing to upgrade
build-1791487305282725968: the build seat did not say whether n3333333 is on its repository's trunk (it predates ADR 0238); registered as before
plan-gate: app built from the source every machine running it runs: no move, nothing sent
plan-gate: done — novox/mesh-catalog at c2, 1 tier(s)
plan-gate: tier 0 built; sent 1 module(s) to anchor first in one send (app), the rest once its gate passes
status could not be composed (after 0s): the store did not answer — `status` answers the last summary, with its age
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
this act by hand could NOT be recorded in the hand-act log, and is done anyway: this control plane has no MESH_BUS_NATS, so it cannot reach the mesh's bus
plan-97b1b2b closed at tier 1 of 2; what was asked still builds and registers, nothing further is asked
plan-tier: tier 0 built; sent 12 module(s) to anchor first in one send (m01, m02, m03, m04, m05, m06, m07, m08, m09, m10, m11, m12), the rest once its gate passes
plan-tier: m01 passed its gate on anchor (healthy 3 times over 0s); the rest are sent
plan-tier: tier 0 built; sent m01, m02, m03, m04, m05, m06, m07, m08, m09, m10, m11, m12 to laptop, one send each
plan-tier: done — novox/mesh-catalog at c2, 1 tier(s)
plan-tier: tier 0 built; sent 3 module(s) to anchor first in one send (app1, app2, node-tools), the rest once its gate passes
node-tools's build c2 failed its gate on anchor and was put back to c1: not healthy within -1s of its apply: raised since it was sent: machine.anchor.core-behind — anchor runs the node tools it was last sent, not yet reported applied, and no plan is rolling them out (its settle window runs to the gate's bound)
plan-tier: the send to anchor in tier 0 failed its gate: not healthy within -1s of its apply: raised since it was sent: machine.anchor.core-behind — anchor runs the node tools it was last sent, not yet reported applied, and no plan is rolling them out (its settle window runs to the gate's bound); app1 passed on its own and is kept; passed on their own and kept: app2; node-tools failed its gate on anchor in tier 0: not healthy within -1s of its apply: raised since it was sent: machine.anchor.core-behind — anchor runs the node tools it was last sent, not yet reported applied, and no plan is rolling them out (its settle window runs to the gate's bound); put back node-tools to c1 on anchor, in one send; none reported left as it was
plan-tier: tier 0 built; sent 3 module(s) to anchor first in one send (app1, app2, app3), the rest once its gate passes
app1's build c2 failed its gate on anchor and was put back to c1: not healthy within -1s of its apply: anchor as a whole: raised since it was sent: machine.anchor.disk-full — anchor's root file system is full
app2's build c2 failed its gate on anchor and was put back to c1: not healthy within -1s of its apply: anchor as a whole: raised since it was sent: machine.anchor.disk-full — anchor's root file system is full
app3's build c2 failed its gate on anchor and was put back to c1: not healthy within -1s of its apply: anchor as a whole: raised since it was sent: machine.anchor.disk-full — anchor's root file system is full
plan-tier: app1 failed its gate on anchor in tier 0: not healthy within -1s of its apply: anchor as a whole: raised since it was sent: machine.anchor.disk-full — anchor's root file system is full; app2 failed its gate on anchor in tier 0: not healthy within -1s of its apply: anchor as a whole: raised since it was sent: machine.anchor.disk-full — anchor's root file system is full; app3 failed its gate on anchor in tier 0: not healthy within -1s of its apply: anchor as a whole: raised since it was sent: machine.anchor.disk-full — anchor's root file system is full; put back app1 to c1, app2 to c1, app3 to c1 on anchor, in one send; none reported left as it was
plan-gate: tier 0 built; sent 1 module(s) to anchor first in one send (app), the rest once its gate passes
plan-gate: the send to anchor in tier 0 failed its gate: not healthy within -1s of its apply: anchor has not reported on what it was sent; app was left as it was — anchor already ran app c2, or a build identical to it, before the send, so nothing of it moved and nothing is put back
plan-gate: the send to anchor in tier 0 failed its gate: not healthy within -1s of its apply: anchor has not reported on what it was sent; app was left as it was — anchor already ran app c2, or a build identical to it, before the send, so nothing of it moved and nothing is put back; none reported left as it was
tier 0: plan-tier: tier 0 built; sent 2 module(s) to anchor first in one send (node-tools, app1), the rest once its gate passes
node-tools's build c2 failed its gate on anchor and was put back to c1: the witness on anchor judged the node-tools c2 and rolled-back: the node tools did not answer
plan-tier: put back at once: node-tools (the witness on anchor judged the node-tools c2 and rolled-back: the node tools did not answer); the rest of the send judged to their own verdicts
plan-tier: the send to anchor in tier 0 failed its gate: the witness on anchor judged the node-tools c2 and rolled-back: the node tools did not answer; node-tools was put back when it broke; passed on their own and kept: app1; none reported left as it was
plan-tier: tier 0 built; sent 2 module(s) to anchor first in one send (app1, node-tools), the rest once its gate passes
node-tools's build c2 failed its gate on anchor and was put back to c1: the witness on anchor judged the node-tools c2 and rolled-back: the node tools did not answer
plan-tier: put back at once: node-tools (the witness on anchor judged the node-tools c2 and rolled-back: the node tools did not answer); the rest of the send judged to their own verdicts
plan-tier: the send to anchor in tier 0 failed its gate: the witness on anchor judged the node-tools c2 and rolled-back: the node tools did not answer; app1 passed on its own and is kept; none reported left as it was
FAIL
FAIL github.com/novox/mesh-controller/cmd/mesh-controller 167.881s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.019s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.023s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.019s
ok github.com/novox/mesh-controller/examples/route-proxy 1.130s
ok github.com/novox/mesh-controller/internal/artifacts 1.056s
ok github.com/novox/mesh-controller/internal/broker 2.559s
ok github.com/novox/mesh-controller/internal/builder 1.824s
ok github.com/novox/mesh-controller/internal/catalogue 4.258s
ok github.com/novox/mesh-controller/internal/conditions 2.198s
ok github.com/novox/mesh-controller/internal/envfile 1.060s
ok github.com/novox/mesh-controller/internal/facts 1.067s
ok github.com/novox/mesh-controller/internal/identity 4.101s
ok github.com/novox/mesh-controller/internal/inventory 72.596s
ok github.com/novox/mesh-controller/internal/lease 17.699s
ok github.com/novox/mesh-controller/internal/licences 3.848s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.055s
ok github.com/novox/mesh-controller/internal/link 50.906s
ok github.com/novox/mesh-controller/internal/lint 1.985s
ok github.com/novox/mesh-controller/internal/outward 1.088s
ok github.com/novox/mesh-controller/internal/overlay 1.070s
ok github.com/novox/mesh-controller/internal/secrets 1.402s
ok github.com/novox/mesh-controller/internal/store 3.265s
ok github.com/novox/mesh-controller/internal/testbus 1.190s
ok github.com/novox/mesh-controller/internal/token 1.017s
FAIL
**Merge check** at `8ca4b043`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller, route-proxy)
- `mesh/repo-check`: **FAIL** — its merge-check.sh failed: FAIL github.com/novox/mesh-controller/cmd/mesh-controller 167.881s
**Delivery plan** — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- tier 2: route-proxy
- ace: receives build-agent, route-proxy
- g14: receives build-agent
- novox: receives mesh-controller, build-agent, route-proxy
- shanks: receives build-agent
- build-agent keeps data (ADR 0233): what it holds is backed up before it moves
- route-proxy provides route: its consumers are sent again after it
- route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on ace as `build-1791490542277087585` (`builds --log build-1791490542277087585`).
```
ace: ace is paused
could not read what is assigned, so the build is asked of node-build-agent: this process has neither MESH_STORE_INVENTORY nor MESH_STORE_INVENTORY_FILE, so it was not granted the inventory store. A context reaches only the store it exclusively owns (novox/hq ADR 0008), so this is either the wrong context or a missing grant — it is never something to work around by reusing another context's connection
g14: nothing on g14 answers node-build-agent.resume: its holder is not running, or is older than the verb
plan-rollout: tier 0 done; asking tier 1: b
tier 1: plan-own: done — novox/a at c0ffee, 1 tier(s)
build-at-commit was built at commit 01234567; a rebuild asks what a follows now, main — `replay build-at-commit` builds that commit
rebuild asked as build-1791490767806834341
could not read what is assigned, so the build is asked of node-build-agent: this process has neither MESH_STORE_INVENTORY nor MESH_STORE_INVENTORY_FILE, so it was not granted the inventory store. A context reaches only the store it exclusively owns (novox/hq ADR 0008), so this is either the wrong context or a missing grant — it is never something to work around by reusing another context's connection
build-1791487174598413738: the build seat did not say whether c1111111 is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487175598413738: the build seat did not say whether c1111111 is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487234598413738: the build seat did not say whether c2222222 is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487235598413738: the build seat did not say whether c2222222 is on its repository's trunk (it predates ADR 0238); registered as before
plan-1: mesh-controller settled from the build records as built (build-2)
plan-3: postgres settled from the build records as built (build-mine)
plan-2: x settled from the build records as failed (b)
release-1791490775612380855: 2 build(s) wait for a gate on anchor, laptop; one machine at a time, each judged
release-1791490775612380855: sent anchor 1 build(s) that waited for a gate; judging them there
release-1791490775612380855: sent laptop 2 build(s) that waited for a gate; judging them there
release-1791490776055195623: 2 build(s) wait for a gate on anchor, laptop; one machine at a time, each judged
release-1791490776055195623: sent anchor 1 build(s) that waited for a gate; judging them there
app's build c2 failed its gate on anchor and was put back to c1: anchor failed what it was sent
release-1791490776055195623: failed its gate on anchor: anchor failed what it was sent — app failed its gate on anchor in tier 0: anchor failed what it was sent; put back app to c1 on anchor, in one send
this act by hand could NOT be recorded in the hand-act log, and is done anyway: this control plane has no MESH_BUS_NATS, so it cannot reach the mesh's bus
release-1791490776135598645: 1 build(s) wait for a gate on laptop; one machine at a time, each judged
release-1791490776135598645 releases it; `plans release-1791490776135598645` says where it is
release-1791490776135598645: sent laptop 1 build(s) that waited for a gate; judging them there
release-1791490776543513493: 3 build(s) wait for a gate on laptop, workstation; one machine at a time, each judged
release-1791490776543513493: sent laptop 3 build(s) that waited for a gate; judging them there
release-1791490776543513493: sent workstation 3 build(s) that waited for a gate; judging them there
modules/sensors is a new module in novox/mesh-catalog: build b-modules/sensors asked at main; registered when it lands, assigned nowhere
novox/mesh-catalog merged into main (5e450125); it changed no module the mesh holds, and adds modules/sensors: built, registered when the build lands, and sent nowhere
b-modules/sensors: the build seat did not say whether 5e450125 is on its repository's trunk (it predates ADR 0238); registered as before
b-modules/sensors: sensors 1 registered, built on anchor from 5e450125
sensors rolls out on build: the machines running it are sent this now, one machine at a time — `upgrade sensors record` first if something must move before it does
b-modules/sensors: laptop is assigned sensors: build b-modules/sensors registered it (pending since 2026-10-08 20:19:37 UTC); `push laptop` sends it
plan-1: dunst passed its gate on laptop in tier 0 (healthy 3 times over 2m5s) and is kept; its walk stopped after: laptop did not report it applied within 30m0s; workstation left as it was
plan-tier: tier 0 built; sent 2 module(s) to anchor first in one send (m01, m02), the rest once its gate passes
plan-tier: tier 0 built; sent m01, m02 to laptop, one send each
plan-tier: done — novox/mesh-catalog at c2, 1 tier(s)
plan-crashloop: tier 0 built; sent 1 module(s) to anchor first in one send (app), the rest once its gate passes
app's build c2 failed its gate on anchor and was put back to c1: not healthy within -1s of its apply: its container app.server on anchor keeps restarting (2 restart(s) counted)
plan-crashloop: app failed its gate on anchor in tier 0: not healthy within -1s of its apply: its container app.server on anchor keeps restarting (2 restart(s) counted); put back app to c1 on anchor, in one send; none reported left as it was
novox/mesh-catalog merged into main (3ad22356); plan plan-1791490781025383183, 1 module(s) in 1 tier(s)
0: app
tier 0: modules/systemd-resolved is a new module in novox/mesh-catalog: build build-modules/systemd-resolved asked at main; registered when it lands, assigned nowhere
novox/mesh-catalog merged into main (3da80a4b); it changed no module the mesh holds, and adds modules/systemd-resolved: built, registered when the build lands, and sent nowhere
build-1791487182208527468: the build seat did not say whether c1111111 is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487242208527468: the build seat did not say whether c2222222 is on its repository's trunk (it predates ADR 0238); registered as before
recorded as act-1791490782308259102-2 in the hand-act log: a push of recorded builds (resolver from c1111111 → c2222222) by an unnamed account at a shell on Ace, because "operator's yes: the resolver's new build on anchor" — the person's word their upgrade policy asks for, which no healer is wanted for
recorded as act-1791490782352751160-3 in the hand-act log: a push of recorded builds (resolver from c1111111 → c2222222) by an unnamed account at a shell on Ace, because "operator's yes: the resolver's new build on laptop" — the person's word their upgrade policy asks for, which no healer is wanted for
laptop is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
laptop is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
build-1791487184911473374: the build seat did not say whether c1aaaaaa is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487244911473374: the build seat did not say whether c2bbbbbb is on its repository's trunk (it predates ADR 0238); registered as before
app at c2bbbbbb was made from the source build-1791487184911473374 was: registered with its artifacts, no move
build-1791487304911473374: the build seat did not say whether c3cccccc is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487364911473374: the build seat did not say whether c4dddddd is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487185282725968: the build seat did not say whether n1111111 is on its repository's trunk (it predates ADR 0238); registered as before
build-1791487245282725968: the build seat did not say whether n2222222 is on its repository's trunk (it predates ADR 0238); registered as before
nats at n2222222 was made from the source build-1791487185282725968 was: registered with its artifacts, no move
every machine running nats runs the build the mesh holds (n2222222): nothing to upgrade
build-1791487305282725968: the build seat did not say whether n3333333 is on its repository's trunk (it predates ADR 0238); registered as before
plan-gate: app built from the source every machine running it runs: no move, nothing sent
plan-gate: done — novox/mesh-catalog at c2, 1 tier(s)
plan-gate: tier 0 built; sent 1 module(s) to anchor first in one send (app), the rest once its gate passes
status could not be composed (after 0s): the store did not answer — `status` answers the last summary, with its age
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is left out of the rest of the mesh: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
anchor is not counted as on the network: it does not resolve: these assignments cannot be applied:
- rival-one and rival-two both claim "the-seat", and only one thing may hold it per node
this act by hand could NOT be recorded in the hand-act log, and is done anyway: this control plane has no MESH_BUS_NATS, so it cannot reach the mesh's bus
plan-97b1b2b closed at tier 1 of 2; what was asked still builds and registers, nothing further is asked
plan-tier: tier 0 built; sent 12 module(s) to anchor first in one send (m01, m02, m03, m04, m05, m06, m07, m08, m09, m10, m11, m12), the rest once its gate passes
plan-tier: m01 passed its gate on anchor (healthy 3 times over 0s); the rest are sent
plan-tier: tier 0 built; sent m01, m02, m03, m04, m05, m06, m07, m08, m09, m10, m11, m12 to laptop, one send each
plan-tier: done — novox/mesh-catalog at c2, 1 tier(s)
plan-tier: tier 0 built; sent 3 module(s) to anchor first in one send (app1, app2, node-tools), the rest once its gate passes
node-tools's build c2 failed its gate on anchor and was put back to c1: not healthy within -1s of its apply: raised since it was sent: machine.anchor.core-behind — anchor runs the node tools it was last sent, not yet reported applied, and no plan is rolling them out (its settle window runs to the gate's bound)
plan-tier: the send to anchor in tier 0 failed its gate: not healthy within -1s of its apply: raised since it was sent: machine.anchor.core-behind — anchor runs the node tools it was last sent, not yet reported applied, and no plan is rolling them out (its settle window runs to the gate's bound); app1 passed on its own and is kept; passed on their own and kept: app2; node-tools failed its gate on anchor in tier 0: not healthy within -1s of its apply: raised since it was sent: machine.anchor.core-behind — anchor runs the node tools it was last sent, not yet reported applied, and no plan is rolling them out (its settle window runs to the gate's bound); put back node-tools to c1 on anchor, in one send; none reported left as it was
plan-tier: tier 0 built; sent 3 module(s) to anchor first in one send (app1, app2, app3), the rest once its gate passes
app1's build c2 failed its gate on anchor and was put back to c1: not healthy within -1s of its apply: anchor as a whole: raised since it was sent: machine.anchor.disk-full — anchor's root file system is full
app2's build c2 failed its gate on anchor and was put back to c1: not healthy within -1s of its apply: anchor as a whole: raised since it was sent: machine.anchor.disk-full — anchor's root file system is full
app3's build c2 failed its gate on anchor and was put back to c1: not healthy within -1s of its apply: anchor as a whole: raised since it was sent: machine.anchor.disk-full — anchor's root file system is full
plan-tier: app1 failed its gate on anchor in tier 0: not healthy within -1s of its apply: anchor as a whole: raised since it was sent: machine.anchor.disk-full — anchor's root file system is full; app2 failed its gate on anchor in tier 0: not healthy within -1s of its apply: anchor as a whole: raised since it was sent: machine.anchor.disk-full — anchor's root file system is full; app3 failed its gate on anchor in tier 0: not healthy within -1s of its apply: anchor as a whole: raised since it was sent: machine.anchor.disk-full — anchor's root file system is full; put back app1 to c1, app2 to c1, app3 to c1 on anchor, in one send; none reported left as it was
plan-gate: tier 0 built; sent 1 module(s) to anchor first in one send (app), the rest once its gate passes
plan-gate: the send to anchor in tier 0 failed its gate: not healthy within -1s of its apply: anchor has not reported on what it was sent; app was left as it was — anchor already ran app c2, or a build identical to it, before the send, so nothing of it moved and nothing is put back
plan-gate: the send to anchor in tier 0 failed its gate: not healthy within -1s of its apply: anchor has not reported on what it was sent; app was left as it was — anchor already ran app c2, or a build identical to it, before the send, so nothing of it moved and nothing is put back; none reported left as it was
tier 0: plan-tier: tier 0 built; sent 2 module(s) to anchor first in one send (node-tools, app1), the rest once its gate passes
node-tools's build c2 failed its gate on anchor and was put back to c1: the witness on anchor judged the node-tools c2 and rolled-back: the node tools did not answer
plan-tier: put back at once: node-tools (the witness on anchor judged the node-tools c2 and rolled-back: the node tools did not answer); the rest of the send judged to their own verdicts
plan-tier: the send to anchor in tier 0 failed its gate: the witness on anchor judged the node-tools c2 and rolled-back: the node tools did not answer; node-tools was put back when it broke; passed on their own and kept: app1; none reported left as it was
plan-tier: tier 0 built; sent 2 module(s) to anchor first in one send (app1, node-tools), the rest once its gate passes
node-tools's build c2 failed its gate on anchor and was put back to c1: the witness on anchor judged the node-tools c2 and rolled-back: the node tools did not answer
plan-tier: put back at once: node-tools (the witness on anchor judged the node-tools c2 and rolled-back: the node tools did not answer); the rest of the send judged to their own verdicts
plan-tier: the send to anchor in tier 0 failed its gate: the witness on anchor judged the node-tools c2 and rolled-back: the node tools did not answer; app1 passed on its own and is kept; none reported left as it was
FAIL
FAIL github.com/novox/mesh-controller/cmd/mesh-controller 167.881s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.019s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.023s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.019s
ok github.com/novox/mesh-controller/examples/route-proxy 1.130s
ok github.com/novox/mesh-controller/internal/artifacts 1.056s
ok github.com/novox/mesh-controller/internal/broker 2.559s
ok github.com/novox/mesh-controller/internal/builder 1.824s
ok github.com/novox/mesh-controller/internal/catalogue 4.258s
ok github.com/novox/mesh-controller/internal/conditions 2.198s
ok github.com/novox/mesh-controller/internal/envfile 1.060s
ok github.com/novox/mesh-controller/internal/facts 1.067s
ok github.com/novox/mesh-controller/internal/identity 4.101s
ok github.com/novox/mesh-controller/internal/inventory 72.596s
ok github.com/novox/mesh-controller/internal/lease 17.699s
ok github.com/novox/mesh-controller/internal/licences 3.848s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.055s
ok github.com/novox/mesh-controller/internal/link 50.906s
ok github.com/novox/mesh-controller/internal/lint 1.985s
ok github.com/novox/mesh-controller/internal/outward 1.088s
ok github.com/novox/mesh-controller/internal/overlay 1.070s
ok github.com/novox/mesh-controller/internal/secrets 1.402s
ok github.com/novox/mesh-controller/internal/store 3.265s
ok github.com/novox/mesh-controller/internal/testbus 1.190s
ok github.com/novox/mesh-controller/internal/token 1.017s
FAIL
```
A packages edge orders nothing, so a module and what packages its source
share a tier by rule; hasCycle counted the edge and the merge handler said
"the last tier depends on itself" of plans with no cycle. Skip the kind as
tiersOf does. The planner tests' cycle rows and property now pass.
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
The test's fixture had no worker-of edge and expected the builder first,
then the controller and the proxy together: the order before hq issue 206.
Since then the build seat's holder follows the controller that defines its
worker, and every controller merge plans controller, builder, proxy in
three tiers. The fixture now carries the edge and the test that order.
Update: the fix is now in this PR. The description above is out of date where it says this PR contains only tests.
8ca4b04 adds the tests. On main they fail on the false cycle report.
add807f is the fix: hasCycle now skips packages edges, as tiersOf does. The cycle rows and the property now pass. The BUG markers have been removed from the comments.
758537d updates TestAMergeIsPlannedInTiersAlongTheThreeKindsOfDependency to plan a controller merge in the worker-of order (hq issue 206). The fixture gains the builder worker-of mesh-controller edge, and the expected tiers are now mesh-controller | builder | route-proxy. Before, the test expected the builder first, then the controller and the proxy together.
I ran merge-check.sh locally against a test postgres. It passed: 26 packages under the race detector, with gofmt and vet clean.
**Update: the fix is now in this PR.** The description above is out of date where it says this PR contains only tests.
- `8ca4b04` adds the tests. On main they fail on the false cycle report.
- `add807f` is the fix: `hasCycle` now skips packages edges, as `tiersOf` does. The cycle rows and the property now pass. The BUG markers have been removed from the comments.
- `758537d` updates `TestAMergeIsPlannedInTiersAlongTheThreeKindsOfDependency` to plan a controller merge in the worker-of order (hq issue 206). The fixture gains the `builder worker-of mesh-controller` edge, and the expected tiers are now `mesh-controller | builder | route-proxy`. Before, the test expected the builder first, then the controller and the proxy together.
I ran `merge-check.sh` locally against a test postgres. It passed: 26 packages under the race detector, with gofmt and vet clean.
build-agent keeps data (ADR 0233): what it holds is backed up before it moves
route-proxy provides route: its consumers are sent again after it
route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on novox as build-1791491185322487332 (builds --log build-1791491185322487332).
--- the gate: build-agent, mesh-controller, route-proxy
mesh-controller: ok, 52 tool(s); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
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 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-08T20:19:18Z 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-08T20:19:18Z
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 3 module(s) in 3 tier(s): build-agent, mesh-controller, route-proxy
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.040s
ok github.com/novox/mesh-controller/cmd/mesh-controller 217.734s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.043s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.042s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.044s
ok github.com/novox/mesh-controller/examples/route-proxy 1.144s
ok github.com/novox/mesh-controller/internal/artifacts 1.084s
ok github.com/novox/mesh-controller/internal/broker 2.761s
ok github.com/novox/mesh-controller/internal/builder 2.634s
ok github.com/novox/mesh-controller/internal/catalogue 5.060s
ok github.com/novox/mesh-controller/internal/conditions 2.216s
ok github.com/novox/mesh-controller/internal/envfile 1.029s
ok github.com/novox/mesh-controller/internal/facts 1.060s
ok github.com/novox/mesh-controller/internal/identity 12.573s
ok github.com/novox/mesh-controller/internal/inventory 99.856s
ok github.com/novox/mesh-controller/internal/lease 18.324s
ok github.com/novox/mesh-controller/internal/licences 12.018s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.015s
ok github.com/novox/mesh-controller/internal/link 57.851s
ok github.com/novox/mesh-controller/internal/lint 2.166s
ok github.com/novox/mesh-controller/internal/outward 1.037s
ok github.com/novox/mesh-controller/internal/overlay 1.026s
ok github.com/novox/mesh-controller/internal/secrets 1.432s
ok github.com/novox/mesh-controller/internal/store 10.781s
ok github.com/novox/mesh-controller/internal/testbus 1.176s
ok github.com/novox/mesh-controller/internal/token 1.019s
**Merge check** at `758537dd`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller, route-proxy)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed
**Delivery plan** — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- tier 2: route-proxy
- ace: receives build-agent, route-proxy
- g14: receives build-agent
- novox: receives mesh-controller, build-agent, route-proxy
- shanks: receives build-agent
- build-agent keeps data (ADR 0233): what it holds is backed up before it moves
- route-proxy provides route: its consumers are sent again after it
- route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on novox as `build-1791491185322487332` (`builds --log build-1791491185322487332`).
```
--- the gate: build-agent, mesh-controller, route-proxy
mesh-controller: ok, 52 tool(s); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
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 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-08T20:19:18Z 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-08T20:19:18Z
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 3 module(s) in 3 tier(s): build-agent, mesh-controller, route-proxy
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.040s
ok github.com/novox/mesh-controller/cmd/mesh-controller 217.734s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.043s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.042s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.044s
ok github.com/novox/mesh-controller/examples/route-proxy 1.144s
ok github.com/novox/mesh-controller/internal/artifacts 1.084s
ok github.com/novox/mesh-controller/internal/broker 2.761s
ok github.com/novox/mesh-controller/internal/builder 2.634s
ok github.com/novox/mesh-controller/internal/catalogue 5.060s
ok github.com/novox/mesh-controller/internal/conditions 2.216s
ok github.com/novox/mesh-controller/internal/envfile 1.029s
ok github.com/novox/mesh-controller/internal/facts 1.060s
ok github.com/novox/mesh-controller/internal/identity 12.573s
ok github.com/novox/mesh-controller/internal/inventory 99.856s
ok github.com/novox/mesh-controller/internal/lease 18.324s
ok github.com/novox/mesh-controller/internal/licences 12.018s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.015s
ok github.com/novox/mesh-controller/internal/link 57.851s
ok github.com/novox/mesh-controller/internal/lint 2.166s
ok github.com/novox/mesh-controller/internal/outward 1.037s
ok github.com/novox/mesh-controller/internal/overlay 1.026s
ok github.com/novox/mesh-controller/internal/secrets 1.432s
ok github.com/novox/mesh-controller/internal/store 10.781s
ok github.com/novox/mesh-controller/internal/testbus 1.176s
ok github.com/novox/mesh-controller/internal/token 1.019s
```
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Tests only, no planner code changed.
What
cmd/mesh-controller/planner_rules_test.goa,b | d,e); a transitive chain; each edge kind alone for widening and for ordering (stands-on, declared, packages, built-by, worker-of); the two cycles the kinds resolve (the runtime and the builder, the builder and the controller); two repositories, including a directory of the same name in the other one; diamonds; a cycle guard; and files no build reads.mesh-controller | build-agent | route-proxy(the live three tiers, including the worker-of order).cmd/mesh-controller/planner_records_test.go(needs the test store)A bug these tests found on main (
8170fc5)hasCycle reports a cycle where there is none. It counts any edge between two modules of the last tier, including a packages edge, and a packages edge puts both modules in the same tier by rule. So the merge handler logs
the last tier depends on itself … built together, in no orderfor any plan whose last tier holds a module and its packager. ADR 0162 says a cycle is put in one last tier and reported, so a cycle reported where there is none breaks the rule. Three table rows and 19 of 500 property cases fail on this. They are marked[BUG: hasCycle counts a packages edge], and the expectations were left as they are. mesh/repo-check will be red until hasCycle is fixed. Every other row and every other invariant passes.A second, related point. TestAMergeIsPlannedInTiersAlongTheThreeKindsOfDependency (release_plan_test.go, the controller case) expects
builderand thencontroller, proxy. Its fixture has no worker-of edge, so that test predates issue 206 and does not match the live plan. I did not change it. The worker-of row here gives the real order.Do not merge before the hasCycle fix lands, or merge the fix first.
Delivery
novox/mesh-controller@758537dd4ea2— delivered since 2026-10-08T20:56:07ZDelivery plan — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
Machines
Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.Merge check at
8ca4b043mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller, route-proxy)mesh/repo-check: FAIL — its merge-check.sh failed: FAIL github.com/novox/mesh-controller/cmd/mesh-controller 167.881sDelivery plan — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
Run by the build seat on ace as
build-1791490542277087585(builds --log build-1791490542277087585).Update: the fix is now in this PR. The description above is out of date where it says this PR contains only tests.
8ca4b04adds the tests. On main they fail on the false cycle report.add807fis the fix:hasCyclenow skips packages edges, astiersOfdoes. The cycle rows and the property now pass. The BUG markers have been removed from the comments.758537dupdatesTestAMergeIsPlannedInTiersAlongTheThreeKindsOfDependencyto plan a controller merge in the worker-of order (hq issue 206). The fixture gains thebuilder worker-of mesh-controlleredge, and the expected tiers are nowmesh-controller | builder | route-proxy. Before, the test expected the builder first, then the controller and the proxy together.I ran
merge-check.shlocally against a test postgres. It passed: 26 packages under the race detector, with gofmt and vet clean.Merge check at
758537ddmesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller, route-proxy)mesh/repo-check: PASS — its merge-check.sh passedDelivery plan — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
Run by the build seat on novox as
build-1791491185322487332(builds --log build-1791491185322487332).