/* RFC-1027: validates that all validator commands with rules[] declarations have corresponding entries in REMEDIATION_CATALOG. Emits REMEDIATION-01 for missing catalog entries and REMEDIATION-02 for catalog entries with no matching validator. In --mode strict, REMEDIATION-01 is blocking. In --mode warning (default), both are warnings. Do not validate diagnostic instances — this command validates catalog coverage, not individual diagnostics. RFC-1027: initial implementation. ADR-0105 fo-review: resolve the full workspace registry via getOrBuildWorkspaceRegistry — a single-module actualState on the fast path produced phantom REMEDIATION-02 for every catalog entry owned by another module (the same blind-spot class as the commands-validate detector gap). */ import { REMEDIATION_CATALOG } from "@warpgogol/werkstatt-shared/remediation"; import type { KernelCommandInput, KernelCommandResult, KernelRuntimeContext, Diagnostic, } from "@warpgogol/werkstatt-shared/kernel"; import { diagnosticsResult } from "@warpgogol/werkstatt-shared/checks/result-helpers"; import { getOrBuildWorkspaceRegistry } from "../kernel/runtime/registry-cache.ts"; import type { ActualState } from "@warpgogol/werkstatt-shared/kernel"; const VALIDATOR_NAME_PATTERN = /\.validate$|\.check$|\.lint$/; export async function runRemediationHintValidate( input: KernelCommandInput, context: KernelRuntimeContext, ): Promise { const mode = (input.flags["mode"] as string) ?? "warning"; const strict = mode === "strict"; // The fast-path may hand this command a single-module actualState (only the // remediation module's commands) — the check needs the FULL workspace // registry, same as validator.inventory.generate (validator-inventory.ts). const registry = (await getOrBuildWorkspaceRegistry(context.workspaceRoot)) ?? context.actualState; const catalogRuleIds = new Set(REMEDIATION_CATALOG.keys()); const validatorRuleIds = collectValidatorRuleIds(registry); const diagnostics: Diagnostic[] = []; for (const ruleId of validatorRuleIds) { if (!catalogRuleIds.has(ruleId)) { diagnostics.push({ ruleId: "REMEDIATION-01", severity: strict ? "error" : "warning", message: `Validator rule "${ruleId}" has no entry in REMEDIATION_CATALOG — add a remediation pattern for this ruleId.`, }); } } for (const ruleId of catalogRuleIds) { if (!validatorRuleIds.has(ruleId)) { diagnostics.push({ ruleId: "REMEDIATION-02", severity: "warning", message: `REMEDIATION_CATALOG entry "${ruleId}" has no matching validator rule[] declaration — the catalog entry may be stale.`, }); } } return diagnosticsResult("remediation.hint.validate", diagnostics); } function collectValidatorRuleIds(registry: ActualState): Set { const ruleIds = new Set(); for (const cmd of registry.commands.values()) { if (cmd.rules && VALIDATOR_NAME_PATTERN.test(cmd.name)) { for (const rule of cmd.rules) { ruleIds.add(rule); } } } return ruleIds; }