Issue 596 (genesis cannot get past its builder step: the installer installs the builder module, which left the catalogue with ADR 0190). Decision: hq ADR 0190 §5 (the build role is node-build-agent, held by the build-agent module; builder is retired).
What
BuilderModule is build-agent. Step 13 reads the catalogue's build-agent manifest.
pinTheCarriedBuilder runs the builder image the installer carried and published, by its registry reference, in every container the manifest runs from an image artifact it builds ("artifact": "server"). Nothing has built that artifact at genesis, and the carried image is that program (mesh-controller cmd/mesh-builder). A manifest with the old placeholder digest is pinned the old way. One with nowhere to put the image is refused.
The agent's bus account is issued as every module's (module issue build-agent --node). Before, it was builder issue, whose --module defaults to builder.
Tests (fail on main)
TestGenesisInstallsTheCataloguesBuildAgent reads the catalogue's own build-agent manifest (MESH_CHECK_BESIDE / beside / loud skip). The pinned manifest must claim node-build-agent and run one container on the carried reference, with no artifact left. On main the catalogue has no builder, and step 13 stopped there.
The package-port test now names the build agent's settings.
merge-check.sh passes.
Lab, 2026-10-13 on g14 (with the issue 597 change): genesis reached step 13 and registered build-agent with the carried image. The controller refused the assignment: nothing provides "npm-package-registry", wanted by build-agent. That is issue 121 (it needs a decision; I added the evidence as a note there). So genesis does not reach the broker step yet.
Not done here, waiting on 121: the packages step still seals an npm-password own-secret to the build agent (deliverBuilderNpm). build-agent has no such own-secret: it takes its registry credential from the npm-package-registry provision. How the build agent gets its registry binding and credential before gitea is a module is the decision issue 121 asks for.
Fixes the missing-module part of issue 596; genesis past step 13 waits on issue 121.
Issue 596 (genesis cannot get past its builder step: the installer installs the builder module, which left the catalogue with ADR 0190). Decision: hq ADR 0190 §5 (the build role is `node-build-agent`, held by the `build-agent` module; `builder` is retired).
**What**
- `BuilderModule` is `build-agent`. Step 13 reads the catalogue's build-agent manifest.
- `pinTheCarriedBuilder` runs the builder image the installer carried and published, by its registry reference, in every container the manifest runs from an image artifact it builds (`"artifact": "server"`). Nothing has built that artifact at genesis, and the carried image is that program (mesh-controller cmd/mesh-builder). A manifest with the old placeholder digest is pinned the old way. One with nowhere to put the image is refused.
- The agent's bus account is issued as every module's (`module issue build-agent --node`). Before, it was `builder issue`, whose `--module` defaults to `builder`.
**Tests (fail on main)**
- `TestGenesisInstallsTheCataloguesBuildAgent` reads the catalogue's own build-agent manifest (MESH_CHECK_BESIDE / beside / loud skip). The pinned manifest must claim `node-build-agent` and run one container on the carried reference, with no artifact left. On main the catalogue has no `builder`, and step 13 stopped there.
- `TestABuildAgentManifestWithNowhereForTheCarriedBuilderIsRefused`.
- The package-port test now names the build agent's settings.
- merge-check.sh passes.
**Lab, 2026-10-13 on g14 (with the issue 597 change)**: genesis reached step 13 and registered build-agent with the carried image. The controller refused the assignment: `nothing provides "npm-package-registry", wanted by build-agent`. That is **issue 121** (it needs a decision; I added the evidence as a note there). So genesis does not reach the broker step yet.
**Not done here, waiting on 121**: the packages step still seals an `npm-password` own-secret to the build agent (`deliverBuilderNpm`). build-agent has no such own-secret: it takes its registry credential from the `npm-package-registry` provision. How the build agent gets its registry binding and credential before gitea is a module is the decision issue 121 asks for.
Fixes the missing-module part of issue 596; genesis past step 13 waits on issue 121.
Genesis's builder step read modules/builder from the catalogue, which retired it on 2026-10-03 for
the build agent (node-build-agent on every machine), so no genesis got past step 13. The step now
installs build-agent from the catalogue, puts the builder image it carried and published where the
manifest names the image it builds, and issues its bus account as any module's.
Deliverynovox/mesh-host@d941d798e9df — delivered since 2026-10-13T00:52:44Z
Delivery plan — builds nothing: the change touches no module of the mesh's graph
Transitions
2026-10-13 00:29 (new) → proposed (announced): novox/mesh-host#101's head announced
2026-10-13 00:31 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
2026-10-13 00:31 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-13 00:40 ready → proposed (trunk moved): out of date: judged against trunk 8431ac9656, the trunk is now d34b4f32e17f; judged again on a recheck or when it is merged
2026-10-13 00:41 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
2026-10-13 00:41 checked → rejected (refused): the gate failed or could not run, or the repository's own check failed
2026-10-13 00:48 rejected → proposed (recheck): repo-check failed on a flaky internal/link test (issue 604: consumer is already bound to a subscription); #101 touches only internal/bootstrap and its merge with d34b4f32 passed 10 of 10 runs locally
2026-10-13 00:49 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
2026-10-13 00:49 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-13 00: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-13 00:52 published → delivered (done): nothing for a walk to move
The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-host@d941d798e9df` — **delivered** since 2026-10-13T00:52:44Z
**Delivery plan** — builds nothing: the change touches no module of the mesh's graph
**Transitions**
- 2026-10-13 00:29 (new) → proposed (announced): novox/mesh-host#101's head announced
- 2026-10-13 00:31 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
- 2026-10-13 00:31 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-13 00:40 ready → proposed (trunk moved): out of date: judged against trunk 8431ac96562e, the trunk is now d34b4f32e17f; judged again on a recheck or when it is merged
- 2026-10-13 00:41 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
- 2026-10-13 00:41 checked → rejected (refused): the gate failed or could not run, or the repository's own check failed
- 2026-10-13 00:48 rejected → proposed (recheck): repo-check failed on a flaky internal/link test (issue 604: consumer is already bound to a subscription); #101 touches only internal/bootstrap and its merge with d34b4f32 passed 10 of 10 runs locally
- 2026-10-13 00:49 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
- 2026-10-13 00:49 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-13 00: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-13 00:52 published → delivered (done): nothing for a walk to move
The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
Independent review (read-only worktree at the head; mesh-catalog main 827b89d and mesh-controller main 4473bc7 beside it through MESH_CHECK_BESIDE).
Acceptance (issue 596, ADR 0190 §11 the build role is node-build-agent): step 13 now reads modules/build-agent, which exists in the catalogue and claims node-build-agent. The PR honestly scopes itself: the lab log (run2) shows pinned to 192.0.2.10:5000/mesh-builder@sha256:80ef…, named in 1 place(s), the module registered, and then assign anchor build-agent refused with nothing provides "npm-package-registry", wanted by build-agent. That is issue 121 (its 2026-10-13 note carries the same evidence), so genesis stops at step 13 on 121 and the PR claims no more. The "Fixes the missing-module part" wording is right; issue 596 should not be resolved on this merge alone if its acceptance is "genesis from bare reaches the end".
Tests fail without the fix: with only BuilderModule set back to "builder", TestGenesisInstallsTheCataloguesBuildAgent fails (the catalogue has no builder). With pinTheCarriedBuilder reduced to the old pinPlaceholder, both new tests fail (no placeholder digest in build-agent). With builder.go wholly reverted the tests do not compile. merge-check.sh passes at the head (bus tests skipped and said). mesh/merge-gate and mesh/repo-check are green at this head. #100 and #101 merged together pass internal/bootstrap and cmd/.
Consistency with the catalogue and the controller: build-agent's single container runs "artifact": "server", an image built from mesh-controller cmd/mesh-builder, which is the program the installer carries (internal/image), so its health command /usr/local/bin/mesh-builder ready is in the carried image. module issue in mesh-controller main calls the same issueOnTheNewBus as builder issue did, plus mayIssue, which build-agent passes (it declares own-secret broker). builder issue defaults --module to builder, so keeping it would have failed; the switch is right. A re-run mints a fresh password, so dropping the "already" tolerance is fine.
Correctness risks read:
json.MarshalIndent over map[string]any reorders keys and escapes <, >, & as <…; both are the same JSON to the controller. build-agent's numbers are small integers, so float64 round-trips them. The controller's module add accepted the result in the lab run. Acceptable; the comment could say the bytes differ from the catalogue's (the old placeholder path also changed them).
The new account line (module issue build-agent --node) has no test that asserts what is told to the controller. Non-blocking; a test on the fake control plane's told list would pin it.
Stale paths still name the build agent with the builder's shape, unreachable today because step 13 stops on 121, but they will bite once 121 is decided: (a) phase_packages.go deliverBuilderNpm seals npm-password to build-agent, which has no such own-secret (the PR body says so); (b) ports.go setFoundationSettings sets serves.port on build-agent when --ports gives a non-default packages port. That one runs inside step 13 itself, before the assignment, and build-agent declares no settings; I did not check whether the controller refuses an undeclared setting. Both belong with the issue 121 decision; please note (b) on issue 121 as well.
No hand workaround.
Verdict: approve at d941d798e9df5928ca10a4c3e658c5a1f597d615
Independent review (read-only worktree at the head; mesh-catalog main 827b89d and mesh-controller main 4473bc7 beside it through MESH_CHECK_BESIDE).
Acceptance (issue 596, ADR 0190 §11 the build role is node-build-agent): step 13 now reads modules/build-agent, which exists in the catalogue and claims node-build-agent. The PR honestly scopes itself: the lab log (run2) shows `pinned to 192.0.2.10:5000/mesh-builder@sha256:80ef…, named in 1 place(s)`, the module registered, and then `assign anchor build-agent` refused with `nothing provides "npm-package-registry", wanted by build-agent`. That is issue 121 (its 2026-10-13 note carries the same evidence), so genesis stops at step 13 on 121 and the PR claims no more. The "Fixes the missing-module part" wording is right; issue 596 should not be resolved on this merge alone if its acceptance is "genesis from bare reaches the end".
Tests fail without the fix: with only `BuilderModule` set back to "builder", `TestGenesisInstallsTheCataloguesBuildAgent` fails (the catalogue has no builder). With `pinTheCarriedBuilder` reduced to the old `pinPlaceholder`, both new tests fail (no placeholder digest in build-agent). With builder.go wholly reverted the tests do not compile. merge-check.sh passes at the head (bus tests skipped and said). mesh/merge-gate and mesh/repo-check are green at this head. #100 and #101 merged together pass internal/bootstrap and cmd/.
Consistency with the catalogue and the controller: build-agent's single container runs `"artifact": "server"`, an image built from mesh-controller cmd/mesh-builder, which is the program the installer carries (internal/image), so its health command `/usr/local/bin/mesh-builder ready` is in the carried image. `module issue` in mesh-controller main calls the same `issueOnTheNewBus` as `builder issue` did, plus `mayIssue`, which build-agent passes (it declares own-secret `broker`). `builder issue` defaults `--module` to `builder`, so keeping it would have failed; the switch is right. A re-run mints a fresh password, so dropping the "already" tolerance is fine.
Correctness risks read:
1. json.MarshalIndent over map[string]any reorders keys and escapes <, >, & as <…; both are the same JSON to the controller. build-agent's numbers are small integers, so float64 round-trips them. The controller's `module add` accepted the result in the lab run. Acceptable; the comment could say the bytes differ from the catalogue's (the old placeholder path also changed them).
2. The new account line (`module issue build-agent --node`) has no test that asserts what is told to the controller. Non-blocking; a test on the fake control plane's told list would pin it.
3. Stale paths still name the build agent with the builder's shape, unreachable today because step 13 stops on 121, but they will bite once 121 is decided: (a) phase_packages.go `deliverBuilderNpm` seals `npm-password` to build-agent, which has no such own-secret (the PR body says so); (b) ports.go `setFoundationSettings` sets `serves.port` on build-agent when --ports gives a non-default packages port. That one runs inside step 13 itself, before the assignment, and build-agent declares no settings; I did not check whether the controller refuses an undeclared setting. Both belong with the issue 121 decision; please note (b) on issue 121 as well.
No hand workaround.
Independent review, replacing the builder's own (review 132 on this PR was written by the builder and is not independent). I read the diff in a fresh clone at the head, with mesh-catalog main and mesh-controller main cloned beside it. I read ADR 0190 through knowledge-base.get. Its section 5 (clauses 11 to 13) says the build role is node-build-agent, held by the build-agent module, which resolves the package registry as a provision, and that the builder module is retired.
No blocking findings. The change takes genesis one step further than main, and it stops honestly at issue 121.
Image placement. pinTheCarriedBuilder replaces "artifact": "server" with the carried reference only in containers whose artifact is an image artifact of the manifest's own build. The catalogue's build-agent manifest has exactly one such container (id server, artifact server, kind image, compiled from mesh-controller cmd/mesh-builder), and its health command runs /usr/local/bin/mesh-builder, which the carried image holds. A manifest with no image artifact is refused, and a manifest still carrying the placeholder digest is pinned the old way. The MarshalIndent round trip reorders keys and escapes <, > and & as unicode escapes. That is the same JSON to the controller, and build-agent's numbers are small integers that survive float64.
Bus account. module issue build-agent --node <node> is the generic verb in mesh-controller main (cmd/mesh-controller/modules.go). It requires the module in the catalogue and an own-secret named broker, and build-agent declares own-secrets.broker. The old builder issue defaults its module to builder, so keeping it would have failed. A re-run mints a new password, so dropping the "already" tolerance is right.
The two leftovers. (a) deliverBuilderNpm still seals an npm-password own-secret to build-agent, which declares no such own-secret; it takes its credential from the npm-package-registry provision (ADR 0190 clause 12). The PR body names this one and ties it to issue 121. (b) setFoundationSettings still sets serves.port on build-agent when --ports gives a non-default package port, and build-agent declares no settings and no mergeable file meant for it. The PR body does NOT name (b); only the builder's own review does. Neither makes this change worse than main. On main, step 13 fails at reading the builder manifest, before either runs. At this head, setFoundationSettings runs in prepareModule after assign, and assign is refused on issue 121 ("nothing provides npm-package-registry"), so both are unreachable until 121 is decided. Please name (b) in the PR body and in a note on issue 121, so whoever decides 121 changes both.
Tests. With only the test file at the head and builder.go from main, the package does not compile (pinTheCarriedBuilder is undefined). With only BuilderModule set back to "builder" and MESH_CHECK_BESIDE pointing at the clones, TestGenesisInstallsTheCataloguesBuildAgent fails: the catalogue has no modules/builder. merge-check.sh passes at the head with MESH_CHECK_BESIDE set. This toolchain holds no nats-server, so the bus tests were skipped, and the script says so.
Non-blocking:
theCataloguesModule skips with "NOT JUDGED: no catalogue beside this checkout" whenever the module's file is missing, even when a catalogue is beside it. With BuilderModule set back to "builder" and no MESH_CHECK_BESIDE, the test skipped instead of failing, while a catalogue was beside the checkout. It should skip only when the catalogue directory is missing, and fail when the catalogue is there but the module is not.
No test asserts what is told to the controller for the account (module issue build-agent --node anchor). A check on the fake control plane's told list would pin it.
Issue 596 should not be resolved on this merge alone, since genesis still stops at step 13 on issue 121. The PR body says "Fixes the missing-module part", which is accurate.
Gitea statuses at this head: mesh/merge-gate success, "head d941d798e9 merged into trunk 8431ac9656 - pass: the change touches no module of the mesh's graph". mesh/repo-check success, "head d941d798e9 merged into trunk 8431ac9656 - pass: its merge-check.sh passed". mesh/delivery success, "ready: it delivers once merged". The trunk is still 8431ac9. If #100 merges first, ask mesh-delivery.recheck for this PR before merging it.
Verdict: approve at d941d798e9df5928ca10a4c3e658c5a1f597d615
Independent review, replacing the builder's own (review 132 on this PR was written by the builder and is not independent). I read the diff in a fresh clone at the head, with mesh-catalog main and mesh-controller main cloned beside it. I read ADR 0190 through knowledge-base.get. Its section 5 (clauses 11 to 13) says the build role is `node-build-agent`, held by the `build-agent` module, which resolves the package registry as a provision, and that the `builder` module is retired.
No blocking findings. The change takes genesis one step further than main, and it stops honestly at issue 121.
Image placement. pinTheCarriedBuilder replaces `"artifact": "server"` with the carried reference only in containers whose artifact is an `image` artifact of the manifest's own build. The catalogue's build-agent manifest has exactly one such container (id server, artifact server, kind image, compiled from mesh-controller cmd/mesh-builder), and its health command runs /usr/local/bin/mesh-builder, which the carried image holds. A manifest with no image artifact is refused, and a manifest still carrying the placeholder digest is pinned the old way. The MarshalIndent round trip reorders keys and escapes <, > and & as unicode escapes. That is the same JSON to the controller, and build-agent's numbers are small integers that survive float64.
Bus account. `module issue build-agent --node <node>` is the generic verb in mesh-controller main (cmd/mesh-controller/modules.go). It requires the module in the catalogue and an own-secret named broker, and build-agent declares `own-secrets.broker`. The old `builder issue` defaults its module to `builder`, so keeping it would have failed. A re-run mints a new password, so dropping the "already" tolerance is right.
The two leftovers. (a) deliverBuilderNpm still seals an `npm-password` own-secret to build-agent, which declares no such own-secret; it takes its credential from the `npm-package-registry` provision (ADR 0190 clause 12). The PR body names this one and ties it to issue 121. (b) setFoundationSettings still sets `serves.port` on build-agent when --ports gives a non-default package port, and build-agent declares no settings and no mergeable file meant for it. The PR body does NOT name (b); only the builder's own review does. Neither makes this change worse than main. On main, step 13 fails at reading the `builder` manifest, before either runs. At this head, setFoundationSettings runs in prepareModule after `assign`, and `assign` is refused on issue 121 ("nothing provides npm-package-registry"), so both are unreachable until 121 is decided. Please name (b) in the PR body and in a note on issue 121, so whoever decides 121 changes both.
Tests. With only the test file at the head and builder.go from main, the package does not compile (pinTheCarriedBuilder is undefined). With only BuilderModule set back to "builder" and MESH_CHECK_BESIDE pointing at the clones, TestGenesisInstallsTheCataloguesBuildAgent fails: the catalogue has no modules/builder. merge-check.sh passes at the head with MESH_CHECK_BESIDE set. This toolchain holds no nats-server, so the bus tests were skipped, and the script says so.
Non-blocking:
1. theCataloguesModule skips with "NOT JUDGED: no catalogue beside this checkout" whenever the module's file is missing, even when a catalogue is beside it. With BuilderModule set back to "builder" and no MESH_CHECK_BESIDE, the test skipped instead of failing, while a catalogue was beside the checkout. It should skip only when the catalogue directory is missing, and fail when the catalogue is there but the module is not.
2. No test asserts what is told to the controller for the account (`module issue build-agent --node anchor`). A check on the fake control plane's told list would pin it.
3. Issue 596 should not be resolved on this merge alone, since genesis still stops at step 13 on issue 121. The PR body says "Fixes the missing-module part", which is accurate.
Gitea statuses at this head: mesh/merge-gate success, "head d941d798e9df merged into trunk 8431ac96562e - pass: the change touches no module of the mesh's graph". mesh/repo-check success, "head d941d798e9df merged into trunk 8431ac96562e - pass: its merge-check.sh passed". mesh/delivery success, "ready: it delivers once merged". The trunk is still 8431ac9. If #100 merges first, ask mesh-delivery.recheck for this PR before merging it.
Merge check at d941d798
Judged: head d941d798e9df merged into trunk d34b4f32e17f; read beside it: mesh-catalog f88e3452f8b8, mesh-controller 4473bc7d7315, mesh-controller-main eb7ee921b533, mesh-tools 954e1a53eef9
mesh/merge-gate: PASS — the change touches no module of the mesh's graph
mesh/repo-check: FAIL — its merge-check.sh failed: --- FAIL: TestNatsAnEnrolmentWithNoReplyAddressIsNotAnswered (0.00s)
Run by the build seat on ace as build-1791852038444845380 (builds --log build-1791852038444845380).
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-host/cmd/mesh-bootstrap 1.014s
ok github.com/novox/mesh-host/cmd/mesh-host 5.706s
ok github.com/novox/mesh-host/examples 1.025s
ok github.com/novox/mesh-host/internal/accounts 1.480s
ok github.com/novox/mesh-host/internal/apply 4.961s
ok github.com/novox/mesh-host/internal/bootstrap 3.747s
ok github.com/novox/mesh-host/internal/bundle 1.050s
ok github.com/novox/mesh-host/internal/declaration 1.084s
ok github.com/novox/mesh-host/internal/firewall 1.692s
ok github.com/novox/mesh-host/internal/identity 1.113s
ok github.com/novox/mesh-host/internal/image 1.053s
ok github.com/novox/mesh-host/internal/inventory 1.062s
--- FAIL: TestNatsAnEnrolmentWithNoReplyAddressIsNotAnswered (0.00s)
asking_nats_test.go:124: consumer is already bound to a subscription
FAIL
FAIL github.com/novox/mesh-host/internal/link 9.599s
ok github.com/novox/mesh-host/internal/liveness 2.125s
ok github.com/novox/mesh-host/internal/meshcli 1.626s
ok github.com/novox/mesh-host/internal/network 1.074s
ok github.com/novox/mesh-host/internal/outward 1.065s
ok github.com/novox/mesh-host/internal/profile 1.618s
ok github.com/novox/mesh-host/internal/reachable 1.058s
ok github.com/novox/mesh-host/internal/store 1.226s
ok github.com/novox/mesh-host/internal/system 1.060s
ok github.com/novox/mesh-host/internal/tunnel 1.057s
ok github.com/novox/mesh-host/internal/units 1.051s
ok github.com/novox/mesh-host/internal/upgrade 1.176s
ok github.com/novox/mesh-host/internal/witness 4.760s
ok github.com/novox/mesh-host/packaging 1.049s
? github.com/novox/mesh-host/rootsearch [no test files]
ok github.com/novox/mesh-host/validate 1.047s
FAIL
--- what failed, picked from the whole of its output (the whole is in the build's log)
--- FAIL: TestNatsAnEnrolmentWithNoReplyAddressIsNotAnswered (0.00s)
asking_nats_test.go:124: consumer is already bound to a subscription
FAIL github.com/novox/mesh-host/internal/link 9.599s
**Merge check** at `d941d798`
Judged: head `d941d798e9df` merged into trunk `d34b4f32e17f`; read beside it: mesh-catalog `f88e3452f8b8`, mesh-controller `4473bc7d7315`, mesh-controller-main `eb7ee921b533`, mesh-tools `954e1a53eef9`
- `mesh/merge-gate`: **PASS** — the change touches no module of the mesh's graph
- `mesh/repo-check`: **FAIL** — its merge-check.sh failed: --- FAIL: TestNatsAnEnrolmentWithNoReplyAddressIsNotAnswered (0.00s)
Run by the build seat on ace as `build-1791852038444845380` (`builds --log build-1791852038444845380`).
```
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-host/cmd/mesh-bootstrap 1.014s
ok github.com/novox/mesh-host/cmd/mesh-host 5.706s
ok github.com/novox/mesh-host/examples 1.025s
ok github.com/novox/mesh-host/internal/accounts 1.480s
ok github.com/novox/mesh-host/internal/apply 4.961s
ok github.com/novox/mesh-host/internal/bootstrap 3.747s
ok github.com/novox/mesh-host/internal/bundle 1.050s
ok github.com/novox/mesh-host/internal/declaration 1.084s
ok github.com/novox/mesh-host/internal/firewall 1.692s
ok github.com/novox/mesh-host/internal/identity 1.113s
ok github.com/novox/mesh-host/internal/image 1.053s
ok github.com/novox/mesh-host/internal/inventory 1.062s
--- FAIL: TestNatsAnEnrolmentWithNoReplyAddressIsNotAnswered (0.00s)
asking_nats_test.go:124: consumer is already bound to a subscription
FAIL
FAIL github.com/novox/mesh-host/internal/link 9.599s
ok github.com/novox/mesh-host/internal/liveness 2.125s
ok github.com/novox/mesh-host/internal/meshcli 1.626s
ok github.com/novox/mesh-host/internal/network 1.074s
ok github.com/novox/mesh-host/internal/outward 1.065s
ok github.com/novox/mesh-host/internal/profile 1.618s
ok github.com/novox/mesh-host/internal/reachable 1.058s
ok github.com/novox/mesh-host/internal/store 1.226s
ok github.com/novox/mesh-host/internal/system 1.060s
ok github.com/novox/mesh-host/internal/tunnel 1.057s
ok github.com/novox/mesh-host/internal/units 1.051s
ok github.com/novox/mesh-host/internal/upgrade 1.176s
ok github.com/novox/mesh-host/internal/witness 4.760s
ok github.com/novox/mesh-host/packaging 1.049s
? github.com/novox/mesh-host/rootsearch [no test files]
ok github.com/novox/mesh-host/validate 1.047s
FAIL
--- what failed, picked from the whole of its output (the whole is in the build's log)
--- FAIL: TestNatsAnEnrolmentWithNoReplyAddressIsNotAnswered (0.00s)
asking_nats_test.go:124: consumer is already bound to a subscription
FAIL github.com/novox/mesh-host/internal/link 9.599s
```
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.
Issue 596 (genesis cannot get past its builder step: the installer installs the builder module, which left the catalogue with ADR 0190). Decision: hq ADR 0190 §5 (the build role is
node-build-agent, held by thebuild-agentmodule;builderis retired).What
BuilderModuleisbuild-agent. Step 13 reads the catalogue's build-agent manifest.pinTheCarriedBuilderruns the builder image the installer carried and published, by its registry reference, in every container the manifest runs from an image artifact it builds ("artifact": "server"). Nothing has built that artifact at genesis, and the carried image is that program (mesh-controller cmd/mesh-builder). A manifest with the old placeholder digest is pinned the old way. One with nowhere to put the image is refused.module issue build-agent --node). Before, it wasbuilder issue, whose--moduledefaults tobuilder.Tests (fail on main)
TestGenesisInstallsTheCataloguesBuildAgentreads the catalogue's own build-agent manifest (MESH_CHECK_BESIDE / beside / loud skip). The pinned manifest must claimnode-build-agentand run one container on the carried reference, with no artifact left. On main the catalogue has nobuilder, and step 13 stopped there.TestABuildAgentManifestWithNowhereForTheCarriedBuilderIsRefused.Lab, 2026-10-13 on g14 (with the issue 597 change): genesis reached step 13 and registered build-agent with the carried image. The controller refused the assignment:
nothing provides "npm-package-registry", wanted by build-agent. That is issue 121 (it needs a decision; I added the evidence as a note there). So genesis does not reach the broker step yet.Not done here, waiting on 121: the packages step still seals an
npm-passwordown-secret to the build agent (deliverBuilderNpm). build-agent has no such own-secret: it takes its registry credential from thenpm-package-registryprovision. How the build agent gets its registry binding and credential before gitea is a module is the decision issue 121 asks for.Fixes the missing-module part of issue 596; genesis past step 13 waits on issue 121.
Delivery
novox/mesh-host@d941d798e9df— delivered since 2026-10-13T00:52:44ZDelivery plan — builds nothing: the change touches no module of the mesh's graph
Transitions
8431ac9656, the trunk is now d34b4f32e17f; judged again on a recheck or when it is mergedd34b4f32passed 10 of 10 runs locallyThe commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.Verdict: approve at
d941d798e9Independent review (read-only worktree at the head; mesh-catalog main 827b89d and mesh-controller main 4473bc7 beside it through MESH_CHECK_BESIDE).
Acceptance (issue 596, ADR 0190 §11 the build role is node-build-agent): step 13 now reads modules/build-agent, which exists in the catalogue and claims node-build-agent. The PR honestly scopes itself: the lab log (run2) shows
pinned to 192.0.2.10:5000/mesh-builder@sha256:80ef…, named in 1 place(s), the module registered, and thenassign anchor build-agentrefused withnothing provides "npm-package-registry", wanted by build-agent. That is issue 121 (its 2026-10-13 note carries the same evidence), so genesis stops at step 13 on 121 and the PR claims no more. The "Fixes the missing-module part" wording is right; issue 596 should not be resolved on this merge alone if its acceptance is "genesis from bare reaches the end".Tests fail without the fix: with only
BuilderModuleset back to "builder",TestGenesisInstallsTheCataloguesBuildAgentfails (the catalogue has no builder). WithpinTheCarriedBuilderreduced to the oldpinPlaceholder, both new tests fail (no placeholder digest in build-agent). With builder.go wholly reverted the tests do not compile. merge-check.sh passes at the head (bus tests skipped and said). mesh/merge-gate and mesh/repo-check are green at this head. #100 and #101 merged together pass internal/bootstrap and cmd/.Consistency with the catalogue and the controller: build-agent's single container runs
"artifact": "server", an image built from mesh-controller cmd/mesh-builder, which is the program the installer carries (internal/image), so its health command/usr/local/bin/mesh-builder readyis in the carried image.module issuein mesh-controller main calls the sameissueOnTheNewBusasbuilder issuedid, plusmayIssue, which build-agent passes (it declares own-secretbroker).builder issuedefaults--moduletobuilder, so keeping it would have failed; the switch is right. A re-run mints a fresh password, so dropping the "already" tolerance is fine.Correctness risks read:
module addaccepted the result in the lab run. Acceptable; the comment could say the bytes differ from the catalogue's (the old placeholder path also changed them).module issue build-agent --node) has no test that asserts what is told to the controller. Non-blocking; a test on the fake control plane's told list would pin it.deliverBuilderNpmsealsnpm-passwordto build-agent, which has no such own-secret (the PR body says so); (b) ports.gosetFoundationSettingssetsserves.porton build-agent when --ports gives a non-default packages port. That one runs inside step 13 itself, before the assignment, and build-agent declares no settings; I did not check whether the controller refuses an undeclared setting. Both belong with the issue 121 decision; please note (b) on issue 121 as well.No hand workaround.
Verdict: approve at
d941d798e9Independent review, replacing the builder's own (review 132 on this PR was written by the builder and is not independent). I read the diff in a fresh clone at the head, with mesh-catalog main and mesh-controller main cloned beside it. I read ADR 0190 through knowledge-base.get. Its section 5 (clauses 11 to 13) says the build role is
node-build-agent, held by thebuild-agentmodule, which resolves the package registry as a provision, and that thebuildermodule is retired.No blocking findings. The change takes genesis one step further than main, and it stops honestly at issue 121.
Image placement. pinTheCarriedBuilder replaces
"artifact": "server"with the carried reference only in containers whose artifact is animageartifact of the manifest's own build. The catalogue's build-agent manifest has exactly one such container (id server, artifact server, kind image, compiled from mesh-controller cmd/mesh-builder), and its health command runs /usr/local/bin/mesh-builder, which the carried image holds. A manifest with no image artifact is refused, and a manifest still carrying the placeholder digest is pinned the old way. The MarshalIndent round trip reorders keys and escapes <, > and & as unicode escapes. That is the same JSON to the controller, and build-agent's numbers are small integers that survive float64.Bus account.
module issue build-agent --node <node>is the generic verb in mesh-controller main (cmd/mesh-controller/modules.go). It requires the module in the catalogue and an own-secret named broker, and build-agent declaresown-secrets.broker. The oldbuilder issuedefaults its module tobuilder, so keeping it would have failed. A re-run mints a new password, so dropping the "already" tolerance is right.The two leftovers. (a) deliverBuilderNpm still seals an
npm-passwordown-secret to build-agent, which declares no such own-secret; it takes its credential from thenpm-package-registryprovision (ADR 0190 clause 12). The PR body names this one and ties it to issue 121. (b) setFoundationSettings still setsserves.porton build-agent when --ports gives a non-default package port, and build-agent declares no settings and no mergeable file meant for it. The PR body does NOT name (b); only the builder's own review does. Neither makes this change worse than main. On main, step 13 fails at reading thebuildermanifest, before either runs. At this head, setFoundationSettings runs in prepareModule afterassign, andassignis refused on issue 121 ("nothing provides npm-package-registry"), so both are unreachable until 121 is decided. Please name (b) in the PR body and in a note on issue 121, so whoever decides 121 changes both.Tests. With only the test file at the head and builder.go from main, the package does not compile (pinTheCarriedBuilder is undefined). With only BuilderModule set back to "builder" and MESH_CHECK_BESIDE pointing at the clones, TestGenesisInstallsTheCataloguesBuildAgent fails: the catalogue has no modules/builder. merge-check.sh passes at the head with MESH_CHECK_BESIDE set. This toolchain holds no nats-server, so the bus tests were skipped, and the script says so.
Non-blocking:
module issue build-agent --node anchor). A check on the fake control plane's told list would pin it.Gitea statuses at this head: mesh/merge-gate success, "head
d941d798e9merged into trunk8431ac9656- pass: the change touches no module of the mesh's graph". mesh/repo-check success, "headd941d798e9merged into trunk8431ac9656- pass: its merge-check.sh passed". mesh/delivery success, "ready: it delivers once merged". The trunk is still8431ac9. If #100 merges first, ask mesh-delivery.recheck for this PR before merging it.Merge check at
d941d798Judged: head
d941d798e9dfmerged into trunkd34b4f32e17f; read beside it: mesh-catalogf88e3452f8b8, mesh-controller4473bc7d7315, mesh-controller-maineb7ee921b533, mesh-tools954e1a53eef9mesh/merge-gate: PASS — the change touches no module of the mesh's graphmesh/repo-check: FAIL — its merge-check.sh failed: --- FAIL: TestNatsAnEnrolmentWithNoReplyAddressIsNotAnswered (0.00s)Run by the build seat on ace as
build-1791852038444845380(builds --log build-1791852038444845380).