Name the two modules after their software: nftables and distribution

A module's identity is the software it is (ADR 0040). Two were named after the
job instead, and the job already had a name.

firewall installs the nftables package and runs nftables.service. The seat it
claims is the-packet-filter, which is correctly named for the role. Calling the
module firewall named neither the software nor the provision, and promised that
any firewall could sit there — the false genericity the naming rule forbids.

registry runs Distribution, the OCI reference implementation, and provides
artifact-store. So registry was a third name for a thing that already had two,
which is how one word ended up meaning the module, the software and the concept
in the same paragraph.

The capability stays firewall, and correctly: a capability IS a functionality, so
a node having one and fail2ban requiring one are both right. Only the module
moves.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
2026-09-15 20:51:00 +02:00
parent bf1f67a485
commit 71bbc7dab0
12 changed files with 3 additions and 3 deletions
+59
View File
@@ -0,0 +1,59 @@
// registry's tools — moved here from the shared sdk (novox/hq ADR 0039), importing registry's own
// client. They return structured data; the mesh serves them through the sdk's tool harness.
import { registerModuleTools, type ToolDefinition } from "@novox/mesh-sdk/tools";
import { RegistryClient } from "../client.js";
export function getRegistryTools(registry: RegistryClient): ToolDefinition[] {
return [
{
name: "registry_list",
description: "List every repository in the Docker registry (the catalog).",
input: {},
run: async () => {
const repositories = await registry.listRepositories();
return { count: repositories.length, repositories };
},
},
{
name: "registry_tags",
description: "List the tags of one repository in the Docker registry.",
input: { repo: { type: "string", description: "the repository name, e.g. 'novox/mesh'" } },
run: async (args) => {
const repo = String(args.repo);
const tags = await registry.listTags(repo);
return { repo, count: tags.length, tags };
},
},
{
name: "registry_delete_image",
description:
"Delete an image tag from the registry (DESTRUCTIVE). Removes the manifest; storage is reclaimed by garbage collection later. Requires confirm: true.",
input: {
repo: { type: "string", description: "the repository name, e.g. 'novox/mesh'" },
tag: { type: "string", description: "the tag to delete, e.g. 'latest'" },
confirm: { type: "boolean", description: "must be true to actually delete" },
},
run: async (args) => {
const repo = String(args.repo);
const tag = String(args.tag);
if (args.confirm !== true) {
return { deleted: false, reason: "confirm must be true to delete an image" };
}
const digest = await registry.getManifestDigest(repo, tag);
await registry.deleteManifest(repo, digest);
return { deleted: true, repo, tag, digest, note: "run registry garbage collection to reclaim storage" };
},
},
];
}
// The tools exist only when a registry URL is configured; otherwise registry contributes none
// rather than failing the whole runtime.
registerModuleTools("registry", (env) => {
try {
return getRegistryTools(RegistryClient.fromEnv(env));
} catch {
return [];
}
});