/**
 * Knowledge Injection Boundary — 知识注入边界三道门
 *
 * 将"可索引""可注入""注入优先级"拆成三道门，
 * 为每次 expand 生成知识注入报告，说明哪些知识被注入、
 * 哪些只能 advisory、哪些被排除以及排除原因。
 */
import { debugLog } from "../core/logger.js";
import { getArtifactSchema, hasArtifactSchema, formatSchemaForPrompt } from "../contracts/artifact_schema_registry.js";
import { getProcessRules, formatProcessRulesForPrompt } from "../contracts/artifact_process_rules.js";
import { fileURLToPath } from "node:url";
import path from "node:path";
import { listBuiltinConsumableAssets, } from "../templates/consumable_asset_registry.js";
import { buildTemplateAssetContracts } from "../templates/template_asset_contract_registry.js";
// ── 辅助函数 ──
const INDEXABLE_STATUSES = new Set(["active", "pending_review"]);
const BLOCKED_CONSUMPTION_MODES = new Set(["manual_reference", "copy_only", "deprecated", "state_runtime"]);
const NON_INJECTABLE_VISIBILITIES = new Set(["index_only", "audit_only", "internal_only", "scaffold_only"]);
const PRIORITY_ORDER = [
    "route_required",
    "project_core_active",
    "project_normal_active",
    "product_constraints",
    "global_core_active",
    "global_normal_active",
    "advisory_pending",
];
const MODULE_PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
function isCoreEntry(entry) {
    return entry.file_path.includes("internal/patterns/");
}
function isProjectEntry(entry) {
    return !entry.file_path.includes("templates/internal/") &&
        !entry.file_path.includes("templates/procedures/") &&
        !entry.file_path.includes("templates/rules/") &&
        !entry.file_path.includes("templates/checklists/") &&
        !entry.file_path.includes("templates/artifacts/") &&
        !entry.file_path.includes("templates/domain/") &&
        !entry.file_path.includes("templates/profiles/") &&
        !entry.file_path.includes("templates/patterns/");
}
function entryToRef(entry, tier, consumptionMode, warning) {
    const ref = {
        id: entry.id,
        name: entry.name,
        priority_tier: tier,
        consumption_mode: consumptionMode,
        tier: isCoreEntry(entry) ? "core" : "normal",
    };
    if (warning) {
        ref.warning = warning;
        ref.warnings = [warning];
    }
    return ref;
}
function findAssetForEntry(entry, assets) {
    return assets.find((a) => {
        // 精确路径匹配
        if (a.path === entry.file_path)
            return true;
        // acceptance_templates 的模板名匹配（条目名称与资产文件名去除扩展后匹配）
        if (entry.type === "acceptance_template" && entry.name === a.path.split("/").pop()?.replace(".md", ""))
            return true;
        return false;
    });
}
function getConsumptionMode(entry, assets) {
    const asset = findAssetForEntry(entry, assets);
    return asset?.consumption_mode ?? "supporting";
}
/** 合同级别 runtime_visibility 查找（缓存整个合约列表避免重复构建） */
let _contractCache = null;
function resolveContractRoot(entry, explicitRoot) {
    if (explicitRoot)
        return explicitRoot;
    const normalized = entry.file_path.replace(/\\/g, "/");
    const templateIdx = normalized.indexOf("/templates/");
    if (templateIdx >= 0)
        return normalized.slice(0, templateIdx);
    return MODULE_PACKAGE_ROOT;
}
function getRuntimeVisibilityForEntry(entry, contractRoot) {
    if (!_contractCache) {
        _contractCache = buildTemplateAssetContracts(resolveContractRoot(entry, contractRoot));
    }
    const normalized = entry.file_path.replace(/\\/g, "/");
    // 直接精确匹配（内置模板加载场景）
    const directMatch = _contractCache.find(c => c.path === normalized);
    if (directMatch)
        return directMatch.runtime_visibility;
    // 从同步资产绝对路径提取 knowledge 相对路径，映射为模板路径
    const marker = "/.soloforge/knowledge/";
    const idx = normalized.indexOf(marker);
    if (idx >= 0) {
        const knowledgeRelPath = normalized.substring(idx + marker.length);
        const templatePath = `templates/${knowledgeRelPath}`;
        const contract = _contractCache.find(c => c.path === templatePath);
        if (contract)
            return contract.runtime_visibility;
    }
    // 非知识目录文件 → 无合同，不设门禁
    return undefined;
}
/** 清除合同缓存（测试/重置时使用） */
export function clearInjectionContractCache() {
    _contractCache = null;
}
function isRouteRequired(entry, routeDecision) {
    if (!routeDecision)
        return false;
    const oa = routeDecision.output_artifact;
    if (!oa)
        return false;
    // 匹配 pipeline_hint 的 pipeline_procedure 条目为 route_required
    if (entry.type === "pipeline_procedure" && routeDecision.pipeline_hint) {
        return entry.when.includes(routeDecision.pipeline_hint.split(":")[0]) ||
            entry.name.includes(routeDecision.pipeline_hint.split(":")[0]);
    }
    // 匹配 output_artifact.template 的 acceptance_template 条目为 route_required
    // 同时检查 output_artifact.kind 是否有对应 schema（即使无 template 也匹配）
    if (entry.type === "acceptance_template") {
        // 优先匹配 template 名称
        if (oa.template && (entry.name === oa.template || entry.file_path.includes(oa.template))) {
            return true;
        }
        // 无 template 但 kind 有对应 schema → 也视为 route_required
        if (hasArtifactSchema(oa.kind)) {
            // 按 kind 触发条件匹配
            const trigger = `output_artifact.kind=${oa.kind}`;
            if (entry.when.includes(trigger) || entry.name.includes(oa.kind))
                return true;
        }
        return false;
    }
    // 匹配 output_artifact.kind 触发条件的条目为 route_required
    const trigger = `output_artifact.kind=${oa.kind}`;
    if (entry.when.includes(trigger) || entry.name.includes(oa.kind))
        return true;
    return false;
}
function scopeMatches(entryScopes, requestScopes) {
    if (entryScopes.length === 0)
        return true;
    if (entryScopes.includes("shared"))
        return true;
    return entryScopes.some((s) => requestScopes.includes(s));
}
function productsMatch(entryProducts, requestProducts) {
    if (entryProducts.length === 0)
        return true;
    if (entryProducts.includes("*"))
        return true;
    return entryProducts.some((p) => requestProducts.includes(p));
}
function assignPriorityTier(entry, routeDecision, _assets, taskStage) {
    if (isRouteRequired(entry, routeDecision))
        return "route_required";
    // 阶段匹配的条目提升到 project_core_active 级别
    const stageMatched = taskStage
        && entry.stages?.length
        && (entry.stages.includes("*") || entry.stages.includes(taskStage));
    if (stageMatched)
        return "project_core_active";
    const isProject = isProjectEntry(entry);
    const isCore = isCoreEntry(entry);
    // 产品约束条目：仅限非项目级别的 domain/product_profile 条目
    if (!isProject && (entry.type === "domain" || entry.file_path.includes("product_profiles"))) {
        return "product_constraints";
    }
    if (entry.status === "pending_review")
        return "advisory_pending";
    if (isProject && isCore)
        return "project_core_active";
    if (isProject && !isCore)
        return "project_normal_active";
    if (!isProject && isCore)
        return "global_core_active";
    return "global_normal_active";
}
// ── 门 1: Indexable Filter ──
/** 门1: 过滤可索引的知识条目，排除非 active/pending_review 状态 */
export function filterIndexable(entries) {
    debugLog("知识注入边界: 门1-可索引过滤开始, 条目数=" + entries.length);
    const passed = [];
    const excluded = [];
    for (const entry of entries) {
        if (INDEXABLE_STATUSES.has(entry.status)) {
            passed.push(entry);
        }
        else {
            const reason = entry.status === "deprecated"
                ? "deprecated"
                : "status_blocked";
            debugLog("知识注入边界: 门1-排除条目, id=" + entry.id + ", name=" + entry.name + ", reason=" + reason);
            excluded.push({ id: entry.id, name: entry.name, reason });
        }
    }
    debugLog("知识注入边界: 门1-可索引过滤完成, 通过=" + passed.length + ", 排除=" + excluded.length);
    return { passed, excluded };
}
// ── 门 2: Injectable Filter ──
/** 门2: 过滤可注入的知识条目，按消费模式、作用域、产品、路由等条件筛选 */
export function filterInjectable(entries, routeDecision, scopeFilters, assets, productFilters = [], contractRoot, taskStage) {
    debugLog("知识注入边界: 门2-可注入过滤开始, 条目数=" + entries.length + ", scope过滤=" + scopeFilters.length + ", product过滤=" + productFilters.length);
    const injectable = [];
    const advisory = [];
    const excluded = [];
    const indexOnlyExcluded = new Set();
    const requestScopes = scopeFilters;
    const requestProducts = productFilters;
    for (const entry of entries) {
        // 状态门禁
        if (entry.status !== "active" && entry.status !== "pending_review") {
            // 已在门1过滤，但做防御性检查
            debugLog("知识注入边界: 门2-状态阻止, id=" + entry.id + ", status=" + entry.status);
            excluded.push({ id: entry.id, name: entry.name, reason: "status_blocked" });
            continue;
        }
        // 阶段感知覆盖：如果条目声明了匹配当前阶段的 stages，提升其注入权限
        const stageMatched = taskStage
            && entry.stages
            && entry.stages.length > 0
            && (entry.stages.includes("*") || entry.stages.includes(taskStage));
        // 消费模式门禁
        const cm = getConsumptionMode(entry, assets);
        if (!stageMatched && BLOCKED_CONSUMPTION_MODES.has(cm)) {
            const cmReason = cm === "deprecated" ? "deprecated" : "manual_reference_only";
            debugLog("知识注入边界: 门2-消费模式阻止, id=" + entry.id + ", mode=" + cm);
            excluded.push({ id: entry.id, name: entry.name, reason: cmReason });
            continue;
        }
        // runtime_visibility 门禁: index_only/internal_only/scaffold_only 不进入注入
        const rv = getRuntimeVisibilityForEntry(entry, contractRoot);
        if (!stageMatched && rv && NON_INJECTABLE_VISIBILITIES.has(rv)) {
            debugLog("知识注入边界: 门2-runtime_visibility 阻止注入, id=" + entry.id + ", visibility=" + rv);
            excluded.push({ id: entry.id, name: entry.name, reason: "manual_reference_only" });
            if (rv === "index_only")
                indexOnlyExcluded.add(entry.id);
            continue;
        }
        // 范围门禁
        if (requestScopes.length > 0 && !scopeMatches(entry.scope, requestScopes)) {
            debugLog("知识注入边界: 门2-作用域不匹配, id=" + entry.id + ", entry_scope=" + JSON.stringify(entry.scope) + ", request_scope=" + JSON.stringify(requestScopes));
            excluded.push({ id: entry.id, name: entry.name, reason: "scope_mismatch" });
            continue;
        }
        // 产品门禁
        if (requestProducts.length > 0 && !productsMatch(entry.products, requestProducts)) {
            debugLog("知识注入边界: 门2-产品不匹配, id=" + entry.id + ", entry_products=" + JSON.stringify(entry.products) + ", request_products=" + JSON.stringify(requestProducts));
            excluded.push({ id: entry.id, name: entry.name, reason: "product_mismatch" });
            continue;
        }
        // 路由门禁 — 仅拒绝明显不匹配的条目
        if (routeDecision && isRouteMismatch(entry, routeDecision)) {
            debugLog("知识注入边界: 门2-路由不匹配, id=" + entry.id + ", type=" + entry.type);
            excluded.push({ id: entry.id, name: entry.name, reason: "route_mismatch" });
            continue;
        }
        // pending_review → 仅为建议
        if (entry.status === "pending_review") {
            debugLog("知识注入边界: 门2-待审条目降级为advisory, id=" + entry.id);
            advisory.push(entry);
            continue;
        }
        injectable.push(entry);
    }
    // Phase 7a: artifact_template 消费语义 — 截断过长的模板 body
    for (const entry of injectable) {
        if (entry.type === "artifact_template" && entry.body && entry.body.length > 200) {
            entry._injection_content =
                entry.body.substring(0, 200) + "\n...\n（完整模板按需加载）";
        }
    }
    debugLog("知识注入边界: 门2-可注入过滤完成, 注入=" + injectable.length + ", advisory=" + advisory.length + ", 排除=" + excluded.length);
    return { injectable, advisory, excluded, indexOnlyExcludedIds: indexOnlyExcluded };
}
// execution_shape → 允许的知识类型映射
const EXECUTION_SHAPE_ALLOWED_TYPES = {
    code_execution: new Set(["pattern", "procedure", "domain", "governance_rule", "pipeline_procedure", "review_rule", "artifact_template", "checklist"]),
    single_artifact: new Set(["acceptance_template", "pipeline_procedure", "pattern", "procedure", "artifact_template"]),
    read_only_analysis: new Set(["domain", "review_rule", "pattern", "governance_rule", "procedure", "artifact_template"]),
    verification_only: new Set(["review_rule", "governance_rule", "pattern", "procedure", "checklist"]),
    multi_stage_plan: new Set(["pipeline_procedure", "pattern", "acceptance_template", "domain", "procedure", "artifact_template", "checklist"]),
    // "none" 无限制
};
function isRouteMismatch(entry, routeDecision) {
    // 门禁：review_rule 在 code_execution / verification_only shape 也允许
    if (entry.type === "review_rule" && routeDecision.route !== "review") {
        const shape = routeDecision.execution_shape;
        if (shape === "code_execution" || shape === "verification_only")
            return false;
        return true;
    }
    // 门禁：带有显式触发条件的 acceptance_template 必须匹配 output_artifact.kind
    if (entry.type === "acceptance_template") {
        const oa = routeDecision.output_artifact;
        if (oa && oa.kind) {
            const trigger = `output_artifact.kind=`;
            if (entry.when.includes(trigger)) {
                const triggeredKind = entry.when.split(trigger)[1]?.split(/[,\s]/)[0];
                if (triggeredKind && triggeredKind !== oa.kind)
                    return true;
            }
        }
    }
    // 门禁：execution_shape 必须允许此知识类型
    const shape = routeDecision.execution_shape;
    if (shape && shape !== "none") {
        const allowed = EXECUTION_SHAPE_ALLOWED_TYPES[shape];
        if (allowed && !allowed.has(entry.type)) {
            return true;
        }
    }
    return false;
}
// ── 门 3: Priority Sort ──
/** 门3: 按优先级排序知识条目，检测冲突，在预算内裁剪 */
export function sortByPriority(entries, routeDecision, assets, budget, taskStage) {
    debugLog("知识注入边界: 门3-优先级排序开始, 条目数=" + entries.length + ", 预算=" + budget);
    const conflicts = [];
    const dropped = [];
    // 为每个条目分配优先级层级
    const withPriority = entries.map((e) => ({
        entry: e,
        tier: assignPriorityTier(e, routeDecision, assets, taskStage),
    }));
    // 按优先级排序 order
    withPriority.sort((a, b) => {
        const ai = PRIORITY_ORDER.indexOf(a.tier);
        const bi = PRIORITY_ORDER.indexOf(b.tier);
        if (ai !== bi)
            return ai - bi;
        // 同层级内, core > normal
        const ac = isCoreEntry(a.entry) ? 0 : 1;
        const bc = isCoreEntry(b.entry) ? 0 : 1;
        if (ac !== bc)
            return ac - bc;
        // 同 core/normal 层级内，置信度高的优先
        return b.entry.confidence - a.entry.confidence;
    });
    // 检测同类型内 core 与 normal 的冲突
    const seenByType = new Map();
    for (const item of withPriority) {
        const typeKey = item.entry.type;
        const existing = seenByType.get(typeKey);
        if (existing && isCoreEntry(existing.entry) && !isCoreEntry(item.entry)) {
            conflicts.push({
                winner_id: existing.entry.id,
                loser_id: item.entry.id,
                field: "tier",
                reason: `core entry "${existing.entry.name}" takes priority over normal entry "${item.entry.name}" for type ${typeKey}`,
            });
        }
        seenByType.set(typeKey, item);
    }
    // 检测产品配置与项目配置的冲突
    // 产品配置不得覆盖项目级条目 — 仅作补充
    const projectEntries = withPriority.filter((w) => w.tier === "project_core_active" || w.tier === "project_normal_active");
    const productEntries = withPriority.filter((w) => w.tier === "product_constraints");
    for (const prod of productEntries) {
        const conflicting = projectEntries.find((proj) => proj.entry.type === prod.entry.type);
        if (conflicting) {
            conflicts.push({
                winner_id: conflicting.entry.id,
                loser_id: prod.entry.id,
                field: "priority_tier",
                reason: `project entry "${conflicting.entry.name}" overrides product profile "${prod.entry.name}" for type ${prod.entry.type} — product profile must not override project config`,
            });
        }
    }
    // 应用预算裁剪
    const sorted = withPriority.slice(0, budget).map((w) => w.entry);
    for (const item of withPriority.slice(budget)) {
        debugLog("知识注入边界: 门3-预算裁剪, id=" + item.entry.id + ", tier=" + item.tier);
        dropped.push({
            id: item.entry.id,
            name: item.entry.name,
            reason: "budget_limit",
        });
    }
    debugLog("知识注入边界: 门3-优先级排序完成, 排序=" + sorted.length + ", 冲突=" + conflicts.length + ", 裁剪=" + dropped.length);
    return { sorted, conflicts, dropped };
}
// ── 产物 Schema 独立注入通道 ──
/**
 * 解析产物 Schema 和 ProcessRules 的独立注入内容。
 *
 * 核心设计决策：Schema 和 ProcessRules 是结构约束，不是知识。
 * 它们绕过三道门的条目数/token 预算限制，作为独立注入通道。
 * 无论知识注入预算是否充足，Schema 始终被注入到 prompt 中。
 *
 * @param outputArtifact 路由决策中的 output_artifact（含 kind 和可选 template）
 * @param operationType 当前操作类型（extract/review/fix/iterate）
 * @returns Schema 注入内容，无匹配产物类型时返回 null
 */
