/*
RFC-1031: registers evolution.candidate.* kernel commands for the
governed capability evolution controller. 9 commands covering the full
candidate lifecycle: define, shadow, test, canary, activate, promote,
rollback, quarantine, inspect.
- Does not implement evolution logic — that lives in controller.ts.
- Does not register non-evolution commands.
- RFC-1031: initial implementation — registers 9 evolution.candidate.* commands.
*/
import type { ModuleExport } from "@warpgogol/werkstatt-shared/kernel";
export async function createEvolutionModule(): Promise {
const {
runCandidateDefine,
runCandidateShadow,
runCandidateTest,
runCandidateCanary,
runCandidateActivate,
runCandidatePromote,
runCandidateRollback,
runCandidateQuarantine,
runCandidateInspect,
} = await import("./evolution-commands.ts");
const modulePath = "packages/werkstatt-engine/src/evolution/evolution.module.ts";
return {
name: "evolution",
version: "0.1.0",
declarations: [],
commands: [
{
name: "evolution.candidate.define",
coverage: "operator" as const,
modulePath,
description:
"Register a new capability candidate in the defined state. " +
"Requires --component-id, --version, --artifact (content-addressed hash). " +
"Optional --allow-agent-written flag for agent-authored candidates (RFC-1031).",
scope: "workspace",
mutatesState: true,
cacheable: false,
generates: [],
flags: {
"component-id": { kind: "string", description: "Component ID for the candidate." },
version: { kind: "string", description: "Semantic version of the candidate." },
artifact: {
kind: "string",
description: "Content-addressed artifact hash (sha256:...).",
},
"allow-agent-written": {
kind: "boolean",
description: "Allow agent-authored candidates (default: false).",
},
},
execute: runCandidateDefine,
},
{
name: "evolution.candidate.shadow",
coverage: "operator" as const,
modulePath,
description:
"Run candidate alongside active component in shadow mode. " +
"Parallel invocation with comparison metric. Records CandidateEvidenceV1 (RFC-1031).",
scope: "workspace",
mutatesState: true,
cacheable: false,
generates: [],
flags: {
"candidate-id": { kind: "string", description: "Candidate ID to shadow." },
metric: { kind: "string", description: "Comparison metric (default: latency)." },
},
execute: runCandidateShadow,
},
{
name: "evolution.candidate.test",
coverage: "operator" as const,
modulePath,
description:
"Run held-out evaluation scenarios against the candidate. " +
"Records CandidateEvidenceV1 for each scenario (RFC-1031).",
scope: "workspace",
mutatesState: true,
cacheable: false,
generates: [],
flags: {
"candidate-id": { kind: "string", description: "Candidate ID to test." },
scenarios: {
kind: "string",
description: "Path to evaluation scenarios (default: src/evolution/fixtures).",
},
},
execute: runCandidateTest,
},
{
name: "evolution.candidate.canary",
coverage: "operator" as const,
modulePath,
description:
"Route a percentage of traffic to the candidate via deterministic hash routing. " +
"Uses Sha256Digest of canonical JSON input bytes (RFC-0849, RFC-1031).",
scope: "workspace",
mutatesState: true,
cacheable: false,
generates: [],
flags: {
"candidate-id": { kind: "string", description: "Candidate ID to canary." },
"traffic-percent": {
kind: "string",
description: "Percentage of traffic to route (default: 10).",
},
},
execute: runCandidateCanary,
},
{
name: "evolution.candidate.activate",
coverage: "operator" as const,
modulePath,
description:
"Atomically replace the active component with the candidate. " +
"Uses ActivationTransaction for atomic replacement (RFC-1031).",
scope: "workspace",
mutatesState: true,
cacheable: false,
generates: [],
flags: {
"candidate-id": { kind: "string", description: "Candidate ID to activate." },
},
execute: runCandidateActivate,
},
{
name: "evolution.candidate.promote",
coverage: "operator" as const,
modulePath,
description:
"Promote the candidate to permanent status via the mission/release pipeline. " +
"Creates a mission with the candidate artifact (RFC-1031).",
scope: "workspace",
mutatesState: true,
cacheable: false,
generates: [],
flags: {
"candidate-id": { kind: "string", description: "Candidate ID to promote." },
"mission-id": { kind: "string", description: "Mission ID for the promotion pipeline." },
},
execute: runCandidatePromote,
},
{
name: "evolution.candidate.rollback",
coverage: "operator" as const,
modulePath,
description:
"Reactivate the previous component and transition the candidate to rolled-back. " +
"Used when a promoted candidate needs to be reverted (RFC-1031).",
scope: "workspace",
mutatesState: true,
cacheable: false,
generates: [],
flags: {
"component-id": { kind: "string", description: "Component ID to roll back." },
},
execute: runCandidateRollback,
},
{
name: "evolution.candidate.quarantine",
coverage: "operator" as const,
modulePath,
description:
"Transition candidate to quarantined state. " +
"Triggered automatically after 3 consecutive health check failures or manually (RFC-1031).",
scope: "workspace",
mutatesState: true,
cacheable: false,
generates: [],
flags: {
"candidate-id": { kind: "string", description: "Candidate ID to quarantine." },
reason: { kind: "string", description: "Reason for quarantine (default: unspecified)." },
},
execute: runCandidateQuarantine,
},
{
name: "evolution.candidate.inspect",
coverage: "operator" as const,
modulePath,
description:
"Inspect all registered candidates with their states and transition history. " +
"Returns JSON array of CapabilityCandidateV1 (RFC-1031).",
scope: "workspace",
mutatesState: false,
cacheable: false,
generates: [],
flags: {},
execute: runCandidateInspect,
},
],
pipelines: [],
};
}