"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.composeAssistantAnswer = composeAssistantAnswer;
function fallbackFromSummary(routeSummary) {
    if (!routeSummary || routeSummary.mode !== "deterministic_v2") {
        return "none";
    }
    return routeSummary.fallback.type;
}
function uniqueStrings(values, limit = 6) {
    return Array.from(new Set(values.map((item) => item.trim()).filter(Boolean))).slice(0, limit);
}
const UUID_PATTERN = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi;
const LONG_HEX_PATTERN = /\b[0-9a-f]{24,}\b/gi;
const RAW_REF_BLOB_PATTERN = /\bevidence_source_ref_v1\|[^\s,;]+/gi;
const RAW_REF_TOKEN_PATTERN = /\b(?:source_ref|canonical_ref|entity_id|fragment_id|guid|uuid)\b/gi;
function looksLikeMojibake(value) {
    const text = String(value ?? "");
    if (!text.trim()) {
        return false;
    }
    if (/(?:Р.|С.){5,}/u.test(text)) {
        return true;
    }
    if (/[ЃѓЂђЌќЎў]/u.test(text)) {
        return true;
    }
    return false;
}
function looksLikeTechnicalIdentifier(value) {
    const text = String(value ?? "").trim();
    if (!text) {
        return false;
    }
    if (UUID_PATTERN.test(text)) {
        UUID_PATTERN.lastIndex = 0;
        return true;
    }
    UUID_PATTERN.lastIndex = 0;
    if (LONG_HEX_PATTERN.test(text)) {
        LONG_HEX_PATTERN.lastIndex = 0;
        return true;
    }
    LONG_HEX_PATTERN.lastIndex = 0;
    return /(?:evidence_source_ref_v1\||cmp%3a|batch_refresh_then_store:|^cmp:)/i.test(text);
}
function scrubRawTechnicalRefs(value) {
    const raw = String(value ?? "").trim();
    if (!raw) {
        return "";
    }
    return raw
        .replace(RAW_REF_BLOB_PATTERN, "linked source")
        .replace(UUID_PATTERN, "[id]")
        .replace(LONG_HEX_PATTERN, "[id]")
        .replace(RAW_REF_TOKEN_PATTERN, "reference")
        .replace(/\(\s*\[id\]\s*\)/g, "")
        .replace(/\[\s*id\s*\](?:\s*,\s*\[\s*id\s*\])+/g, "[id]")
        .replace(/\s{2,}/g, " ")
        .trim();
}
function sanitizeUserFacingReply(value) {
    return scrubRawTechnicalRefs(value)
        .replace(/[ \t]+\n/g, "\n")
        .replace(/\n{3,}/g, "\n\n")
        .trim();
}
function sanitizeUserText(value) {
    const normalized = scrubRawTechnicalRefs(String(value ?? "").replace(/\s+/g, " ").trim());
    if (!normalized) {
        return null;
    }
    if (looksLikeMojibake(normalized)) {
        return null;
    }
    return normalized;
}
function sanitizeUserLines(values, limit = 6) {
    const cleaned = values
        .map((item) => sanitizeUserText(item))
        .filter((item) => Boolean(item));
    return uniqueStrings(cleaned, limit);
}
function formatList(items) {
    if (items.length === 0) {
        return "";
    }
    return items.map((item) => `- ${item}`).join("\n");
}
function formatSafeItemLine(entity, sourceId, riskScore) {
    const entityLabel = sanitizeUserText(String(entity ?? "")) ?? "Record";
    const idRaw = String(sourceId ?? "").trim();
    const exposeId = idRaw.length > 0 && !looksLikeTechnicalIdentifier(idRaw);
    const subject = exposeId ? `${entityLabel} (${idRaw})` : entityLabel;
    if (riskScore !== undefined) {
        return `${subject} - risk ${String(riskScore)}.`;
    }
    return `${subject}.`;
}
function extractTopFacts(results) {
    const lines = [];
    for (const result of results.filter((item) => item.status === "ok").slice(0, 3)) {
        if (result.result_type === "chain") {
            const top = result.items.slice(0, 3).map((item) => {
                const counterparty = String(item.counterparty_id ?? "").trim();
                const operations = String(item.operations_count ?? "0");
                const docs = String(item.document_refs_count ?? "0");
                const counterpartyLabel = counterparty.length > 0 && !looksLikeTechnicalIdentifier(counterparty) ? `Counterparty ${counterparty}` : "Counterparty";
                return `${counterpartyLabel}: operations ${operations}, linked docs ${docs}.`;
            });
            lines.push(...top);
            continue;
        }
        if (result.result_type === "ranking") {
            const top = result.items
                .slice(0, 5)
                .map((item) => `${item.rank ?? "*"}. ${String(item.entity ?? "Entity")} - ${String(item.records_count ?? 0)}.`);
            lines.push(...top);
            continue;
        }
        if (result.result_type === "list") {
            const top = result.items.slice(0, 5).map((item) => {
                if (item.risk_score !== undefined) {
                    return formatSafeItemLine(item.source_entity ?? "Record", item.source_id ?? "", item.risk_score);
                }
                return formatSafeItemLine(item.source_entity ?? "Record", item.source_id ?? "");
            });
            lines.push(...top);
            continue;
        }
        const top = result.items
            .slice(0, 3)
            .map((item) => formatSafeItemLine(item.source_entity ?? "Record", item.source_id ?? ""));
        lines.push(...top);
    }
    return sanitizeUserLines(lines, 8);
}
function extractWhyIncluded(results) {
    return sanitizeUserLines(results.flatMap((item) => item.why_included));
}
function extractSelectionReasons(results) {
    return sanitizeUserLines(results.flatMap((item) => item.selection_reason));
}
function extractRiskFactors(results) {
    return sanitizeUserLines(results.flatMap((item) => item.risk_factors));
}
function extractBusinessInterpretation(results) {
    return sanitizeUserLines(results.flatMap((item) => item.business_interpretation));
}
function extractLimitations(results) {
    return sanitizeUserLines(results.flatMap((item) => item.limitations), 10);
}
function summaryValue(result, key) {
    const summary = result.summary ?? {};
    return Object.prototype.hasOwnProperty.call(summary, key) ? summary[key] : undefined;
}
function summaryBoolean(result, key) {
    return summaryValue(result, key) === true;
}
function summaryString(result, key) {
    const value = summaryValue(result, key);
    return typeof value === "string" ? value : null;
}
function summaryNumber(result, key) {
    const value = summaryValue(result, key);
    return typeof value === "number" && Number.isFinite(value) ? value : null;
}
function summaryStringArray(result, key) {
    const value = summaryValue(result, key);
    if (!Array.isArray(value)) {
        return [];
    }
    return sanitizeUserLines(value.map((item) => String(item)), 6);
}
function buildFallbackWhyIncluded(results) {
    const lines = [];
    for (const result of results.slice(0, 2)) {
        const routeFocus = summaryString(result, "route_focus");
        const sourceRecords = summaryNumber(result, "source_records");
        const filteredRecords = summaryNumber(result, "filtered_records_after_narrowing");
        const checkedRecords = summaryNumber(result, "checked_records");
        if (routeFocus) {
            lines.push(`Проверка выполнена по профилю ${routeFocus}.`);
        }
        if (sourceRecords !== null && filteredRecords !== null && filteredRecords < sourceRecords) {
            lines.push(`Применено сужение выборки: ${filteredRecords} из ${sourceRecords} записей.`);
        }
        if (checkedRecords !== null) {
            lines.push(`Проверено записей в текущем проходе: ${checkedRecords}.`);
        }
    }
    return sanitizeUserLines(lines, 4);
}
function buildFallbackSelectionReasons(results) {
    const lines = [];
    for (const result of results.slice(0, 2)) {
        if (summaryBoolean(result, "semantic_narrowing_applied")) {
            lines.push("Отбор выполнен по семантическому сужению предметной области.");
        }
        const rankingBasis = summaryStringArray(result, "ranking_basis");
        if (rankingBasis.length > 0) {
            lines.push(`Ранжирование основано на: ${rankingBasis.join(", ")}.`);
        }
        if (summaryBoolean(result, "broad_guard_applied")) {
            lines.push("Применен broad-query guard для контроля ложной точности.");
        }
    }
    if (lines.length === 0) {
        lines.push("Отбор выполнен по совпадению предметных сигналов и доступной evidence-опоры.");
    }
    return sanitizeUserLines(lines, 4);
}
function suggestNextStep(requirements, coverage) {
    const next = [];
    if (coverage.clarification_needed_for.length > 0) {
        next.push("Уточните период, счет, документ или контрагента для требований: " + coverage.clarification_needed_for.join(", ") + ".");
    }
    if (coverage.requirements_uncovered.length > 0) {
        next.push("Проверьте непокрытые требования: " + coverage.requirements_uncovered.join(", ") + ".");
    }
    if (coverage.out_of_scope_requirements.length > 0) {
        next.push("Часть запроса вне текущего учетного контура: " + coverage.out_of_scope_requirements.join(", ") + ".");
    }
    if (next.length === 0 && requirements.length > 0) {
        next.push("Следующим шагом можно открыть технический разбор и углубить проверку по выбранным объектам.");
    }
    return next;
}
const PROBLEM_HEAVY_TYPES = new Set([
    "document_conflict",
    "broken_chain_segment",
    "lifecycle_anomaly_node",
    "unresolved_settlement_cluster",
    "period_risk_cluster",
    "cross_branch_inconsistency_cluster"
]);
function flattenEvidence(results) {
    return results.flatMap((item) => item.evidence);
}
function flattenProblemUnits(results) {
    const units = [];
    for (const result of results) {
        if (!Array.isArray(result.problem_units)) {
            continue;
        }
        units.push(...result.problem_units);
    }
    const byId = new Map();
    for (const unit of units) {
        byId.set(unit.problem_unit_id, unit);
    }
    return Array.from(byId.values());
}
function selectProblemUnitSummary(results) {
    let selected = null;
    for (const result of results) {
        if (!result.problem_unit_summary) {
            continue;
        }
        if (!selected || result.problem_unit_summary.units_total > selected.units_total) {
            selected = result.problem_unit_summary;
        }
    }
    return selected;
}
function formatAffectedScope(unit) {
    const scopeParts = [];
    if (unit.affected_accounts.length > 0) {
        scopeParts.push(`счета: ${unit.affected_accounts.slice(0, 2).join(", ")}`);
    }
    if (unit.affected_counterparties.length > 0) {
        scopeParts.push(`контрагенты: ${unit.affected_counterparties.slice(0, 2).join(", ")}`);
    }
    if (unit.affected_documents.length > 0) {
        scopeParts.push(`документы: ${unit.affected_documents.slice(0, 2).join(", ")}`);
    }
    if (scopeParts.length === 0 && unit.affected_entities.length > 0) {
        scopeParts.push(`объекты: ${unit.affected_entities.slice(0, 2).join(", ")}`);
    }
    if (scopeParts.length === 0) {
        return "затронутый контур требует уточнения";
    }
    return scopeParts.join("; ");
}
function formatLifecycleScope(unit) {
    if (!unit.lifecycle_domain) {
        return null;
    }
    const parts = [`domain=${unit.lifecycle_domain}`];
    if (unit.current_lifecycle_state) {
        parts.push(`current=${unit.current_lifecycle_state}`);
    }
    if (unit.expected_lifecycle_state) {
        parts.push(`expected=${unit.expected_lifecycle_state}`);
    }
    if (unit.lifecycle_defect_type) {
        parts.push(`defect=${unit.lifecycle_defect_type}`);
    }
    if (unit.missing_transition) {
        parts.push(`missing_transition=${unit.missing_transition}`);
    }
    if (unit.invalid_transition) {
        parts.push(`invalid_transition=${unit.invalid_transition}`);
    }
    if (unit.stale_duration) {
        parts.push(`stale_duration=${unit.stale_duration}`);
    }
    return parts.join(", ");
}
function rankProblemUnitsForAnswer(units, lifecycleAnswerEnabled) {
    if (!lifecycleAnswerEnabled) {
        return units.slice().sort((left, right) => {
            const severityDiff = right.severity.score - left.severity.score;
            if (severityDiff !== 0)
                return severityDiff;
            return right.confidence.score - left.confidence.score;
        });
    }
    return units.slice().sort((left, right) => {
        const lifecycleRankDiff = (right.lifecycle_ranking_score ?? 0) - (left.lifecycle_ranking_score ?? 0);
        if (lifecycleRankDiff !== 0)
            return lifecycleRankDiff;
        const lifecycleConfidenceDiff = (right.lifecycle_confidence?.score ?? 0) - (left.lifecycle_confidence?.score ?? 0);
        if (lifecycleConfidenceDiff !== 0)
            return lifecycleConfidenceDiff;
        const severityDiff = right.severity.score - left.severity.score;
        if (severityDiff !== 0)
            return severityDiff;
        return right.confidence.score - left.confidence.score;
    });
}
function hasLifecycleResolution(units) {
    return units.some((unit) => Boolean(unit.lifecycle_domain) &&
        Boolean(unit.current_lifecycle_state) &&
        Boolean(unit.expected_lifecycle_state) &&
        Boolean(unit.lifecycle_defect_type));
}
function buildProblemCentricActions(input) {
    const actions = [];
    const unitTypes = new Set(input.units.map((item) => item.problem_unit_type));
    if (unitTypes.has("broken_chain_segment")) {
        actions.push("Проверьте связку выписка -> документ -> проводка по проблемным участкам цепочки.");
    }
    if (unitTypes.has("unresolved_settlement_cluster")) {
        actions.push("Сверьте хвосты по расчетам: закрылся ли документ оплаты корректным закрывающим документом.");
    }
    if (unitTypes.has("period_risk_cluster")) {
        actions.push("Оцените влияние дефекта на закрытие периода и корректность регламентных операций.");
    }
    if (unitTypes.has("cross_branch_inconsistency_cluster")) {
        actions.push("Сверьте противоречия между документами, проводками и регистрами по НДС/межконтурным связям.");
    }
    if (unitTypes.has("lifecycle_anomaly_node")) {
        actions.push("Проверьте lifecycle объекта: ожидаемый этап не должен оставаться в partially_linked состоянии.");
    }
    for (const unit of input.units) {
        if (unit.lifecycle_defect_type === "stale_active_state") {
            actions.push("Проверьте, почему объект завис: ожидаемый переход не должен оставаться в активной стадии.");
        }
        if (unit.lifecycle_defect_type === "misclosed_state") {
            actions.push("Проверьте закрывающий документ и проводки: закрытие может быть формальным, но некорректным по пути.");
        }
        if (unit.lifecycle_defect_type === "cross_branch_state_conflict") {
            actions.push("Сверьте бухгалтерскую и смежную ветки (например, НДС/расчеты): обнаружен межконтурный конфликт состояния.");
        }
    }
    if (input.mode === "clarification_required") {
        if (input.missingAnchors.period) {
            actions.push("Уточните период проверки, чтобы зафиксировать границы проблемного контура.");
        }
        if (input.missingAnchors.account) {
            actions.push("Уточните счет или группу счетов для предметной локализации дефекта.");
        }
        if (input.missingAnchors.documentOrObject) {
            actions.push("Укажите конкретный документ или объект трассировки для проверки механизма отклонения.");
        }
        if (input.missingAnchors.counterparty) {
            actions.push("Укажите контрагента/договор, чтобы проверить хвосты и разрывы на конкретной связке.");
        }
    }
    if (input.coverageReport.requirements_uncovered.length > 0) {
        actions.push(`Закройте непокрытые требования: ${input.coverageReport.requirements_uncovered.join(", ")}.`);
    }
    return uniqueStrings(actions, 6);
}
function buildProblemCentricClarifications(input) {
    if (input.mode !== "clarification_required") {
        return [];
    }
    const questions = [];
    const unitTypes = new Set(input.units.map((item) => item.problem_unit_type));
    if (input.missingAnchors.period) {
        questions.push("Уточните период (например, 2020-06), в котором нужно проверить проблемный кластер.");
    }
    if (input.missingAnchors.account) {
        questions.push("Уточните счет или связку счетов (например, 51/60), где вы ожидаете дефект.");
    }
    if (input.missingAnchors.documentOrObject) {
        questions.push("Укажите документ/объект, от которого нужно строить проверку цепочки.");
    }
    if (input.missingAnchors.counterparty) {
        questions.push("Укажите контрагента или договор, по которому проверить незакрытую экспозицию.");
    }
    if (unitTypes.has("broken_chain_segment")) {
        questions.push("Уточните участок цепочки: выписка, платежный документ или проводка.");
    }
    if (unitTypes.has("period_risk_cluster")) {
        questions.push("Уточните, какой этап закрытия периода критичен: начисление, закрытие счетов или НДС-блок.");
    }
    if (unitTypes.has("unresolved_settlement_cluster")) {
        questions.push("Уточните, интересуют хвосты поставщиков, покупателей или оба направления.");
    }
    if (input.coverageReport.clarification_needed_for.length > 0) {
        questions.push(`Закройте уточнения для требований: ${input.coverageReport.clarification_needed_for.join(", ")}.`);
    }
    return uniqueStrings(questions, 6);
}
function buildClaimEvidenceLinks(results) {
    const byClaim = new Map();
    for (const evidence of flattenEvidence(results)) {
        const claimRef = String(evidence.claim_ref ?? "").trim();
        const evidenceId = String(evidence.evidence_id ?? "").trim();
        if (!claimRef || !evidenceId) {
            continue;
        }
        const current = byClaim.get(claimRef) ?? [];
        current.push(evidenceId);
        byClaim.set(claimRef, current);
    }
    return Array.from(byClaim.entries())
        .slice(0, 10)
        .map(([claim_ref, evidenceIds]) => ({
        claim_ref,
        evidence_ids: uniqueStrings(evidenceIds, 10)
    }));
}
function aggregatePolicySignals(results) {
    const broad_query_detected = results.some((item) => summaryBoolean(item, "broad_query_detected"));
    const broad_result_flag = results.some((item) => summaryBoolean(item, "broad_result_flag"));
    const minimum_evidence_failed = results.some((item) => summaryBoolean(item, "minimum_evidence_failed"));
    let degraded_to = null;
    for (const result of results) {
        const degraded = summaryString(result, "degraded_to");
        if (degraded === "clarification") {
            degraded_to = "clarification";
            break;
        }
        if (degraded === "partial") {
            degraded_to = "partial";
        }
    }
    const narrowingOrder = {
        weak: 0,
        medium: 1,
        strong: 2
    };
    let narrowing_strength = null;
    for (const result of results) {
        const value = summaryString(result, "narrowing_strength");
        if (value !== "weak" && value !== "medium" && value !== "strong") {
            continue;
        }
        if (!narrowing_strength || narrowingOrder[value] < narrowingOrder[narrowing_strength]) {
            narrowing_strength = value;
        }
    }
    return {
        broad_query_detected,
        broad_result_flag,
        minimum_evidence_failed,
        degraded_to,
        narrowing_strength
    };
}
function confidenceToScore(value) {
    if (value === "high")
        return 3;
    if (value === "medium")
        return 2;
    return 1;
}
function aggregateConfidence(results, evidenceItems) {
    const scores = [];
    for (const evidence of evidenceItems) {
        scores.push(confidenceToScore(evidence.confidence));
    }
    for (const result of results) {
        if (result.status === "error") {
            continue;
        }
        scores.push(confidenceToScore(result.confidence));
    }
    if (scores.length === 0) {
        return "low";
    }
    const average = scores.reduce((acc, item) => acc + item, 0) / scores.length;
    if (average >= 2.6)
        return "high";
    if (average >= 1.8)
        return "medium";
    return "low";
}
function collectLimitationReasonCodes(evidenceItems) {
    const codes = evidenceItems
        .map((item) => item.limitation?.reason_code ?? null)
        .filter((item) => Boolean(item));
    return uniqueStrings(codes, 8);
}
function limitationReasonToText(code) {
    if (code === "snapshot_only")
        return "Evidence is snapshot-only and may lag source-of-record.";
    if (code === "heuristic_inference")
        return "Part of the conclusion relies on heuristic inference.";
    if (code === "missing_mechanism")
        return "Mechanism is unresolved for part of the evidence.";
    if (code === "weak_source_mapping")
        return "Source mapping is weak for part of the evidence.";
    if (code === "insufficient_detail")
        return "Evidence lacks detail for a strong factual claim.";
    return "Some evidence limitations remain unresolved.";
}
function detectMissingAnchors(userMessage) {
    const lower = String(userMessage ?? "").toLowerCase();
    const hasPeriod = /\b20\d{2}(?:[-./](?:0[1-9]|1[0-2]))?\b/.test(lower);
    const hasAccount = /(?:\bсчет\b|\baccount\b|\bschet\b|\b\d{2}(?:\.\d{2})?\b)/i.test(lower);
    const hasDocumentOrObject = /(?:документ|invoice|guid|object|obj|#\d+|\bid\b|\bref\b|dokument|doc)/i.test(lower);
    const hasCounterparty = /(?:контрагент|supplier|buyer|customer|kontragent|postavsh|pokupatel)/i.test(lower);
    const hasAnomalyType = /(?:аномал|risk|отклон|разрыв|mismatch|duplicate|tail|цепочк|anomali|hvost)/i.test(lower);
    return {
        period: !hasPeriod,
        account: !hasAccount,
        documentOrObject: !hasDocumentOrObject,
        counterparty: !hasCounterparty,
        anomalyType: !hasAnomalyType
    };
}
function buildClarificationQuestions(input) {
    const questions = [];
    const shouldAsk = input.mode === "clarification_required" || input.coverageReport.clarification_needed_for.length > 0;
    if (!shouldAsk) {
        return questions;
    }
    if (input.missingAnchors.period) {
        questions.push("Уточните период проверки (например, 2020-06).");
    }
    if (input.missingAnchors.account) {
        questions.push("Уточните счет или группу счетов (например, 19, 60, 62).");
    }
    if (input.missingAnchors.documentOrObject) {
        questions.push("Укажите документ/GUID/конкретный объект для трассировки.");
    }
    if (input.missingAnchors.counterparty) {
        questions.push("Укажите контрагента или группу контрагентов.");
    }
    if (input.policySignals.broad_query_detected && input.missingAnchors.anomalyType) {
        questions.push("Уточните тип отклонения: разрыв цепочки, неверный документ или аномальный риск.");
    }
    if (input.coverageReport.clarification_needed_for.length > 0) {
        questions.push(`Закройте уточнения для требований: ${input.coverageReport.clarification_needed_for.join(", ")}.`);
    }
    return uniqueStrings(questions, 6);
}
function buildRecommendedActions(input) {
    const actions = [];
    if (input.mode === "focused_grounded") {
        actions.push("Проверьте 1-2 ключевые записи в учетной базе и зафиксируйте итог в рабочем файле проверки.");
    }
    if (input.mode === "broad_partial") {
        actions.push("Сузьте запрос до периода + счета или периода + документа и повторите проверку.");
    }
    if (input.mode === "clarification_required") {
        actions.push("Дайте недостающие якоря (период/счет/объект), иначе сильный factual вывод невозможен.");
    }
    if (input.coverageReport.requirements_uncovered.length > 0) {
        actions.push(`Закройте непокрытые требования: ${input.coverageReport.requirements_uncovered.join(", ")}.`);
    }
    if (input.coverageReport.requirements_partially_covered.length > 0) {
        actions.push(`Доуточните частично покрытые требования: ${input.coverageReport.requirements_partially_covered.join(", ")}.`);
    }
    if (input.policySignals.broad_query_detected && input.policySignals.narrowing_strength !== "strong") {
        actions.push("Добавьте более узкий контекст: тип отклонения, группу документов и бизнес-участок.");
    }
    if (input.limitationReasonCodes.includes("snapshot_only")) {
        actions.push("Сверьте критичные выводы с live source-of-record в 1C.");
    }
    if (input.limitationReasonCodes.includes("weak_source_mapping")) {
        actions.push("Проверьте source mapping для связей document/register по указанным ref.");
    }
    if (input.sourceRefs.length > 0) {
        actions.push(`Начните проверку с ${input.sourceRefs.length} подтвержденных записей и сверьте их с первичными документами.`);
    }
    return uniqueStrings(actions, 6);
}
function firstMeaningfulFact(results) {
    const facts = extractTopFacts(results);
    return facts.length > 0 ? facts[0] : null;
}
function buildPolicyDecision(input) {
    const hasCoverageGaps = input.coverageReport.requirements_uncovered.length > 0 ||
        input.coverageReport.requirements_partially_covered.length > 0 ||
        input.coverageReport.clarification_needed_for.length > 0 ||
        input.coverageReport.out_of_scope_requirements.length > 0;
    if (input.fallbackType === "out_of_scope" && input.coverageReport.requirements_covered === 0) {
        return {
            mode: "out_of_scope",
            fallback_type: "out_of_scope",
            reply_type: "out_of_scope"
        };
    }
    if (input.groundingCheck.status === "route_mismatch_blocked") {
        return {
            mode: "route_mismatch",
            fallback_type: "partial",
            reply_type: "route_mismatch_blocked"
        };
    }
    if ((input.policySignals.degraded_to === "clarification" && input.policySignals.minimum_evidence_failed) ||
        (input.fallbackType === "clarification" && !input.hasSupport) ||
        (input.groundingCheck.status === "no_grounded_answer" && !input.hasSupport)) {
        return {
            mode: "clarification_required",
            fallback_type: "clarification",
            reply_type: "clarification_required"
        };
    }
    if (input.errorResults.length > 0 && input.okResults.length === 0 && input.partialResults.length === 0) {
        return {
            mode: "backend_error",
            fallback_type: input.fallbackType,
            reply_type: "backend_error"
        };
    }
    if (input.okResults.length === 0 && input.partialResults.length === 0 && input.emptyResults.length > 0) {
        return {
            mode: "empty",
            fallback_type: input.fallbackType,
            reply_type: "empty_but_valid"
        };
    }
    if (input.groundingCheck.status === "no_grounded_answer" && input.okResults.length === 0 && input.partialResults.length === 0) {
        return {
            mode: "no_grounded",
            fallback_type: input.fallbackType,
            reply_type: "no_grounded_answer"
        };
    }
    if (input.focusedStrong &&
        !input.policySignals.broad_query_detected &&
        !input.policySignals.minimum_evidence_failed &&
        !hasCoverageGaps) {
        return {
            mode: "focused_grounded",
            fallback_type: "none",
            reply_type: "factual_with_explanation"
        };
    }
    if (input.okResults.length > 0 ||
        input.partialResults.length > 0 ||
        hasCoverageGaps ||
        input.policySignals.minimum_evidence_failed ||
        input.policySignals.broad_result_flag ||
        input.groundingCheck.status === "partial") {
        return {
            mode: "broad_partial",
            fallback_type: "partial",
            reply_type: "partial_coverage"
        };
    }
    return {
        mode: "backend_error",
        fallback_type: "unknown",
        reply_type: "backend_error"
    };
}
function buildAnswerSummary(mode) {
    if (mode === "focused_grounded")
        return "Сформирован прямой ответ на основе подтвержденной опоры.";
    if (mode === "broad_partial")
        return "Вывод ограничен: есть частичная опора, но не полный coverage.";
    if (mode === "clarification_required")
        return "Нужны уточнения: без сужения strong factual вывод ненадежен.";
    if (mode === "out_of_scope")
        return "Запрос вне доступного учетного контура.";
    if (mode === "route_mismatch")
        return "Результат маршрута не совпал с предметом вопроса.";
    if (mode === "empty")
        return "В текущем срезе данных релевантные записи не обнаружены.";
    if (mode === "no_grounded")
        return "Недостаточно опоры для обоснованного ответа.";
    return "Не удалось собрать обоснованный ответ по текущему запросу.";
}
function buildDirectAnswer(input) {
    const topFact = firstMeaningfulFact(input.retrievalResults);
    if (input.mode === "focused_grounded") {
        return topFact ?? "Подтвержденный результат получен; можно продолжать предметную проверку без деградации.";
    }
    if (input.mode === "broad_partial") {
        if (topFact) {
            return `Доступен ограниченный подтвержденный фрагмент: ${topFact}`;
        }
        return "Есть только ограниченная опора; вывод дан в частичном режиме без ложной точности.";
    }
    if (input.mode === "clarification_required") {
        return "Текущий запрос слишком широкий или недоопределен; надежный factual вывод пока невозможен.";
    }
    if (input.mode === "out_of_scope") {
        return "Могу отвечать только в пределах данных доступного учетного контура.";
    }
    if (input.mode === "route_mismatch") {
        return "Предмет результата не совпал с предметом вопроса; требуется уточнение фокуса.";
    }
    if (input.mode === "empty") {
        return "В текущем срезе данных проблемные записи по заданному условию не найдены.";
    }
    if (input.mode === "no_grounded") {
        return "Недостаточно подтвержденной опоры для ответа в требуемой точности.";
    }
    if (input.policySignals.minimum_evidence_failed) {
        return "Маршрут отработал, но минимальная evidence-опора не пройдена.";
    }
    return "Не удалось сформировать обоснованный ответ; нужно уточнение запроса.";
}
function buildProblemCentricAnswerSummary(input) {
    if (input.lifecycleEnriched && input.summary?.lifecycle_enriched_units && input.summary.lifecycle_enriched_units > 0) {
        if (input.mode === "clarification_required") {
            return "Выявлены lifecycle-дефекты, но для надежного вывода требуется уточнение предметных якорей.";
        }
        return `Сформирован lifecycle-aware problem срез: выделено ${input.summary.lifecycle_enriched_units} lifecycle-узлов с приоритетом по дефектам перехода.`;
    }
    if (input.mode === "clarification_required") {
        return "Выявлены проблемные кластеры, но для надежного вывода требуется предметное уточнение фокуса.";
    }
    if (input.weakUnits) {
        return "Сформирован problem-centric срез с ограниченной опорой; вывод предварительный и требует до-проверки.";
    }
    if (input.summary?.units_total && input.summary.units_total > 1) {
        return `Сформирован problem-centric срез: выделено ${input.summary.units_total} проблемных кластера с приоритетами.`;
    }
    return "Сформирован problem-centric срез: выделен ключевой проблемный кластер и затронутый контур.";
}
function buildProblemCentricDirectAnswer(input) {
    const lead = input.mode === "clarification_required"
        ? "Обнаружены проблемные зоны, но без уточнения якорей сильный factual-вывод преждевременен."
        : input.weakUnits
            ? "Выделены проблемные зоны с ограниченной надежностью; вывод дан в ограниченном режиме."
            : input.lifecycleAnswerEnabled && hasLifecycleResolution(input.units)
                ? "Выделены lifecycle-проблемы: определены текущие/ожидаемые стадии и тип нарушения перехода."
                : "Выделены ключевые проблемные зоны и их влияние на учетный контур.";
    const unitLines = input.units.map((unit) => {
        const scope = formatAffectedScope(unit);
        const lifecycleScope = input.lifecycleAnswerEnabled ? formatLifecycleScope(unit) : null;
        const lifecycleInterpretation = input.lifecycleAnswerEnabled ? unit.business_lifecycle_interpretation : null;
        const segments = [
            `${unit.title}: ${unit.business_defect_class}`,
            scope,
            lifecycleScope,
            lifecycleInterpretation,
            `severity=${unit.severity.grade}`,
            `confidence=${unit.confidence.grade}`,
            unit.lifecycle_confidence ? `lifecycle_confidence=${unit.lifecycle_confidence.grade}` : null
        ].filter((item) => Boolean(item));
        return `- ${segments.join("; ")}.`;
    });
    if (unitLines.length === 0) {
        return `${lead}\nПроблемные кластеры не удалось детализировать в текущем срезе.`;
    }
    return [lead, "Проблемные кластеры:", ...unitLines].join("\n");
}
function buildProblemCentricAnswerStructure(input) {
    const weakUnits = input.selectedUnits.every((item) => item.confidence.grade === "low");
    const lifecycleEnriched = input.lifecycleAnswerEnabled && hasLifecycleResolution(input.selectedUnits);
    const unitMechanismNotes = uniqueStrings(input.selectedUnits
        .map((item) => item.mechanism_summary)
        .filter((item) => typeof item === "string" && item.trim().length > 0), 6);
    const sourceRefs = uniqueStrings(input.evidenceItems
        .map((item) => item.source_ref?.canonical_ref)
        .filter((item) => typeof item === "string" && item.trim().length > 0), 6);
    const evidenceIds = uniqueStrings(input.evidenceItems.map((item) => item.evidence_id), 10);
    const mechanismStatus = unitMechanismNotes.length === 0
        ? "unresolved"
        : weakUnits || input.limitationReasonCodes.includes("missing_mechanism")
            ? "limited"
            : "grounded";
    const problemSpecificLimitations = [];
    if (weakUnits) {
        problemSpecificLimitations.push("Problem units remain weak-confidence; conclusions are intentionally limited.");
    }
    if (input.problemSummary?.duplicate_collapses && input.problemSummary.duplicate_collapses > 0) {
        problemSpecificLimitations.push("Part of the problem signal was merged due to duplicate collapse.");
    }
    const limitations = uniqueStrings([
        ...problemSpecificLimitations,
        ...input.limitationReasonCodes.map((code) => limitationReasonToText(code)),
        ...extractLimitations(input.retrievalResults),
        ...input.groundingCheck.reasons
    ], 10);
    const openUncertainties = uniqueStrings([
        ...input.groundingCheck.missing_requirements,
        ...(input.mode === "clarification_required" && input.missingAnchors.period ? ["missing_anchor:period"] : []),
        ...(input.mode === "clarification_required" && input.missingAnchors.account ? ["missing_anchor:account"] : []),
        ...(input.mode === "clarification_required" && input.missingAnchors.documentOrObject
            ? ["missing_anchor:document_or_object"]
            : []),
        ...(input.mode === "clarification_required" && input.missingAnchors.counterparty ? ["missing_anchor:counterparty"] : [])
    ], 8);
    return {
        schema_version: "answer_structure_v1_1",
        answer_summary: buildProblemCentricAnswerSummary({
            mode: input.mode,
            weakUnits,
            summary: input.problemSummary,
            lifecycleEnriched
        }),
        direct_answer: buildProblemCentricDirectAnswer({
            mode: input.mode,
            units: input.selectedUnits,
            weakUnits,
            lifecycleAnswerEnabled: input.lifecycleAnswerEnabled
        }),
        mechanism_block: {
            status: mechanismStatus,
            mechanism_notes: unitMechanismNotes,
            limitation_reason_codes: input.limitationReasonCodes
        },
        evidence_block: {
            evidence_ids: evidenceIds,
            source_refs: sourceRefs,
            mechanism_notes: unitMechanismNotes,
            coverage_note: input.coverageReport.requirements_total > 0 &&
                input.coverageReport.requirements_total === input.coverageReport.requirements_covered &&
                input.coverageReport.requirements_uncovered.length === 0 &&
                input.coverageReport.requirements_partially_covered.length === 0
                ? "coverage_full_or_near_full"
                : "coverage_partial_or_limited",
            ...(input.claimEvidenceLinks.length > 0
                ? {
                    claim_evidence_links: input.claimEvidenceLinks
                }
                : {})
        },
        uncertainty_block: {
            open_uncertainties: openUncertainties,
            limitations
        },
        next_step_block: {
            recommended_actions: buildProblemCentricActions({
                units: input.selectedUnits,
                mode: input.mode,
                missingAnchors: input.missingAnchors,
                coverageReport: input.coverageReport
            }),
            clarification_questions: buildProblemCentricClarifications({
                units: input.selectedUnits,
                missingAnchors: input.missingAnchors,
                coverageReport: input.coverageReport,
                mode: input.mode
            })
        }
    };
}
function renderPolicyReply(structure) {
    const mechanismLines = [`status=${structure.mechanism_block.status}`];
    if (structure.mechanism_block.mechanism_notes.length > 0) {
        mechanismLines.push(...structure.mechanism_block.mechanism_notes.map((item) => `note: ${item}`));
    }
    if (structure.mechanism_block.limitation_reason_codes.length > 0) {
        mechanismLines.push(`limitation_codes: ${structure.mechanism_block.limitation_reason_codes.join(", ")}`);
    }
    if (structure.mechanism_block.status === "unresolved" && structure.mechanism_block.mechanism_notes.length === 0) {
        mechanismLines.push("mechanism_note is intentionally omitted due to weak or missing mechanism evidence");
    }
    const sourceRefCount = Array.isArray(structure.evidence_block.source_refs) ? structure.evidence_block.source_refs.length : 0;
    const claimLinkCount = Array.isArray(structure.evidence_block.claim_evidence_links)
        ? structure.evidence_block.claim_evidence_links.length
        : 0;
    const evidenceLines = [
        `coverage=${structure.evidence_block.coverage_note}`,
        `supporting_evidence_count=${structure.evidence_block.evidence_ids.length}`,
        `supporting_source_count=${sourceRefCount}`,
        `claim_support_links=${claimLinkCount}`
    ];
    if (sourceRefCount > 0) {
        evidenceLines.push("Detailed source references are available in debug payload.");
    }
    const uncertaintyLines = [
        ...structure.uncertainty_block.open_uncertainties.map((item) => `open: ${item}`),
        ...structure.uncertainty_block.limitations.map((item) => `limit: ${item}`)
    ];
    if (uncertaintyLines.length === 0) {
        uncertaintyLines.push("No material uncertainty detected in current scoped answer.");
    }
    const nextStepLines = [
        ...structure.next_step_block.recommended_actions.map((item) => `action: ${item}`),
        ...structure.next_step_block.clarification_questions.map((item) => `clarify: ${item}`)
    ];
    if (nextStepLines.length === 0) {
        nextStepLines.push("No additional action is required for this scoped answer.");
    }
    return sanitizeUserFacingReply([
        `Answer summary: ${structure.answer_summary}`,
        `Direct answer:\n${structure.direct_answer}`,
        `Mechanism block:\n${formatList(mechanismLines)}`,
        `Evidence block:\n${formatList(evidenceLines)}`,
        `Uncertainty block:\n${formatList(uncertaintyLines)}`,
        `Next step block:\n${formatList(nextStepLines)}`
    ]
        .filter(Boolean)
        .join("\n\n"));
}
function composeAssistantAnswerV11(input) {
    const fallbackType = fallbackFromSummary(input.routeSummary);
    const okResults = input.retrievalResults.filter((item) => item.status === "ok");
    const partialResults = input.retrievalResults.filter((item) => item.status === "partial");
    const emptyResults = input.retrievalResults.filter((item) => item.status === "empty");
    const errorResults = input.retrievalResults.filter((item) => item.status === "error");
    const evidenceItems = flattenEvidence(input.retrievalResults);
    const policySignals = aggregatePolicySignals(input.retrievalResults);
    const limitationReasonCodes = collectLimitationReasonCodes(evidenceItems);
    const sourceRefs = uniqueStrings(evidenceItems
        .map((item) => item.source_ref?.canonical_ref)
        .filter((item) => typeof item === "string" && item.trim().length > 0), 8);
    const mechanismNotes = uniqueStrings(evidenceItems
        .map((item) => item.mechanism_note)
        .filter((item) => typeof item === "string" && item.trim().length > 0), 6);
    const lifecycleAnswerEnabled = Boolean(input.enableLifecycleAnswerV1);
    const problemUnits = flattenProblemUnits(input.retrievalResults);
    const problemUnitSummary = selectProblemUnitSummary(input.retrievalResults);
    const problemHeavyUnits = problemUnits.filter((item) => PROBLEM_HEAVY_TYPES.has(item.problem_unit_type));
    const selectedProblemUnits = rankProblemUnitsForAnswer(problemHeavyUnits, lifecycleAnswerEnabled).slice(0, 4);
    const claimEvidenceLinks = buildClaimEvidenceLinks(input.retrievalResults);
    const aggregateEvidenceConfidence = aggregateConfidence(input.retrievalResults, evidenceItems);
    const lowConfidenceSignals = evidenceItems.filter((item) => item.confidence === "low").length;
    const lowConfidenceShare = evidenceItems.length > 0 ? lowConfidenceSignals / evidenceItems.length : 0;
    const lowConfidenceConcentration = lowConfidenceShare >= 0.6;
    const hasSupport = okResults.length > 0 ||
        partialResults.length > 0 ||
        evidenceItems.length > 0 ||
        input.retrievalResults.some((item) => item.items.length > 0);
    const hasCoverageGaps = input.coverageReport.requirements_uncovered.length > 0 ||
        input.coverageReport.requirements_partially_covered.length > 0 ||
        input.coverageReport.clarification_needed_for.length > 0 ||
        input.coverageReport.out_of_scope_requirements.length > 0;
    const hasCriticalEvidenceLimitation = limitationReasonCodes.includes("weak_source_mapping") ||
        limitationReasonCodes.includes("insufficient_detail");
    const hasNonLowRouteConfidence = input.retrievalResults.some((item) => item.status === "ok" && item.confidence !== "low");
    const focusedStrong = okResults.length > 0 &&
        input.groundingCheck.status === "grounded" &&
        !hasCoverageGaps &&
        !policySignals.broad_query_detected &&
        !policySignals.broad_result_flag &&
        !policySignals.minimum_evidence_failed &&
        !hasCriticalEvidenceLimitation &&
        (aggregateEvidenceConfidence !== "low" || hasNonLowRouteConfidence);
    const decision = buildPolicyDecision({
        fallbackType,
        coverageReport: input.coverageReport,
        groundingCheck: input.groundingCheck,
        okResults,
        partialResults,
        emptyResults,
        errorResults,
        hasSupport,
        focusedStrong,
        policySignals
    });
    const missingAnchors = detectMissingAnchors(input.userMessage);
    const hasProblemWeakSignal = policySignals.narrowing_strength !== "strong" ||
        policySignals.minimum_evidence_failed ||
        limitationReasonCodes.includes("missing_mechanism") ||
        limitationReasonCodes.includes("weak_source_mapping") ||
        aggregateEvidenceConfidence === "low" ||
        lowConfidenceConcentration;
    const hardBlockedMode = decision.mode === "out_of_scope" || decision.mode === "route_mismatch" || decision.mode === "backend_error";
    const problemCentricModeEligible = decision.mode === "broad_partial" ||
        decision.mode === "clarification_required" ||
        (decision.mode === "focused_grounded" && hasProblemWeakSignal);
    const shouldUseProblemCentricAnswer = Boolean(input.enableProblemCentricAnswerV1) &&
        !hardBlockedMode &&
        problemCentricModeEligible &&
        (!focusedStrong || hasProblemWeakSignal) &&
        selectedProblemUnits.length > 0;
    if (shouldUseProblemCentricAnswer) {
        const problemCentricStructure = buildProblemCentricAnswerStructure({
            mode: decision.mode,
            selectedUnits: selectedProblemUnits,
            problemSummary: problemUnitSummary,
            evidenceItems,
            claimEvidenceLinks,
            limitationReasonCodes,
            groundingCheck: input.groundingCheck,
            retrievalResults: input.retrievalResults,
            missingAnchors,
            coverageReport: input.coverageReport,
            lifecycleAnswerEnabled
        });
        const lifecycleModeActive = lifecycleAnswerEnabled && hasLifecycleResolution(selectedProblemUnits);
        return {
            assistant_reply: renderPolicyReply(problemCentricStructure),
            fallback_type: decision.fallback_type,
            reply_type: decision.reply_type,
            answer_structure_v11: problemCentricStructure,
            problem_centric_answer_applied: true,
            problem_units_used_count: selectedProblemUnits.length,
            problem_answer_mode: lifecycleModeActive ? "stage3_lifecycle_aware_v1" : "stage2_problem_centric_v1",
            problem_unit_ids_used: selectedProblemUnits.map((item) => item.problem_unit_id)
        };
    }
    const clarificationQuestions = buildClarificationQuestions({
        mode: decision.mode,
        missingAnchors,
        coverageReport: input.coverageReport,
        policySignals
    });
    const recommendedActions = buildRecommendedActions({
        mode: decision.mode,
        coverageReport: input.coverageReport,
        policySignals,
        limitationReasonCodes,
        sourceRefs
    });
    const limitations = uniqueStrings([
        ...limitationReasonCodes.map((code) => limitationReasonToText(code)),
        ...extractLimitations(input.retrievalResults),
        ...input.groundingCheck.reasons,
        ...(policySignals.minimum_evidence_failed ? ["Minimum evidence gate failed for current scope."] : []),
        ...(policySignals.broad_query_detected && policySignals.narrowing_strength === "weak"
            ? ["Broad query remains weakly narrowed; precision is intentionally limited."]
            : [])
    ], 10);
    const openUncertainties = uniqueStrings([
        ...input.groundingCheck.missing_requirements,
        ...(decision.mode === "clarification_required" && missingAnchors.period ? ["missing_anchor:period"] : []),
        ...(decision.mode === "clarification_required" && missingAnchors.account ? ["missing_anchor:account"] : []),
        ...(decision.mode === "clarification_required" && missingAnchors.documentOrObject ? ["missing_anchor:document_or_object"] : []),
        ...(decision.mode === "clarification_required" && missingAnchors.counterparty ? ["missing_anchor:counterparty"] : [])
    ], 8);
    const mechanismStatus = mechanismNotes.length === 0
        ? "unresolved"
        : limitationReasonCodes.includes("missing_mechanism") || limitationReasonCodes.includes("heuristic_inference")
            ? "limited"
            : "grounded";
    const answerStructure = {
        schema_version: "answer_structure_v1_1",
        answer_summary: buildAnswerSummary(decision.mode),
        direct_answer: buildDirectAnswer({
            mode: decision.mode,
            retrievalResults: input.retrievalResults,
            policySignals
        }),
        mechanism_block: {
            status: mechanismStatus,
            mechanism_notes: mechanismNotes,
            limitation_reason_codes: limitationReasonCodes
        },
        evidence_block: {
            evidence_ids: uniqueStrings(evidenceItems.map((item) => item.evidence_id), 10),
            source_refs: sourceRefs,
            mechanism_notes: mechanismNotes,
            coverage_note: input.coverageReport.requirements_total > 0 &&
                input.coverageReport.requirements_total === input.coverageReport.requirements_covered &&
                input.coverageReport.requirements_uncovered.length === 0 &&
                input.coverageReport.requirements_partially_covered.length === 0
                ? "coverage_full_or_near_full"
                : "coverage_partial_or_limited",
            ...(claimEvidenceLinks.length > 0
                ? {
                    claim_evidence_links: claimEvidenceLinks
                }
                : {})
        },
        uncertainty_block: {
            open_uncertainties: openUncertainties,
            limitations
        },
        next_step_block: {
            recommended_actions: recommendedActions,
            clarification_questions: clarificationQuestions
        }
    };
    return {
        assistant_reply: renderPolicyReply(answerStructure),
        fallback_type: decision.fallback_type,
        reply_type: decision.reply_type,
        answer_structure_v11: answerStructure,
        problem_centric_answer_applied: false,
        problem_units_used_count: 0,
        problem_answer_mode: "stage1_policy_v11"
    };
}
function composeExplainableAnswer(input, scopeLabel) {
    const facts = extractTopFacts(input.retrievalResults);
    const whyIncludedRaw = extractWhyIncluded(input.retrievalResults);
    const selectionReasonsRaw = extractSelectionReasons(input.retrievalResults);
    const whyIncluded = whyIncludedRaw.length > 0 ? whyIncludedRaw : buildFallbackWhyIncluded(input.retrievalResults);
    const selectionReasons = selectionReasonsRaw.length > 0 ? selectionReasonsRaw : buildFallbackSelectionReasons(input.retrievalResults);
    const riskFactors = extractRiskFactors(input.retrievalResults);
    const interpretation = extractBusinessInterpretation(input.retrievalResults);
    const limitations = uniqueStrings([...extractLimitations(input.retrievalResults), ...input.groundingCheck.reasons]);
    const nextSteps = suggestNextStep(input.requirements, input.coverageReport);
    const lead = scopeLabel === "full"
        ? "Итог: запрос обработан по предмету, найденные объекты подтверждены данными контура."
        : "Итог: запрос обработан частично, ниже подтвержденная часть и ограничения.";
    return [
        lead,
        facts.length > 0 ? "Подтвержденные результаты:\n" + formatList(facts) : "",
        whyIncluded.length > 0 ? "Почему это попало в ответ:\n" + formatList(whyIncluded) : "",
        selectionReasons.length > 0 ? "Основание отбора:\n" + formatList(selectionReasons) : "",
        riskFactors.length > 0 ? "Подтверждающие признаки:\n" + formatList(riskFactors) : "",
        interpretation.length > 0 ? "Практический смысл:\n" + formatList(interpretation) : "",
        limitations.length > 0 ? "Ограничения:\n" + formatList(limitations) : "",
        nextSteps.length > 0 ? "Что проверить дальше:\n" + formatList(nextSteps) : ""
    ]
        .filter(Boolean)
        .join("\n\n");
}
function composeAssistantAnswer(input) {
    if (input.enableAnswerPolicyV11) {
        return composeAssistantAnswerV11(input);
    }
    const fallbackType = fallbackFromSummary(input.routeSummary);
    const okResults = input.retrievalResults.filter((item) => item.status === "ok");
    const partialResults = input.retrievalResults.filter((item) => item.status === "partial");
    const emptyResults = input.retrievalResults.filter((item) => item.status === "empty");
    const errorResults = input.retrievalResults.filter((item) => item.status === "error");
    const hasBroadMinimumEvidenceSignal = input.retrievalResults.some((item) => summaryBoolean(item, "broad_guard_applied") && summaryBoolean(item, "minimum_evidence_failed"));
    const hasBroadClarificationSignal = input.retrievalResults.some((item) => summaryBoolean(item, "broad_guard_applied") &&
        summaryBoolean(item, "minimum_evidence_failed") &&
        summaryString(item, "degraded_to") === "clarification");
    if (fallbackType === "out_of_scope" && input.coverageReport.requirements_covered === 0) {
        return {
            assistant_reply: "Я могу отвечать только по данным вашей учетной базы. Этот запрос выходит за рамки доступного контура.",
            fallback_type: "out_of_scope",
            reply_type: "out_of_scope"
        };
    }
    if (input.groundingCheck.status === "route_mismatch_blocked") {
        return {
            assistant_reply: [
                "Не отправляю финальный ответ, потому что предмет результата не совпал с предметом вопроса.",
                "Уточните формулировку (например, нужный счет/участок учета), и я выполню повторный проход."
            ].join("\n\n"),
            fallback_type: "partial",
            reply_type: "route_mismatch_blocked"
        };
    }
    if (input.groundingCheck.status === "no_grounded_answer" && okResults.length === 0 && !hasBroadMinimumEvidenceSignal) {
        return {
            assistant_reply: "Пока не удалось собрать предметно подтвержденный ответ по вашему вопросу. Нужны дополнительные уточнения по периоду или объекту проверки.",
            fallback_type: fallbackType,
            reply_type: "no_grounded_answer"
        };
    }
    if (hasBroadClarificationSignal && okResults.length === 0 && partialResults.length === 0) {
        return {
            assistant_reply: "Запрос слишком широкий для надежного вывода по текущей опоре. Уточните период, участок учета или объект проверки, после чего я дам предметный результат.",
            fallback_type: "clarification",
            reply_type: "clarification_required"
        };
    }
    if (fallbackType === "clarification" && okResults.length === 0 && partialResults.length === 0) {
        return {
            assistant_reply: "Уточните, пожалуйста, период, счет, документ или контрагента, чтобы закрыть все части вопроса корректно.",
            fallback_type: "clarification",
            reply_type: "clarification_required"
        };
    }
    if (errorResults.length > 0 && okResults.length === 0 && partialResults.length === 0) {
        return {
            assistant_reply: "Не удалось получить данные из контура. Попробуйте повторить запрос или уточнить формулировку.",
            fallback_type: fallbackType,
            reply_type: "backend_error"
        };
    }
    if (partialResults.length > 0 && okResults.length === 0) {
        return {
            assistant_reply: composeExplainableAnswer(input, "partial"),
            fallback_type: "partial",
            reply_type: "partial_coverage"
        };
    }
    if (okResults.length === 0 && partialResults.length === 0 && emptyResults.length > 0) {
        return {
            assistant_reply: "По заданному условию в текущем срезе данных явных проблемных записей не найдено.",
            fallback_type: fallbackType,
            reply_type: "empty_but_valid"
        };
    }
    const hasPartialCoverage = input.coverageReport.requirements_uncovered.length > 0 ||
        input.coverageReport.requirements_partially_covered.length > 0 ||
        input.coverageReport.clarification_needed_for.length > 0 ||
        input.coverageReport.out_of_scope_requirements.length > 0 ||
        input.groundingCheck.status === "partial" ||
        errorResults.length > 0;
    if (okResults.length > 0 && hasPartialCoverage) {
        return {
            assistant_reply: composeExplainableAnswer(input, "partial"),
            fallback_type: "partial",
            reply_type: "partial_coverage"
        };
    }
    if (okResults.length > 0) {
        return {
            assistant_reply: composeExplainableAnswer(input, "full"),
            fallback_type: "none",
            reply_type: "factual_with_explanation"
        };
    }
    return {
        assistant_reply: "По текущему запросу не удалось построить обоснованный ответ. Уточните формулировку и попробуйте снова.",
        fallback_type: "unknown",
        reply_type: "backend_error"
    };
}
