/*
Facilitates JSON schema validation for integrity files using AJV, ensuring compliance with defined schemas.
- Do not handle schema definition or modification logic.
- Do not parse raw content of JSON files outside validation context.
- Do not manage the lifecycle of AJV instances beyond loading and validation.
- RFC-1097: step 6 — compass.migrate codemod run
Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.
- RFC-1097: sweep — werkstatt-engine clean
Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.
*/
/**
* JSON schema validation for integrity files using AJV.
* Validates all integrity JSON files against their defined schemas.
*/
import { discoverManagedDirectories } from "./discover.ts";
import { pathExists } from "./fs.ts";
import { readJsonFile } from "./json.ts";
import {
buildLatestDir,
currentPathsPath,
deletedLogPath,
entitiesByIdPath,
manifestPathForDirectory,
outputsPath,
policyPath,
provenancePath,
schemaDir,
} from "./paths.ts";
import type { VerifyIssue } from "./types.ts";
type AjvValidateFunction = {
(data: unknown): boolean;
errors?: Array<{ instancePath?: string; message?: string }> | null;
};
interface AjvLike {
compile(schema: object): AjvValidateFunction;
}
interface LoadedAjv {
ajv: AjvLike;
addFormats: (ajv: AjvLike) => void;
}
interface SchemaTarget {
schemaFile: string;
dataFile: string;
pathLabel: string;
optional?: boolean;
}
function formatAjvErrors(
errors: Array<{ instancePath?: string; message?: string }> | null | undefined,
): string {
if (!errors?.length) return "schema validation failed";
return errors
.map((error) => `${error.instancePath || "/"} ${error.message ?? "is invalid"}`.trim())
.join("; ");
}
async function tryLoadAjv(): Promise {
try {
const [{ default: Ajv2020 }, addFormatsModule] = await Promise.all([
import("ajv/dist/2020.js"),
import("ajv-formats"),
]);
const ajv = new Ajv2020({ allErrors: true, strict: false }) as AjvLike;
const addFormats = (addFormatsModule.default ?? addFormatsModule) as unknown as (
ajv: AjvLike,
) => void;
addFormats(ajv);
return { ajv, addFormats };
} catch {
return null;
}
}
async function loadValidator(
ajv: AjvLike,
root: string,
schemaFile: string,
): Promise {
const schema = await readJsonFile