/**
 * 证据驱动与反幻觉契约 (Evidence-Grounded / Anti-Hallucination Contract)
 *
 * 问题六十：约束任务理解、知识注入、方案生成、代码实现、验证交付必须基于证据。
 * AI 不得无证据声称项目事实、把推测当事实、把验证计划当结果。
 */
import crypto from "node:crypto";
// ── 声明类别→允许证据源映射 ──
/**
 * 声明类别对应的允许证据源类型（source_type 级别）。
 * task_context/classification 只能支撑分类/路由/意图识别，不能支撑项目事实。
 * 未列入的类别无源类型限制。
 */
export const CATEGORY_REQUIRED_SOURCES = {
    project_fact: ["project_file", "knowledge_asset", "command_output", "user_confirmation"],
    tech_stack: ["project_file", "knowledge_asset", "command_output", "user_confirmation"],
    architecture: ["project_file", "knowledge_asset", "command_output", "user_confirmation"],
    validation_result: ["validation_result", "command_output"],
    release_status: ["validation_result", "command_output", "project_file", "knowledge_asset"],
};
/**
 * 声明类别对应的允许证据角色（evidence_role 级别）。
 * template_guidance（默认模板/规则/流程）不得支撑 project_fact/architecture/tech_stack 等事实声明。
 * 只有真实项目证据（project_source_file/existing_system_analysis/user_confirmation/command_result）才能支撑。
 */
