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
@@ -22,7 +22,7 @@
* the seed), and mosquitto's provisioner — running in the assigned runtime — creates a scoped client
* for a contribution the mesh delivered, which then authenticates with the password the mesh minted.
*
* MESH_LAB_HOST_BINARY=.../mesh-host MESH_LAB_BUNDLE=.../examples/substrate-first-node.lock
* MESH_LAB_HOST_BINARY=.../mesh-host MESH_LAB_BUNDLE=.../examples/foundation-first-node.lock
* scripts/build-module-runtime.sh mosquitto builds mesh-runtime-mosquitto:development (carrying
* mosquitto_ctrl and the compiled bootstrap entrypoint) into the local daemon, which
* scenarios/catalogue-mqtt.yml stocks. eclipse-mosquitto:2 must be in the local daemon to be
@@ -36,7 +36,7 @@ import { loadScenario } from "../../src/declaration/parse.ts";
import { raise } from "../../src/lifecycle/raise.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 type { HeldImage } from "../../src/pinning.ts";
const capability = await labIsUsable();
@@ -48,7 +48,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 = "catalogue-mqtt";
@@ -78,7 +78,7 @@ async function must(command: string, timeoutMs?: number): Promise<string> {
/** The control plane, a container on the node. */
async function mesh(command: string, timeoutMs?: number): Promise<string> {
return must(`docker exec mesh-control /mesh-control ${command}`, timeoutMs);
return must(`docker exec mesh-controller /mesh-controller ${command}`, timeoutMs);
}
/** The reference a manifest should carry, once this scenario has been raised. */
@@ -87,9 +87,9 @@ function pinned(reference: string): string {
return onTheMachine(reference, held);
}
/** The substrate bundle: ours by the ID the machine holds, everything else upstream. */
/** The foundation bundle: ours by the ID the machine holds, everything else upstream. */
function bundleFor(images: HeldImage[]): string {
return substrateBundle(bundle, images);
return foundationBundle(bundle, images);
}
function tokenFrom(said: string): string {
@@ -102,7 +102,7 @@ async function settled(withinMs = 600_000): Promise<void> {
const until = Date.now() + withinMs;
let last = "";
while (Date.now() < until) {
const asked = await on(`docker exec mesh-control /mesh-control status --json`);
const asked = await on(`docker exec mesh-controller /mesh-controller status --json`);
if (asked.ok) {
try {
const state = JSON.parse(asked.out) as {
@@ -134,12 +134,12 @@ before(async () => {
instanceId = raised.instanceId;
held = raised.images;
// Raise the substrate — store, broker, control — from the bundle.
await must(`cat > /tmp/substrate.lock <<'MESHBUNDLE'\n${bundleFor(raised.images)}\nMESHBUNDLE`);
await must(`${HOST_PATH} apply /tmp/substrate.lock`, 600_000);
// Raise the foundation — store, broker, control — from the bundle.
await must(`cat > /tmp/foundation.lock <<'MESHBUNDLE'\n${bundleFor(raised.images)}\nMESHBUNDLE`);
await must(`${HOST_PATH} apply /tmp/foundation.lock`, 600_000);
const up = await must(`docker ps --format '{{.Names}}'`);
for (const c of ["mesh-store", "mesh-broker", "mesh-control"]) {
assert.match(up, new RegExp(c), `the substrate did not raise ${c}:\n${up}`);
for (const c of ["mesh-store", "mesh-broker", "mesh-controller"]) {
assert.match(up, new RegExp(c), `the foundation did not raise ${c}:\n${up}`);
}
// The node joins its own mesh and starts the host so it applies what it is pushed.
@@ -187,7 +187,7 @@ test("the mesh assigns mosquitto: a run-once step seeds dynsec before the broker
serves: { "mqtt-topic": {} },
emits: ["module.mosquitto.topic.provisioned", "module.mosquitto.topic.deprovisioned"],
// The events entrypoint subscribes to its own lifecycle events (an audit log), so it consumes
// them too — declared, or the substrate never makes the queue the runtime binds (ADR 0046).
// them too — declared, or the foundation never makes the queue the runtime binds (ADR 0046).
consumes: ["module.mosquitto.topic.provisioned", "module.mosquitto.topic.deprovisioned"],
receives: { "mqtt-topic": "/var/lib/mosquitto-module/grants/mesh.json" },
grants: { "mqtt-topic": "/var/lib/mosquitto-module/grants" },
@@ -254,7 +254,7 @@ test("the mesh assigns mosquitto: a run-once step seeds dynsec before the broker
],
});
await must(`printf %s ${quote(manifest)} > /tmp/mosquitto.json && docker cp /tmp/mosquitto.json mesh-control:/mosquitto.json`);
await must(`printf %s ${quote(manifest)} > /tmp/mosquitto.json && docker cp /tmp/mosquitto.json mesh-controller:/mosquitto.json`);
await mesh("module add /mosquitto.json");
const issued = await mesh(`module issue mosquitto --node ${MACHINE}`);
assert.match(issued, /scoped to what it emits and consumes/, issued);
@@ -324,7 +324,7 @@ test("the mesh assigns mosquitto: a run-once step seeds dynsec before the broker
// each consumer it reads the login the mesh derived and the mesh-minted password the host unsealed,
// and creates exactly that dynsec client, scoped to its own topic subtree (ADR 0048). A
// hand-written contributions file + secret stand in for the control plane's write; their SHAPE is
// what mesh-control produces. The proof is authentication as the consumer with the mesh's password
// what mesh-controller produces. The proof is authentication as the consumer with the mesh's password
// — a provisioner that invented its own would refuse the connection.
const consumerPw = "mesh-minted-mqtt-7b2e1a";
await must(`printf %s ${quote(consumerPw)} > /var/lib/mosquitto-module/grants/app.secret`);