"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DEFAULT_TRACE_LIMITS = exports.DECISION_TRACE_SCHEMA_VERSION = void 0;
exports.createDecisionTrace = createDecisionTrace;
const paths_1 = require("../paths");
exports.DECISION_TRACE_SCHEMA_VERSION = 1;
exports.DEFAULT_TRACE_LIMITS = { maxEvidenceReferences: 16, maxRuleIds: 16, maxTransitionIds: 16 };
function createDecisionTrace(input, limits = exports.DEFAULT_TRACE_LIMITS) {
    if (!input.enabled)
        return null;
    const evidence = bound(input.evidenceReferences ?? [], limits.maxEvidenceReferences, sanitizeEvidenceReference);
    const rules = bound(input.ruleIds ?? [], limits.maxRuleIds, normalizeOpaqueId);
    const transitions = bound(input.transitionIds ?? [], limits.maxTransitionIds, normalizeOpaqueId);
    const omittedCount = evidence.omitted + rules.omitted + transitions.omitted;
    return {
        schemaVersion: exports.DECISION_TRACE_SCHEMA_VERSION,
        commandId: normalizeOpaqueId(input.commandId),
        requestId: normalizeOpaqueId(input.requestId),
        workspaceId: normalizeOpaqueId(input.workspaceId),
        exitClassification: normalizeOpaqueId(input.exitClassification),
        evidenceReferences: evidence.values,
        ruleIds: rules.values,
        transitionIds: transitions.values,
        freshnessChecks: metric(input.freshnessChecks),
        cacheHit: input.cacheHit ?? null,
        scanCount: metric(input.scanCount),
        inputCount: metric(input.inputCount),
        resultCount: metric(input.resultCount),
        outputBytes: metric(input.outputBytes),
        elapsedMs: metric(input.elapsedMs),
        complete: omittedCount === 0,
        omittedCount
    };
}
function sanitizeEvidenceReference(value) {
    if (value.length > 256 || value.includes("\n") || value.includes("\r") || /(^|[\\/])\.\.([\\/]|$)/.test(value))
        return "<sensitive-omitted>";
    if (/^[a-zA-Z]:[\\/]/.test(value) || value.startsWith("/") || value.startsWith("~") || value.includes("="))
        return "<sensitive-omitted>";
    try {
        return (0, paths_1.parseRepositoryRelativePath)(value).normalizedPath;
    }
    catch {
        return "<sensitive-omitted>";
    }
}
function normalizeOpaqueId(value) {
    if (!/^[a-z0-9][a-z0-9._:-]{0,127}$/i.test(value))
        throw new Error("Decision trace identifiers must be bounded opaque values.");
    return value;
}
function metric(value) {
    const normalized = value ?? 0;
    if (!Number.isSafeInteger(normalized) || normalized < 0)
        throw new Error("Decision trace metrics must be non-negative safe integers.");
    return normalized;
}
function bound(values, limit, normalize) {
    if (!Number.isSafeInteger(limit) || limit < 0 || limit > 100)
        throw new Error("Decision trace limits must be safe integers from 0 through 100.");
    const normalized = [...new Set(values.map(normalize))].sort();
    return { values: normalized.slice(0, limit), omitted: Math.max(0, normalized.length - limit) };
}
