/**
 * pipeline/assert-grader-judgments-persisted.ts
 *
 * Post-persist guard for the grader-judgments write junction in
 * `calculateAndWriteScores`.
 *
 * `extractGraderJudgmentsResilient` returns N judgments in memory, after which
 * `runBorderlinePass` may mutate the array in place and a `judgments.length > 0`
 * guard decides whether `grader-judgments.json` is written. A transient read
 * anomaly or an unexpected in-place emptying can leave the file absent or empty
 * even though extraction yielded judgments. Silently skipping the write strands
 * gap-analysis and ships a scored report with no test details.
 *
 * This guard re-reads the file from disk — the same read gap-analysis performs
 * — and fails loud when a non-empty extraction did not round-trip. The check is
 * deliberately narrow: it fires only on the catastrophic "extracted N>0,
 * persisted 0" divergence, never on a genuinely judgment-free run.
 */
import { existsSync, readFileSync } from "node:fs";
/**
 * Parse `grader-judgments.json` and return its array length. Every "no usable
 * judgments" shape (missing, unreadable, invalid JSON, non-array) collapses to
 * 0 — mirroring how the downstream enrichment precondition reads the same file.
 */
function defaultCountPersisted(path) {
    if (!existsSync(path))
        return 0;
    try {
        const parsed = JSON.parse(readFileSync(path, "utf-8"));
        return Array.isArray(parsed) ? parsed.length : 0;
    }
    catch {
        return 0;
    }
}
/**
 * Fail loud when a non-empty grader-judgment extraction did not round-trip to
 * disk. No-ops when nothing was extracted — a judgment-free run (all api-errors
 * / no llm-rubric) is valid and persists nothing by design.
 *
 * @param extractedCount  Judgments returned by extraction, captured BEFORE any
 *   in-place mutation (e.g. the borderline-consensus pass) so the count
 *   reflects what extraction actually produced.
 * @param judgmentsPath  Absolute path to `grader-judgments.json`.
 * @param deps  Injectable disk reader; defaults to the real filesystem.
 * @throws {Error} when `extractedCount > 0` but the persisted file holds 0.
 */
export function assertGraderJudgmentsPersisted(extractedCount, judgmentsPath, deps = { countPersisted: defaultCountPersisted }) {
    if (extractedCount <= 0)
        return;
    const persisted = deps.countPersisted(judgmentsPath);
    if (persisted <= 0) {
        throw new Error(`Grader judgments extract/persist divergence: extracted ${extractedCount} ` +
            `judgment(s) but grader-judgments.json persisted 0. Refusing to finish ` +
            `scoring — a scored report with no grader judgments would strand ` +
            `gap-analysis and ship with no test details.`);
    }
}
