Genesis makes six claims; assert them separately

Genesis is twelve steps and was reported as one line, so a failure said nothing
about which claim broke and a pass was one tick standing in for six things being
true: the substrate up, the control plane built rather than handed over, the
pivot finished, the registry serving what was published into it, the machine
enrolled with an agent actually running, and the builder installed as a module.

Each is asked of the machine rather than read from the installer's own output.
The installer saying it published an image and the registry serving one are
different facts, and only the second matters.

And the catalogue is invoked by its real entrypoint. 'mesh-tools' is not on PATH
in the runtime image; the image runs 'node dist/main.js', and the invoke mode is
missing from the header comment that says there are three modes.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
2026-09-14 21:58:58 +02:00
parent 7641bb2059
commit 2f470f27b8
+78 -2
View File
@@ -103,6 +103,12 @@ const MUST_RUN = ["mesh-control", "mesh-registry", "mesh-broker", "mesh-store",
/** Named once, because the step title is also how later steps say what they waited on. */
const NEEDS = "the mesh runs a broker for that module to talk to";
const GENESIS = "a bare machine becomes a mesh of one, raised by the installer";
const SUBSTRATE = "the substrate is up — a store and a broker of the mesh's own";
const BUILT_CP = "the control plane is one this mesh built, not one it was handed";
const PIVOTED = "the pivot finished — what raised the mesh is gone";
const HAS_REGISTRY = "the registry serves this mesh its own images";
const ENROLLED = "the machine is enrolled, and an agent is running on it";
const HAS_BUILDER = "the builder is installed as a module, with an account";
const BASE_BUILT = "the mesh builds the shared base from source";
const STORE_RUNS = "the mesh builds and runs a store of its own";
const CATALOGUE_RUNS = "the mesh builds and runs its own catalogue";
@@ -365,6 +371,69 @@ before(async () => {
return raised.report.join("\n");
});
// ---- WHAT GENESIS CLAIMED, ASKED OF THE MACHINE ----------------------------------------------
//
// **Genesis is twelve steps and was reported as one line.** All the work of raising a mesh
// happens inside it, so "genesis failed" said nothing about which of its claims broke, and
// "genesis passed" was one tick standing in for six separate things being true.
//
// Each is asked of the machine rather than read from the installer's own output — the installer
// saying it published an image and the registry serving one are different facts, and it is the
// second that matters.
await step(SUBSTRATE, GENESIS, async () => {
await waitForContainer(CONTROL, "mesh-store", 120);
await waitForContainer(CONTROL, "mesh-broker", 120);
return (await on(CONTROL, `docker ps --format '{{.Names}}\t{{.Status}}'`)).out;
});
// **The whole reason the installer carries a builder.** A carried control-plane image would
// satisfy "a control plane is running" equally well, which is what makes this worth asserting:
// the image has to be one this mesh's own registry serves.
await step(BUILT_CP, GENESIS, async () => {
const image = (await on(CONTROL,
`docker inspect -f '{{.Config.Image}}' mesh-control 2>&1`)).out.trim();
assert.match(image, /@sha256:[0-9a-f]{64}/,
`the control plane names its image by tag, not by digest: ${image}`);
assert.ok(image.includes(":5000/"),
`the control plane runs an image no registry of this mesh served: ${image}`);
return image;
});
await step(PIVOTED, BUILT_CP, async () => {
const ps = (await on(CONTROL, `docker ps -a --format '{{.Names}}'`)).out;
assert.doesNotMatch(ps, /^temp-mesh-control$/m,
`the temporary control plane is still here, so the pivot did not finish:\n${ps}`);
return ps;
});
await step(HAS_REGISTRY, SUBSTRATE, async () => {
await waitForContainer(CONTROL, "mesh-registry", 120);
const held = (await on(CONTROL,
`curl -sS --max-time 15 http://127.0.0.1:5000/v2/_catalog`)).out;
assert.match(held, /mesh-control/,
`the registry serves no mesh-control, so nothing was published into it:\n${held}`);
return held.trim();
});
await step(ENROLLED, GENESIS, async () => {
const nodes = await mesh("node list");
assert.match(nodes, new RegExp(`^${CONTROL}\\b`, "m"),
`the mesh has not heard from the machine it is running on:\n${nodes}`);
// Heard from once is not an agent running, and the difference is the whole of joining.
const agent = (await on(CONTROL, `pgrep -af '[m]esh-host run' | head -3`)).out.trim();
assert.ok(agent, `no host agent is running, so nothing would apply what the mesh sends`);
return `${nodes.trim()}\n${agent}`;
});
await step(HAS_BUILDER, HAS_REGISTRY, async () => {
await waitForContainer(CONTROL, "mesh-builder", 120);
const modules = await mesh("module list");
assert.match(modules, /^builder\b/m,
`the builder is running but the mesh holds no record of it as a module:\n${modules}`);
return modules;
});
// ---- 2..6. THE MESH BECOMES ONE --------------------------------------------------------------
//
// **Joining used to be here, second, and that was the wrong order.** Three machines were enrolled
@@ -380,7 +449,7 @@ before(async () => {
// The toolchain and runtime every module with code of its own stands on. It is a module, and it
// is built like one — cloned from the forge by the builder installing put here, compiled on the
// machine, published into the mesh's own registry.
await step(BASE_BUILT, GENESIS, async () => {
await step(BASE_BUILT, HAS_BUILDER, async () => {
// Registered from the manifest the builder will also read, so what the mesh holds and what it
// builds are the same description of the same module.
//
@@ -507,7 +576,8 @@ before(async () => {
// And the catalogue, ASKED rather than observed. These five questions are what it exists for.
const ask = async (tool: string, args = "{}") =>
must(CONTROL, `docker exec mesh-catalog mesh-tools invoke mesh-catalog ${tool} ${quote(args)}`,
must(CONTROL, `docker exec mesh-catalog node /app/dist/main.js invoke mesh-catalog ` +
`${tool} ${quote(args)}`,
120_000);
const held = await ask("catalog_modules");
@@ -631,6 +701,12 @@ after(async () => {
for (const name of [
GENESIS,
SUBSTRATE,
BUILT_CP,
PIVOTED,
HAS_REGISTRY,
ENROLLED,
HAS_BUILDER,
BASE_BUILT,
STORE_RUNS,
CATALOGUE_RUNS,