/**
 * Configuration Precedence Contract — Governance & Reporting
 *
 * 治理校验、中文解释、冲突报告、CLI 写入守卫。
 */
import { PRECEDENCE_RULES, STALE_RULES } from "./constants.js";
import { debug } from "../../core/logger.js";
import { getPrecedenceRank, isCClassField, mapEvidenceSource, sourceLabel, lifetimeLabel, } from "./resolution.js";
import { hashValue } from "./evidence.js";
import { PRECEDENCE_ORDER } from "./constants.js";
// ── 查询函数 (委托 constants) ──
/** 列出所有配置优先级规则
 * @returns 优先级规则数组
 */
export function listPrecedenceRules() {
    return PRECEDENCE_RULES;
}
/** 列出所有配置过期检测规则
 * @returns 过期规则数组
 */
export function listStaleRules() {
    return STALE_RULES;
}
// ── CLI 参数写入守卫 ──
/** 判断来源是否可安全写入配置（非 CLI/MCP 临时参数）
 * @param source - 配置来源
 * @returns 是否可安全写入
 */
export function isCliWriteSafe(source) {
    return source !== "cli_flag" && source !== "mcp_param";
}
// ── 中文解释 ──
/** 生成配置字段解析结果的中文解释
 * @param report - 配置解析报告
 * @returns 格式化的中文解释文本
 */
export function explainField(report) {
    const lines = [];
    const sel = report.selected;
    lines.push(`字段: ${report.field_path}`);
    lines.push(`当前值: ${JSON.stringify(sel.value)}`);
    lines.push(`来源: ${sourceLabel(sel.source)} (优先级 ${getPrecedenceRank(sel.source) + 1}/${PRECEDENCE_ORDER.length})`);
    lines.push(`生命周期: ${lifetimeLabel(report.lifetime)}`);
    lines.push(`置信度: ${sel.confidence}`);
    if (sel.evidence_ref) {
        lines.push(`证据: ${sel.evidence_ref}`);
    }
    if (report.candidates.length > 1) {
        lines.push(`其他候选:`);
        for (let i = 1; i < report.candidates.length; i++) {
            const c = report.candidates[i];
            lines.push(`  - ${sourceLabel(c.source)}: ${JSON.stringify(c.value)} (未被采用: ${notSelectedReason(report, c)})`);
        }
    }
    if (report.overridden_by_guard) {
        lines.push(`⚠️ 被上位约束 ${report.overridden_by_guard} 阻止`);
    }
    if (report.conflicts.length > 0) {
        lines.push(`冲突:`);
        for (const c of report.conflicts) {
            lines.push(`  - ${sourceLabel(c.source_a)} vs ${sourceLabel(c.source_b)}: ${c.reason}`);
            if (c.requires_human) {
                lines.push(`    需要人工确认`);
            }
        }
    }
    return lines.join("\n");
}
function notSelectedReason(report, candidate) {
    const selectedRank = getPrecedenceRank(report.selected.source);
    const candidateRank = getPrecedenceRank(candidate.source);
    if (candidateRank > selectedRank) {
        return `优先级低于 ${sourceLabel(report.selected.source)}`;
    }
    return "值相同，无冲突";
}
// ── 治理校验 ──
/** 执行配置优先级治理校验
 * @param reports - 配置解析报告列表
 * @param entries - 配置证据条目列表
 * @returns 治理发现列表
 */
