Rename mesh-control -> mesh-controller, substrate -> foundation

One name per thing, per the HQ glossary: the module/container/image/binary/repo
becomes mesh-controller, the seat the-controller, and the store+broker pair the
foundation (embedded base bundles, default template and example lock renamed with
their go:embed directives). No behaviour change — a pure vocabulary rename.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
2026-09-16 18:40:40 +02:00
parent 49b80d8516
commit 5d6e8fbe7a
89 changed files with 785 additions and 785 deletions
+47 -47
View File
@@ -6,10 +6,10 @@
* project keeps saying cannot be checked any other way (novox/hq ADR 0001: every fault of
* 2026-08-22 was found in production because nothing could be stood up locally).
*
* It needs a host binary and the substrate bundle:
* It needs a host binary and the foundation bundle:
*
* MESH_LAB_HOST_BINARY=.../mesh-host
* MESH_LAB_BUNDLE=.../examples/substrate-first-node.lock
* MESH_LAB_BUNDLE=.../examples/foundation-first-node.lock
*
* The bundle's image references are rewritten to the ones this scenario's own registry serves.
* A digest belongs to whatever registry serves it, so a committed bundle names a registry that is
@@ -24,7 +24,7 @@ import { raise } from "../../src/lifecycle/raise.ts";
import { pinnedInto, stillUnpinned, type HeldImage } from "../../src/pinning.ts";
import { destroy, exec } from "../../src/lifecycle/operate.ts";
import { hostBinaryPath, HOST_PATH } from "../../src/lifecycle/place.ts";
import { labIsUsable, destroyAll, substrateBundle, onTheMachine } from "./harness.ts";
import { labIsUsable, destroyAll, foundationBundle, onTheMachine } from "./harness.ts";
import { incus } from "../../src/incus/client.ts";
import { machineName } from "../../src/lifecycle/names.ts";
import { ready, returnTo, keep, rememberStock, warmStock } from "../../src/warm.ts";
@@ -36,7 +36,7 @@ const capability = await labIsUsable();
const binary = hostBinaryPath();
const bundle = process.env["MESH_LAB_BUNDLE"] ?? "";
const builder = process.env["MESH_LAB_BUILDER"] ?? "";
/** mesh-control's `examples/modules`, so the manifests proven here are the ones that ship. */
/** mesh-controller's `examples/modules`, so the manifests proven here are the ones that ship. */
const moduleExamples = process.env["MESH_LAB_MODULES"] ?? "";
const skip = !capability.usable
@@ -44,7 +44,7 @@ const skip = !capability.usable
: !binary || !existsSync(binary)
? "MESH_LAB_HOST_BINARY is not set to a built mesh-host"
: !bundle || !existsSync(bundle)
? "MESH_LAB_BUNDLE is not set to a substrate bundle (mesh-host examples/)"
? "MESH_LAB_BUNDLE is not set to a foundation bundle (mesh-host examples/)"
: false;
const SCENARIO = "two-nodes";
@@ -105,7 +105,7 @@ async function must(machine: string, command: string, timeoutMs?: number): Promi
/** The control plane, which runs in a container on the first node. */
async function mesh(command: string, timeoutMs?: number): Promise<string> {
return must("anchor", `docker exec mesh-control /mesh-control ${command}`, timeoutMs);
return must("anchor", `docker exec mesh-controller /mesh-controller ${command}`, timeoutMs);
}
/**
@@ -144,7 +144,7 @@ async function settled(node: string, withinMs = 480_000): Promise<void> {
let said = "";
try {
const asked = await on("anchor",
`docker exec mesh-control /mesh-control status --json`);
`docker exec mesh-controller /mesh-controller status --json`);
said = asked.out;
// Parsed inside the try on purpose: a truncated answer from a struggling machine is the
// same fact as no answer, and the likeliest moment for one is exactly the machine this
@@ -186,11 +186,11 @@ async function settled(node: string, withinMs = 480_000): Promise<void> {
* The bundle, as a machine should receive it.
*
* The committed example was written for a target that had a registry the lab raised. Its two
* third-party images become upstream references the machine pulls itself; mesh-control, which
* third-party images become upstream references the machine pulls itself; mesh-controller, which
* exists in no registry, becomes the ID this machine was handed.
*/
function bundleFor(images: HeldImage[]): string {
return substrateBundle(bundle, images);
return foundationBundle(bundle, images);
}
/** Take a token out of what `token issue` printed. It is the one base64url blob on its own line. */
@@ -253,8 +253,8 @@ before(async () => {
// because the control plane's image is named by the ID this machine holds it under, which is not
// knowable until it has been handed over.
held = raised.images;
await must("anchor", `cat > /tmp/substrate.lock <<'MESHBUNDLE'\n${bundleFor(raised.images)}\nMESHBUNDLE`);
await must("anchor", `${HOST_PATH} apply /tmp/substrate.lock`);
await must("anchor", `cat > /tmp/foundation.lock <<'MESHBUNDLE'\n${bundleFor(raised.images)}\nMESHBUNDLE`);
await must("anchor", `${HOST_PATH} apply /tmp/foundation.lock`);
// A build machine, so anything here can ask the mesh to build something. Placed rather than
// assumed: nothing else in this scenario would start one.
@@ -289,7 +289,7 @@ after(async () => {
test("a bare machine becomes a mesh", { skip, timeout: 600_000 }, async () => {
const running = await must("anchor", `docker ps --format '{{.Names}}'`);
for (const container of ["mesh-store", "mesh-broker", "mesh-control"]) {
for (const container of ["mesh-store", "mesh-broker", "mesh-controller"]) {
assert.match(running, new RegExp(container), `${container} is not running`);
}
// Answering, not merely up. A container that is running is not a control plane that replies —
@@ -334,8 +334,8 @@ test("a credential reaches both ends and the mesh holds neither", { skip, timeou
`"content":"PGHOST=$\{bound:postgres-database:at\}\\nPGPORT=$\{bound:postgres-database:port\}\\n` +
`PGUSER=$\{bound:postgres-database:as\}\\nPGPASSWORD=$\{secret:postgres-database\}\\n"}]}' ` +
`> /tmp/app.json`);
await must("anchor", `docker cp /tmp/pg.json mesh-control:/pg.json`);
await must("anchor", `docker cp /tmp/app.json mesh-control:/app.json`);
await must("anchor", `docker cp /tmp/pg.json mesh-controller:/pg.json`);
await must("anchor", `docker cp /tmp/app.json mesh-controller:/app.json`);
await mesh("module add /pg.json");
await mesh("module add /app.json");
@@ -423,7 +423,7 @@ test("when a machine cannot do what it was told, the mesh says which and why", {
// is the situation `status` exists to distinguish from a machine that refused everything.
await must("anchor", `printf %s '{"module":"impossible","version":"1","resources":[` +
`{"id":"nothing","type":"package","package":"a-package-that-does-not-exist"}]}' > /tmp/imp.json`);
await must("anchor", `docker cp /tmp/imp.json mesh-control:/imp.json`);
await must("anchor", `docker cp /tmp/imp.json mesh-controller:/imp.json`);
await mesh("module add /imp.json");
await mesh("assign laptop impossible");
await mesh("push laptop");
@@ -471,7 +471,7 @@ test("a declaration waits for a machine that is switched off", { skip, timeout:
await must("anchor", `printf %s '{"module":"while-away","version":"1","resources":[` +
`{"id":"note","type":"file","path":"/etc/mesh-while-away","content":"waited"}]}' > /tmp/away.json`);
await must("anchor", `docker cp /tmp/away.json mesh-control:/away.json`);
await must("anchor", `docker cp /tmp/away.json mesh-controller:/away.json`);
await mesh("module add /away.json");
await mesh("assign laptop while-away");
await mesh("push laptop");
@@ -512,13 +512,13 @@ test("a declaration waits for a machine that is switched off", { skip, timeout:
test("unassigning takes away exactly what it should", { skip, timeout: 900_000 }, async () => {
// Removal is the half nobody tests. The mesh takes away what IT declared and no longer declares,
// and never what the machine raised for itself from its bundle — which is the fault that
// destroyed a substrate once (novox/hq 04-ISSUES/010).
// destroyed a foundation once (novox/hq 04-ISSUES/010).
//
// Two modules, so the test can tell "removed the right one" from "removed everything".
for (const [name, path] of [["kept", "/etc/mesh-kept"], ["going", "/etc/mesh-going"]] as const) {
await must("anchor", `printf %s '{"module":"${name}","version":"1","resources":[` +
`{"id":"note","type":"file","path":"${path}","content":"${name}"}]}' > /tmp/${name}.json`);
await must("anchor", `docker cp /tmp/${name}.json mesh-control:/${name}.json`);
await must("anchor", `docker cp /tmp/${name}.json mesh-controller:/${name}.json`);
await mesh(`module add /${name}.json`);
await mesh(`assign anchor ${name}`);
}
@@ -536,11 +536,11 @@ test("unassigning takes away exactly what it should", { skip, timeout: 900_000 }
assert.ok((await on("anchor", `test -f /etc/mesh-kept`)).ok,
"unassigning one module took another one's file with it");
// And the substrate this machine raised from its own bundle is untouched. It was not declared by
// And the foundation this machine raised from its own bundle is untouched. It was not declared by
// the mesh, so the mesh must never remove it — the machine would take its own control plane
// away, which is exactly what happened before origins existed.
const running = await must("anchor", `docker ps --format '{{.Names}}'`);
for (const container of ["mesh-store", "mesh-broker", "mesh-control"]) {
for (const container of ["mesh-store", "mesh-broker", "mesh-controller"]) {
assert.match(running, new RegExp(container),
`${container} was removed by a declaration that never declared it`);
}
@@ -565,7 +565,7 @@ test("a machine that fell behind catches up without being named", { skip, timeou
await must("anchor", `printf %s '{"module":"fixable","version":"1","resources":[` +
`{"id":"pkg","type":"package","package":"a-package-that-does-not-exist-yet"},` +
`{"id":"note","type":"file","path":"/etc/mesh-fixable","content":"here"}]}' > /tmp/fix.json`);
await must("anchor", `docker cp /tmp/fix.json mesh-control:/fix.json`);
await must("anchor", `docker cp /tmp/fix.json mesh-controller:/fix.json`);
await mesh("module add /fix.json");
await mesh("assign laptop fixable");
await mesh("push laptop");
@@ -585,7 +585,7 @@ test("a machine that fell behind catches up without being named", { skip, timeou
// Fix the cause, the way somebody would: the module stops asking for the impossible thing.
await must("anchor", `printf %s '{"module":"fixable","version":"1","resources":[` +
`{"id":"note","type":"file","path":"/etc/mesh-fixable","content":"here"}]}' > /tmp/fix.json`);
await must("anchor", `docker cp /tmp/fix.json mesh-control:/fix.json`);
await must("anchor", `docker cp /tmp/fix.json mesh-controller:/fix.json`);
await mesh("module add /fix.json");
// And nobody names the machine.
@@ -626,7 +626,7 @@ test("the mesh runs its own artifact store", { skip, timeout: 900_000 }, async (
// and a builder will not start without an artifact store to publish to, so a mesh that has just
// bootstrapped cannot build the module that gives it one. Adding the manifest directly is the
// path a real first mesh has to take, so it is the path this walks.
await must("anchor", `docker cp /root/registry/module.json mesh-control:/registry.json`);
await must("anchor", `docker cp /root/registry/module.json mesh-controller:/registry.json`);
await mesh("module add /registry.json");
await mesh("assign anchor registry");
await mesh("push anchor");
@@ -658,7 +658,7 @@ test("a machine serves its internal name with a certificate the mesh issued", {
`"certificate":{"into":"/etc/mesh/serving.crt","authority":"/etc/mesh/authority.crt"},` +
`"resources":[{"id":"dir","type":"directory","path":"/etc/mesh","mode":"0755"}]}' ` +
`> /tmp/served.json`);
await must("anchor", `docker cp /tmp/served.json mesh-control:/served.json`);
await must("anchor", `docker cp /tmp/served.json mesh-controller:/served.json`);
await mesh("module add /served.json");
await mesh("assign anchor served");
await mesh("push anchor");
@@ -768,7 +768,7 @@ test("a machine filters exactly what its modules declared, and nothing else", {
`{"id":"filter","type":"service","unit":"mesh-filter.service","state":"running",` +
`"boot":"enabled","restart-on":["filtering"]}]}' > /tmp/firewall.json`);
for (const f of ["talker", "firewall"]) {
await must("anchor", `docker cp /tmp/${f}.json mesh-control:/${f}.json`);
await must("anchor", `docker cp /tmp/${f}.json mesh-controller:/${f}.json`);
await mesh(`module add /${f}.json`);
}
await mesh("assign laptop talker");
@@ -972,7 +972,7 @@ test("rotating a credential moves both ends, and the old one stops working", {
`"resources":[{"id":"dir","type":"directory","path":"/etc/realapp","mode":"0755"}]}' ` +
`> /tmp/realapp.json`);
for (const f of ["realstore", "realapp"]) {
await must("anchor", `docker cp /tmp/${f}.json mesh-control:/${f}.json`);
await must("anchor", `docker cp /tmp/${f}.json mesh-controller:/${f}.json`);
await mesh(`module add /${f}.json`);
}
await mesh("assign anchor realstore");
@@ -1081,7 +1081,7 @@ test("a route is a grant: a workload is reached by the name it asked for", {
`{"id":"app","type":"container","name":"storefront",` +
`"image":"${ARTIFACT_STORE}","ports":["8088:5000"]}]}' > /tmp/storefront.json`);
for (const f of ["frontdoor", "storefront"]) {
await must("anchor", `docker cp /tmp/${f}.json mesh-control:/${f}.json`);
await must("anchor", `docker cp /tmp/${f}.json mesh-controller:/${f}.json`);
await mesh(`module add /${f}.json`);
}
await mesh("assign anchor frontdoor");
@@ -1135,7 +1135,7 @@ test("a route is a grant: a workload is reached by the name it asked for", {
assert.ok(withdrawn,
`the route outlived the module that asked for it:\n${after}\n\n` +
`the machine did apply — this is what the mesh would send now:\n` +
`${(await on("anchor", `docker exec mesh-control /mesh-control plan anchor --files`)).out}`);
`${(await on("anchor", `docker exec mesh-controller /mesh-controller plan anchor --files`)).out}`);
let gone = false;
for (let i = 0; i < 15 && !gone; i++) {
@@ -1159,7 +1159,7 @@ test("model access is answered by a record, and the key the mesh took is one it
`"secrets":{"model-access":"/etc/assistant/key"},` +
`"resources":[{"id":"dir","type":"directory","path":"/etc/assistant","mode":"0755"}]}' ` +
`> /tmp/assistant.json`);
await must("anchor", `docker cp /tmp/assistant.json mesh-control:/assistant.json`);
await must("anchor", `docker cp /tmp/assistant.json mesh-controller:/assistant.json`);
await mesh("module add /assistant.json");
// The licences first. With none recorded at all the honest answer is that nothing provides
@@ -1171,7 +1171,7 @@ test("model access is answered by a record, and the key the mesh took is one it
// then says the machine's set cannot be applied. The refusal names both candidates and the
// command. ADR 0024 warns this will be felt — which is correct, and correct is not the same as
// usable.
const refused = await on("anchor", `docker exec mesh-control /mesh-control assign laptop assistant`);
const refused = await on("anchor", `docker exec mesh-controller /mesh-controller assign laptop assistant`);
assert.ok(!refused.ok,
`a consumer was given model access without anybody saying which:\n${refused.out}`);
for (const want of ["personal", "the-organisation", "licence use"]) {
@@ -1182,7 +1182,7 @@ test("model access is answered by a record, and the key the mesh took is one it
await mesh("licence use personal laptop assistant");
// Chosen, and still no key: the mesh has one thing to deliver and has not been given it.
const noKey = await on("anchor", `docker exec mesh-control /mesh-control plan laptop`);
const noKey = await on("anchor", `docker exec mesh-controller /mesh-controller plan laptop`);
assert.ok(!noKey.ok, `a module was planned with a licence that has no key:\n${noKey.out}`);
assert.match(noKey.out, /licence key personal/, noKey.out);
@@ -1190,7 +1190,7 @@ test("model access is answered by a record, and the key the mesh took is one it
// command line is a key in shell history and in every process listing taken while it ran.
const secret = "sk-test-" + "0123456789abcdef".repeat(2);
const accepted = await must("anchor",
`printf %s ${quote(secret)} | docker exec -i mesh-control /mesh-control licence key personal`);
`printf %s ${quote(secret)} | docker exec -i mesh-controller /mesh-controller licence key personal`);
assert.match(accepted, /sealed to 1 holder/, accepted);
assert.doesNotMatch(accepted, new RegExp(secret),
"the key was echoed back, so the one copy that matters is on a terminal");
@@ -1298,11 +1298,11 @@ test("the board names the machine that is not doing what it was told", {
await must("anchor", `printf %s '{"module":"board","version":"1",` +
`"listens":[{"port":8090,"from":"mesh","why":"the board"}],` +
`"resources":[]}' > /tmp/board.json`);
await must("anchor", `docker cp /tmp/board.json mesh-control:/board.json`);
await must("anchor", `docker cp /tmp/board.json mesh-controller:/board.json`);
await mesh("module add /board.json");
// Served from the control plane's own container, reading the mesh on every request.
await must("anchor", `docker exec -d mesh-control /mesh-control board --listen 0.0.0.0:8090`);
await must("anchor", `docker exec -d mesh-controller /mesh-controller board --listen 0.0.0.0:8090`);
await new Promise((r) => setTimeout(r, 3000));
const read = async (path: string) =>
@@ -1325,7 +1325,7 @@ test("the board names the machine that is not doing what it was told", {
await must("anchor", `printf %s '{"module":"impossible","version":"1",` +
`"resources":[{"id":"nowhere","type":"service","unit":"nothing-like-this.service",` +
`"state":"running"}]}' > /tmp/impossible.json`);
await must("anchor", `docker cp /tmp/impossible.json mesh-control:/impossible.json`);
await must("anchor", `docker cp /tmp/impossible.json mesh-controller:/impossible.json`);
await mesh("module add /impossible.json");
await mesh("assign laptop impossible");
await mesh("push laptop");
@@ -1389,7 +1389,7 @@ test("the hub can be filtered without severing the mesh", {
`ExecStart=/usr/bin/nft -f ${rules}\\n[Install]\\nWantedBy=multi-user.target\\n"},` +
`{"id":"filter","type":"service","unit":"hub-filter.service","state":"running",` +
`"boot":"enabled","restart-on":["filtering"]}]}' > /tmp/hubfilter.json`);
await must("anchor", `docker cp /tmp/hubfilter.json mesh-control:/hubfilter.json`);
await must("anchor", `docker cp /tmp/hubfilter.json mesh-controller:/hubfilter.json`);
await mesh("module add /hubfilter.json");
await mesh("assign anchor hubfilter");
await mesh("push anchor");
@@ -1414,7 +1414,7 @@ test("the hub can be filtered without severing the mesh", {
await must("anchor", `printf %s '{"module":"stillworks","version":"1",` +
`"resources":[{"id":"marker","type":"file","path":"/etc/mesh-still-works",` +
`"content":"yes","mode":"0644"}]}' > /tmp/stillworks.json`);
await must("anchor", `docker cp /tmp/stillworks.json mesh-control:/stillworks.json`);
await must("anchor", `docker cp /tmp/stillworks.json mesh-controller:/stillworks.json`);
await mesh("module add /stillworks.json");
await mesh("assign laptop stillworks");
await mesh("push laptop");
@@ -1450,7 +1450,7 @@ test("a container reaches another machine by the name the mesh gave it", {
`"capabilities":["container-runtime"],` +
`"resources":[{"id":"idle","type":"container","name":"resolves",` +
`"image":"${ARTIFACT_STORE}"}]}' > /tmp/resolves.json`);
await must("anchor", `docker cp /tmp/resolves.json mesh-control:/resolves.json`);
await must("anchor", `docker cp /tmp/resolves.json mesh-controller:/resolves.json`);
await mesh("module add /resolves.json");
await mesh("assign laptop resolves");
await mesh("push laptop");
@@ -1539,7 +1539,7 @@ test("every name under a machine resolves to that machine", {
});
test("a service is reached by a name under the machine it runs on", {
skip: skip || (!moduleExamples ? "set MESH_LAB_MODULES to mesh-control's examples/modules" : false),
skip: skip || (!moduleExamples ? "set MESH_LAB_MODULES to mesh-controller's examples/modules" : false),
timeout: 900_000,
}, async () => {
// postgres.novox.internal, plex.ace.internal — the first label is the service and the rest is
@@ -1555,7 +1555,7 @@ test("a service is reached by a name under the machine it runs on", {
for (const name of ["dnsmasq", "resolved-split-dns"]) {
const manifest = readFileSync(`${moduleExamples}/${name}.json`, "utf8");
await must("anchor", `cat > /tmp/${name}.json <<'MANIFEST'\n${manifest}\nMANIFEST`);
await must("anchor", `docker cp /tmp/${name}.json mesh-control:/${name}.json`);
await must("anchor", `docker cp /tmp/${name}.json mesh-controller:/${name}.json`);
await mesh(`module add /${name}.json`);
}
@@ -1700,18 +1700,18 @@ test("a third-party workload is adopted, with the credential it already had", {
},
],
}))} > /umami.json`);
await must("anchor", `docker cp /umami.json mesh-control:/umami.json`);
await must("anchor", `docker cp /umami.json mesh-controller:/umami.json`);
await mesh("module add /umami.json");
// **Accepted, not generated.** The value is what the database already answers to; the mesh
// seals it and cannot read it again. Given whole, as the environment lines the containers read.
await must("anchor",
`printf %s ${quote(`POSTGRES_PASSWORD=${password}`)} | ` +
`docker exec -i mesh-control /mesh-control secret accept anchor umami database --from -`);
`docker exec -i mesh-controller /mesh-controller secret accept anchor umami database --from -`);
await must("anchor",
`printf %s ${quote(
`DATABASE_URL=postgresql://umami:${password}@umami-db:5432/umami`)} | ` +
`docker exec -i mesh-control /mesh-control secret accept anchor umami app --from -`);
`docker exec -i mesh-controller /mesh-controller secret accept anchor umami app --from -`);
await mesh("assign anchor umami");
await mesh("push anchor", 300_000);
@@ -1815,7 +1815,7 @@ test("the real modules resolve together, and compose a declaration a host accept
}
planned.push(name);
await must("anchor", `printf %s ${quote(pinned)} > /${name}.json`);
await must("anchor", `docker cp /${name}.json mesh-control:/${name}.json`);
await must("anchor", `docker cp /${name}.json mesh-controller:/${name}.json`);
await mesh(`module add /${name}.json`);
}
@@ -1932,7 +1932,7 @@ test("the forge runs, on a database the mesh gave it", { skip, timeout: 900_000
assert.deepEqual(stillUnpinned(pinned), [],
`${name} still names an image nothing serves, so it could not start`);
await must("anchor", `printf %s ${quote(pinned)} > /run-${name}.json`);
await must("anchor", `docker cp /run-${name}.json mesh-control:/run-${name}.json`);
await must("anchor", `docker cp /run-${name}.json mesh-controller:/run-${name}.json`);
await mesh(`module add /run-${name}.json`);
await mesh(`assign anchor ${name}`);
}
@@ -2018,7 +2018,7 @@ test("a consumer's cache grant means exactly its own keys", { skip, timeout: 600
assert.deepEqual(stillUnpinned(pinned), [],
"redis still names an image nothing serves, so it could not start");
await must("anchor", `printf %s ${quote(pinned)} > /run-redis.json`);
await must("anchor", `docker cp /run-redis.json mesh-control:/run-redis.json`);
await must("anchor", `docker cp /run-redis.json mesh-controller:/run-redis.json`);
await mesh("module add /run-redis.json");
// A consumer with no container: what is under test is the credential's reach, and files on the
@@ -2030,7 +2030,7 @@ test("a consumer's cache grant means exactly its own keys", { skip, timeout: 600
`"secrets":{"redis-cache":"/var/lib/cachetest/cache.secret"},` +
`"resources":[{"id":"state","type":"directory","path":"/var/lib/cachetest","mode":"0700"}]}' ` +
`> /cachetest.json`);
await must("anchor", `docker cp /cachetest.json mesh-control:/cachetest.json`);
await must("anchor", `docker cp /cachetest.json mesh-controller:/cachetest.json`);
await mesh("module add /cachetest.json");
await mesh("assign anchor redis");