"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AGENT_STRICT_RETRY_CATEGORIES = exports.REQUIRED_AGENT_TRAJECTORY_EXCLUSIONS = exports.AGENT_TRAJECTORY_BUDGETS = void 0;
exports.evaluateAgentTrajectoryBudget = evaluateAgentTrajectoryBudget;
exports.AGENT_TRAJECTORY_BUDGETS = Object.freeze({
    bootstrap: Object.freeze({ maxBytes: 16 * 1024, maxCalls: 4 }),
    "implementation-handoff": Object.freeze({ maxBytes: 24 * 1024, maxCalls: 5 }),
    review: Object.freeze({ maxBytes: 32 * 1024, maxCalls: 6 }),
    "closeout-reconciliation": Object.freeze({ maxBytes: 48 * 1024, maxCalls: 8 })
});
exports.REQUIRED_AGENT_TRAJECTORY_EXCLUSIONS = Object.freeze([
    "repository-source",
    "compiler-output",
    "task-validation-output"
]);
exports.AGENT_STRICT_RETRY_CATEGORIES = Object.freeze([
    "necessary-typed",
    "invalid-invocation",
    "repeated-orientation",
    "unsupported-fallback",
    "stale-evidence-reuse",
    "unchanged-gate-reopen"
]);
function evaluateAgentTrajectoryBudget(input) {
    const limit = exports.AGENT_TRAJECTORY_BUDGETS[input.lane];
    const observations = input.observations.map((observation, index) => {
        const stdoutBytes = Buffer.byteLength(observation.stdout, "utf8");
        const stderrBytes = Buffer.byteLength(observation.stderr, "utf8");
        return {
            ...observation,
            index,
            stdoutBytes,
            stderrBytes,
            controlPlaneBytes: stdoutBytes + stderrBytes
        };
    });
    const stdoutBytes = observations.reduce((total, observation) => total + observation.stdoutBytes, 0);
    const stderrBytes = observations.reduce((total, observation) => total + observation.stderrBytes, 0);
    const controlPlaneBytes = stdoutBytes + stderrBytes;
    const violations = [];
    const strictCycleEnabled = input.strictCycle === true
        || observations.some((observation) => observation.strictCycle !== undefined);
    const strictRetryCategories = Object.fromEntries(exports.AGENT_STRICT_RETRY_CATEGORIES.map((category) => [category, 0]));
    const strictObservations = [];
    const strictEvidenceIdentities = new Set();
    let strictNecessaryRetries = 0;
    let strictAvoidableRetries = 0;
    let strictEvidenceReuse = 0;
    let strictStaleEvidenceReuse = 0;
    let strictCompleteDecisionLanes = 0;
    let strictIncompleteDecisionLanes = 0;
    let strictEvaluatedGates = 0;
    let strictReusedGates = 0;
    let strictReopenedGates = 0;
    let strictUnchangedReopenedGates = 0;
    let strictFailures = 0;
    let strictNoWriteFailures = 0;
    let strictCallableRecoveryFailures = 0;
    let strictMissingCallableRecoveryFailures = 0;
    const declaredExclusionClasses = new Set(input.excludedEvidence.map((evidence) => evidence.class));
    for (const requiredClass of exports.REQUIRED_AGENT_TRAJECTORY_EXCLUSIONS) {
        if (!declaredExclusionClasses.has(requiredClass)) {
            violations.push({
                code: "TRAJECTORY_REQUIRED_EXCLUSION_MISSING",
                exclusionClass: requiredClass,
                message: `Required excluded evidence class '${requiredClass}' was not declared.`
            });
        }
    }
    const defaultOrientations = observations.filter((observation) => observation.orientation === "default");
    if (defaultOrientations.length > 1) {
        for (const repeated of defaultOrientations.slice(1)) {
            violations.push({
                code: "TRAJECTORY_REPEATED_DEFAULT_ORIENTATION",
                observationIndex: repeated.index,
                command: repeated.command,
                actual: defaultOrientations.length,
                limit: 1,
                message: `Default orientation repeated at observation ${repeated.index}; one terminal bootstrap orientation is allowed.`
            });
        }
    }
    for (const observation of observations) {
        if (observation.actionValidity === "invalid") {
            violations.push({
                code: "TRAJECTORY_INVALID_ACTION",
                observationIndex: observation.index,
                command: observation.command,
                message: `Observation ${observation.index} records invalid action '${observation.command}'.`
            });
        }
        else if (observation.actionValidity === "unconditional") {
            violations.push({
                code: "TRAJECTORY_UNCONDITIONAL_ACTION",
                observationIndex: observation.index,
                command: observation.command,
                message: `Observation ${observation.index} records unconditional action '${observation.command}'.`
            });
        }
        if (!strictCycleEnabled) {
            continue;
        }
        const evidence = observation.strictCycle;
        if (evidence === undefined) {
            violations.push({
                code: "TRAJECTORY_STRICT_EVIDENCE_MISSING",
                observationIndex: observation.index,
                command: observation.command,
                message: `Observation ${observation.index} is missing required strict-cycle evidence.`
            });
            continue;
        }
        const evidenceIdentity = evidence.evidenceIdentity.trim();
        const decisionLane = evidence.decisionLane.trim();
        strictObservations.push({
            index: observation.index,
            command: observation.command,
            evidenceIdentity,
            evidenceFreshness: evidence.evidenceFreshness,
            decisionLane,
            complete: evidence.complete,
            outcome: evidence.outcome,
            writeOutcome: evidence.writeOutcome,
            retryCategory: evidence.retryCategory ?? null,
            gateAction: evidence.gate?.action ?? null
        });
        if (evidenceIdentity === "") {
            violations.push({
                code: "TRAJECTORY_STRICT_IDENTITY_MISSING",
                observationIndex: observation.index,
                command: observation.command,
                message: `Observation ${observation.index} is missing a stable strict-cycle evidence identity.`
            });
        }
        else {
            strictEvidenceIdentities.add(evidenceIdentity);
        }
        if (decisionLane === "") {
            violations.push({
                code: "TRAJECTORY_STRICT_DECISION_LANE_MISSING",
                observationIndex: observation.index,
                command: observation.command,
                message: `Observation ${observation.index} is missing its strict-cycle decision lane.`
            });
        }
        if (evidence.complete) {
            strictCompleteDecisionLanes += 1;
        }
        else {
            strictIncompleteDecisionLanes += 1;
            violations.push({
                code: "TRAJECTORY_STRICT_DECISION_LANE_INCOMPLETE",
                observationIndex: observation.index,
                command: observation.command,
                message: `Observation ${observation.index} has incomplete decision-lane evidence.`
            });
        }
        if (evidence.retryCategory !== undefined) {
            strictRetryCategories[evidence.retryCategory] += 1;
            if (evidence.retryCategory === "necessary-typed") {
                strictNecessaryRetries += 1;
                if ((evidence.typedFailure ?? "").trim() === "") {
                    violations.push({
                        code: "TRAJECTORY_STRICT_NECESSARY_RETRY_UNTYPED",
                        observationIndex: observation.index,
                        command: observation.command,
                        message: `Observation ${observation.index} classifies a necessary retry without a typed failure.`
                    });
                }
            }
            else {
                strictAvoidableRetries += 1;
                violations.push({
                    code: "TRAJECTORY_STRICT_AVOIDABLE_RETRY",
                    observationIndex: observation.index,
                    command: observation.command,
                    message: `Observation ${observation.index} records avoidable retry category '${evidence.retryCategory}'.`
                });
            }
        }
        const gate = evidence.gate;
        if (gate !== undefined) {
            if (gate.action === "evaluate")
                strictEvaluatedGates += 1;
            if (gate.action === "reuse") {
                strictReusedGates += 1;
                strictEvidenceReuse += 1;
                if (evidence.evidenceFreshness === "stale") {
                    strictStaleEvidenceReuse += 1;
                    violations.push({
                        code: "TRAJECTORY_STRICT_STALE_EVIDENCE_REUSED",
                        observationIndex: observation.index,
                        command: observation.command,
                        message: `Observation ${observation.index} reuses stale evidence for gate '${gate.identity}'.`
                    });
                }
            }
            if (gate.action === "reopen") {
                strictReopenedGates += 1;
                if (!gate.evidenceChanged) {
                    strictUnchangedReopenedGates += 1;
                    violations.push({
                        code: "TRAJECTORY_STRICT_UNCHANGED_GATE_REOPENED",
                        observationIndex: observation.index,
                        command: observation.command,
                        message: `Observation ${observation.index} reopens unchanged gate '${gate.identity}'.`
                    });
                }
            }
        }
        if (evidence.outcome === "failure") {
            strictFailures += 1;
            if (evidence.writeOutcome === "not-written") {
                strictNoWriteFailures += 1;
            }
            else {
                violations.push({
                    code: "TRAJECTORY_STRICT_FAILURE_WRITE_OUTCOME",
                    observationIndex: observation.index,
                    command: observation.command,
                    message: `Observation ${observation.index} failed without preserving an explicit no-write outcome.`
                });
            }
            if (evidence.preconditionsComplete) {
                if (evidence.recovery === undefined || evidence.recovery.command.trim() === "") {
                    strictMissingCallableRecoveryFailures += 1;
                    violations.push({
                        code: "TRAJECTORY_STRICT_RECOVERY_MISSING",
                        observationIndex: observation.index,
                        command: observation.command,
                        message: `Observation ${observation.index} has complete recovery preconditions but no recovery locator.`
                    });
                }
                else if (!evidence.recovery.callable) {
                    strictMissingCallableRecoveryFailures += 1;
                    violations.push({
                        code: "TRAJECTORY_STRICT_RECOVERY_NOT_CALLABLE",
                        observationIndex: observation.index,
                        command: observation.command,
                        message: `Observation ${observation.index} has a recovery locator that is not callable.`
                    });
                }
                else {
                    strictCallableRecoveryFailures += 1;
                }
            }
        }
    }
    if (observations.length > limit.maxCalls) {
        violations.push({
            code: "TRAJECTORY_CALL_BUDGET_EXCEEDED",
            actual: observations.length,
            limit: limit.maxCalls,
            message: `Trajectory used ${observations.length} calls; lane '${input.lane}' allows ${limit.maxCalls}.`
        });
    }
    if (controlPlaneBytes > limit.maxBytes) {
        violations.push({
            code: "TRAJECTORY_BYTE_BUDGET_EXCEEDED",
            actual: controlPlaneBytes,
            limit: limit.maxBytes,
            message: `Trajectory used ${controlPlaneBytes} control-plane UTF-8 bytes; lane '${input.lane}' allows ${limit.maxBytes}.`
        });
    }
    return {
        lane: input.lane,
        limit: { ...limit },
        usage: {
            calls: observations.length,
            stdoutBytes,
            stderrBytes,
            controlPlaneBytes
        },
        observations,
        excludedEvidence: {
            requiredClasses: [...exports.REQUIRED_AGENT_TRAJECTORY_EXCLUSIONS],
            declared: input.excludedEvidence.map((evidence) => ({ ...evidence })),
            totalBytes: input.excludedEvidence.reduce((total, evidence) => total + evidence.bytes, 0)
        },
        observationalTokens: {
            estimatedTokens: Math.ceil(controlPlaneBytes / 4),
            normative: false,
            basis: "control-plane UTF-8 bytes divided by four and rounded up"
        },
        strictCycle: {
            enabled: strictCycleEnabled,
            observations: strictObservations,
            retries: {
                total: strictNecessaryRetries + strictAvoidableRetries,
                necessary: strictNecessaryRetries,
                avoidable: strictAvoidableRetries,
                categories: strictRetryCategories
            },
            evidence: {
                identities: [...strictEvidenceIdentities].sort(),
                reused: strictEvidenceReuse,
                staleReuse: strictStaleEvidenceReuse
            },
            decisionLanes: {
                complete: strictCompleteDecisionLanes,
                incomplete: strictIncompleteDecisionLanes
            },
            gates: {
                evaluated: strictEvaluatedGates,
                reused: strictReusedGates,
                reopened: strictReopenedGates,
                unchangedReopened: strictUnchangedReopenedGates
            },
            failures: {
                total: strictFailures,
                noWritePreserved: strictNoWriteFailures,
                callableRecovery: strictCallableRecoveryFailures,
                missingCallableRecovery: strictMissingCallableRecoveryFailures
            }
        },
        violations,
        withinBudget: violations.length === 0
    };
}
