/*
RFC-0565: Kernel module registering DHT workspace commands. All commands are
workspace-scoped and not cacheable (they depend on external network state and
workshop-local files). Commands are added incrementally as they are implemented.
- Do not implement command handlers — those live in their own files.
- Do not implement DHT routing — that lives in node.ts.
- Module registers commands only — DHT logic lives in the sibling handler modules.
- All commands are workspace-scoped — no app context is required.
- RFC-0565: initial implementation — dht module with dht.node.init command.
- RFC-1097: step 6 — compass.migrate codemod run
Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.
- RFC-1097: sweep — werkstatt-engine clean
Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.
- RFC-1173: declare mutatesState on all kernel commands — collectDeclarationDiagnostics emits error-severity MUTATES-STATE-DECLARED, command.manifest.validate is the blocking consumer in packages.check, sweep declares the flag on every command definition (factories hardcode false for read-only check specs)
- RFC-1173: fixup: flip mutatesState to true on 19 commands that declare writes/generates — the codemod's name-suffix rules misclassified leitstand.dev-deploy, leitstand.certify, coverage.report and peers as read-only; declared writes imply mutation
*/
import type { ModuleExport } from "@warpgogol/werkstatt-shared/kernel";
export async function createDhtModule(): Promise {
const { runDhtNodeInit } = await import("./init.ts");
const { runDhtLookup } = await import("./lookup.ts");
const { runDhtRegister } = await import("./register.ts");
const { runDhtCapacityPublish } = await import("./capacity.ts");
const { runDhtPlacement } = await import("./placement.ts");
const { runDhtStatus } = await import("./status.ts");
return {
name: "dht",
version: "0.1.0",
declarations: [],
commands: [
{
name: "dht.node.init",
coverage: "operator" as const,
mutatesState: true,
modulePath: "packages/werkstatt-engine/src/kernel/dht/dht-module.ts",
generates: [],
description:
"RFC-0565: initialize DHT configuration. Creates werkstatt.dht.json with " +
"bind address, bootstrap nodes, replication factor, and timeout parameters. " +
"Use --bind to specify the bind address. Use --bootstrap " +
"to specify a bootstrap node (can be repeated). Use --json for machine-readable output.",
scope: "workspace",
cacheable: false,
flags: {
bind: { kind: "string", description: "Bind address (host:port)." },
bootstrap: {
kind: "string[]",
description: "Bootstrap node (host:port, repeatable).",
},
},
reads: ["werkstatt.identity.json"],
writes: ["werkstatt.dht.json"],
execute: runDhtNodeInit,
},
{
name: "dht.lookup",
coverage: "operator" as const,
mutatesState: true,
modulePath: "packages/werkstatt-engine/src/kernel/dht/dht-module.ts",
generates: [],
description:
"RFC-0565: resolve a site id to its DHT entry. Queries the DHT (or local " +
"cache if fresh) and validates the entry signature. Routes around dead " +
"workshops detected by SWIM. Use --site-id to specify the site. " +
"Use --force to bypass cache. Use --json for machine-readable output.",
scope: "workspace",
cacheable: false,
flags: {
"site-id": { kind: "string", required: true, description: "Site id to resolve." },
force: { kind: "boolean", description: "Bypass the local cache." },
},
reads: [
"werkstatt.dht.json",
"werkstatt.dht.cache.json",
"werkstatt.identity.json",
"werkstatt.swim.json",
"werkstatt.genome.log",
],
writes: ["werkstatt.dht.cache.json"],
execute: runDhtLookup,
},
{
name: "dht.register",
coverage: "operator" as const,
mutatesState: true,
modulePath: "packages/werkstatt-engine/src/kernel/dht/dht-module.ts",
generates: [],
description:
"RFC-0565: publish a local registry entry to the DHT. Signs the entry with " +
"the operator's Ed25519 keypair. Uses LWW on lastUpdated for conflict resolution. " +
"Required flags: --site-id , --owner , --endpoint . " +
"Optional: --mirrors (can be repeated). Use --json for output.",
scope: "workspace",
cacheable: false,
flags: {
"site-id": { kind: "string", required: true, description: "Site id to register." },
owner: {
kind: "string",
required: true,
description: "Owner identity (did:web identifier).",
},
endpoint: {
kind: "string",
required: true,
description: "Workshop endpoint (host:port).",
},
mirrors: {
kind: "string[]",
description: "Additional mirror endpoints (host:port, repeatable).",
},
},
reads: ["werkstatt.dht.json", "werkstatt.identity.json"],
writes: ["werkstatt.dht.cache.json"],
execute: runDhtRegister,
},
{
name: "dht.capacity.publish",
coverage: "operator" as const,
coverageNote: "DHT capacity publication",
mutatesState: true,
modulePath: "packages/werkstatt-engine/src/kernel/dht/dht-module.ts",
generates: [],
description:
"RFC-0565: publish workshop capacity to the DHT for placement decisions. " +
"Signs the capacity entry with the operator's Ed25519 keypair. " +
"Required: --workshop-id , --available-slots . " +
"Optional: --endpoint , --storage-limit-mb , --bandwidth-limit-mbps . Use --json for output.",
scope: "workspace",
cacheable: false,
flags: {
"workshop-id": {
kind: "string",
required: true,
description: "Workshop id publishing capacity.",
},
"available-slots": {
kind: "string",
required: true,
description: "Number of available placement slots.",
},
endpoint: {
kind: "string",
description: "Workshop endpoint (host:port, default 0.0.0.0:0).",
},
"storage-limit-mb": { kind: "string", description: "Storage limit in MB." },
"bandwidth-limit-mbps": {
kind: "string",
description: "Bandwidth limit in Mbps.",
},
},
reads: ["werkstatt.dht.json", "werkstatt.identity.json"],
writes: [],
execute: runDhtCapacityPublish,
},
{
name: "dht.placement",
coverage: "operator" as const,
mutatesState: false,
modulePath: "packages/werkstatt-engine/src/kernel/dht/dht-module.ts",
generates: [],
description:
"RFC-0565: determine the best workshop for placing a site by querying DHT " +
"capacity entries. Uses least-loaded strategy by default. " +
"Required: --site-id , --workshops (or repeated). " +
"Optional: --strategy . Use --json for output.",
scope: "workspace",
cacheable: false,
flags: {
"site-id": { kind: "string", required: true, description: "Site id to place." },
strategy: {
kind: "string",
description: "Placement strategy (least-loaded|nearest|owner-preference).",
},
workshops: {
kind: "string[]",
required: true,
description: "Candidate workshop ids (comma-separated or repeated).",
},
},
reads: ["werkstatt.dht.json", "werkstatt.identity.json", "werkstatt.swim.json"],
writes: [],
execute: runDhtPlacement,
},
{
name: "dht.status",
coverage: "operator" as const,
mutatesState: false,
modulePath: "packages/werkstatt-engine/src/kernel/dht/dht-module.ts",
generates: [],
description:
"RFC-0565: report local DHT node status including config, cache entries, " +
"identity bootstrap state, and SWIM configuration. Local-only query — no network I/O. " +
"Use --json for machine-readable output.",
scope: "workspace",
cacheable: false,
flags: {},
reads: [
"werkstatt.dht.json",
"werkstatt.dht.cache.json",
"werkstatt.identity.json",
"werkstatt.swim.json",
],
writes: [],
execute: runDhtStatus,
},
],
pipelines: [],
};
}