/* 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", }; }