export const CATEGORY_REQUIRED_ROLES = {
    project_fact: ["project_source_file", "existing_system_analysis", "user_confirmation", "command_result"],
    tech_stack: ["project_source_file", "existing_system_analysis", "user_confirmation", "command_result"],
    architecture: ["project_source_file", "existing_system_analysis", "user_confirmation", "command_result"],
    validation_result: ["validation_result", "command_result"],
    release_status: ["validation_result", "command_result", "project_source_file", "existing_system_analysis"],
};
// ── 证据源注册表 ──
export class EvidenceSourceRegistry {
    sources = new Map();
    register(item) {
        const id = `ev-${crypto.randomUUID().slice(0, 8)}`;
        const entry = {
            ...item,
            id,
            timestamp: new Date().toISOString(),
        };
        this.sources.set(id, entry);
        return entry;
    }
    get(id) {
        return this.sources.get(id);
    }
    query(filter) {
        return [...this.sources.values()].filter((e) => {
            if (filter.source_type && e.source_type !== filter.source_type)
                return false;
            if (filter.authority && e.authority !== filter.authority)
                return false;
            if (filter.freshness && e.freshness !== filter.freshness)
                return false;
            if (filter.permission && e.permission !== filter.permission)
                return false;
            if (filter.evidence_role && e.evidence_role !== filter.evidence_role)
                return false;
            return true;
        });
    }
    clear() {
        this.sources.clear();
    }
    size() {
        return this.sources.size;
    }
}
// ── 检索契约 ──
export class RetrievalContract {
    registry;
    constructor(registry) {
        this.registry = registry;
    }
    retrieve(plan) {
        let results = [...this.registry.query({})];
        if (plan.source_types.length > 0) {
            results = results.filter((e) => plan.source_types.includes(e.source_type));
        }
        if (plan.keywords.length > 0) {
            const kw = plan.keywords.map((k) => k.toLowerCase());
            results = results.filter((e) => kw.some((k) => e.description.toLowerCase().includes(k) || (e.source_ref ?? "").toLowerCase().includes(k)));
        }
        // 过滤禁止源
        results = results.filter((e) => e.permission !== "forbidden");
        // 按 authority 排序
        const authorityOrder = {
            authoritative: 0, trusted: 1, supporting: 2, weak: 3, forbidden: 99,
        };
        results.sort((a, b) => authorityOrder[a.authority] - authorityOrder[b.authority]);
        return results.slice(0, plan.max_results);
    }
}
// ── 证据冲突检测器 ──
export class EvidenceConflictDetector {
    detect(evidence, claims) {
        const conflicts = [];
        for (const claim of claims) {
            const claimEvidence = evidence.filter((e) => claim.evidence_ids.includes(e.id));
            // deprecated 证据仍在使用（不要求 >= 2 条证据）
            const deprecatedEv = claimEvidence.filter((e) => e.freshness === "deprecated");
            if (deprecatedEv.length > 0) {
                conflicts.push({
                    claim_id: claim.id,
                    conflicting_evidence_ids: deprecatedEv.map((e) => e.id),
                    description: `声明「${claim.claim_text}」引用了过期证据`,
                    resolution_status: "unresolved",
                    recommended_action: "替换为当前证据或标注不确定性",
                });
            }
            if (claimEvidence.length < 2)
                continue;
            // 检测冲突：同一 claim 有相互矛盾的证据（不同 authority 下的不同描述）
            const descriptions = new Map();
            for (const ev of claimEvidence) {
                const key = `${ev.source_type}:${ev.source_ref ?? "unknown"}`;
                if (!descriptions.has(key))
                    descriptions.set(key, []);
                descriptions.get(key).push(ev);
            }
            // 同一 claim 来自不同 source_type 的 authoritative 证据存在矛盾
            const authSources = claimEvidence.filter((e) => e.authority === "authoritative");
            if (authSources.length >= 2) {
                const refs = new Set(authSources.map((e) => e.source_ref ?? ""));
                if (refs.size >= 2) {
                    conflicts.push({
                        claim_id: claim.id,
                        conflicting_evidence_ids: authSources.map((e) => e.id),
                        description: `声明「${claim.claim_text}」有多个权威证据来源互相矛盾`,
                        resolution_status: "unresolved",
                        recommended_action: "需要用户确认选择哪个证据源",
                    });
                }
            }
        }
        return conflicts;
    }
}
// ── 幻觉风险分类器 ──
export class HallucinationRiskClassifier {
    classify(claim, evidence, taskRisk) {
        const claimEvidence = evidence.filter((e) => claim.evidence_ids.includes(e.id));
        // 无任何证据
        if (claimEvidence.length === 0) {
            return taskRisk === "low" ? "medium" : "critical";
        }
        // 只有 generated_inference 且非低风险
        const onlyInference = claimEvidence.every((e) => e.source_type === "generated_inference");
        if (onlyInference && taskRisk !== "low") {
            return "high";
        }
        // 有 forbidden 证据
        if (claimEvidence.some((e) => e.permission === "forbidden")) {
            return "critical";
        }
        // 有 stale/unknown 且高风险
        const hasWeak = claimEvidence.some((e) => e.freshness === "stale" || e.freshness === "unknown");
        if (hasWeak && (taskRisk === "high" || taskRisk === "critical")) {
            return "high";
        }
        // 有 deprecated
        if (claimEvidence.some((e) => e.freshness === "deprecated")) {
            return "high";
        }
        // 有权威证据且 current
        const hasAuthoritative = claimEvidence.some((e) => e.authority === "authoritative" && e.freshness === "current");
        if (hasAuthoritative)
            return "low";
        return "medium";
    }
}
// ── 事实声明校验器 ──
export class FactClaimVerifier {
    registry;
    classifier;
    constructor(registry, classifier) {
        this.registry = registry;
        this.classifier = classifier;
    }
    verify(claims, taskRisk) {
        const evidence = [...this.registry.query({})];
        const verified = [];
        const unsupported = [];
        const risk_summary = { low: 0, medium: 0, high: 0, critical: 0 };
        for (const claim of claims) {
            const risk = this.classifier.classify(claim, evidence, taskRisk);
            risk_summary[risk]++;
            // 检测 generated_inference 单独支撑项目事实
            const claimEvidence = evidence.filter((e) => claim.evidence_ids.includes(e.id));
            const onlyInference = claimEvidence.length > 0 && claimEvidence.every((e) => e.source_type === "generated_inference");
            const isFactClaim = ["project_fact", "tech_stack", "file_change", "test_execution", "release_status", "validation_result"].includes(claim.category);
            if (onlyInference && isFactClaim) {
                claim.is_uncertain = true;
                unsupported.push(claim);
                continue;
            }
            // 检测证据源类型与声明类别的适配性
            const allowedSources = claim.required_source_types ?? CATEGORY_REQUIRED_SOURCES[claim.category];
            if (allowedSources) {
                const compatibleEvidence = claimEvidence.filter((e) => allowedSources.includes(e.source_type));
                if (compatibleEvidence.length === 0) {
                    claim.is_uncertain = true;
                    unsupported.push(claim);
                    continue;
                }
            }
            // 检测证据角色与声明类别的适配性（template_guidance 不得支撑事实声明）
            const requiredRoles = CATEGORY_REQUIRED_ROLES[claim.category];
            if (requiredRoles) {
                const roleCompatible = claimEvidence.filter((e) => e.evidence_role && requiredRoles.includes(e.evidence_role));
                if (roleCompatible.length === 0) {
                    claim.is_uncertain = true;
                    unsupported.push(claim);
                    continue;
                }
            }
            // 检测 validation_plan 冒充 validation_result
            if (claim.category === "validation_result") {
                const hasRealResult = claimEvidence.some((e) => e.source_type === "validation_result" || e.source_type === "command_output");
                if (!hasRealResult) {
                    claim.is_uncertain = true;
                    unsupported.push(claim);
                    continue;
                }
            }
            // 检测 fake validation / tests-only / gate-only / scenario-only 自证
            if (this.isSelfAttestation(claim, claimEvidence)) {
                claim.is_uncertain = true;
                unsupported.push(claim);
                continue;
            }
            if (risk === "critical" || (risk === "high" && (taskRisk === "high" || taskRisk === "critical"))) {
                claim.is_uncertain = true;
                unsupported.push(claim);
            }
            else {
                verified.push(claim);
            }
        }
        return { verified, unsupported, risk_summary };
    }
    /** 检测自证模式：只用 tests/scenario/gate 调用证明主链路消费 */
    isSelfAttestation(_claim, evidence) {
        const selfAttestPatterns = [
            /only.*test/i, /tests[-_]only/i,
            /only.*scenario/i, /scenario[-_]only/i,
            /only.*gate/i, /gate[-_]only/i,
            /fake.*validation/i, /fake.*metric/i,
        ];
        for (const ev of evidence) {
            for (const pattern of selfAttestPatterns) {
                if (pattern.test(ev.description) || pattern.test(ev.source_ref ?? "")) {
                    return true;
                }
            }
        }
        // 所有证据都是测试文件
        if (evidence.length > 0 && evidence.every((e) => (e.source_ref ?? "").includes("test") || (e.source_ref ?? "").includes(".test."))) {
            return true;
        }
        return false;
    }
}
// ── 无证据声明门禁 ──
export class UnsupportedClaimGate {
    constructor(_conflictDetector) { }
    evaluate(matrix, taskRisk) {
        const unsupported_claims = [];
        const unresolved_conflicts = [];
        const missing_evidence = [];
        const requires_user_confirmation = [];
        // 1. 无证据声明
        for (const claim of matrix.unsupported_claims) {
            unsupported_claims.push(claim);
        }
        // 2. 未裁决冲突
        for (const conflict of matrix.conflicts) {
            if (conflict.resolution_status === "unresolved" || conflict.resolution_status === "blocked") {
                unresolved_conflicts.push(conflict.claim_id);
            }
        }
        // 3. 检查高风险 claim 证据缺失
        for (const claim of matrix.claims) {
            if (claim.evidence_ids.length === 0 && claim.risk_level !== "low") {
                missing_evidence.push(claim.id);
            }
        }
        // 计算综合风险
        const riskSummary = matrix.risk_summary;
        const overallRisk = (riskSummary.critical ?? 0) > 0 ? "critical"
            : (riskSummary.high ?? 0) > 0 ? "high"
                : (riskSummary.medium ?? 0) > 0 ? "medium"
                    : "low";
        // 判断是否允许通过
        let allowed = true;
        let reason_zh = "证据驱动门禁通过";
        // 高风险任务不允许无证据声明或未裁决冲突
        if (taskRisk === "high" || taskRisk === "critical") {
            if (unsupported_claims.length > 0) {
                allowed = false;
                reason_zh = `高风险任务存在 ${unsupported_claims.length} 条无证据声明，不得继续`;
            }
            if (unresolved_conflicts.length > 0) {
                allowed = false;
                reason_zh += `；存在 ${unresolved_conflicts.length} 条未裁决证据冲突`;
            }
            if (missing_evidence.length > 0) {
                allowed = false;
                reason_zh += `；${missing_evidence.length} 条高风险声明缺少证据`;
            }
        }
        // 任何风险等级都不允许 forbidden 证据
        const forbiddenEvidence = matrix.evidence.filter((e) => e.permission === "forbidden");
        if (forbiddenEvidence.length > 0) {
            allowed = false;
            reason_zh += `；发现 ${forbiddenEvidence.length} 条禁止源证据`;
        }
        // 不确定项需要用户确认
        const uncertainClaims = matrix.claims.filter((c) => c.is_uncertain);
        if (uncertainClaims.length > 0) {
            for (const c of uncertainClaims) {
                requires_user_confirmation.push(`声明「${c.claim_text}」证据不足，需要确认`);
            }
        }
        return {
            allowed,
            reason_zh,
            diagnostic_code: allowed ? "SF-EVIDENCE-6000" : "SF-EVIDENCE-6001",
            unsupported_claims,
            unresolved_conflicts,
            missing_evidence,
            risk_level: overallRisk,
            requires_user_confirmation,
        };
    }
}
// ── 接地上下文构建器 ──
export class GroundedContextBuilder {
    retrieval;
    constructor(_registry, retrieval) {
        this.retrieval = retrieval;
    }
    buildContext(claims, plan) {
        const evidence = this.retrieval.retrieve(plan);
        const conflictDetector = new EvidenceConflictDetector();
        const conflicts = conflictDetector.detect(evidence, claims);
        const unsupported_claims = [];
        for (const claim of claims) {
            if (claim.evidence_ids.length === 0 || claim.is_uncertain) {
                unsupported_claims.push(claim.id);
            }
        }
        const risk_summary = { low: 0, medium: 0, high: 0, critical: 0 };
        for (const claim of claims) {
            risk_summary[claim.risk_level]++;
        }
        return {
            task_id: "",
            claims,
            evidence,
            conflicts,
            unsupported_claims,
            risk_summary,
            created_at: new Date().toISOString(),
        };
    }
}
// ── 便捷工厂 ──
export function createEvidenceGroundingSystem() {
    const registry = new EvidenceSourceRegistry();
    const retrieval = new RetrievalContract(registry);
    const classifier = new HallucinationRiskClassifier();
    const conflictDetector = new EvidenceConflictDetector();
    const verifier = new FactClaimVerifier(registry, classifier);
    const gate = new UnsupportedClaimGate(conflictDetector);
    const builder = new GroundedContextBuilder(registry, retrieval);
    return { registry, retrieval, classifier, conflictDetector, verifier, gate, builder };
}
// ── 高风险任务类型判定 ──
const HIGH_RISK_CATEGORIES = [
    "release_status", "architecture", "security", "performance",
];
export function isHighRiskClaimCategory(category) {
    return HIGH_RISK_CATEGORIES.includes(category);
}
/** 判断任务风险等级 */
export function assessTaskRisk(taskType, routeDecision, intentKeywords) {
    if (!taskType && !routeDecision && !intentKeywords)
        return "medium";
    const highRiskKeywords = /发布|release|架构|architecture|安全|security|迁移|migration/i;
    const criticalKeywords = /发布门禁|validate.release|production|生产/i;
    if (intentKeywords && criticalKeywords.test(intentKeywords))
        return "critical";
    if (intentKeywords && highRiskKeywords.test(intentKeywords))
        return "high";
    if (routeDecision === "code_change" || routeDecision === "artifact_generation")
        return "high";
    if (taskType === "feature" || taskType === "bugfix")
        return "medium";
    return "low";
}
//# sourceMappingURL=evidence_grounding_contract.js.map