export function validateConfigPrecedence(reports, entries) {
    debug("配置优先级", "开始治理校验，共 %d 个报告", reports.length);
    const findings = [];
    // 规则 1: CLI flag 不静默写入 config
    for (const e of entries) {
        if (e.source === "cli_flag" || e.source === "mcp_param") {
            if (e.lifetime === "project_persistent") {
                findings.push({
                    severity: "hard_fail",
                    rule: "gc-cli-no-persist",
                    field_path: e.field_path,
                    message: `CLI/MCP 参数 (${e.source}) 不应持久化到 config — ${e.field_path}`,
                });
            }
        }
    }
    // 规则 2: fingerprint 不覆盖 confirmed_config
    for (const r of reports) {
        if (r.selected.source === "fingerprint") {
            const hasConfirmed = r.candidates.some((c) => c.source === "confirmed_config");
            if (hasConfirmed) {
                findings.push({
                    severity: "hard_fail",
                    rule: "gc-fingerprint-no-override",
                    field_path: r.field_path,
                    message: `fingerprint 不应覆盖 confirmed_config — ${r.field_path}`,
                });
            }
        }
    }
    // 规则 3: product_profile 不覆盖 config
    for (const r of reports) {
        if (r.selected.source === "product_profile") {
            const hasConfirmed = r.candidates.some((c) => c.source === "confirmed_config");
            if (hasConfirmed) {
                findings.push({
                    severity: "hard_fail",
                    rule: "gc-profile-no-override",
                    field_path: r.field_path,
                    message: `product_profile 不应覆盖 confirmed_config — ${r.field_path}`,
                });
            }
        }
    }
    // 规则 4: knowledge_default 不覆盖 config
    for (const r of reports) {
        if (r.selected.source === "knowledge_default") {
            const hasConfig = r.candidates.some((c) => c.source === "confirmed_config" || c.source === "project_policy");
            if (hasConfig) {
                findings.push({
                    severity: "hard_fail",
                    rule: "gc-knowledge-no-override",
                    field_path: r.field_path,
                    message: `knowledge_default 不应覆盖 config — ${r.field_path}`,
                });
            }
        }
    }
    // 规则 5: C 类字段不得自动写入 — only confirmed_config (from user_declared/confirmed) allowed
    for (const e of entries) {
        if (isCClassField(e.field_path)) {
            const canonical = mapEvidenceSource(e.source);
            if (canonical !== "confirmed_config") {
                findings.push({
                    severity: "hard_fail",
                    rule: "gc-c-class-no-auto",
                    field_path: e.field_path,
                    message: `C 类字段 ${e.field_path} 不得自动写入 (当前来源: ${e.source})`,
                });
            }
        }
    }
    // 规则 6: guard 不可被配置绕过 — check that guard-blocked fields stay blocked
    for (const r of reports) {
        if (r.overridden_by_guard) {
            findings.push({
                severity: "advisory",
                rule: "gc-guard-block",
                field_path: r.field_path,
                message: `字段 ${r.field_path} 被上位约束 ${r.overridden_by_guard} 保护`,
            });
        }
    }
    // 规则 7: conflict 必须被报告 (advisory)
    for (const r of reports) {
        if (r.conflicts.length > 0) {
            const configFpConflict = r.conflicts.find((c) => c.source_a === "confirmed_config" && c.source_b === "fingerprint");
            if (configFpConflict) {
                findings.push({
                    severity: "advisory",
                    rule: "gc-conflict-report",
                    field_path: r.field_path,
                    message: `字段 ${r.field_path} 存在 confirmed_config 与 fingerprint 冲突，已自动处理`,
                });
            }
        }
    }
    // 规则 9: value_hash 不匹配 — 证据条目的 hash 必须与解析值一致
    for (const r of reports) {
        const entry = entries.find((e) => e.field_path === r.field_path);
        if (entry) {
            const computed = hashValue(r.selected.value);
            if (entry.value_hash !== computed) {
                findings.push({
                    severity: "hard_fail",
                    rule: "gc-evidence-hash-mismatch",
                    field_path: r.field_path,
                    message: `字段 ${r.field_path} evidence value_hash 不匹配 (entry=${entry.value_hash}, computed=${computed}) — evidence 可能过期`,
                });
            }
        }
    }
    // 规则 10: blueprint 与 fingerprint/confirmed_config 不一致 (advisory)
    for (const r of reports) {
        const blueprintCandidate = r.candidates.find((c) => c.source === "blueprint");
        if (!blueprintCandidate)
            continue;
        const higherCandidate = r.candidates.find((c) => c.source === "fingerprint" || c.source === "confirmed_config");
        if (!higherCandidate)
            continue;
        if (JSON.stringify(blueprintCandidate.value) !== JSON.stringify(higherCandidate.value)) {
            findings.push({
                severity: "advisory",
                rule: "gc-blueprint-mismatch",
                field_path: r.field_path,
                message: `字段 ${r.field_path} blueprint (${JSON.stringify(blueprintCandidate.value)}) 与 ${higherCandidate.source} (${JSON.stringify(higherCandidate.value)}) 不一致 — blueprint 可能需要更新`,
            });
        }
    }
    // 规则 8: 每个 resolved 字段应有 evidence
    for (const r of reports) {
        const hasEntry = entries.some((e) => e.field_path === r.field_path);
        if (!hasEntry) {
            findings.push({
                severity: "advisory",
                rule: "gc-evidence-required",
                field_path: r.field_path,
                message: `字段 ${r.field_path} 已解析但缺少 ConfigEvidenceEntry`,
            });
        }
    }
    if (findings.length > 0) {
        const hardFails = findings.filter(f => f.severity === "hard_fail");
        if (hardFails.length > 0) {
            debug("配置优先级", "治理校验发现 %d 个 hard_fail", hardFails.length);
        }
    }
    return findings;
}
//# sourceMappingURL=governance.js.map