import type { HousekeepingRegistry } from "../foundation/registry"; import type { MigrationEntry } from "../migration/types"; import type { HousekeepingRouteHandler } from "../route-handlers"; export interface HousekeepingParityReport { readonly discovered: 137; readonly mapped: number; readonly verified: number; readonly removed: number; readonly unresolved: readonly string[]; readonly capabilityGaps: readonly string[]; readonly handlerGaps: readonly string[]; } function expectedEvidence(row: MigrationEntry): string { return `runtime-parity:${row.legacyPath}`; } function capabilityMatches( row: MigrationEntry, route: HousekeepingRegistry["domains"][number]["routes"][number], ): boolean { const declared = new Set(row.capabilities.read); if (route.capability.mode === "all") { return route.capability.slugs.every((slug) => declared.has(slug)); } return route.capability.slugs.some((slug) => declared.has(slug)); } export function verifyHousekeepingRuntimeParity( matrix: readonly MigrationEntry[], registry: HousekeepingRegistry, handlers: readonly HousekeepingRouteHandler[], ): HousekeepingParityReport { if (matrix.length !== 137) { throw new Error( `Housekeeping parity requires exactly 137 discovered rows; received ${matrix.length}`, ); } const routes = registry.domains.flatMap((domain) => domain.routes); const routesByHref = new Map( routes.map((route) => [route.href, route]), ); const routesById = new Map(routes.map((route) => [route.id, route])); const handlersByRouteId = new Map(); for (const handler of handlers) { const matching = handlersByRouteId.get(handler.routeId) ?? []; matching.push(handler); handlersByRouteId.set(handler.routeId, matching); } const unresolved = new Set(); const capabilityGaps = new Set(); const handlerGaps = new Set(); let mapped = 0; let verified = 0; let removed = 0; for (const row of matrix) { let rowMapped = false; let rowCapabilityVerified = true; let rowHandlerVerified = true; if (row.decision === "REMOVE") { removed += 1; rowMapped = row.targetPath === null; if (!rowMapped) unresolved.add(`${row.legacyPath}: removed target exists`); } else if (row.targetPath === null) { unresolved.add(`${row.legacyPath}: retained target is missing`); } else { const route = routesByHref.get(row.targetPath); if (!route) { unresolved.add( `${row.legacyPath}: no registered route for ${row.targetPath}`, ); } else { rowMapped = true; if (!capabilityMatches(row, route)) { rowCapabilityVerified = false; capabilityGaps.add( `${row.legacyPath}: ${row.targetPath} capability mismatch`, ); } const matchingHandlers = handlersByRouteId.get(route.id) ?? []; if (matchingHandlers.length !== 1) { rowHandlerVerified = false; handlerGaps.add( `${row.legacyPath}: ${route.id} has ${matchingHandlers.length} handlers`, ); } } } if (rowMapped) mapped += 1; const expectedStatus = row.decision === "REMOVE" ? "REMOVED" : "VERIFIED"; if ( rowMapped && rowCapabilityVerified && rowHandlerVerified && row.status === expectedStatus && row.parityEvidence.includes(expectedEvidence(row)) ) { verified += 1; } } for (const route of routes) { const matchingHandlers = handlersByRouteId.get(route.id) ?? []; if (matchingHandlers.length !== 1) { handlerGaps.add( `registry route ${route.id} has ${matchingHandlers.length} handlers`, ); } } for (const handler of handlers) { if (!routesById.has(handler.routeId)) { handlerGaps.add(`orphan handler ${handler.routeId}`); } } return { discovered: 137, mapped, verified, removed, unresolved: [...unresolved].sort(), capabilityGaps: [...capabilityGaps].sort(), handlerGaps: [...handlerGaps].sort(), }; }