/*
RFC-0479: migrator.registry.validate — validate the RFC-id-keyed migrator
registry for id uniqueness, RFC-id ordering, and test coverage.
- Do not apply migrators or touch the filesystem.
- RFC-0479: initial migrator.registry.validate command.
- RFC-1149: migrate ambient filesystem and process IO to the WorkspaceIO port across engine and shared
- RFC-1249: wire werkstatt.commands.validate into packages.check + retire CMD-OUTPUT debt
*/
import path from "node:path";
import type {
KernelCommandInput,
KernelCommandResult,
KernelRuntimeContext,
} from "@warpgogol/werkstatt-engine/kernel";
import { migratorRegistry, numericRfcId, allMigratorIds } from "../migrators/registry.ts";
import { failResult } from "@warpgogol/werkstatt-shared/checks/result-helpers";
export interface MigratorRegistryValidateData {
migratorCount: number;
violations: string[];
}
export async function runMigratorRegistryValidate(
_input: KernelCommandInput,
context: KernelRuntimeContext,
): Promise> {
const { workspaceRoot, logger } = context;
const violations: string[] = [];
logger.section("[migrator.registry.validate]");
logger.info(` ${migratorRegistry.length} migrator(s) in registry`);
const ids = migratorRegistry.map((m) => m.id);
const seen = new Set();
for (const id of ids) {
if (seen.has(id)) {
violations.push(`duplicate migrator-id: ${id}`);
}
seen.add(id);
}
const sortedIds = allMigratorIds();
for (let i = 1; i < sortedIds.length; i++) {
if (numericRfcId(sortedIds[i]) <= numericRfcId(sortedIds[i - 1])) {
violations.push(`ordering violation: ${sortedIds[i]} should come after ${sortedIds[i - 1]}`);
}
}
for (const migrator of migratorRegistry) {
const migratorDir = path.dirname(
path.resolve(workspaceRoot, "packages/werkstatt-engine/src/migrators/registry.ts"),
);
const pbtTestPath = path.join(migratorDir, `${migrator.id}.pbt.test.ts`);
const snapshotTestPath = path.join(migratorDir, `${migrator.id}.snapshot.test.ts`);
if (!(await context.io.exists(pbtTestPath))) {
violations.push(`missing PBT test: ${migrator.id}.pbt.test.ts`);
}
if (!(await context.io.exists(snapshotTestPath))) {
violations.push(`missing snapshot test: ${migrator.id}.snapshot.test.ts`);
}
}
if (violations.length > 0) {
for (const v of violations) {
logger.error(` ${v}`);
}
return {
...failResult("migrator.registry.validate", [
`[migrator.registry.validate] ${violations.length} violation${violations.length === 1 ? "" : "s"}`,
]),
data: { migratorCount: migratorRegistry.length, violations },
};
}
logger.success("[migrator.registry.validate] OK — no violations");
return {
data: { migratorCount: migratorRegistry.length, violations: [] },
exitCode: 0,
summary: "[migrator.registry.validate] OK — no violations",
};
}