Beds read the catalogue: a shared loader, eight beds converted, the rest declared

catalogueModule() in the harness reads a module's manifest from the catalogue and
rewrites only what the lab must: the build section goes, each artifact becomes the
image the machine holds, images are pinned, and a bed may declare a host-port remap
or a lab-local address. confluence, gitlab, openai-consumer, audit-logger, ollama,
local-model-consumer, model-usage, mosquitto, anthropic-manager and
anthropic-consumer now install the catalogue's manifest. A unit test refuses any
inline copy naming a catalogue module unless the bed is declared with its reason;
the declared list is the debt (novox/hq 04-ISSUES/073).
This commit is contained in:
2026-09-21 14:27:49 +02:00
parent f2d29491b2
commit 2456b2f533
10 changed files with 259 additions and 361 deletions
+9 -43
View File
@@ -26,7 +26,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, foundationBundle, onTheMachine } from "./harness.ts";
import { labIsUsable, destroyAll, foundationBundle, onTheMachine, catalogueModule, catalogueIsPresent } from "./harness.ts";
import type { HeldImage } from "../../src/pinning.ts";
const capability = await labIsUsable();
@@ -39,7 +39,7 @@ const skip = !capability.usable
? "MESH_LAB_HOST_BINARY is not set to a built mesh-host"
: !bundle || !existsSync(bundle)
? "MESH_LAB_BUNDLE is not set to a foundation bundle (mesh-host examples/)"
: false;
: catalogueIsPresent();
const SCENARIO = "local-model-bed";
const MACHINE = "anchor";
@@ -153,47 +153,13 @@ after(async () => {
test("a node hosting a model answers model-access, and the consumer is handed its endpoint", {
skip, timeout: 1_500_000,
}, async () => {
const ollamaImage = pinned("ollama/ollama");
// The provider: ollama runs the model server and `provides: ["model-access"]` at node scope, serving
// its port and model. It mints nothing — provides/serves are declaration the mesh reads, so there is
// no runtime container, only the server.
const ollamaManifest = JSON.stringify({
module: "ollama",
version: "1",
capabilities: ["container-runtime"],
provides: [{ name: "model-access", scope: "node" }],
listens: [{ port: 11434, protocol: "tcp", from: "machine", why: "local consumers reaching the model server" }],
serves: { "model-access": { port: 11434, model: "llama3.2" } },
resources: [
{ id: "state", type: "directory", path: "/services/ollama", mode: "0700" },
{
id: "server", type: "container", name: "ollama",
image: ollamaImage, network: "host", env: { OLLAMA_HOST: "0.0.0.0:11434" },
volumes: ["/services/ollama:/root/.ollama"],
},
],
});
// The consumer: it requires model-access and is answered by the local node. No secret (the local
// server is keyless), only the bound endpoint facts, templated into an openai.env the mesh writes.
const consumerManifest = JSON.stringify({
module: "local-model-consumer",
version: "1",
slug: "local",
requires: ["model-access"],
binds: { "model-access": "/var/lib/local-model-consumer/model.json" },
resources: [
{ id: "state", type: "directory", path: "/var/lib/local-model-consumer", mode: "0700" },
{ id: "config", type: "directory", path: "/var/lib/local-model-consumer/config", mode: "0700" },
{
id: "openai-env", type: "file", path: "/var/lib/local-model-consumer/config/openai.env", mode: "0600",
content:
"OPENAI_BASE_URL=http://${bound:model-access:at}:${bound:model-access:port}/v1\n" +
"OPENAI_MODEL=${bound:model-access:model}\nOPENAI_API_KEY=local\n",
},
],
});
// Both manifests are the catalogue's own (novox/hq 04-ISSUES/073). The provider: ollama runs the
// model server and `provides: ["model-access"]` at node scope, serving its port and model. It mints
// nothing — provides/serves are declaration the mesh reads, so there is no runtime container, only
// the server. The consumer requires model-access and is answered by the local node: no secret (the
// local server is keyless), only the bound endpoint facts, templated into an openai.env the mesh writes.
const ollamaManifest = catalogueModule("ollama", held);
const consumerManifest = catalogueModule("local-model-consumer", held);
await addAssign("ollama", ollamaManifest);
await addAssign("local-model-consumer", consumerManifest);