"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PHASE06_TRAJECTORY_RECEIPT_SCHEMA_VERSION = void 0;
exports.writePhase06TrajectoryReceipt = writePhase06TrajectoryReceipt;
const node_crypto_1 = require("node:crypto");
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const index_1 = require("./index");
const build_input_manifest_1 = require("../runtime/build-input-manifest");
exports.PHASE06_TRAJECTORY_RECEIPT_SCHEMA_VERSION = 1;
const PHASE06_TRAJECTORY_LANES = [
    { id: "bootstrap", lane: "bootstrap" },
    { id: "implementation-handoff", lane: "implementation-handoff" },
    { id: "review", lane: "review" },
    { id: "task-closeout", lane: "closeout-reconciliation" },
    { id: "milestone-reconciliation", lane: "closeout-reconciliation" },
    { id: "phase-review", lane: "review" }
];
const PHASE01_BASELINE = {
    bootstrap: { controlPlaneBytes: 9_969, calls: 4 },
    "implementation-handoff": { controlPlaneBytes: 14_732, calls: 5 },
    review: { controlPlaneBytes: 17_775, calls: 6 },
    "combined-closeout-reconciliation": { controlPlaneBytes: 25_660, calls: 8 },
    total: { controlPlaneBytes: 68_136, calls: 23 }
};
function writePhase06TrajectoryReceipt(options) {
    validateReceiptInputs(options);
    const manifest = (0, build_input_manifest_1.inspectBuildInputManifest)(options.repositoryRoot);
    if (manifest.status !== "current" || manifest.aggregateDigest === null) {
        throw new Error(`Phase 06 trajectory receipt requires current manifest evidence, found ${manifest.status}.`);
    }
    const total = options.lanes.reduce((result, lane) => ({
        controlPlaneBytes: result.controlPlaneBytes + lane.controlPlaneBytes,
        calls: result.calls + lane.calls
    }), { controlPlaneBytes: 0, calls: 0 });
    const directLaneComparisons = Object.fromEntries(["bootstrap", "implementation-handoff", "review"].map((id) => {
        const lane = requireLane(options.lanes, id);
        return [id, {
                current: laneResult(lane),
                delta: delta(PHASE01_BASELINE[id], lane)
            }];
    }));
    const expandedCloseoutLaneIds = [
        "task-closeout",
        "milestone-reconciliation",
        "phase-review"
    ];
    const expandedCloseout = expandedCloseoutLaneIds
        .map((id) => requireLane(options.lanes, id))
        .reduce((result, lane) => ({
        controlPlaneBytes: result.controlPlaneBytes + lane.controlPlaneBytes,
        calls: result.calls + lane.calls
    }), { controlPlaneBytes: 0, calls: 0 });
    const receipt = {
        schemaVersion: exports.PHASE06_TRAJECTORY_RECEIPT_SCHEMA_VERSION,
        fixtureIdentity: options.fixtureIdentity,
        buildInputDigest: manifest.aggregateDigest,
        exclusions: [...new Set(options.lanes.flatMap((lane) => lane.exclusions))].sort(),
        lanes: options.lanes.map((lane) => ({
            id: lane.id,
            lane: lane.lane,
            controlPlaneBytes: lane.controlPlaneBytes,
            calls: lane.calls,
            retryCategories: lane.retryCategories
        })),
        total: {
            ...total,
            observationalTokenEstimate: Math.ceil(total.controlPlaneBytes / 4)
        },
        phase01Comparison: {
            baseline: PHASE01_BASELINE,
            directLanes: directLaneComparisons,
            expandedCloseout: {
                baselineLane: "combined-closeout-reconciliation",
                currentLaneIds: expandedCloseoutLaneIds,
                current: expandedCloseout,
                delta: delta(PHASE01_BASELINE["combined-closeout-reconciliation"], expandedCloseout)
            },
            totalDelta: delta(PHASE01_BASELINE.total, total),
            closeoutMapping: "Phase 01 combined closeout/reconciliation is compared with the aggregate of Phase 06 task-closeout, milestone-reconciliation, and phase-review lanes; expanded scope is not normalized.",
            nonComparableScopeChanges: [
                {
                    id: "expanded-closeout-lane-schema",
                    description: "Phase 01 recorded one combined closeout/reconciliation lane; Phase 06 records task-closeout, milestone-reconciliation, and phase-review separately and compares only their labeled aggregate."
                }
            ]
        }
    };
    const canonical = `${JSON.stringify(receipt, null, 2)}\n`;
    const receiptIdentity = `sha256:${(0, node_crypto_1.createHash)("sha256").update(canonical).digest("hex")}`;
    const output = { ...receipt, receiptIdentity };
    node_fs_1.default.mkdirSync(options.outputDirectory, { recursive: true, mode: 0o700 });
    const outputPath = node_path_1.default.join(options.outputDirectory, `phase06-trajectory-${receiptIdentity.slice("sha256:".length)}.json`);
    const temporaryPath = `${outputPath}.${process.pid}.tmp`;
    node_fs_1.default.writeFileSync(temporaryPath, `${JSON.stringify(output, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
    node_fs_1.default.renameSync(temporaryPath, outputPath);
    return { path: outputPath, receiptIdentity };
}
function validateReceiptInputs(options) {
    if (!/^sha256:[0-9a-f]{64}$/.test(options.fixtureIdentity)) {
        throw new Error("Phase 06 trajectory receipt requires a SHA-256 fixture identity.");
    }
    if (options.lanes.length !== PHASE06_TRAJECTORY_LANES.length) {
        throw new Error(`Phase 06 trajectory receipt requires exactly ${PHASE06_TRAJECTORY_LANES.length} canonical lanes.`);
    }
    for (const [index, expected] of PHASE06_TRAJECTORY_LANES.entries()) {
        const lane = options.lanes[index];
        if (lane.id !== expected.id || lane.lane !== expected.lane) {
            throw new Error(`Phase 06 trajectory lane ${index + 1} must be '${expected.id}' with budget lane '${expected.lane}'.`);
        }
        if (!Number.isSafeInteger(lane.controlPlaneBytes) || lane.controlPlaneBytes < 0) {
            throw new Error(`Phase 06 trajectory lane '${lane.id}' has invalid control-plane bytes.`);
        }
        if (!Number.isSafeInteger(lane.calls) || lane.calls < 0) {
            throw new Error(`Phase 06 trajectory lane '${lane.id}' has invalid call evidence.`);
        }
        if (!lane.withinBudget || !lane.strictCycleComplete || lane.failureCount !== 0) {
            throw new Error(`Phase 06 trajectory lane '${lane.id}' is incomplete or failed.`);
        }
        if (!sameStrings(lane.exclusions, index_1.REQUIRED_AGENT_TRAJECTORY_EXCLUSIONS)) {
            throw new Error(`Phase 06 trajectory lane '${lane.id}' does not preserve required exclusions.`);
        }
        const retryKeys = Object.keys(lane.retryCategories);
        if (!sameStrings(retryKeys, index_1.AGENT_STRICT_RETRY_CATEGORIES)) {
            throw new Error(`Phase 06 trajectory lane '${lane.id}' does not preserve strict retry categories.`);
        }
        if (index_1.AGENT_STRICT_RETRY_CATEGORIES.some((category) => {
            const count = lane.retryCategories[category];
            return !Number.isSafeInteger(count) || count < 0;
        })) {
            throw new Error(`Phase 06 trajectory lane '${lane.id}' has invalid retry-category counts.`);
        }
    }
}
function requireLane(lanes, id) {
    const lane = lanes.find((candidate) => candidate.id === id);
    if (lane === undefined) {
        throw new Error(`Phase 06 trajectory receipt is missing lane '${id}'.`);
    }
    return lane;
}
function laneResult(lane) {
    return {
        controlPlaneBytes: lane.controlPlaneBytes,
        calls: lane.calls
    };
}
function sameStrings(actual, expected) {
    return actual.length === expected.length
        && actual.every((value, index) => value === expected[index]);
}
function delta(baseline, current) {
    return {
        controlPlaneBytes: current.controlPlaneBytes - baseline.controlPlaneBytes,
        calls: current.calls - baseline.calls,
        controlPlaneBytesPercent: ((current.controlPlaneBytes - baseline.controlPlaneBytes) / baseline.controlPlaneBytes) * 100,
        callsPercent: ((current.calls - baseline.calls) / baseline.calls) * 100
    };
}
