"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SCOPE_GUARD_RECOVERY_GUIDANCE = exports.SCOPE_GUARD_FINDING_IDS = void 0;
exports.evaluateScopeGuard = evaluateScopeGuard;
exports.isRequestedPathWithinDeclaredTarget = isRequestedPathWithinDeclaredTarget;
const output_1 = require("../output");
exports.SCOPE_GUARD_FINDING_IDS = [
    "SCOPE_GUARD_IN_SCOPE",
    "SCOPE_GUARD_OUT_OF_SCOPE",
    "SCOPE_GUARD_MISSING_DECLARATION",
    "SCOPE_GUARD_AMBIGUOUS_DECLARATION",
    "SCOPE_GUARD_INVALID_REQUEST",
    "SCOPE_GUARD_UNSAFE_MISMATCH"
];
exports.SCOPE_GUARD_RECOVERY_GUIDANCE = {
    "in-scope": {
        nextAction: "none",
        recovery: "No recovery is required.",
        noWriteRequired: false
    },
    "out-of-scope": {
        nextAction: "capture-discovered-work",
        recovery: "Review whether this is discovered work, then capture it in planning or adjust the request before implementation.",
        noWriteRequired: false
    },
    "missing-declaration": {
        nextAction: "revise-planning",
        recovery: "Add explicit repository-relative target paths to the task or milestone child task evidence before relying on this guard.",
        noWriteRequired: false
    },
    "ambiguous-declaration": {
        nextAction: "stop-unsafe-automation",
        recovery: "Resolve duplicate or conflicting declared target-path evidence before rerunning the guard.",
        noWriteRequired: true
    },
    "invalid-input": {
        nextAction: "correct-input",
        recovery: "Correct the requested implementation path input and rerun without guessing a normalized target.",
        noWriteRequired: true
    },
    "unsafe-mismatch": {
        nextAction: "stop-unsafe-automation",
        recovery: "Realign the request with declared scope or create explicit follow-up planning before rerunning.",
        noWriteRequired: true
    }
};
function evaluateScopeGuard(input) {
    const results = [];
    const declaredPaths = input.declaredTargetEvidence
        .filter((entry) => entry.state === "explicit" && entry.path !== undefined)
        .map((entry) => ({
        path: entry.path,
        artifactPath: entry.sourceArtifactPath
    }));
    const ambiguousEvidence = input.declaredTargetEvidence.filter((entry) => entry.state === "duplicate");
    const missingEvidence = input.declaredTargetEvidence.filter((entry) => entry.state === "missing-section"
        || entry.state === "placeholder"
        || entry.state === "prose"
        || entry.state === "unreadable-child-artifact");
    for (const requestedEvidence of input.requestedPathEvidence) {
        if (requestedEvidence.state === "invalid-input") {
            results.push(createInvalidInputResult(requestedEvidence));
            continue;
        }
        if (requestedEvidence.state === "duplicate") {
            continue;
        }
        const requestedPath = requestedEvidence.normalizedPath;
        if (requestedPath === undefined) {
            continue;
        }
        if (ambiguousEvidence.length > 0) {
            results.push(createAmbiguousDeclarationResult(requestedPath, ambiguousEvidence));
            continue;
        }
        if (declaredPaths.length === 0) {
            results.push(createMissingDeclarationResult(requestedPath, missingEvidence));
            continue;
        }
        const matchingDeclaredPath = declaredPaths.find((declaredPath) => isRequestedPathWithinDeclaredTarget(requestedPath, declaredPath.path));
        if (matchingDeclaredPath !== undefined) {
            results.push(createInScopeResult(requestedPath, matchingDeclaredPath.path, matchingDeclaredPath.artifactPath));
            continue;
        }
        results.push(input.options?.treatOutOfScopeAsUnsafe === true
            ? createUnsafeMismatchResult(requestedPath, declaredPaths.map((entry) => entry.path))
            : createOutOfScopeResult(requestedPath, declaredPaths.map((entry) => entry.path)));
    }
    return {
        results,
        findings: results.map((result) => result.finding),
        readOnly: true
    };
}
function isRequestedPathWithinDeclaredTarget(requestedPath, declaredTargetPath) {
    return requestedPath === declaredTargetPath || requestedPath.startsWith(`${declaredTargetPath}/`);
}
function createInScopeResult(requestedPath, declaredPath, artifactPath) {
    const recovery = exports.SCOPE_GUARD_RECOVERY_GUIDANCE["in-scope"];
    const finding = (0, output_1.createValidationFinding)({
        id: "SCOPE_GUARD_IN_SCOPE",
        code: "SCOPE_GUARD_IN_SCOPE",
        level: "informational",
        severity: "informational",
        summary: `Requested path '${requestedPath}' is within declared scope '${declaredPath}'.`,
        message: `Requested path '${requestedPath}' is within declared scope '${declaredPath}'.`,
        affectedPaths: [
            createAffectedPath("command-evidence", requestedPath, "Requested implementation path."),
            createAffectedPath("declared-target", declaredPath, "Matching declared target path.", artifactPath)
        ],
        artifacts: [createArtifactReference(artifactPath)],
        recovery: recovery.recovery,
        evidence: {
            category: "scope-guard",
            details: {
                category: "in-scope",
                nextAction: recovery.nextAction,
                blocking: false,
                noWriteRequired: recovery.noWriteRequired,
                readOnly: true
            }
        }
    });
    return {
        category: "in-scope",
        requestedPath,
        declaredPath,
        recovery,
        finding,
        blocking: false,
        readOnly: true
    };
}
function createOutOfScopeResult(requestedPath, declaredPaths) {
    const recovery = exports.SCOPE_GUARD_RECOVERY_GUIDANCE["out-of-scope"];
    const finding = (0, output_1.createAdvisoryValidationFinding)({
        id: "SCOPE_GUARD_OUT_OF_SCOPE",
        code: "SCOPE_GUARD_OUT_OF_SCOPE",
        advisoryReason: "possible-discovered-work",
        summary: `Requested path '${requestedPath}' is outside declared scope.`,
        message: `Requested path '${requestedPath}' is outside declared scope.`,
        detail: `Declared targets: ${declaredPaths.join(", ") || "(none)"}.`,
        affectedPaths: [createAffectedPath("command-evidence", requestedPath, "Requested implementation path outside declared target paths.")],
        recovery: recovery.recovery,
        evidence: {
            category: "scope-guard",
            details: {
                category: "out-of-scope",
                nextAction: recovery.nextAction,
                blocking: false,
                declaredPaths,
                readOnly: true
            }
        }
    });
    return {
        category: "out-of-scope",
        requestedPath,
        recovery,
        finding,
        blocking: false,
        readOnly: true
    };
}
function createMissingDeclarationResult(requestedPath, evidence) {
    const recovery = exports.SCOPE_GUARD_RECOVERY_GUIDANCE["missing-declaration"];
    const artifactPaths = unique(evidence.map((entry) => entry.sourceArtifactPath));
    const finding = (0, output_1.createAdvisoryValidationFinding)({
        id: "SCOPE_GUARD_MISSING_DECLARATION",
        code: "SCOPE_GUARD_MISSING_DECLARATION",
        advisoryReason: "weak-evidence",
        summary: "Declared target-path evidence is missing or unusable.",
        message: `Requested path '${requestedPath}' cannot be matched because declared target-path evidence is missing or unusable.`,
        detail: evidence.map((entry) => entry.message).join(" "),
        affectedPaths: [createAffectedPath("command-evidence", requestedPath, "Requested implementation path without usable declared target evidence.")],
        artifacts: artifactPaths.map((artifactPath) => createArtifactReference(artifactPath)),
        recovery: recovery.recovery,
        evidence: {
            category: "scope-guard",
            details: {
                category: "missing-declaration",
                nextAction: recovery.nextAction,
                blocking: false,
                evidenceStates: evidence.map((entry) => entry.state),
                readOnly: true
            }
        }
    });
    return {
        category: "missing-declaration",
        requestedPath,
        recovery,
        finding,
        blocking: false,
        readOnly: true
    };
}
function createAmbiguousDeclarationResult(requestedPath, evidence) {
    const recovery = exports.SCOPE_GUARD_RECOVERY_GUIDANCE["ambiguous-declaration"];
    const artifactPaths = unique(evidence.map((entry) => entry.sourceArtifactPath));
    const finding = (0, output_1.createBlockingValidationFinding)({
        id: "SCOPE_GUARD_AMBIGUOUS_DECLARATION",
        code: "SCOPE_GUARD_AMBIGUOUS_DECLARATION",
        blockingReason: "unsafe-scope-mismatch",
        summary: "Declared target-path evidence is ambiguous.",
        message: `Requested path '${requestedPath}' cannot be safely matched because declared target-path evidence is ambiguous.`,
        detail: evidence.map((entry) => entry.message).join(" "),
        affectedPaths: [
            createAffectedPath("command-evidence", requestedPath, "Requested implementation path blocked by ambiguous declared target evidence."),
            ...evidence
                .filter((entry) => entry.path !== undefined)
                .map((entry) => createAffectedPath("declared-target", entry.path, "Ambiguous declared target path.", entry.sourceArtifactPath))
        ],
        artifacts: artifactPaths.map((artifactPath) => createArtifactReference(artifactPath)),
        recovery: recovery.recovery,
        evidence: {
            category: "scope-guard",
            details: {
                category: "ambiguous-declaration",
                nextAction: recovery.nextAction,
                blocking: true,
                readOnly: true
            }
        }
    });
    return {
        category: "ambiguous-declaration",
        requestedPath,
        recovery,
        finding,
        blocking: true,
        readOnly: true
    };
}
function createInvalidInputResult(requestedEvidence) {
    const recovery = exports.SCOPE_GUARD_RECOVERY_GUIDANCE["invalid-input"];
    const finding = (0, output_1.createBlockingValidationFinding)({
        id: "SCOPE_GUARD_INVALID_REQUEST",
        code: "SCOPE_GUARD_INVALID_REQUEST",
        blockingReason: "invalid-command-input",
        summary: "Requested implementation path input is invalid.",
        message: requestedEvidence.message,
        affectedPaths: [createAffectedPath("command-evidence", requestedEvidence.rawInput, "Invalid requested implementation path input.")],
        recovery: recovery.recovery,
        evidence: {
            category: "scope-guard",
            details: {
                category: "invalid-input",
                nextAction: recovery.nextAction,
                blocking: true,
                rejectionCode: requestedEvidence.rejectionCode,
                readOnly: true
            }
        }
    });
    return {
        category: "invalid-input",
        requestedPath: requestedEvidence.rawInput,
        recovery,
        finding,
        blocking: true,
        readOnly: true
    };
}
function createUnsafeMismatchResult(requestedPath, declaredPaths) {
    const recovery = exports.SCOPE_GUARD_RECOVERY_GUIDANCE["unsafe-mismatch"];
    const finding = (0, output_1.createBlockingValidationFinding)({
        id: "SCOPE_GUARD_UNSAFE_MISMATCH",
        code: "SCOPE_GUARD_UNSAFE_MISMATCH",
        blockingReason: "unsafe-scope-mismatch",
        summary: `Requested path '${requestedPath}' is an unsafe mismatch for declared scope.`,
        message: `Requested path '${requestedPath}' is outside declared scope and this guard invocation treats scope mismatches as blocking.`,
        detail: `Declared targets: ${declaredPaths.join(", ") || "(none)"}.`,
        affectedPaths: [createAffectedPath("command-evidence", requestedPath, "Requested implementation path blocked as unsafe scope mismatch.")],
        recovery: recovery.recovery,
        evidence: {
            category: "scope-guard",
            details: {
                category: "unsafe-mismatch",
                nextAction: recovery.nextAction,
                blocking: true,
                declaredPaths,
                readOnly: true
            }
        }
    });
    return {
        category: "unsafe-mismatch",
        requestedPath,
        recovery,
        finding,
        blocking: true,
        readOnly: true
    };
}
function createAffectedPath(role, path, description, artifactPath) {
    return {
        role,
        path,
        description,
        artifact: artifactPath === undefined ? undefined : createArtifactReference(artifactPath)
    };
}
function createArtifactReference(path) {
    return {
        family: path.endsWith("task-definition.md") ? "task_definition" : "other",
        path
    };
}
function unique(values) {
    return [...new Set(values)];
}