export function resolveArtifactSchemaInjection(outputArtifact, operationType) {
    if (!outputArtifact?.kind)
        return null;
    // 从 Schema 注册中心查找
    const schema = getArtifactSchema(outputArtifact.kind);
    if (!schema)
        return null;
    // Schema 文本始终注入
    const schema_text = formatSchemaForPrompt(schema);
    // ProcessRules 按 operationType 选择
    const rules = getProcessRules(outputArtifact.kind);
    const opType = operationType ?? "extract";
    const process_rules_text = rules
        ? formatProcessRulesForPrompt(rules, opType)
        : "";
    // 如果两个都为空文本则不注入
    if (!schema_text && !process_rules_text)
        return null;
    debugLog(`知识注入边界: 产物Schema独立注入, kind=${outputArtifact.kind}, opType=${opType}`);
    return {
        schema_text,
        process_rules_text,
    };
}
// ── 主入口 ──
const DEFAULT_BUDGET = 15;
/** 默认 token 预算 — 按字符/4 估算，限制注入知识总量 */
const DEFAULT_MAX_TOKEN_BUDGET = 12000;
/** 知识注入边界主入口，依次执行三道门并生成注入报告 */
export function enforceKnowledgeInjectionBoundary(entries, routeDecision, scopeFilters, assets, budget = DEFAULT_BUDGET, productFilters = [], contractRoot, maxTokenBudget = DEFAULT_MAX_TOKEN_BUDGET, taskStage) {
    debugLog("知识注入边界: 主入口开始执行, 总条目数=" + entries.length + ", 预算=" + budget + ", scope过滤=" + scopeFilters.length + ", product过滤=" + productFilters.length);
    const allAssets = assets ?? listBuiltinConsumableAssets();
    const allExcluded = [];
    // ── 产物 Schema 独立注入（绕过三道门预算） ──
    const artifactSchemaInjection = resolveArtifactSchemaInjection(routeDecision?.output_artifact, routeDecision?.operation_type);
    // 门 1: Indexable
    const gate1 = filterIndexable(entries);
    allExcluded.push(...gate1.excluded);
    debugLog("知识注入边界: 门1结果, 通过=" + gate1.passed.length + ", 排除=" + gate1.excluded.length);
    // 门1通过 → 标记为已索引
    const indexed = gate1.passed.map((e) => {
        const cm = getConsumptionMode(e, allAssets);
        const tier = assignPriorityTier(e, routeDecision, allAssets, taskStage);
        return entryToRef(e, tier, cm);
    });
    // 门 2: Injectable
    const gate2 = filterInjectable(gate1.passed, routeDecision, scopeFilters, allAssets, productFilters, contractRoot, taskStage);
    allExcluded.push(...gate2.excluded);
    debugLog("知识注入边界: 门2结果, 注入=" + gate2.injectable.length + ", advisory=" + gate2.advisory.length + ", 排除=" + gate2.excluded.length);
    // 门2通过 → 标记为可注入
    const injectableRefs = gate2.injectable.map((e) => {
        const cm = getConsumptionMode(e, allAssets);
        const tier = assignPriorityTier(e, routeDecision, allAssets, taskStage);
        return entryToRef(e, tier, cm);
    });
    // 门 3: Priority sort (applied to injectable entries)
    const gate3 = sortByPriority(gate2.injectable, routeDecision, allAssets, budget, taskStage);
    allExcluded.push(...gate3.dropped);
    debugLog("知识注入边界: 门3结果, 排序=" + gate3.sorted.length + ", 冲突=" + gate3.conflicts.length + ", 裁剪=" + gate3.dropped.length);
    // 门3b: Token 预算约束 — 在条目数预算之上额外限制总 token 量
    let tokenUsed = 0;
    const tokenFiltered = gate3.sorted.filter((entry) => {
        const bodyLen = entry.body;
        const estimated = Math.ceil((bodyLen?.length ?? 0) / 4);
        if (tokenUsed + estimated > maxTokenBudget) {
            allExcluded.push({ id: entry.id, name: entry.name, reason: "token_budget_exceeded" });
            return false;
        }
        tokenUsed += estimated;
        return true;
    });
    if (tokenFiltered.length < gate3.sorted.length) {
        debugLog("知识注入边界: Token预算裁剪, 裁剪前=" + gate3.sorted.length + ", 裁剪后=" + tokenFiltered.length + ", token已用=" + tokenUsed);
    }
    // 从排序结果中分离 required 和 supporting
    const injectedRequired = [];
    const injectedSupporting = [];
    for (const entry of tokenFiltered) {
        const cm = getConsumptionMode(entry, allAssets);
        const tier = assignPriorityTier(entry, routeDecision, allAssets, taskStage);
        const ref = entryToRef(entry, tier, cm);
        if (cm === "required" || tier === "route_required") {
            injectedRequired.push(ref);
        }
        else {
            injectedSupporting.push(ref);
        }
    }
    // Advisory 条目 — pending_review 必须携带 warning
    const advisoryOnly = gate2.advisory.map((e) => {
        const cm = getConsumptionMode(e, allAssets);
        return entryToRef(e, "advisory_pending", cm, "pending_review_not_injected");
    });
    // 从路由决策推导缺失的必需知识
    // 对照门1通过结果（全部可索引条目）检测存在但被范围/产品过滤的知识
    // index_only 资产被 runtime_visibility 门禁排除，不算"缺失"
    const missingRequiredKnowledge = deriveMissingRequiredKnowledge(routeDecision, gate1.passed, gate2.injectable, gate2.indexOnlyExcludedIds);
    debugLog("知识注入边界: 主入口完成, 必需注入=" + injectedRequired.length + ", 辅助注入=" + injectedSupporting.length + ", advisory=" + advisoryOnly.length + ", 总排除=" + allExcluded.length + ", 缺失必需=" + missingRequiredKnowledge.length);
    return {
        indexed,
        injectable: injectableRefs,
        injected_required: injectedRequired,
        injected_supporting: injectedSupporting,
        advisory_only: advisoryOnly,
        excluded: allExcluded,
        missing_required_knowledge: missingRequiredKnowledge,
        conflicts: gate3.conflicts,
        budget: {
            requested: entries.length,
            injected: tokenFiltered.length,
            advisory: gate2.advisory.length,
            dropped: allExcluded.length,
        },
        generated_at: new Date().toISOString(),
        artifact_schema_injection: artifactSchemaInjection ?? undefined,
    };
}
// ── 必需知识推导 ──
function deriveMissingRequiredKnowledge(routeDecision, allIndexable, injectableEntries, indexOnlyExcludedIds = new Set()) {
    const missing = [];
    if (!routeDecision)
        return missing;
    const oa = routeDecision.output_artifact;
    const route = routeDecision.route;
    const shape = routeDecision.execution_shape;
    // acceptance_template 预期
    const needsAcceptanceTemplate = ((route === "source_extraction" || shape === "single_artifact") && oa?.kind === "prototype_spec")
        || (oa?.template && oa.kind);
    if (needsAcceptanceTemplate) {
        const matchFn = (e) => {
            if (e.type !== "acceptance_template")
                return false;
            if (oa?.kind && e.when.includes(`output_artifact.kind=${oa.kind}`))
                return true;
            if (oa?.template && (e.name === oa.template || e.file_path.includes(oa.template)))
                return true;
            return false;
        };
        const hasInInjectable = injectableEntries.some(matchFn);
        const hasInIndexable = allIndexable.some(matchFn);
        const isIndexOnly = allIndexable.some(e => matchFn(e) && indexOnlyExcludedIds.has(e.id));
        if (!hasInInjectable && !isIndexOnly) {
            if (hasInIndexable) {
                // 存在但不可注入 — 被范围/产品/状态/路由/消费模式门禁阻止
                missing.push({
                    kind: oa?.kind,
                    template: oa?.template,
                    reason: oa?.template
                        ? `required knowledge exists but is not injectable: acceptance_template matching template="${oa.template}" is blocked by scope/product/status/route/consumption gate`
                        : `required knowledge exists but is not injectable: acceptance_template for output_artifact.kind=${oa?.kind} is blocked by scope/product/status/route/consumption gate`,
                });
            }
            else {
                missing.push({
                    kind: oa?.kind,
                    template: oa?.template,
                    reason: oa?.template
                        ? `output_artifact.kind=${oa.kind} with template="${oa.template}" has no matching acceptance_template (type=acceptance_template) in indexed knowledge`
                        : `source_extraction + prototype_spec route requires an acceptance_template matching output_artifact.kind=prototype_spec, but none found`,
                });
            }
        }
    }
    // pipeline_hint 预期
    if (routeDecision.pipeline_hint) {
        const pipelineName = routeDecision.pipeline_hint.split(":")[0];
        const matchFn = (e) => {
            if (e.type !== "pipeline_procedure")
                return false;
            return e.when.includes(pipelineName) || e.name.includes(pipelineName);
        };
        const hasInInjectable = injectableEntries.some(matchFn);
        const hasInIndexable = allIndexable.some(matchFn);
        const isIndexOnly = allIndexable.some(e => matchFn(e) && indexOnlyExcludedIds.has(e.id));
        if (!hasInInjectable && !isIndexOnly) {
            if (hasInIndexable) {
                missing.push({
                    pipeline_hint: routeDecision.pipeline_hint,
                    reason: `required knowledge exists but is not injectable: pipeline_procedure matching pipeline_hint="${routeDecision.pipeline_hint}" is blocked by scope/product/status/route/consumption gate`,
                });
            }
            else {
                missing.push({
                    pipeline_hint: routeDecision.pipeline_hint,
                    reason: `pipeline_hint="${routeDecision.pipeline_hint}" has no matching pipeline_procedure (type=pipeline_procedure) in indexed knowledge`,
                });
            }
        }
    }
    return missing;
}
// ── 自治理 ──
/** 自治理验证知识注入报告的合规性 */
export function validateInjectionReport(report) {
    debugLog("知识注入边界: 自治理验证开始, 注入总数=" + (report.injected_required.length + report.injected_supporting.length) + ", advisory=" + report.advisory_only.length + ", 排除=" + report.excluded.length);
    const findings = [];
    const allInjected = [...report.injected_required, ...report.injected_supporting];
    // 检查: missing indexed field
    if (!report.indexed) {
        findings.push({
            severity: "hard_fail",
            subject_id: "indexed",
            field: "indexed",
            message: "report is missing required field: indexed",
        });
    }
    // 检查: missing injectable field
    if (!report.injectable) {
        findings.push({
            severity: "hard_fail",
            subject_id: "injectable",
            field: "injectable",
            message: "report is missing required field: injectable",
        });
    }
    // 检查: missing_required_knowledge → hard_fail
    if (report.missing_required_knowledge && report.missing_required_knowledge.length > 0) {
        debugLog("知识注入边界: 自治理验证-检测到缺失必需知识, 数量=" + report.missing_required_knowledge.length);
        for (const missing of report.missing_required_knowledge) {
            findings.push({
                severity: "hard_fail",
                subject_id: "missing_required_knowledge",
                field: missing.kind ?? missing.template ?? missing.pipeline_hint ?? "unknown",
                message: `missing required knowledge: ${missing.reason}`,
            });
        }
    }
    // 检查: no draft/quarantine/deprecated in injected
    for (const ref of allInjected) {
        if (ref.tier === "draft" || ref.tier === "quarantine" || ref.tier === "deprecated") {
            debugLog("知识注入边界: 自治理验证-阻止层级注入, id=" + ref.id + ", tier=" + ref.tier);
            findings.push({
                severity: "hard_fail",
                subject_id: ref.id,
                field: "tier",
                message: `injected knowledge "${ref.name}" has blocked tier "${ref.tier}"`,
            });
        }
    }
    // 检查: pending_review only in advisory_only
    for (const ref of allInjected) {
        if (ref.priority_tier === "advisory_pending") {
            debugLog("知识注入边界: 自治理验证-advisory_pending误注入, id=" + ref.id);
            findings.push({
                severity: "hard_fail",
                subject_id: ref.id,
                field: "priority_tier",
                message: `advisory_pending knowledge "${ref.name}" must be in advisory_only, not injected`,
            });
        }
    }
    // 检查: advisory_only pending_review must have warning
    for (const ref of report.advisory_only) {
        if (ref.priority_tier === "advisory_pending" && !ref.warning && (!ref.warnings || ref.warnings.length === 0)) {
            findings.push({
                severity: "hard_fail",
                subject_id: ref.id,
                field: "warning",
                message: `advisory_only entry "${ref.name}" with advisory_pending tier must carry a warning`,
            });
        }
    }
    // 检查: budget consistency (advisory_only not counted in injected)
    const injectedCount = report.injected_required.length + report.injected_supporting.length;
    if (report.budget.injected !== injectedCount) {
        findings.push({
            severity: "hard_fail",
            subject_id: "budget",
            field: "injected",
            message: `budget.injected (${report.budget.injected}) does not match actual injected count (${injectedCount})`,
        });
    }
    // 检查: conflicts have valid winner/loser
    for (const conflict of report.conflicts) {
        if (conflict.winner_id === conflict.loser_id) {
            findings.push({
                severity: "advisory",
                subject_id: conflict.winner_id,
                field: "conflict",
                message: `self-conflict: winner and loser are the same entry`,
            });
        }
    }
    // 建议: no required knowledge injected
    if (report.injected_required.length === 0 && report.budget.requested > 0) {
        findings.push({
            severity: "advisory",
            subject_id: "injected_required",
            field: "length",
            message: "no required knowledge was injected — route may be missing required assets",
        });
    }
    // 建议: budget insufficient for all entries
    if (report.budget.dropped > 0) {
        findings.push({
            severity: "advisory",
            subject_id: "budget",
            field: "dropped",
            message: `${report.budget.dropped} entries dropped due to budget limit`,
        });
    }
    const hardFails = findings.filter(f => f.severity === "hard_fail");
    const advisories = findings.filter(f => f.severity === "advisory");
    debugLog("知识注入边界: 自治理验证完成, 硬失败=" + hardFails.length + ", 建议=" + advisories.length);
    return findings;
}
/**
 * 从报告中获取已注入的条目，回溯到原始 KnowledgeEntry 对象。
 */
export function getInjectedEntryIds(report) {
    const ids = [
        ...report.injected_required,
        ...report.injected_supporting,
    ].map((r) => r.id);
    debugLog("知识注入边界: 获取已注入条目ID, 数量=" + ids.length);
    return ids;
}
//# sourceMappingURL=knowledge_injection_boundary.js.map