/**
 * RouteDecision 合同验证器 — 验证 route_decision 与 workflow_trace 的一致性。
 *
 * 被 sf_verify、scenario runner、negative tests 共用。
 */
export function verifyRouteDecisionContract(input) {
    const findings = [];
    const rd = input.route_decision;
    const wt = input.workflow_trace;
    // 1. route_decision 必须存在
    if (!rd) {
        findings.push({ severity: "hard_fail", rule: "rd-missing", message: "route_decision 不存在，验证无法继续" });
        return findings;
    }
    // 2. route_decision 存在时 workflow_trace 也必须存在
    if (!wt) {
        findings.push({ severity: "hard_fail", rule: "wt-missing", message: "workflow_trace 不存在，无法验证路由一致性" });
    }
    // 3. workflow_trace.route 必须与 route_decision.route 一致
    if (wt && wt.route !== rd.route) {
        findings.push({
            severity: "hard_fail",
            rule: "wt-route-mismatch",
            message: `workflow_trace.route="${wt.route}" !== route_decision.route="${rd.route}"`,
        });
    }
    // 4. workflow_trace.execution_shape 必须与 route_decision.execution_shape 一致
    if (wt && wt.execution_shape !== rd.execution_shape) {
        findings.push({
            severity: "hard_fail",
            rule: "wt-shape-mismatch",
            message: `workflow_trace.execution_shape="${wt.execution_shape}" !== route_decision.execution_shape="${rd.execution_shape}"`,
        });
    }
    // 5. missing_required_inputs 非空时必须阻止正常验证
    if (rd.missing_required_inputs && rd.missing_required_inputs.length > 0) {
        findings.push({
            severity: "blocked",
            rule: "rd-missing-inputs",
            message: `missing_required_inputs 非空: ${rd.missing_required_inputs.join(", ")}`,
        });
    }
    // 6. input_materials 保留检查
    if (rd.input_materials && rd.input_materials.length > 0 && input.expansion_input_materials) {
        new Set(rd.input_materials.map(m => m.kind));
        const expRefs = input.expansion_input_materials.map(m => m.path_or_ref ?? "").filter(r => r.length > 0);
        // 至少一个 expansion input_material 应对应一个 rd input_material
        const rdPaths = rd.input_materials.filter(m => m.path).map(m => m.path);
        if (rdPaths.length > 0 && expRefs.length > 0) {
            const anyPreserved = rdPaths.some(p => expRefs.some(e => e.includes(p)));
            if (!anyPreserved) {
                findings.push({
                    severity: "degraded",
                    rule: "rd-inputs-lost",
                    message: `route_decision input_materials 路径 [${rdPaths.join(",")}] 未在 expansion input_materials 中保留`,
                });
            }
        }
    }
    // 7. mutation_allowed / scope 一致性
    if (rd.scope && rd.scope.read_only !== undefined && rd.scope.read_only !== !rd.mutation_allowed) {
        findings.push({
            severity: "hard_fail",
            rule: "rd-scope-mutation-mismatch",
            message: `scope.read_only=${rd.scope.read_only} 与 mutation_allowed=${rd.mutation_allowed} 不一致`,
        });
    }
    // 8. mutation_allowed 升级检测（source_extraction 必须为 false）
    if (rd.route === "source_extraction" && rd.mutation_allowed === true) {
        findings.push({
            severity: "hard_fail",
            rule: "rd-mutation-upgraded",
            message: "source_extraction 路由必须设置 mutation_allowed=false，当前为 true（检测到升级）",
        });
    }
    // 9. output_artifact 一致性检查
    const rdArtifact = rd.output_artifact;
    const expArtifact = input.expansion_output_artifact;
    if (rdArtifact) {
        if (!expArtifact) {
            findings.push({
                severity: "hard_fail",
                rule: "rd-output-artifact-missing",
                message: `route_decision.output_artifact 存在 (kind=${rdArtifact.kind ?? "?"}) 但 expansion output artifact 缺失`,
            });
        }
        else {
            if (rdArtifact.kind && expArtifact.kind && rdArtifact.kind !== expArtifact.kind) {
                findings.push({
                    severity: "hard_fail",
                    rule: "rd-output-artifact-kind-mismatch",
                    message: `route_decision.output_artifact.kind="${rdArtifact.kind}" !== expansion output kind="${expArtifact.kind}"`,
                });
            }
            if (rdArtifact.path && expArtifact.path && rdArtifact.path !== expArtifact.path) {
                findings.push({
                    severity: "hard_fail",
                    rule: "rd-output-artifact-path-mismatch",
                    message: `route_decision.output_artifact.path="${rdArtifact.path}" !== expansion output path="${expArtifact.path}"`,
                });
            }
        }
    }
    // 10. constraints 保留检查
    // 10a. 如果显式提供了 expansion_constraints，与 rd.constraints 对比
    if (rd.constraints && rd.constraints.length > 0 && Array.isArray(input.expansion_constraints)) {
        const expConstraints = input.expansion_constraints;
        if (expConstraints.length === 0) {
            findings.push({
                severity: "hard_fail",
                rule: "rd-constraints-lost",
                message: `route_decision.constraints [${rd.constraints.join(",")}] 未在 expansion 中保留（为空）`,
            });
        }
        else {
            if (rd.route === "source_extraction" && rd.constraints.includes("no_mutation") && !expConstraints.includes("no_mutation")) {
                findings.push({
                    severity: "hard_fail",
                    rule: "rd-constraint-no-mutation-lost",
                    message: "source_extraction 的 no_mutation 约束在 expansion 中丢失",
                });
            }
        }
    }
    // 10b. 自洽性: source_extraction 且 mutation_allowed=false 时必须有 no_mutation 约束
    if (rd.route === "source_extraction" && !rd.mutation_allowed && rd.constraints && !rd.constraints.includes("no_mutation")) {
        findings.push({
            severity: "hard_fail",
            rule: "rd-constraint-no-mutation-missing",
            message: "source_extraction 且 mutation_allowed=false 时必须有 no_mutation 约束",
        });
    }
    // 10c. 如果 rd 有 constraints 但被完全移除（constraints 字段为空或缺失）
    if (rd.route === "source_extraction" && !rd.mutation_allowed && (!rd.constraints || rd.constraints.length === 0)) {
        findings.push({
            severity: "hard_fail",
            rule: "rd-constraints-empty",
            message: "source_extraction 且 mutation_allowed=false 时 constraints 为空",
        });
    }
    // 11. input_materials 存在但 expansion_input_materials 缺失/为空 → blocked
    if (rd.input_materials && rd.input_materials.length > 0) {
        const expInputs = input.expansion_input_materials;
        if (!expInputs || expInputs.length === 0) {
            findings.push({
                severity: "blocked",
                rule: "rd-inputs-no-expansion",
                message: `route_decision 有 ${rd.input_materials.length} 个 input_materials 但 expansion_input_materials 为空或缺失`,
            });
        }
    }
    return findings;
}
//# sourceMappingURL=route_decision_contract_verifier.js.map