"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DIFF_SCOPE_RECOVERY_GUIDANCE = exports.DIFF_SCOPE_FINDING_IDS = void 0;
exports.classifyDiffScopeComparison = classifyDiffScopeComparison;
const output_1 = require("../output");
const scope_guard_1 = require("./scope-guard");
exports.DIFF_SCOPE_FINDING_IDS = [
    "DIFF_SCOPE_PLANNED_IN_SCOPE",
    "DIFF_SCOPE_PLANNED_OUT_OF_SCOPE",
    "DIFF_SCOPE_DISCOVERED_WORK",
    "DIFF_SCOPE_BACKLOG_CANDIDATE",
    "DIFF_SCOPE_INVALID_INPUT",
    "DIFF_SCOPE_MISSING_DECLARATION",
    "DIFF_SCOPE_AMBIGUOUS_DECLARATION",
    "DIFF_SCOPE_UNSAFE_MISMATCH"
];
exports.DIFF_SCOPE_RECOVERY_GUIDANCE = {
    "planned-in-scope": {
        nextAction: "none",
        recovery: "No recovery is required.",
        noWriteRequired: false
    },
    "planned-out-of-scope": {
        nextAction: "review-scope",
        recovery: "Review whether the task or milestone scope should include this planned work before relying on downstream automation.",
        noWriteRequired: false
    },
    "discovered-work": {
        nextAction: "capture-discovered-work",
        recovery: "Confirm whether this is discovered work, then record an explicit planning decision before treating it as implementation scope.",
        noWriteRequired: false
    },
    "backlog-candidate": {
        nextAction: "route-backlog",
        recovery: "Route this item through planning or backlog triage before treating it as current implementation scope.",
        noWriteRequired: false
    },
    "invalid-input": {
        nextAction: "correct-input",
        recovery: "Correct the changed-path input and rerun without guessing a normalized path.",
        noWriteRequired: true
    },
    "missing-or-weak-declaration": {
        nextAction: "revise-planning",
        recovery: "Add explicit repository-relative target paths to task or milestone scope evidence before relying on diff-check results.",
        noWriteRequired: false
    },
    "ambiguous-declaration": {
        nextAction: "stop-unsafe-automation",
        recovery: "Resolve duplicate or conflicting declared target-path evidence before rerunning diff-check automation.",
        noWriteRequired: true
    },
    "unsafe-mismatch": {
        nextAction: "stop-unsafe-automation",
        recovery: "Realign changed-path evidence with declared scope or create explicit follow-up planning before rerunning.",
        noWriteRequired: true
    }
};
function classifyDiffScopeComparison(comparison, options = {}) {
    const results = [];
    const duplicateDeclarationEvidence = comparison.declarationIssueEvidence
        .filter((entry) => entry.state === "duplicate");
    const missingOrWeakDeclarationEvidence = comparison.declarationIssueEvidence
        .filter((entry) => entry.state !== "duplicate");
    for (const match of comparison.matchedGroups) {
        results.push(createPlannedInScopeResult(match));
    }
    for (const invalidEvidence of comparison.invalidChangedPathEvidence) {
        results.push(createInvalidInputResult(invalidEvidence));
    }
    if (missingOrWeakDeclarationEvidence.length > 0) {
        results.push(createMissingOrWeakDeclarationResult(missingOrWeakDeclarationEvidence));
    }
    if (duplicateDeclarationEvidence.length > 0) {
        results.push(createAmbiguousDeclarationResult(duplicateDeclarationEvidence));
    }
    for (const unmatchedPath of comparison.unmatchedChangedPaths) {
        results.push(createUnmatchedPathResult(unmatchedPath, options));
    }
    return {
        results,
        findings: results.map((result) => result.finding),
        readOnly: true
    };
}
function createPlannedInScopeResult(match) {
    const recovery = exports.DIFF_SCOPE_RECOVERY_GUIDANCE["planned-in-scope"];
    const finding = (0, output_1.createValidationFinding)({
        id: "DIFF_SCOPE_PLANNED_IN_SCOPE",
        code: "DIFF_SCOPE_PLANNED_IN_SCOPE",
        level: "informational",
        severity: "informational",
        summary: `Changed paths match declared scope '${match.declaredPath}'.`,
        message: `Changed paths match declared scope '${match.declaredPath}'.`,
        affectedPaths: [
            createAffectedPath("declared-target", match.declaredPath, "Matching declared target path.", match.sourceArtifactPath),
            ...match.changedPaths.map((changedPath) => createAffectedPath("command-evidence", changedPath, "Changed path within declared scope."))
        ],
        artifacts: [createArtifactReference(match.sourceArtifactPath)],
        recovery: recovery.recovery,
        evidence: {
            category: "diff-check",
            details: {
                category: "planned-in-scope",
                nextAction: recovery.nextAction,
                blocking: false,
                noWriteRequired: recovery.noWriteRequired,
                changedPaths: match.changedPaths,
                declaredPath: match.declaredPath,
                readOnly: true
            }
        }
    });
    return {
        category: "planned-in-scope",
        declaredPath: match.declaredPath,
        recovery,
        finding,
        blocking: false,
        readOnly: true
    };
}
function createUnmatchedPathResult(unmatchedPath, options) {
    if (options.treatAllOutOfScopeAsUnsafe === true
        || matchesAnyScope(unmatchedPath.changedPath, options.unsafeMismatchPaths ?? [])) {
        return createUnsafeMismatchResult(unmatchedPath);
    }
    if (matchesAnyScope(unmatchedPath.changedPath, options.plannedOutOfScopePaths ?? [])) {
        return createPlannedOutOfScopeResult(unmatchedPath);
    }
    if (matchesAnyScope(unmatchedPath.changedPath, options.backlogCandidatePaths ?? [])) {
        return createBacklogCandidateResult(unmatchedPath);
    }
    return createDiscoveredWorkResult(unmatchedPath);
}
function createPlannedOutOfScopeResult(unmatchedPath) {
    const recovery = exports.DIFF_SCOPE_RECOVERY_GUIDANCE["planned-out-of-scope"];
    const finding = (0, output_1.createAdvisoryValidationFinding)({
        id: "DIFF_SCOPE_PLANNED_OUT_OF_SCOPE",
        code: "DIFF_SCOPE_PLANNED_OUT_OF_SCOPE",
        advisoryReason: "impact-question",
        summary: `Changed path '${unmatchedPath.changedPath}' is planned work outside current declared scope.`,
        message: `Changed path '${unmatchedPath.changedPath}' is planned work outside current declared scope.`,
        detail: `Compared declared targets: ${formatDeclaredPaths(unmatchedPath.comparedDeclaredPaths)}.`,
        affectedPaths: [createAffectedPath("command-evidence", unmatchedPath.changedPath, "Changed path outside current declared scope with explicit planned-work evidence.")],
        recovery: recovery.recovery,
        evidence: {
            category: "diff-check",
            details: {
                category: "planned-out-of-scope",
                nextAction: recovery.nextAction,
                blocking: false,
                comparedDeclaredPaths: unmatchedPath.comparedDeclaredPaths,
                readOnly: true
            }
        }
    });
    return {
        category: "planned-out-of-scope",
        changedPath: unmatchedPath.changedPath,
        recovery,
        finding,
        blocking: false,
        readOnly: true
    };
}
function createDiscoveredWorkResult(unmatchedPath) {
    const recovery = exports.DIFF_SCOPE_RECOVERY_GUIDANCE["discovered-work"];
    const finding = (0, output_1.createAdvisoryValidationFinding)({
        id: "DIFF_SCOPE_DISCOVERED_WORK",
        code: "DIFF_SCOPE_DISCOVERED_WORK",
        advisoryReason: "possible-discovered-work",
        summary: `Changed path '${unmatchedPath.changedPath}' is outside declared scope.`,
        message: `Changed path '${unmatchedPath.changedPath}' is outside declared scope and is preserved as possible discovered-work evidence.`,
        detail: `Compared declared targets: ${formatDeclaredPaths(unmatchedPath.comparedDeclaredPaths)}.`,
        affectedPaths: [createAffectedPath("command-evidence", unmatchedPath.changedPath, "Changed path outside declared scope.")],
        recovery: recovery.recovery,
        evidence: {
            category: "diff-check",
            details: {
                category: "discovered-work",
                nextAction: recovery.nextAction,
                blocking: false,
                comparedDeclaredPaths: unmatchedPath.comparedDeclaredPaths,
                readOnly: true
            }
        }
    });
    return {
        category: "discovered-work",
        changedPath: unmatchedPath.changedPath,
        recovery,
        finding,
        blocking: false,
        readOnly: true
    };
}
function createBacklogCandidateResult(unmatchedPath) {
    const recovery = exports.DIFF_SCOPE_RECOVERY_GUIDANCE["backlog-candidate"];
    const finding = (0, output_1.createAdvisoryValidationFinding)({
        id: "DIFF_SCOPE_BACKLOG_CANDIDATE",
        code: "DIFF_SCOPE_BACKLOG_CANDIDATE",
        advisoryReason: "backlog-candidate",
        summary: `Changed path '${unmatchedPath.changedPath}' is a backlog candidate outside declared scope.`,
        message: `Changed path '${unmatchedPath.changedPath}' is a backlog candidate outside declared scope.`,
        detail: `Compared declared targets: ${formatDeclaredPaths(unmatchedPath.comparedDeclaredPaths)}.`,
        affectedPaths: [createAffectedPath("command-evidence", unmatchedPath.changedPath, "Changed path outside declared scope with explicit backlog-candidate evidence.")],
        recovery: recovery.recovery,
        evidence: {
            category: "diff-check",
            details: {
                category: "backlog-candidate",
                nextAction: recovery.nextAction,
                blocking: false,
                comparedDeclaredPaths: unmatchedPath.comparedDeclaredPaths,
                readOnly: true
            }
        }
    });
    return {
        category: "backlog-candidate",
        changedPath: unmatchedPath.changedPath,
        recovery,
        finding,
        blocking: false,
        readOnly: true
    };
}
function createInvalidInputResult(evidence) {
    const recovery = exports.DIFF_SCOPE_RECOVERY_GUIDANCE["invalid-input"];
    const finding = (0, output_1.createBlockingValidationFinding)({
        id: "DIFF_SCOPE_INVALID_INPUT",
        code: "DIFF_SCOPE_INVALID_INPUT",
        blockingReason: "invalid-command-input",
        summary: "Changed-path input is invalid.",
        message: evidence.message,
        affectedPaths: [createAffectedPath("command-evidence", evidence.rawInput, "Invalid changed-path input.")],
        recovery: recovery.recovery,
        evidence: {
            category: "diff-check",
            details: {
                category: "invalid-input",
                nextAction: recovery.nextAction,
                blocking: true,
                rejectionCode: evidence.rejectionCode,
                readOnly: true
            }
        }
    });
    return {
        category: "invalid-input",
        changedPath: evidence.rawInput,
        recovery,
        finding,
        blocking: true,
        readOnly: true
    };
}
function createMissingOrWeakDeclarationResult(evidence) {
    const recovery = exports.DIFF_SCOPE_RECOVERY_GUIDANCE["missing-or-weak-declaration"];
    const artifactPaths = unique(evidence.map((entry) => entry.sourceArtifactPath));
    const finding = (0, output_1.createAdvisoryValidationFinding)({
        id: "DIFF_SCOPE_MISSING_DECLARATION",
        code: "DIFF_SCOPE_MISSING_DECLARATION",
        advisoryReason: "weak-evidence",
        summary: "Declared scope evidence is missing or weak.",
        message: "Declared scope evidence is missing, unreadable, placeholder-like, or prose-only.",
        detail: evidence.map((entry) => entry.message).join(" "),
        artifacts: artifactPaths.map((artifactPath) => createArtifactReference(artifactPath)),
        recovery: recovery.recovery,
        evidence: {
            category: "diff-check",
            details: {
                category: "missing-or-weak-declaration",
                nextAction: recovery.nextAction,
                blocking: false,
                evidenceStates: evidence.map((entry) => entry.state),
                readOnly: true
            }
        }
    });
    return {
        category: "missing-or-weak-declaration",
        recovery,
        finding,
        blocking: false,
        readOnly: true
    };
}
function createAmbiguousDeclarationResult(evidence) {
    const recovery = exports.DIFF_SCOPE_RECOVERY_GUIDANCE["ambiguous-declaration"];
    const artifactPaths = unique(evidence.map((entry) => entry.sourceArtifactPath));
    const finding = (0, output_1.createBlockingValidationFinding)({
        id: "DIFF_SCOPE_AMBIGUOUS_DECLARATION",
        code: "DIFF_SCOPE_AMBIGUOUS_DECLARATION",
        blockingReason: "unsafe-scope-mismatch",
        summary: "Declared scope evidence is ambiguous.",
        message: "Declared scope evidence is ambiguous and cannot be safely used for diff-check automation.",
        detail: evidence.map((entry) => entry.message).join(" "),
        affectedPaths: 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: "diff-check",
            details: {
                category: "ambiguous-declaration",
                nextAction: recovery.nextAction,
                blocking: true,
                readOnly: true
            }
        }
    });
    return {
        category: "ambiguous-declaration",
        recovery,
        finding,
        blocking: true,
        readOnly: true
    };
}
function createUnsafeMismatchResult(unmatchedPath) {
    const recovery = exports.DIFF_SCOPE_RECOVERY_GUIDANCE["unsafe-mismatch"];
    const finding = (0, output_1.createBlockingValidationFinding)({
        id: "DIFF_SCOPE_UNSAFE_MISMATCH",
        code: "DIFF_SCOPE_UNSAFE_MISMATCH",
        blockingReason: "unsafe-scope-mismatch",
        summary: `Changed path '${unmatchedPath.changedPath}' is an unsafe mismatch for declared scope.`,
        message: `Changed path '${unmatchedPath.changedPath}' is outside declared scope and this diff-check invocation treats the mismatch as blocking.`,
        detail: `Compared declared targets: ${formatDeclaredPaths(unmatchedPath.comparedDeclaredPaths)}.`,
        affectedPaths: [createAffectedPath("command-evidence", unmatchedPath.changedPath, "Changed path blocked as unsafe scope mismatch.")],
        recovery: recovery.recovery,
        evidence: {
            category: "diff-check",
            details: {
                category: "unsafe-mismatch",
                nextAction: recovery.nextAction,
                blocking: true,
                comparedDeclaredPaths: unmatchedPath.comparedDeclaredPaths,
                readOnly: true
            }
        }
    });
    return {
        category: "unsafe-mismatch",
        changedPath: unmatchedPath.changedPath,
        recovery,
        finding,
        blocking: true,
        readOnly: true
    };
}
function matchesAnyScope(path, scopes) {
    return scopes.some((scopePath) => (0, scope_guard_1.isRequestedPathWithinDeclaredTarget)(path, scopePath));
}
function formatDeclaredPaths(declaredPaths) {
    return declaredPaths.join(", ") || "(none)";
}
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)];
}
