The lab runs on the laptop again: the walk's builder on the bus, runtime images on node-tools, enumeration tests independent of the host's incus (hq issues 307, 308)
#63
Merged
mesh-adminmerged 6 commits from fix/the-lab-runs-on-the-laptop into main2026-10-08 08:34:40 +00:00
Stacked on #61 (now merged): this shows only its own commits. Relates to #62: the prover's module subdirectory is #62's Module field, not repeated here.
Issue numbers: the runtime image and the walk are hq issue 307; the enumeration tests are hq issue 308 (both in hq #192).
Enumeration tests no longer depend on the host's incus (hq issue 308). test/enumerate.test.ts set MESH_LAB_INCUS=false in its body, but an ES module's imports run first, so src/incus/client.ts had already read the variable and the tests asked the real incus. They passed where none is installed (the build seat) and failed on the workstation that runs the lab. The client now takes the command by injection (useIncusCommand); the test names false and gets it everywhere.
scripts/build-module-runtime.sh builds on node-tools (hq issue 307). It copied mesh-tools' old TypeScript runtime. The runtime is now node-tools, a Go binary in mesh-tools' node-tools/, which launches each bundle through the <entry>.serve.mjs launcher the builder writes (ADR 0193). The script compiles the module's declared entrypoints against the sibling SDK, writes the builder's launchers, stages the SDK, builds node-tools with Go and makes it the entrypoint. The image runs on the node's runtime credential or MESH_BROKER_URL: the Go runtime refuses to serve a module on that module's own credential.
The two-node walk's builder uses the bus (hq issue 307). It dialled the old AMQP broker. The walk now adds a lab module that claims node-build-agent with its own broker secret, assigns it to the anchor, waits for the sealed credential and starts the builder on NATS with MESH_NODE, once the anchor has joined.
The walk stops stocking mesh-runtime-nftables: the catalogue's nftables module has no container, so the image was never run.
Tests.sh merge-check.sh: typecheck, unit suite 161 pass / 0 fail / 2 skipped, and the Go part (gofmt, vet, register tests) all pass. build-module-runtime.sh nftables builds the image; its launcher answers MCP initialize and tools/list. node-tools inside it connected to a real NATS and launched the bundle, but served 0 tools without a mesh membership, so serving under a real membership is not proven.
Not proven: the walk end to end. A raise on 2026-10-08 stopped at the lab's egress check, because the laptop could not reach the public container registry. The object store provisioner image cannot be built either: its mc base image is gone upstream. Still open in issue 307: builds.test.ts still dials AMQP, and beds that run a per-module runtime container on the module's own credential.
**Stacked on #61** (now merged): this shows only its own commits. Relates to #62: the prover's module subdirectory is #62's `Module` field, not repeated here.
**Issue numbers:** the runtime image and the walk are hq issue **307**; the enumeration tests are hq issue **308** (both in hq #192).
1. **Enumeration tests no longer depend on the host's incus** (hq issue 308). `test/enumerate.test.ts` set `MESH_LAB_INCUS=false` in its body, but an ES module's imports run first, so `src/incus/client.ts` had already read the variable and the tests asked the real incus. They passed where none is installed (the build seat) and failed on the workstation that runs the lab. The client now takes the command by injection (`useIncusCommand`); the test names `false` and gets it everywhere.
2. **`scripts/build-module-runtime.sh` builds on node-tools** (hq issue 307). It copied mesh-tools' old TypeScript runtime. The runtime is now node-tools, a Go binary in mesh-tools' `node-tools/`, which launches each bundle through the `<entry>.serve.mjs` launcher the builder writes (ADR 0193). The script compiles the module's declared entrypoints against the sibling SDK, writes the builder's launchers, stages the SDK, builds node-tools with Go and makes it the entrypoint. The image runs on the node's runtime credential or `MESH_BROKER_URL`: the Go runtime refuses to serve a module on that module's own credential.
3. **The two-node walk's builder uses the bus** (hq issue 307). It dialled the old AMQP broker. The walk now adds a lab module that claims `node-build-agent` with its own `broker` secret, assigns it to the anchor, waits for the sealed credential and starts the builder on NATS with `MESH_NODE`, once the anchor has joined.
4. **The walk stops stocking `mesh-runtime-nftables`**: the catalogue's nftables module has no container, so the image was never run.
**Tests.** `sh merge-check.sh`: typecheck, unit suite 161 pass / 0 fail / 2 skipped, and the Go part (gofmt, vet, register tests) all pass. `build-module-runtime.sh nftables` builds the image; its launcher answers MCP `initialize` and `tools/list`. node-tools inside it connected to a real NATS and launched the bundle, but served 0 tools without a mesh membership, so serving under a real membership is not proven.
**Not proven: the walk end to end.** A raise on 2026-10-08 stopped at the lab's egress check, because the laptop could not reach the public container registry. The object store provisioner image cannot be built either: its `mc` base image is gone upstream. Still open in issue 307: `builds.test.ts` still dials AMQP, and beds that run a per-module runtime container on the module's own credential.
A third machine makes its tunnel key, is issued a token for it, and
enrols while the anchor drops its packets to the bus at the first hook;
it can only have arrived over the tunnel (novox/hq ADR 0169).
This bed raises genesis by hand, so it places the composed user list
after each token and each enrolment, as the trust bed does (novox/hq
issue 146); without it the first join was refused.
A token carries the bus's address, and at genesis that is the anchor's
loopback, which no other machine reaches. The anchor joins locally and
becomes the hub; the laptop makes its tunnel key, is issued a token for
it and joins over the tunnel (novox/hq ADR 0169, issue 146).
The filter module now serves its verbs from a runtime the mesh builds
(novox/hq ADR 0170), and a bed registered its raw manifest, which the
mesh refuses as unbuilt. The bed stocks mesh-runtime-nftables and the
filter helper registers the module through the stocked image.
Two machines: the anchor raises the foundation, joins over its own
loopback and becomes the hub; the joiner makes its tunnel key, is issued
a token for it and enrols with the bus's port closed to its own address,
so the enrolment can arrive only over the tunnel (novox/hq ADR 0169). The
check that had been added to the two-node walk moves here, closing the
port the bundle publishes the bus on rather than the bus's own.
And the uplink's range may be named: behind a VPN client that routes
every private range, incus had none left to pick and no scenario could
be raised.
The tests set MESH_LAB_INCUS in their body, which runs after the client module has read it, so they
asked the real incus: green where none is installed, red on the workstation that runs the lab.
The tool runtime is a Go binary that launches each bundle through the launcher the builder writes; the
repository root has no package.json any more, so the old script failed at its first step.
It dialled the old broker's guest account, which the builder no longer reads and the mesh no longer
runs. And the walk stops stocking a packet-filter runtime no container of the module names.
Correction to the description's test list: started against a real NATS on MESH_BROKER_URL, node-tools launched the bundle and completed its handshake, then served 0 tools. It said nftables registers under node-packet-filter, which is not served until the mesh issues the claim. That is expected with no mesh-issued membership. Whether the image serves under a membership is not proven here.
Correction to the description's test list: started against a real NATS on `MESH_BROKER_URL`, node-tools launched the bundle and completed its handshake, then served **0 tools**. It said nftables registers under `node-packet-filter`, which is not served until the mesh issues the claim. That is expected with no mesh-issued membership. Whether the image serves under a membership is not proven here.
Issue numbers corrected: 306 was taken while this was open. Wherever the title and description say hq issue 306, read 307 (the beds that kept the bus and the runtime the mesh had left). Wherever they say 307, read 308 (the unit test whose verdict depended on the host's incus). Registered in novox/hq#192.
Issue numbers corrected: 306 was taken while this was open. Wherever the title and description say hq issue **306**, read **307** (the beds that kept the bus and the runtime the mesh had left). Wherever they say **307**, read **308** (the unit test whose verdict depended on the host's incus). Registered in novox/hq#192.
Deliverynovox/mesh-lab@83685162537c — delivered since 2026-10-08T08:35:03Z
Delivery plan — builds nothing: the change touches no module of the mesh's graph
Transitions
2026-10-08 08:24 (new) → proposed (announced): novox/mesh-lab#63's head announced
2026-10-08 08:24 proposed → checked (checked): the verdict names this commit
2026-10-08 08:24 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-08 08:35 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 08:35 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-lab@83685162537c` — **delivered** since 2026-10-08T08:35:03Z
**Delivery plan** — builds nothing: the change touches no module of the mesh's graph
**Transitions**
- 2026-10-08 08:24 (new) → proposed (announced): novox/mesh-lab#63's head announced
- 2026-10-08 08:24 proposed → checked (checked): the verdict names this commit
- 2026-10-08 08:24 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-08 08:35 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 08:35 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-admin
changed title from The lab runs on the laptop again: the walk's builder on the bus, runtime images on node-tools, enumeration tests independent of the host's incus (hq issues 306, 307) to The lab runs on the laptop again: the walk's builder on the bus, runtime images on node-tools, enumeration tests independent of the host's incus (hq issues 307, 308)2026-10-08 08:24:57 +00:00
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.
Stacked on #61 (now merged): this shows only its own commits. Relates to #62: the prover's module subdirectory is #62's
Modulefield, not repeated here.Issue numbers: the runtime image and the walk are hq issue 307; the enumeration tests are hq issue 308 (both in hq #192).
test/enumerate.test.tssetMESH_LAB_INCUS=falsein its body, but an ES module's imports run first, sosrc/incus/client.tshad already read the variable and the tests asked the real incus. They passed where none is installed (the build seat) and failed on the workstation that runs the lab. The client now takes the command by injection (useIncusCommand); the test namesfalseand gets it everywhere.scripts/build-module-runtime.shbuilds on node-tools (hq issue 307). It copied mesh-tools' old TypeScript runtime. The runtime is now node-tools, a Go binary in mesh-tools'node-tools/, which launches each bundle through the<entry>.serve.mjslauncher the builder writes (ADR 0193). The script compiles the module's declared entrypoints against the sibling SDK, writes the builder's launchers, stages the SDK, builds node-tools with Go and makes it the entrypoint. The image runs on the node's runtime credential orMESH_BROKER_URL: the Go runtime refuses to serve a module on that module's own credential.node-build-agentwith its ownbrokersecret, assigns it to the anchor, waits for the sealed credential and starts the builder on NATS withMESH_NODE, once the anchor has joined.mesh-runtime-nftables: the catalogue's nftables module has no container, so the image was never run.Tests.
sh merge-check.sh: typecheck, unit suite 161 pass / 0 fail / 2 skipped, and the Go part (gofmt, vet, register tests) all pass.build-module-runtime.sh nftablesbuilds the image; its launcher answers MCPinitializeandtools/list. node-tools inside it connected to a real NATS and launched the bundle, but served 0 tools without a mesh membership, so serving under a real membership is not proven.Not proven: the walk end to end. A raise on 2026-10-08 stopped at the lab's egress check, because the laptop could not reach the public container registry. The object store provisioner image cannot be built either: its
mcbase image is gone upstream. Still open in issue 307:builds.test.tsstill dials AMQP, and beds that run a per-module runtime container on the module's own credential.Correction to the description's test list: started against a real NATS on
MESH_BROKER_URL, node-tools launched the bundle and completed its handshake, then served 0 tools. It said nftables registers undernode-packet-filter, which is not served until the mesh issues the claim. That is expected with no mesh-issued membership. Whether the image serves under a membership is not proven here.Issue numbers corrected: 306 was taken while this was open. Wherever the title and description say hq issue 306, read 307 (the beds that kept the bus and the runtime the mesh had left). Wherever they say 307, read 308 (the unit test whose verdict depended on the host's incus). Registered in novox/hq#192.
Delivery
novox/mesh-lab@83685162537c— delivered since 2026-10-08T08:35:03ZDelivery plan — builds nothing: the change touches no module of the mesh's graph
Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.The lab runs on the laptop again: the walk's builder on the bus, runtime images on node-tools, enumeration tests independent of the host's incus (hq issues 306, 307)to The lab runs on the laptop again: the walk's builder on the bus, runtime images on node-tools, enumeration tests independent of the host's incus (hq issues 307, 308)