diff --git a/docs/orchestration/agent_business_overview_counterparty_reliability_20260524.json b/docs/orchestration/agent_business_overview_counterparty_reliability_20260524.json new file mode 100644 index 0000000..91b020f --- /dev/null +++ b/docs/orchestration/agent_business_overview_counterparty_reliability_20260524.json @@ -0,0 +1,276 @@ +{ + "schema_version": "domain_scenario_pack_v1", + "pack_id": "agent_business_overview_counterparty_reliability_20260524", + "domain": "agent_business_overview_counterparty_reliability", + "title": "Agent business overview and counterparty documents reliability proof", + "description": "Focused proof pack for business-useful company overview, money flow, VAT/document boundaries, all-time scope reset, and explicit SVK counterparty document separation.", + "analysis_context": { + "as_of_date": "2026-05-24", + "source": "agent_reliability_uplift_business_overview_counterparty_slice" + }, + "bindings": { + "main_organization": "ООО Альтернатива Плюс", + "control_year": "2020", + "svk_counterparty": "Группа СВК" + }, + "scenarios": [ + { + "scenario_id": "company_business_overview_scope", + "title": "Company overview, money flow, VAT boundary, and all-time scope reset", + "description": "Validates that the assistant can answer a broad business question directly, keep period scope honest, and reset from 2020 to all available time without carrying stale tax claims.", + "steps": [ + { + "step_id": "s01_business_overview_2020", + "title": "Direct business overview for the company and year", + "node_role": "root", + "question": "Дай взрослый бизнес-обзор {{bindings.main_organization}} за {{bindings.control_year}} год по данным 1С: обороты, входящие и исходящие деньги, нетто, НДС, долги, склад, клиенты, поставщики и что пока нельзя утверждать.", + "expected_intents": ["business_overview"], + "semantic_tags": ["business_overview", "money", "vat", "debt", "inventory", "scope_guard"], + "required_answer_shape": "direct_answer_first", + "required_answer_patterns_all": [ + "Альтернатива", + "2020" + ], + "forbidden_answer_patterns": [ + "(?i)capability_id", + "(?i)selected_chain_id", + "(?i)runtime_", + "(?i)business_overview_route_template_v1", + "(?i)mcp_discovery" + ] + }, + { + "step_id": "s02_money_followup", + "title": "Money follow-up with counterparty highlights", + "question": "Раскрой деньги подробнее: сколько получили, сколько заплатили, какой чистый денежный поток, кто главный клиент и главный поставщик в {{bindings.control_year}}.", + "depends_on": ["s01_business_overview_2020"], + "semantic_tags": ["money", "counterparty", "scope_guard"], + "required_answer_shape": "direct_answer_first", + "required_answer_patterns_all": [ + "2020" + ], + "forbidden_answer_patterns": [ + "(?i)capability_id", + "(?i)runtime_" + ] + }, + { + "step_id": "s03_vat_documents_boundary", + "title": "VAT and document evidence boundary", + "question": "Что с НДС за {{bindings.control_year}} год по {{bindings.main_organization}}: какая позиция видна, на чем она основана и чего не хватает для налогового вывода?", + "depends_on": ["s02_money_followup"], + "semantic_tags": ["vat", "documents", "scope_guard"], + "required_answer_shape": "direct_answer_first", + "required_answer_patterns_all": [ + "НДС", + "2020" + ], + "forbidden_answer_patterns": [ + "(?i)capability_id", + "(?i)runtime_", + "(?i)точно подтвержден.*налогов" + ] + }, + { + "step_id": "s04_all_time_scope_reset", + "title": "All-time company overview without stale VAT carryover", + "question": "Теперь за все доступное время дай обзор компании в целом, но не тащи НДС за {{bindings.control_year}} как подтвержденную общую налоговую позицию.", + "depends_on": ["s03_vat_documents_boundary"], + "semantic_tags": ["business_overview", "vat", "scope_guard"], + "required_answer_shape": "direct_answer_first", + "required_answer_patterns_all": [ + "доступн", + "НДС" + ], + "forbidden_answer_patterns": [ + "(?i)capability_id", + "(?i)runtime_", + "(?i)НДС за 2020.*общая налоговая позиция" + ] + } + ] + }, + { + "scenario_id": "svk_counterparty_documents_scope", + "title": "Explicit SVK counterparty money and document scope", + "description": "Validates that an explicit counterparty request is not confused with company overview context and that document evidence is separated from business conclusions.", + "steps": [ + { + "step_id": "s01_svk_money_documents", + "title": "Explicit counterparty money flow and evidence", + "node_role": "root", + "question": "Отдельно по контрагенту {{bindings.svk_counterparty}}, без опоры на прошлый диалог: сколько денег прошло, что входящее, что исходящее и есть ли документы или движения, на которых это основано?", + "expected_intents": ["value_flow"], + "semantic_tags": ["counterparty", "money", "documents", "scope_guard"], + "required_answer_shape": "direct_answer_first", + "required_answer_patterns_all": [ + "СВК" + ], + "forbidden_answer_patterns": [ + "(?i)capability_id", + "(?i)selected_chain_id", + "(?i)runtime_", + "(?i)mcp_discovery", + "(?i)Альтернатива Плюс.*контрагент" + ] + }, + { + "step_id": "s02_svk_documents_followup", + "title": "Counterparty documents follow-up", + "question": "Покажи документы по этой цепочке и не смешивай {{bindings.svk_counterparty}} с организацией {{bindings.main_organization}}.", + "depends_on": ["s01_svk_money_documents"], + "semantic_tags": ["counterparty", "documents", "scope_guard"], + "required_answer_shape": "direct_answer_first", + "required_answer_patterns_all": [ + "СВК" + ], + "forbidden_answer_patterns": [ + "(?i)capability_id", + "(?i)runtime_", + "(?i)Альтернатива Плюс.*как контрагент" + ] + }, + { + "step_id": "s03_company_vs_svk_summary", + "title": "Separate company and counterparty conclusions", + "question": "Собери короткий итог: что мы подтвердили по компании, что отдельно по {{bindings.svk_counterparty}}, какие выводы можно делать и какие нельзя.", + "depends_on": ["s01_svk_money_documents", "s02_svk_documents_followup"], + "semantic_tags": ["business_overview", "counterparty", "scope_guard"], + "required_answer_shape": "direct_answer_first", + "required_answer_patterns_all": [ + "СВК", + "компан" + ], + "forbidden_answer_patterns": [ + "(?i)capability_id", + "(?i)runtime_" + ] + } + ] + }, + { + "scenario_id": "company_business_overview_colloquial_scope", + "title": "Colloquial company overview and money follow-up", + "description": "Adds colloquial wording coverage for the same company-level business overview edge without changing the business contract.", + "steps": [ + { + "step_id": "s01_colloquial_company_overview_2020", + "title": "Colloquial business overview for the company", + "node_role": "root", + "question": "По-человечески посмотри {{bindings.main_organization}} за {{bindings.control_year}}: что по бизнесу видно в 1С по деньгам, НДС, долгам, складу, клиентам/поставщикам и где пока нельзя делать вывод?", + "expected_intents": ["business_overview"], + "semantic_tags": ["business_overview", "colloquial", "money", "vat", "debt", "inventory", "scope_guard"], + "required_answer_shape": "direct_answer_first", + "required_answer_patterns_all": [ + "2020", + "НДС" + ], + "forbidden_answer_patterns": [ + "(?i)capability_id", + "(?i)selected_chain_id", + "(?i)runtime_", + "(?i)mcp_discovery" + ] + }, + { + "step_id": "s02_colloquial_money_leaders", + "title": "Colloquial money leaders follow-up", + "question": "А по деньгам в этом же году кто больше всего занес и кому больше всего ушло? Банк не называй обычным клиентом без оговорки.", + "depends_on": ["s01_colloquial_company_overview_2020"], + "semantic_tags": ["money", "counterparty", "colloquial", "scope_guard"], + "required_answer_shape": "direct_answer_first", + "required_answer_patterns_all": [ + "2020" + ], + "forbidden_answer_patterns": [ + "(?i)capability_id", + "(?i)runtime_" + ] + } + ] + }, + { + "scenario_id": "svk_selected_object_followup_scope", + "title": "Selected-object style SVK counterparty follow-up", + "description": "Adds pronoun and selected-object style coverage for the SVK counterparty edge: root counterparty fact, documents by selected object, and separated summary.", + "steps": [ + { + "step_id": "s01_select_svk_counterparty_money", + "title": "Select SVK as the active counterparty", + "node_role": "root", + "question": "Возьми как выбранного контрагента {{bindings.svk_counterparty}}: сколько по нему входящих денег, исходящих денег и расчетное нетто, на чем это основано?", + "expected_intents": ["value_flow"], + "semantic_tags": ["counterparty", "money", "selected_object", "scope_guard"], + "required_answer_shape": "direct_answer_first", + "required_answer_patterns_all": [ + "СВК" + ], + "forbidden_answer_patterns": [ + "(?i)capability_id", + "(?i)selected_chain_id", + "(?i)runtime_", + "(?i)mcp_discovery" + ] + }, + { + "step_id": "s02_pronoun_documents_for_selected_svk", + "title": "Documents for the selected counterparty by pronoun", + "question": "Теперь по нему покажи документы и не переключайся на организацию.", + "depends_on": ["s01_select_svk_counterparty_money"], + "semantic_tags": ["counterparty", "documents", "selected_object", "pronoun_followup", "scope_guard"], + "required_answer_shape": "direct_answer_first", + "required_answer_patterns_all": [ + "СВК" + ], + "forbidden_answer_patterns": [ + "(?i)capability_id", + "(?i)runtime_", + "(?i)Альтернатива Плюс.*как контрагент" + ] + }, + { + "step_id": "s03_selected_svk_company_boundary_summary", + "title": "Boundary summary after selected-object document follow-up", + "question": "И коротко сравни: что у нас подтверждено по компании, что отдельно по выбранному контрагенту, и какие выводы нельзя делать?", + "depends_on": ["s01_select_svk_counterparty_money", "s02_pronoun_documents_for_selected_svk"], + "semantic_tags": ["business_overview", "counterparty", "selected_object", "scope_guard"], + "required_answer_shape": "direct_answer_first", + "required_answer_patterns_all": [ + "СВК", + "компан" + ], + "forbidden_answer_patterns": [ + "(?i)capability_id", + "(?i)runtime_" + ] + }, + { + "step_id": "s04_org_clarification_boundary_summary", + "title": "Complete boundary summary after organization clarification", + "question": "{{bindings.main_organization}}", + "depends_on": [ + "s03_selected_svk_company_boundary_summary" + ], + "semantic_tags": [ + "business_overview", + "counterparty", + "selected_object", + "organization_clarification", + "scope_guard" + ], + "required_answer_shape": "direct_answer_first", + "required_answer_patterns_all": [ + "Альтернатива Плюс", + "СВК", + "Нельзя" + ], + "forbidden_answer_patterns": [ + "(?i)capability_id", + "(?i)runtime_", + "(?i)mcp_discovery" + ] + } + ] +} + ] +} diff --git a/llm_normalizer/backend/dist/services/addressIntentResolver.js b/llm_normalizer/backend/dist/services/addressIntentResolver.js index bfa795a..f6c8df8 100644 --- a/llm_normalizer/backend/dist/services/addressIntentResolver.js +++ b/llm_normalizer/backend/dist/services/addressIntentResolver.js @@ -1664,6 +1664,27 @@ function hasBidirectionalValueFlowComparisonSignal(text) { const hasNetAmountCue = /(?:сколько|сумм|итог|нетто|сальдо|минус|net|total|sum)/iu.test(normalized); return hasIncomingCue && hasOutgoingCue && hasComparisonCue && (hasValueFlowCue || hasNetAmountCue); } +function countBroadBusinessOverviewBridgeAxes(text) { + const axisPatterns = [ + /(?:\u0434\u0435\u043d\p{L}*|\u043e\u0431\u043e\u0440\u043e\u0442|\u0432\u044b\u0440\u0443\u0447\p{L}*|\u043f\u043e\u0441\u0442\u0443\u043f\p{L}*|\u043f\u043b\u0430\u0442\p{L}*|money|cash|revenue|turnover)/iu, + /(?:\u043d\u0434\u0441|vat)/iu, + /(?:\u0434\u043e\u043b\p{L}*|\u0434\u0435\u0431\u0438\u0442\u043e\u0440\p{L}*|\u043a\u0440\u0435\u0434\u0438\u0442\u043e\u0440\p{L}*|receivable|payable|debt)/iu, + /(?:\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u0442\u043e\u0432\u0430\u0440|warehouse|stock|inventory)/iu, + /(?:\u043a\u043b\u0438\u0435\u043d\u0442|\u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b|\u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a|customer|client|buyer)/iu, + /(?:\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a|\u0432\u0435\u043d\u0434\u043e\u0440|\u0437\u0430\u043a\u0443\u043f|supplier|vendor|procurement)/iu, + /(?:\u0433\u0434\u0435[\s\S]{0,80}(?:\u043d\u0435\u043b\u044c\u0437\u044f|\u043d\u0435\s+\u0434\u0435\u043b\u0430\p{L}*|\u043d\u0435\s+\u0445\u0432\u0430\p{L}*)|\u0447\u0442\u043e[\s\S]{0,80}(?:\u043d\u0435\u043b\u044c\u0437\u044f|\u043d\u0435\s+\u0445\u0432\u0430\p{L}*)|cannot|unknown|missing|limitation)/iu + ]; + return axisPatterns.reduce((count, pattern) => count + (pattern.test(text) ? 1 : 0), 0); +} +function hasBroadBusinessOverviewBridgeSignal(text) { + const normalized = String(text ?? "").trim().toLowerCase(); + if (!normalized) { + return false; + } + const hasBroadCue = /(?:\u043f\u043e[-\s]*\u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\p{L}*|\u0447\u0442\u043e\s+\u043f\u043e\s+\u0431\u0438\u0437\u043d\u0435\u0441\u0443\s+\u0432\u0438\u0434\u043d\p{L}*|\u043f\u043e\u0441\u043c\u043e\u0442\p{L}*[\s\S]{0,100}(?:\u0431\u0438\u0437\u043d\u0435\u0441|\u0434\u0435\u044f\u0442\u0435\u043b\p{L}*)|\u0431\u0438\u0437\u043d\u0435\u0441[\s\S]{0,80}(?:\u0432\u0438\u0434\u043d\p{L}*|\u0432\u044b\u0432\u043e\u0434|\u0441\u0440\u0435\u0437)|human\s+readable\s+business\s+view)/iu.test(normalized); + const hasCompanyScope = /(?:\u043e\u043e\u043e|\u0438\u043f|\u0430\u043e|\u043f\u0430\u043e|\u0437\u0430\u043e|\u043e\u0430\u043e|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+1\s?\u0441|1\s?c|company|organization|business|(?:19|20)\d{2})/iu.test(normalized); + return hasBroadCue && hasCompanyScope && countBroadBusinessOverviewBridgeAxes(normalized) >= 3; +} function hasNomenclatureMarginRankingSignal(text) { const normalized = String(text ?? "").trim().toLowerCase(); if (!normalized) { @@ -1776,6 +1797,9 @@ function resolveUnicodeAddressIntentBridge(text) { if (!hasContractCue && (hasTopYearRevenueRankingCue || hasCustomerRevenueRankingBridgeSignal(normalized))) { return unicodeBridgeResolution("customer_revenue_and_payments", "high", "unicode_customer_revenue_ranking_bridge_signal_detected"); } + if (hasBroadBusinessOverviewBridgeSignal(normalized)) { + return unicodeBridgeResolution("unknown", "high", "unicode_business_overview_multi_surface_deferred_to_discovery"); + } if (hasOrganizationLevelEarningsOverviewBridgeSignal(normalized)) { return unicodeBridgeResolution("unknown", "high", "unicode_business_overview_earnings_deferred_to_discovery"); } diff --git a/llm_normalizer/backend/dist/services/addressNavigationState.js b/llm_normalizer/backend/dist/services/addressNavigationState.js index 790096f..1b6593f 100644 --- a/llm_normalizer/backend/dist/services/addressNavigationState.js +++ b/llm_normalizer/backend/dist/services/addressNavigationState.js @@ -11,6 +11,7 @@ const MAX_RESULT_SETS = 40; const MAX_NAVIGATION_EVENTS = 120; const MAX_ENTITY_REFS_PER_RESULT_SET = 40; const DISPLAY_ENTITY_TYPE_BY_INTENT = { + business_overview: "organization", counterparty_activity_lifecycle: "counterparty", customer_revenue_and_payments: "counterparty", supplier_payouts_profile: "counterparty", @@ -33,6 +34,7 @@ const DISPLAY_ENTITY_TYPE_BY_INTENT = { inventory_aging_by_purchase_date: "item" }; const RESULT_SET_TYPE_BY_INTENT = { + business_overview: "profile_summary", counterparty_activity_lifecycle: "counterparty_list", customer_revenue_and_payments: "counterparty_list", supplier_payouts_profile: "counterparty_list", @@ -69,6 +71,18 @@ function toObject(value) { } return value; } +function cloneRecord(value) { + const record = toObject(value); + if (!record) { + return null; + } + try { + return JSON.parse(JSON.stringify(record)); + } + catch { + return { ...record }; + } +} function toNonEmptyString(value) { if (typeof value !== "string") { return null; @@ -76,6 +90,40 @@ function toNonEmptyString(value) { const trimmed = value.trim(); return trimmed.length > 0 ? trimmed : null; } +function candidateLabel(value) { + const direct = toNonEmptyString(value); + if (direct && direct !== "[object Object]") { + return direct; + } + const record = toObject(value); + if (!record) { + return null; + } + return (toNonEmptyString(record.value) ?? + toNonEmptyString(record.name) ?? + toNonEmptyString(record.ref) ?? + toNonEmptyString(record.text)); +} +function readNavigationDiscoveryCounterparty(debug) { + const entry = toObject(debug.assistant_mcp_discovery_entry_point_v1); + const turnInput = toObject(entry?.turn_input); + const turnMeaning = toObject(turnInput?.turn_meaning_ref); + const dataNeedGraph = toObject(turnInput?.data_need_graph); + const candidates = [ + ...(Array.isArray(turnMeaning?.business_overview_separate_entity_candidates) + ? turnMeaning.business_overview_separate_entity_candidates + : []), + ...(Array.isArray(turnMeaning?.explicit_entity_candidates) ? turnMeaning.explicit_entity_candidates : []), + ...(Array.isArray(dataNeedGraph?.subject_candidates) ? dataNeedGraph.subject_candidates : []) + ]; + for (const candidate of candidates) { + const label = candidateLabel(candidate); + if (label) { + return label; + } + } + return null; +} function toAddressFocusObjectType(value) { const normalized = toNonEmptyString(value); if (!normalized) { @@ -194,6 +242,21 @@ function cloneFocusObject(value) { selected_at: value.selected_at }; } +function cloneComparisonProofBundles(value) { + const record = toObject(value); + if (!record) { + return null; + } + const counterpartyValueFlowBundle = cloneRecord(record.counterparty_value_flow_bundle ?? record.previous_counterparty_value_flow_bundle); + const counterpartyDocumentBundle = cloneRecord(record.counterparty_document_bundle ?? record.previous_counterparty_document_bundle); + if (!counterpartyValueFlowBundle && !counterpartyDocumentBundle) { + return null; + } + return { + counterparty_value_flow_bundle: counterpartyValueFlowBundle, + counterparty_document_bundle: counterpartyDocumentBundle + }; +} function cloneResultSet(input) { return { result_set_id: input.result_set_id, @@ -252,8 +315,63 @@ function buildFocusObject(objectType, label, resultSetId, createdAt) { selected_at: createdAt }; } +function cloneComparisonScope(value) { + if (!value || typeof value !== "object") { + return null; + } + return { + organization: cloneFocusObject(value.organization), + counterparty: cloneFocusObject(value.counterparty), + proof_bundles: cloneComparisonProofBundles(value.proof_bundles) + }; +} +function sameBusinessLabel(left, right) { + const normalizedLeft = toNonEmptyString(left)?.toLocaleLowerCase("ru-RU"); + const normalizedRight = toNonEmptyString(right)?.toLocaleLowerCase("ru-RU"); + return Boolean(normalizedLeft && normalizedRight && normalizedLeft === normalizedRight); +} +function readBusinessOverviewComparisonProofBundles(debug) { + const entryPoint = toObject(debug.assistant_mcp_discovery_entry_point_v1); + const turnInput = toObject(entryPoint?.turn_input); + const turnMeaning = toObject(turnInput?.turn_meaning_ref); + const bridge = toObject(entryPoint?.bridge); + const pilot = toObject(bridge?.pilot); + const counterpartyValueFlowBundle = cloneRecord(turnMeaning?.previous_counterparty_value_flow_bundle) ?? + cloneRecord(pilot?.derived_bidirectional_value_flow); + const counterpartyDocumentBundle = cloneRecord(turnMeaning?.previous_counterparty_document_bundle); + const counterparty = toNonEmptyString(counterpartyValueFlowBundle?.counterparty) ?? + toNonEmptyString(counterpartyDocumentBundle?.counterparty) ?? + readNavigationDiscoveryCounterparty(debug); + if (!counterparty) { + return null; + } + if (!counterpartyValueFlowBundle && !counterpartyDocumentBundle) { + return null; + } + return { + counterparty_value_flow_bundle: counterpartyValueFlowBundle, + counterparty_document_bundle: counterpartyDocumentBundle + }; +} function buildFocusObjectFromDebug(debug, resultSetId, createdAt) { const extractedFilters = toObject(debug.extracted_filters) ?? {}; + const selectedDiscoveryChain = toNonEmptyString(debug.mcp_discovery_selected_chain_id); + if (selectedDiscoveryChain === "business_overview" && debug.mcp_discovery_response_applied === true) { + const counterparty = (0, assistantContinuityPolicy_1.readAddressDebugCounterparty)(debug, toNonEmptyString) ?? readNavigationDiscoveryCounterparty(debug); + if (counterparty) { + return buildFocusObject("counterparty", counterparty, resultSetId, createdAt); + } + const organization = (0, assistantContinuityPolicy_1.readAddressDebugOrganization)(debug, toNonEmptyString); + if (organization) { + return buildFocusObject("organization", organization, resultSetId, createdAt); + } + } + if (selectedDiscoveryChain === "value_flow_comparison" && debug.mcp_discovery_response_applied === true) { + const counterparty = (0, assistantContinuityPolicy_1.readAddressDebugCounterparty)(debug, toNonEmptyString) ?? readNavigationDiscoveryCounterparty(debug); + if (counterparty) { + return buildFocusObject("counterparty", counterparty, resultSetId, createdAt); + } + } const objectType = toAddressFocusObjectType(debug.anchor_type); const canonicalType = objectType === "unknown" ? inferDisplayEntityType(toAddressIntent(debug.detected_intent)) : objectType; if (canonicalType === "item") { @@ -282,9 +400,13 @@ function capNavigationEvents(events) { return events.slice(events.length - MAX_NAVIGATION_EVENTS); } function isAddressAssistantItem(item) { - return (item.role === "assistant" && - Boolean(item.debug) && - toNonEmptyString(item.debug?.detected_mode) === "address_query"); + if (item.role !== "assistant" || !item.debug) { + return false; + } + if (toNonEmptyString(item.debug.detected_mode) === "address_query") { + return true; + } + return item.debug.mcp_discovery_response_applied === true && Boolean(toNonEmptyString(item.debug.mcp_discovery_selected_chain_id)); } function createEmptyAddressNavigationState(sessionId, nowIso = new Date().toISOString()) { return { @@ -294,6 +416,7 @@ function createEmptyAddressNavigationState(sessionId, nowIso = new Date().toISOS session_context: { active_result_set_id: null, active_focus_object: null, + comparison_scope: null, last_confirmed_route: null, date_scope: { as_of_date: null, @@ -317,6 +440,7 @@ function cloneAddressNavigationState(value) { session_context: { active_result_set_id: value.session_context.active_result_set_id, active_focus_object: cloneFocusObject(value.session_context.active_focus_object), + comparison_scope: cloneComparisonScope(value.session_context.comparison_scope), last_confirmed_route: value.session_context.last_confirmed_route, date_scope: { as_of_date: value.session_context.date_scope.as_of_date, @@ -347,6 +471,7 @@ function normalizeAddressNavigationState(value, sessionId) { session_context: { active_result_set_id: toNonEmptyString(context.active_result_set_id), active_focus_object: cloneFocusObject(context.active_focus_object), + comparison_scope: cloneComparisonScope(context.comparison_scope), last_confirmed_route: toNonEmptyString(context.last_confirmed_route), date_scope: { as_of_date: toNonEmptyString(dateScope.as_of_date), @@ -400,21 +525,40 @@ function evolveAddressNavigationStateWithAssistantItem(state, item, turnIndex) { return state; } const debug = item.debug; - const intent = toAddressIntent(debug.detected_intent); - if (intent === "unknown") { + const selectedDiscoveryChain = toNonEmptyString(debug.mcp_discovery_selected_chain_id); + const discoveryIntent = selectedDiscoveryChain === "business_overview" + ? "business_overview" + : selectedDiscoveryChain === "value_flow_comparison" + ? "customer_revenue_and_payments" + : "unknown"; + const detectedIntent = toNonEmptyString(debug.detected_intent); + const intent = toAddressIntent(detectedIntent && detectedIntent !== "unknown" ? detectedIntent : discoveryIntent); + const trackableDiscoveryTurn = debug.mcp_discovery_response_applied === true && Boolean(selectedDiscoveryChain); + if (intent === "unknown" && !trackableDiscoveryTurn) { return state; } const createdAt = toNonEmptyString(item.created_at) ?? new Date().toISOString(); const resultSetId = `rs-${item.message_id}`; - const routeId = toNonEmptyString(debug.selected_recipe); + const routeId = toNonEmptyString(debug.selected_recipe) ?? selectedDiscoveryChain; const filters = normalizeFilters(debug.extracted_filters); - const derivedOrganizationScope = resolveDerivedOrganizationScope(debug, filters, item.text); + const derivedOrganizationScope = resolveDerivedOrganizationScope(debug, filters, item.text) ?? (0, assistantContinuityPolicy_1.readAddressDebugOrganization)(debug, toNonEmptyString); + const derivedCounterpartyScope = selectedDiscoveryChain === "value_flow_comparison" && debug.mcp_discovery_response_applied === true + ? (0, assistantContinuityPolicy_1.readAddressDebugCounterparty)(debug, toNonEmptyString) ?? readNavigationDiscoveryCounterparty(debug) + : null; const filtersWithDerivedScope = derivedOrganizationScope && !toNonEmptyString(filters.organization) ? { ...filters, - organization: derivedOrganizationScope + organization: derivedOrganizationScope, + ...(derivedCounterpartyScope && !toNonEmptyString(filters.counterparty) + ? { counterparty: derivedCounterpartyScope } + : {}) } - : filters; + : derivedCounterpartyScope && !toNonEmptyString(filters.counterparty) + ? { + ...filters, + counterparty: derivedCounterpartyScope + } + : filters; const sourceRefs = routeId ? [routeId] : []; const entityRefs = extractEntityRefsFromAssistantReply(item.text, intent); const resultSet = { @@ -430,6 +574,34 @@ function evolveAddressNavigationStateWithAssistantItem(state, item, turnIndex) { }; const previousResultSetId = state.session_context.active_result_set_id; const focusObject = buildFocusObjectFromDebug(debug, resultSetId, createdAt); + const comparisonCounterparty = selectedDiscoveryChain === "business_overview" && debug.mcp_discovery_response_applied === true + ? readNavigationDiscoveryCounterparty(debug) + : null; + const comparisonOrganization = selectedDiscoveryChain === "business_overview" && debug.mcp_discovery_response_applied === true + ? derivedOrganizationScope ?? toNonEmptyString(filtersWithDerivedScope.organization) + : null; + const currentComparisonProofBundles = selectedDiscoveryChain === "business_overview" && debug.mcp_discovery_response_applied === true + ? readBusinessOverviewComparisonProofBundles(debug) + : null; + const inheritedComparisonScope = state.session_context.comparison_scope; + const inheritedComparisonProofBundles = comparisonCounterparty && + sameBusinessLabel(inheritedComparisonScope?.counterparty?.label, comparisonCounterparty) + ? cloneComparisonProofBundles(inheritedComparisonScope?.proof_bundles) + : null; + const comparisonProofBundles = currentComparisonProofBundles ?? inheritedComparisonProofBundles; + const comparisonOrganizationObject = comparisonOrganization + ? buildFocusObject("organization", comparisonOrganization, resultSetId, createdAt) + : cloneFocusObject(inheritedComparisonScope?.organization ?? null); + const comparisonCounterpartyObject = comparisonCounterparty + ? buildFocusObject("counterparty", comparisonCounterparty, resultSetId, createdAt) + : cloneFocusObject(inheritedComparisonScope?.counterparty ?? null); + const comparisonScope = comparisonOrganizationObject || comparisonCounterpartyObject || comparisonProofBundles + ? { + organization: comparisonOrganizationObject, + counterparty: comparisonCounterpartyObject, + proof_bundles: comparisonProofBundles + } + : null; const action = resolveNavigationAction(debug, Boolean(focusObject)); const navigationEvent = { event_id: `nav-${(0, nanoid_1.nanoid)(10)}`, @@ -440,10 +612,11 @@ function evolveAddressNavigationStateWithAssistantItem(state, item, turnIndex) { turn_index: turnIndex, created_at: createdAt }; + const discoveryTemporalScope = (0, assistantContinuityPolicy_1.readAddressDebugTemporalScope)(debug, toNonEmptyString); const normalizedDateScope = { - as_of_date: toNonEmptyString(filtersWithDerivedScope.as_of_date), - period_from: toNonEmptyString(filtersWithDerivedScope.period_from), - period_to: toNonEmptyString(filtersWithDerivedScope.period_to) + as_of_date: toNonEmptyString(filtersWithDerivedScope.as_of_date) ?? discoveryTemporalScope.asOfDate, + period_from: toNonEmptyString(filtersWithDerivedScope.period_from) ?? discoveryTemporalScope.periodFrom, + period_to: toNonEmptyString(filtersWithDerivedScope.period_to) ?? discoveryTemporalScope.periodTo }; const organizationScope = toNonEmptyString(filtersWithDerivedScope.organization); const nextResultSets = capResultSets([...state.result_sets.filter((itemSet) => itemSet.result_set_id !== resultSetId), resultSet].sort((left, right) => left.created_from_turn - right.created_from_turn)); @@ -452,6 +625,7 @@ function evolveAddressNavigationStateWithAssistantItem(state, item, turnIndex) { ? { active_result_set_id: resultSetId, active_focus_object: focusObject ?? null, + comparison_scope: comparisonScope, last_confirmed_route: routeId ?? null, date_scope: { as_of_date: normalizedDateScope.as_of_date, @@ -463,6 +637,7 @@ function evolveAddressNavigationStateWithAssistantItem(state, item, turnIndex) { : { active_result_set_id: resultSetId, active_focus_object: focusObject ?? state.session_context.active_focus_object, + comparison_scope: comparisonScope ?? state.session_context.comparison_scope, last_confirmed_route: routeId ?? state.session_context.last_confirmed_route, date_scope: { as_of_date: normalizedDateScope.as_of_date ?? state.session_context.date_scope.as_of_date, diff --git a/llm_normalizer/backend/dist/services/address_runtime/composeStage.js b/llm_normalizer/backend/dist/services/address_runtime/composeStage.js index fb97b1b..fcd7214 100644 --- a/llm_normalizer/backend/dist/services/address_runtime/composeStage.js +++ b/llm_normalizer/backend/dist/services/address_runtime/composeStage.js @@ -542,6 +542,33 @@ function needsVatCalendarDetails(userMessage) { } return /(?:срок|когда|дата\s+уплат|декларац|дол(?:я|ями)|по\s+частям|платежн(?:ый|ого)\s+график)/iu.test(text); } +function needsVatPurchaseDateAnchorDisclosure(userMessage) { + const text = normalizeQuestionText(userMessage); + if (!text) { + return false; + } + return /(?:дата|дату|дате|момент)\s+(?:покуп|закуп)|(?:покуп|закуп)\S*\s+(?:дат|момент)|purchase\s+date|date\s+of\s+purchase/iu.test(text); +} +function buildVatPurchaseDateAnchorDisclosureLine(options, periodWindowLabel) { + if (!periodWindowLabel || !needsVatPurchaseDateAnchorDisclosure(options.userMessage)) { + return null; + } + const asOfDate = normalizeIsoDateOnly(options.asOfDate); + const periodFrom = normalizeIsoDateOnly(options.periodFrom); + const periodTo = normalizeIsoDateOnly(options.periodTo); + const asOfTs = toUtcDayTimestamp(asOfDate); + const fromTs = toUtcDayTimestamp(periodFrom); + const toTs = toUtcDayTimestamp(periodTo); + if (asOfDate && + asOfTs !== null && + fromTs !== null && + toTs !== null && + asOfTs >= fromTs && + asOfTs <= toTs) { + return `- Якорь периода: дата покупки ${formatDateRu(asOfDate)} попадает в налоговый период ${periodWindowLabel}; поэтому расчет ниже взят из книг продаж/покупок за это окно.`; + } + return `- Якорь периода: дата покупки из вопроса/контекста использована для выбора налогового периода ${periodWindowLabel}; сам расчет ниже взят из книг продаж/покупок за это окно.`; +} function detectRankingLimit(userMessage, fallback = 20) { const text = normalizeQuestionText(userMessage); if (!text) { @@ -3033,6 +3060,7 @@ function composeFactualReplyBody(intent, rows, options = {}) { const formatConfirmedMoney = (value) => (options.useRubCurrency ? formatMoneyRub(value) : formatMoney(value)); const organizationLabel = (0, assistantOrganizationMatcher_1.normalizeOrganizationScopeValue)(options.organizationHint); const organizationScopeLabel = organizationLabel ? ` по организации ${organizationLabel}` : ""; + const purchaseDateAnchorLine = buildVatPurchaseDateAnchorDisclosureLine(options, periodWindowLabel); const lines = [ `Коротко: подтвержденный НДС к уплате за налоговый период${organizationScopeLabel} — ${formatConfirmedMoney(vatToPay)}.`, "Расчет сделан по книгам продаж и покупок.", @@ -3040,6 +3068,7 @@ function composeFactualReplyBody(intent, rows, options = {}) { "Что вошло в расчет:", ...(organizationLabel ? [`- Организация: ${organizationLabel}.`] : []), `- Налоговый период расчета: ${periodWindowLabel ?? "не задан (нужен явный период)"}.`, + ...(purchaseDateAnchorLine ? [purchaseDateAnchorLine] : []), `- НДС по книге продаж: ${formatConfirmedMoney(salesVat)}.`, `- НДС по книге покупок (вычеты): ${formatConfirmedMoney(purchaseVat)}.`, `- Нетто НДС (книга продаж - книга покупок): ${formatConfirmedMoney(netVat)}.` diff --git a/llm_normalizer/backend/dist/services/assistantAddressLaneResponseRuntimeAdapter.js b/llm_normalizer/backend/dist/services/assistantAddressLaneResponseRuntimeAdapter.js index c58ed78..ea7fe54 100644 --- a/llm_normalizer/backend/dist/services/assistantAddressLaneResponseRuntimeAdapter.js +++ b/llm_normalizer/backend/dist/services/assistantAddressLaneResponseRuntimeAdapter.js @@ -31,6 +31,121 @@ function toNullableBoolean(value) { function normalizeAddressReplyType(value) { return value === "factual" || value === "partial_coverage" ? value : "partial_coverage"; } +function sameBusinessLabel(left, right) { + const normalizedLeft = toNullableString(left)?.toLocaleLowerCase("ru-RU").replace(/ё/g, "е"); + const normalizedRight = toNullableString(right)?.toLocaleLowerCase("ru-RU").replace(/ё/g, "е"); + return Boolean(normalizedLeft && + normalizedRight && + (normalizedLeft === normalizedRight || + normalizedLeft.includes(normalizedRight) || + normalizedRight.includes(normalizedLeft))); +} +function firstString(values) { + for (const value of values) { + const text = toNullableString(value); + if (text) { + return text; + } + } + return null; +} +function legalOrganizationLabelFromClarification(value) { + const text = toNullableString(value); + if (!text) { + return null; + } + const compact = text.replace(/\s+/gu, " ").replace(/[.!?]+$/u, "").trim(); + if (compact.length > 120 || !/^(?:ООО|ПАО|АО|ИП)\s+\S/iu.test(compact)) { + return null; + } + return compact; +} +function cleanComparisonScopeCompanyLine(line, organization) { + let clean = String(line ?? "") + .replace(/\bcompany-level\b/giu, "общий по компании") + .replace(/\breusable bundle\b/giu, "сохраненный подтвержденный срез"); + if (organization) { + clean = clean.replace(/по компании\s+Альтернатива Плюс/iu, `по компании ${organization}`); + } + return clean.trim(); +} +function buildComparisonScopeProofReply(input) { + const entryPoint = toRecordObject(input.debug.assistant_mcp_discovery_entry_point_v1); + const turnInput = toRecordObject(entryPoint?.turn_input); + const turnMeaning = toRecordObject(turnInput?.turn_meaning_ref); + const isBusinessOverview = toNullableString(turnMeaning?.asked_domain_family) === "business_overview"; + if (!isBusinessOverview) { + return null; + } + const separateCandidates = Array.isArray(turnMeaning?.business_overview_separate_entity_candidates) + ? turnMeaning.business_overview_separate_entity_candidates + : []; + const separateSubject = firstString([...separateCandidates, turnMeaning?.metadata_scope_hint]); + if (!separateSubject) { + return null; + } + const sessionRecord = toRecordObject(input.session); + const addressNavigationState = toRecordObject(sessionRecord?.address_navigation_state); + const sessionContext = toRecordObject(addressNavigationState?.session_context); + const comparisonScope = toRecordObject(sessionContext?.comparison_scope); + const comparisonCounterparty = toRecordObject(comparisonScope?.counterparty); + const proofBundles = toRecordObject(comparisonScope?.proof_bundles); + const valueBundle = toRecordObject(proofBundles?.counterparty_value_flow_bundle); + const documentBundle = toRecordObject(proofBundles?.counterparty_document_bundle); + if (!valueBundle || !sameBusinessLabel(separateSubject, valueBundle.counterparty ?? comparisonCounterparty?.label)) { + return null; + } + const incoming = toRecordObject(valueBundle.incoming_customer_revenue); + const outgoing = toRecordObject(valueBundle.outgoing_supplier_payout); + const incomingAmount = toNullableString(incoming?.total_amount_human_ru); + const outgoingAmount = toNullableString(outgoing?.total_amount_human_ru); + const netAmount = toNullableString(valueBundle.net_amount_human_ru); + if (!incomingAmount && !outgoingAmount && !netAmount) { + return null; + } + const organization = legalOrganizationLabelFromClarification(input.userMessage) + ?? toNullableString(turnMeaning?.explicit_organization_scope) + ?? toNullableString(toRecordObject(comparisonScope?.organization)?.label); + const documentCount = Number(toRecordObject(documentBundle)?.document_count); + const documentText = Number.isFinite(documentCount) && documentCount > 0 ? `, документы: ${documentCount}` : ""; + const lines = String(input.baseReply ?? "") + .split(/\r?\n/u) + .map((line) => line.trim()) + .filter(Boolean); + const companyLine = cleanComparisonScopeCompanyLine(lines[0] ?? `Коротко: по компании ${organization ?? "выбранной организации"} подтвержден общий денежный срез.`, organization); + const netDirection = valueBundle.net_direction === "net_outgoing" ? "нетто в минус" : "нетто в нашу сторону"; + const counterparty = toNullableString(valueBundle.counterparty) ?? separateSubject; + return { + reply: [ + `${companyLine}; отдельно по ${counterparty}: получили ${incomingAmount ?? "0 руб."}, заплатили ${outgoingAmount ?? "0 руб."}, ${netDirection} ${netAmount ?? "0 руб."}${documentText}.`, + `Отдельно по контрагенту ${counterparty}: это ранее подтвержденный контрагентский срез, а не перенос общих сумм компании на контрагента.`, + `Нельзя утверждать: чистую прибыль, полноценный финрезультат, юридические роли клиентов/поставщиков и выводы по ${counterparty} из общих сумм компании без отдельного контрагентского среза.` + ].join("\n"), + audit: { + applied: true, + source: "address_navigation_state.comparison_scope.proof_bundles", + counterparty, + organization: organization ?? null, + document_count: Number.isFinite(documentCount) && documentCount > 0 ? documentCount : null + } + }; +} +function buildAppliedMcpDiscoveryRoutePatch(debug, applied) { + if (!applied) { + return {}; + } + const selectedChain = toNullableString(debug.mcp_discovery_selected_chain_id); + if (selectedChain === "business_overview") { + return { + detected_intent: "business_overview", + detected_intent_confidence: "high", + selected_recipe: "business_overview", + response_type: "LIMITED_WITH_REASON", + mcp_discovery_effective_response_route: "business_overview" + }; + } + return {}; +} function normalizeAddressLaneDebug(value) { return (toRecordObject(value) ?? {}); } @@ -231,18 +346,27 @@ function runAssistantAddressLaneResponseRuntime(input) { const finalAssistantReply = mcpDiscoveryResponsePolicy.applied ? mcpDiscoveryResponsePolicy.reply_text : guardedResponse.assistantReply; + const comparisonScopeProofReply = buildComparisonScopeProofReply({ + baseReply: finalAssistantReply, + debug: debugWithResponseGuard, + session: input.getSession(input.sessionId), + userMessage: input.userMessage + }); + const finalAssistantReplyWithComparisonProof = comparisonScopeProofReply?.reply ?? finalAssistantReply; const finalReplyType = mcpDiscoveryResponsePolicy.applied ? "partial_coverage" : guardedResponse.replyType; const finalDebug = { ...debugWithResponseGuard, mcp_discovery_response_policy_v1: mcpDiscoveryResponsePolicy, mcp_discovery_response_candidate_v1: mcpDiscoveryResponsePolicy.candidate, - mcp_discovery_response_applied: mcpDiscoveryResponsePolicy.applied + mcp_discovery_response_applied: mcpDiscoveryResponsePolicy.applied, + comparison_scope_response_augmentation_v1: comparisonScopeProofReply?.audit ?? null, + ...buildAppliedMcpDiscoveryRoutePatch(debugWithResponseGuard, mcpDiscoveryResponsePolicy.applied) }; const finalization = finalizeAddressTurnSafe({ sessionId: input.sessionId, userMessage: input.userMessage, effectiveAddressUserMessage: input.effectiveAddressUserMessage, - assistantReply: finalAssistantReply, + assistantReply: finalAssistantReplyWithComparisonProof, replyType: finalReplyType, addressLaneDebug: normalizeAddressLaneDebug(input.addressLane.debug), debug: finalDebug, diff --git a/llm_normalizer/backend/dist/services/assistantAddressOrchestrationRuntimeAdapter.js b/llm_normalizer/backend/dist/services/assistantAddressOrchestrationRuntimeAdapter.js index e998cce..6ee74ed 100644 --- a/llm_normalizer/backend/dist/services/assistantAddressOrchestrationRuntimeAdapter.js +++ b/llm_normalizer/backend/dist/services/assistantAddressOrchestrationRuntimeAdapter.js @@ -151,6 +151,256 @@ function mergeBusinessOverviewDateContextForCompactCashflow(input) { } }; } +function firstString(values, toNonEmptyString) { + for (const value of values) { + const text = toNonEmptyString(value); + if (text) { + return text; + } + } + return null; +} +function comparableEntityName(value) { + const text = compactLower(value); + return text ? text.replace(/["'«»„“”]+/g, "") : null; +} +function sameEntityHint(expected, actual) { + const left = comparableEntityName(expected); + const right = comparableEntityName(actual); + if (!left || !right) { + return true; + } + return left === right || left.includes(right) || right.includes(left); +} +function isBusinessOverviewDiscoveryFollowup(followupContext, toNonEmptyString) { + if (!followupContext) { + return false; + } + return [ + followupContext.previous_discovery_pilot_scope, + followupContext.previous_discovery_loop_selected_chain_id, + followupContext.previous_discovery_loop_asked_domain_family, + followupContext.previous_intent, + followupContext.target_intent + ] + .map((value) => toNonEmptyString(value)) + .some((value) => value === "business_overview" || value === "business_overview_route_template_v1"); +} +function businessOverviewCounterpartyHint(followupContext, toNonEmptyString) { + const previousFilters = toRecordObject(followupContext.previous_filters); + const rootFilters = toRecordObject(followupContext.root_filters); + return (toNonEmptyString(followupContext.previous_discovery_loop_metadata_scope_hint) ?? + (toNonEmptyString(followupContext.previous_anchor_type) === "counterparty" + ? toNonEmptyString(followupContext.previous_anchor_value) + : null) ?? + toNonEmptyString(previousFilters?.counterparty) ?? + toNonEmptyString(rootFilters?.counterparty)); +} +function turnMeaningCounterpartyName(turnMeaningRef, valueBundle, documentBundle, toNonEmptyString) { + const separateEntities = Array.isArray(turnMeaningRef.business_overview_separate_entity_candidates) + ? turnMeaningRef.business_overview_separate_entity_candidates + : []; + return (toNonEmptyString(valueBundle?.counterparty) ?? + toNonEmptyString(documentBundle?.counterparty) ?? + toNonEmptyString(turnMeaningRef.metadata_scope_hint) ?? + firstString(separateEntities, toNonEmptyString)); +} +function parseBusinessOverviewProofBundlesFromText(value, toNonEmptyString) { + const text = toNonEmptyString(value); + if (!text) { + return null; + } + const valueMatch = text.match(/Отдельно\s+по\s+контрагенту\s+([^:\n]+):\s*подтверждено\s+получили\s+([^,\n]+?руб\.?),\s*заплатили\s+([^,\n]+?руб\.?),\s*расчетное\s+нетто\s+в\s+нашу\s+сторону\s+([^.\n]+?руб\.?)/iu); + const directDocumentMatch = text.match(/Контрагент:\s*([^.\n]+)\.\s*Найдено\s+документов:\s*(\d+)/iu); + const summaryDocumentMatch = text.match(/документы\s+по\s+цепочке:\s*найдено\s*(\d+)/iu); + const counterparty = toNonEmptyString(valueMatch?.[1]) ?? toNonEmptyString(directDocumentMatch?.[1]); + if (!counterparty) { + return null; + } + const valueBundle = valueMatch + ? { + counterparty, + incoming_customer_revenue: { + total_amount_human_ru: toNonEmptyString(valueMatch[2]) + }, + outgoing_supplier_payout: { + total_amount_human_ru: toNonEmptyString(valueMatch[3]) + }, + net_amount_human_ru: toNonEmptyString(valueMatch[4]), + net_direction: "net_incoming", + inference_basis: "parsed_from_previous_business_overview_summary" + } + : null; + const documentCount = Number(directDocumentMatch?.[2] ?? summaryDocumentMatch?.[1]); + const documentBundle = Number.isFinite(documentCount) && documentCount > 0 + ? { + counterparty, + document_count: documentCount + } + : null; + return valueBundle || documentBundle ? { valueBundle, documentBundle } : null; +} +function parseBusinessOverviewProofBundlesFromTextV2(value, counterpartyHint, toNonEmptyString) { + const text = toNonEmptyString(value); + if (!text) { + return null; + } + const comparableHint = comparableEntityName(counterpartyHint); + const lines = text + .split(/\r?\n/u) + .map((line) => line.trim()) + .filter(Boolean); + const candidateLines = comparableHint + ? lines.filter((line) => comparableEntityName(line)?.includes(comparableHint)) + : lines; + const rubAmountPattern = /[0-9][0-9\s.,]*\s*\u0440\u0443\u0431\.?/giu; + const valueLine = candidateLines.find((line) => (line.match(rubAmountPattern) ?? []).length >= 3) ?? null; + const valueAmounts = valueLine?.match(rubAmountPattern) ?? []; + const directDocumentMatch = candidateLines + .map((line) => line.match(/\u041a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442:\s*([^.\n]+)\.\s*\u041d\u0430\u0439\u0434\u0435\u043d\u043e\s+\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u043e\u0432:\s*(\d+)/iu)) + .find(Boolean); + const summaryDocumentMatch = candidateLines + .map((line) => line.match(/\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u044b\s+\u043f\u043e\s+\u0446\u0435\u043f\u043e\u0447\u043a\u0435:\s*\u043d\u0430\u0439\u0434\u0435\u043d\u043e\s*(\d+)/iu)) + .find(Boolean); + const counterparty = counterpartyHint ?? toNonEmptyString(directDocumentMatch?.[1]); + if (!counterparty) { + return null; + } + const valueBundle = valueAmounts.length >= 3 + ? { + counterparty, + incoming_customer_revenue: { + total_amount_human_ru: toNonEmptyString(valueAmounts[0]) + }, + outgoing_supplier_payout: { + total_amount_human_ru: toNonEmptyString(valueAmounts[1]) + }, + net_amount_human_ru: toNonEmptyString(valueAmounts[2]), + net_direction: "net_incoming", + inference_basis: "parsed_from_previous_business_overview_summary" + } + : null; + const documentCount = Number(directDocumentMatch?.[2] ?? summaryDocumentMatch?.[1]); + const documentBundle = Number.isFinite(documentCount) && documentCount > 0 + ? { + counterparty, + document_count: documentCount + } + : null; + return valueBundle || documentBundle ? { valueBundle, documentBundle } : null; +} +function findRecentBusinessOverviewProofBundles(input) { + if (!input.counterpartyHint) { + return null; + } + for (let index = input.sessionItems.length - 1; index >= 0; index -= 1) { + const item = toRecordObject(input.sessionItems[index]); + if (input.toNonEmptyString(item?.role) !== "assistant") { + continue; + } + const debug = toRecordObject(item?.debug); + const entryPoint = toRecordObject(debug?.assistant_mcp_discovery_entry_point_v1); + const turnInput = toRecordObject(entryPoint?.turn_input); + const turnMeaningRef = toRecordObject(turnInput?.turn_meaning_ref); + if (turnMeaningRef) { + const valueBundle = toRecordObject(turnMeaningRef.previous_counterparty_value_flow_bundle); + const documentBundle = toRecordObject(turnMeaningRef.previous_counterparty_document_bundle); + if (valueBundle || documentBundle) { + const bundleCounterparty = turnMeaningCounterpartyName(turnMeaningRef, valueBundle, documentBundle, input.toNonEmptyString); + if (sameEntityHint(input.counterpartyHint, bundleCounterparty)) { + return { valueBundle, documentBundle }; + } + } + } + const parsedBundles = parseBusinessOverviewProofBundlesFromTextV2(item?.text, input.counterpartyHint, input.toNonEmptyString) ?? + parseBusinessOverviewProofBundlesFromText(item?.text, input.toNonEmptyString); + if (!parsedBundles) { + continue; + } + const parsedCounterparty = input.toNonEmptyString(parsedBundles.valueBundle?.counterparty) ?? + input.toNonEmptyString(parsedBundles.documentBundle?.counterparty); + if (!sameEntityHint(input.counterpartyHint, parsedCounterparty)) { + continue; + } + return parsedBundles; + } + return null; +} +function mergeBusinessOverviewProofBundlesFromNavigationState(input) { + const currentValueBundle = toRecordObject(input.followupContext?.previous_discovery_bidirectional_value_flow); + const currentDocumentBundle = toRecordObject(input.followupContext?.previous_discovery_document_summary); + if (currentValueBundle && currentDocumentBundle) { + return input.followupContext; + } + const state = toRecordObject(input.sessionAddressNavigationState); + const sessionContext = toRecordObject(state?.session_context); + const comparisonScope = toRecordObject(sessionContext?.comparison_scope); + const proofBundles = toRecordObject(comparisonScope?.proof_bundles); + const valueBundle = toRecordObject(proofBundles?.counterparty_value_flow_bundle); + const documentBundle = toRecordObject(proofBundles?.counterparty_document_bundle); + if (!valueBundle && !documentBundle) { + return input.followupContext; + } + const entities = toRecordObject(input.predecomposeContract?.entities); + const hasCurrentOrganizationSelection = Boolean(input.toNonEmptyString(entities?.organization)); + const businessOverviewFollowup = isBusinessOverviewDiscoveryFollowup(input.followupContext, input.toNonEmptyString); + if (!businessOverviewFollowup && !hasCurrentOrganizationSelection) { + return input.followupContext; + } + const comparisonCounterparty = toRecordObject(comparisonScope?.counterparty); + const counterpartyHint = (input.followupContext ? businessOverviewCounterpartyHint(input.followupContext, input.toNonEmptyString) : null) ?? + input.toNonEmptyString(comparisonCounterparty?.label); + const bundleCounterparty = input.toNonEmptyString(valueBundle?.counterparty) ?? input.toNonEmptyString(documentBundle?.counterparty); + if (!counterpartyHint || !sameEntityHint(counterpartyHint, bundleCounterparty)) { + return input.followupContext; + } + return { + ...(input.followupContext ?? {}), + previous_intent: input.toNonEmptyString(input.followupContext?.previous_intent) ?? "business_overview", + target_intent: input.toNonEmptyString(input.followupContext?.target_intent) ?? "business_overview", + previous_discovery_pilot_scope: input.toNonEmptyString(input.followupContext?.previous_discovery_pilot_scope) ?? + "business_overview_route_template_v1", + previous_discovery_loop_status: input.toNonEmptyString(input.followupContext?.previous_discovery_loop_status) ?? "awaiting_clarification", + previous_discovery_loop_selected_chain_id: input.toNonEmptyString(input.followupContext?.previous_discovery_loop_selected_chain_id) ?? "business_overview", + previous_discovery_loop_pending_axes: Array.isArray(input.followupContext?.previous_discovery_loop_pending_axes) + ? input.followupContext?.previous_discovery_loop_pending_axes + : ["organization"], + previous_discovery_loop_asked_domain_family: input.toNonEmptyString(input.followupContext?.previous_discovery_loop_asked_domain_family) ?? "business_overview", + previous_discovery_loop_asked_action_family: input.toNonEmptyString(input.followupContext?.previous_discovery_loop_asked_action_family) ?? "broad_evaluation", + previous_discovery_loop_metadata_scope_hint: input.toNonEmptyString(input.followupContext?.previous_discovery_loop_metadata_scope_hint) ?? counterpartyHint, + previous_anchor_type: input.toNonEmptyString(input.followupContext?.previous_anchor_type) ?? "counterparty", + previous_anchor_value: input.toNonEmptyString(input.followupContext?.previous_anchor_value) ?? counterpartyHint, + previous_filters: toRecordObject(input.followupContext?.previous_filters) ?? {}, + previous_discovery_bidirectional_value_flow: currentValueBundle ?? valueBundle ?? undefined, + previous_discovery_document_summary: currentDocumentBundle ?? documentBundle ?? undefined + }; +} +function mergeBusinessOverviewProofBundlesFromSessionItems(input) { + if (!isBusinessOverviewDiscoveryFollowup(input.followupContext, input.toNonEmptyString)) { + return input.followupContext; + } + const currentValueBundle = toRecordObject(input.followupContext?.previous_discovery_bidirectional_value_flow); + const currentDocumentBundle = toRecordObject(input.followupContext?.previous_discovery_document_summary); + if (currentValueBundle && currentDocumentBundle) { + return input.followupContext; + } + const counterpartyHint = input.followupContext + ? businessOverviewCounterpartyHint(input.followupContext, input.toNonEmptyString) + : null; + const proofBundles = findRecentBusinessOverviewProofBundles({ + sessionItems: input.sessionItems, + counterpartyHint, + toNonEmptyString: input.toNonEmptyString + }); + if (!proofBundles) { + return input.followupContext; + } + return { + ...(input.followupContext ?? {}), + previous_discovery_bidirectional_value_flow: currentValueBundle ?? proofBundles.valueBundle ?? undefined, + previous_discovery_document_summary: currentDocumentBundle ?? proofBundles.documentBundle ?? undefined + }; +} function hasSelectedObjectInventorySignal(text) { return /(?:по\s+выбранному\s+объекту|по\s+выбранной\s+позиции|по\s+этой\s+позиции|по\s+этому\s+товару|по\s+ним|selected\s+object)/iu.test(String(text ?? "")); } @@ -324,6 +574,17 @@ async function buildAssistantAddressOrchestrationRuntime(input) { sessionItems: input.sessionItems, toNonEmptyString: input.toNonEmptyString }); + const discoveryFollowupContextWithProofBundles = mergeBusinessOverviewProofBundlesFromSessionItems({ + followupContext: discoveryFollowupContext, + sessionItems: input.sessionItems, + toNonEmptyString: input.toNonEmptyString + }); + const discoveryFollowupContextWithStateProofBundles = mergeBusinessOverviewProofBundlesFromNavigationState({ + followupContext: discoveryFollowupContextWithProofBundles, + sessionAddressNavigationState: input.sessionAddressNavigationState, + predecomposeContract, + toNonEmptyString: input.toNonEmptyString + }); const dialogContinuationContract = input.buildAddressDialogContinuationContractV2(input.userMessage, addressInputMessage, carryover, addressPreDecompose); const runDiscoveryEntryPoint = input.runMcpDiscoveryRuntimeEntryPoint ?? assistantMcpDiscoveryRuntimeEntryPoint_1.runAssistantMcpDiscoveryRuntimeEntryPoint; let mcpDiscoveryRuntimeEntryPoint = null; @@ -334,7 +595,7 @@ async function buildAssistantAddressOrchestrationRuntime(input) { effectiveMessage: addressInputMessage, assistantTurnMeaning: toRecordObject(orchestrationContract?.assistant_turn_meaning), predecomposeContract, - followupContext: discoveryFollowupContext, + followupContext: discoveryFollowupContextWithStateProofBundles, knownOrganizations: sessionKnownOrganizations(input.sessionOrganizationScope ?? null) })); } diff --git a/llm_normalizer/backend/dist/services/assistantContinuityPolicy.js b/llm_normalizer/backend/dist/services/assistantContinuityPolicy.js index 8a9b80e..84592fb 100644 --- a/llm_normalizer/backend/dist/services/assistantContinuityPolicy.js +++ b/llm_normalizer/backend/dist/services/assistantContinuityPolicy.js @@ -238,6 +238,9 @@ function readAssistantMcpDiscoveryMetadataAmbiguityEntitySets(debug, toNonEmptyS return readAssistantMcpDiscoveryTurnMeaningMetadataAmbiguityEntitySets(debug, toNonEmptyString); } function mapAssistantMcpDiscoveryPilotScopeToAddressIntent(pilotScope, actionFamily) { + if (pilotScope === "business_overview_route_template_v1" || actionFamily === "broad_evaluation") { + return "business_overview"; + } if (pilotScope === "counterparty_lifecycle_query_documents_v1") { return "counterparty_activity_lifecycle"; } diff --git a/llm_normalizer/backend/dist/services/assistantLivingChatRuntimeAdapter.js b/llm_normalizer/backend/dist/services/assistantLivingChatRuntimeAdapter.js index 2c16df3..ab8e6c0 100644 --- a/llm_normalizer/backend/dist/services/assistantLivingChatRuntimeAdapter.js +++ b/llm_normalizer/backend/dist/services/assistantLivingChatRuntimeAdapter.js @@ -42,6 +42,17 @@ function shouldProbeBareOrganizationScopeCandidate(input) { function buildDeterministicSmalltalkLeadReply() { return "\u041f\u0440\u0438\u0432\u0435\u0442! \u0412\u0441\u0451 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e."; } +function hasFirstTurnSmalltalkGreetingSignal(value) { + const normalized = String(value ?? "") + .toLowerCase() + .replace(/\u0451/gu, "\u0435") + .replace(/\s+/gu, " ") + .trim(); + if (!normalized) { + return false; + } + return /^(?:привет(?:ик)?|здравствуй(?:те)?|хай|йо|yo|hello|hi|че\s+как|че\s+там)(?:[\s,.!?;:()\-]+(?:как|дела|там|че|что|у\s+тебя|как\s+там|как\s+дела))*[\s,.!?;:()\-]*$/iu.test(normalized); +} function hasConversationExecutiveSummarySignal(value) { const normalized = String(value ?? "") .toLowerCase() @@ -114,6 +125,13 @@ async function runAssistantLivingChatRuntime(input) { let knownOrganizations = [...organizationAuthority.knownOrganizations]; let selectedOrganization = organizationAuthority.selectedOrganization; let activeOrganization = organizationAuthority.activeOrganization; + const shouldHandleFirstTurnSmalltalkDeterministically = !selectedOrganization && + !activeOrganization && + !continuitySnapshot.hasGroundedAddressContext && + !hasPriorAssistantTurn(input.sessionItems) && + input.modeDecision?.mode === "chat" && + hasFirstTurnSmalltalkGreetingSignal(userMessage) && + input.hasLivingChatSignal(userMessage); const addressRuntimeMeta = (input.addressRuntimeMeta && typeof input.addressRuntimeMeta === "object" ? input.addressRuntimeMeta : {}); @@ -263,6 +281,28 @@ async function runAssistantLivingChatRuntime(input) { chatText = input.buildAssistantCapabilityContractReply(userMessage); livingChatSource = "deterministic_capability_contract"; } + else if (shouldHandleFirstTurnSmalltalkDeterministically) { + const proactiveScopeProbe = await input.resolveDataScopeProbe(); + const mergedKnownOrganizations = input.mergeKnownOrganizations([ + ...knownOrganizations, + ...(Array.isArray(proactiveScopeProbe?.organizations) ? proactiveScopeProbe.organizations : []) + ]); + knownOrganizations = mergedKnownOrganizations; + if (!activeOrganization && mergedKnownOrganizations.length === 1) { + activeOrganization = mergedKnownOrganizations[0]; + } + const proactiveOffer = input.buildAssistantProactiveOrganizationOfferReply(proactiveScopeProbe); + chatText = [buildDeterministicSmalltalkLeadReply(), proactiveOffer] + .filter((part) => String(part ?? "").trim().length > 0) + .join(" "); + livingChatProactiveScopeOfferApplied = Boolean(proactiveOffer); + livingChatSource = proactiveOffer + ? "deterministic_smalltalk_with_proactive_scope_offer" + : "deterministic_smalltalk"; + if (!dataScopeProbe) { + dataScopeProbe = proactiveScopeProbe; + } + } else { chatText = await input.executeLlmChat(); const scriptGuard = input.applyScriptGuard(chatText, userMessage); @@ -283,34 +323,6 @@ async function runAssistantLivingChatRuntime(input) { livingChatGroundingGuardReason = groundingGuard.reason; livingChatSource = "llm_chat_grounding_guard"; } - const shouldOfferProactiveOrganizationScope = !selectedOrganization && - !activeOrganization && - !continuitySnapshot.hasGroundedAddressContext && - !hasPriorAssistantTurn(input.sessionItems) && - input.modeDecision?.mode === "chat" && - input.hasLivingChatSignal(userMessage); - if (shouldOfferProactiveOrganizationScope) { - const proactiveScopeProbe = await input.resolveDataScopeProbe(); - const mergedKnownOrganizations = input.mergeKnownOrganizations([ - ...knownOrganizations, - ...(Array.isArray(proactiveScopeProbe?.organizations) ? proactiveScopeProbe.organizations : []) - ]); - knownOrganizations = mergedKnownOrganizations; - if (!activeOrganization && mergedKnownOrganizations.length === 1) { - activeOrganization = mergedKnownOrganizations[0]; - } - const proactiveOffer = input.buildAssistantProactiveOrganizationOfferReply(proactiveScopeProbe); - if (proactiveOffer) { - chatText = [buildDeterministicSmalltalkLeadReply(), proactiveOffer] - .filter((part) => String(part ?? "").trim().length > 0) - .join(" "); - livingChatProactiveScopeOfferApplied = true; - livingChatSource = "deterministic_smalltalk_with_proactive_scope_offer"; - if (!dataScopeProbe) { - dataScopeProbe = proactiveScopeProbe; - } - } - } } if (!chatText) { return { diff --git a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryExecutionHandoff.js b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryExecutionHandoff.js index 30a5914..779d604 100644 --- a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryExecutionHandoff.js +++ b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryExecutionHandoff.js @@ -3,7 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.ASSISTANT_MCP_DISCOVERY_EXECUTION_HANDOFF_SCHEMA_VERSION = void 0; exports.buildAssistantMcpDiscoveryExecutionHandoff = buildAssistantMcpDiscoveryExecutionHandoff; exports.ASSISTANT_MCP_DISCOVERY_EXECUTION_HANDOFF_SCHEMA_VERSION = "assistant_mcp_discovery_execution_handoff_v1"; -const HOT_HANDOFF_CHAIN_ALLOWLIST = ["value_flow"]; +const HOT_HANDOFF_CHAIN_ALLOWLIST = [ + "value_flow", + "value_flow_comparison", + "business_overview" +]; function uniqueStrings(values) { const result = []; for (const value of values) { diff --git a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryResponseCandidate.js b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryResponseCandidate.js index c320483..f1d40ee 100644 --- a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryResponseCandidate.js +++ b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryResponseCandidate.js @@ -24,16 +24,51 @@ function normalizeQuestionText(value) { .replace(/\s+/g, " ") .trim(); } -function requestsFinancialCounterpartyBoundary(turnMeaning, graph) { - const text = normalizeQuestionText([ +function normalizedTurnAndGraphText(turnMeaning, graph) { + return normalizeQuestionText([ turnMeaning?.raw_message, turnMeaning?.effective_message, graph?.source_message, graph?.question ].join(" ")); +} +function requestsFinancialCounterpartyBoundary(turnMeaning, graph) { + const text = normalizedTurnAndGraphText(turnMeaning, graph); return (/(?:банк|сбербанк|финанс|кредит|депозит)/iu.test(text) && /(?:клиент|поставщик|выручк|топ|обычн|роль|поток)/iu.test(text)); } +function requestsBroadBusinessOverviewSurface(turnMeaning, graph) { + const text = normalizedTurnAndGraphText(turnMeaning, graph); + if (!text) { + return false; + } + if (/(?:не\s+обзор|просто\s+ден\p{L}*|одной\s+строк\p{L}*|только\s+итог|без\s+разбив\p{L}*)/iu.test(text)) { + return false; + } + if (/(?:бизнес[-\s]*обзор|взросл\p{L}{0,10}\s+бизнес|что\s+(?:пока\s+)?нельзя\s+утвержд)/iu.test(text)) { + return true; + } + const markers = [ + /(?:ндс|налог\p{L}*)/iu, + /(?:долг\p{L}*|дебитор|кредитор)/iu, + /(?:склад|остатк|товар\p{L}*)/iu, + /(?:клиент|заказчик|покупател)/iu, + /(?:поставщик|получател)/iu, + /(?:оборот\p{L}*)/iu, + /(?:ограничен|не\s+подтвержд|нельзя\s+утвержд)/iu + ]; + return markers.filter((marker) => marker.test(text)).length >= 3; +} +function requestsCounterpartyLeaderSurface(turnMeaning, graph) { + const text = normalizedTurnAndGraphText(turnMeaning, graph); + if (!text) { + return false; + } + if (/(?:кто|кому)[\s\S]{0,60}(?:больше\s+всего|крупнее\s+всего|основн\p{L}*)[\s\S]{0,60}(?:зан[её]с|прин[её]с|платил|ушло|получил|перев[её]л|заплатил|внес|вн[её]с)/iu.test(text)) { + return true; + } + return /(?:(?:кто|как\p{L}*|покаж\p{L}*|назов\p{L}*|раскро\p{L}*)[\s\S]{0,100}(?:главн\p{L}*|крупнейш\p{L}*|основн\p{L}*|ведущ\p{L}*|топ)[\s\S]{0,80}(?:клиент|заказчик|поставщик|получател)|(?:главн\p{L}*|крупнейш\p{L}*|основн\p{L}*|ведущ\p{L}*)[\s\S]{0,80}(?:клиент|заказчик|поставщик|получател)|(?:топ[-\s]*(?:клиент|заказчик|поставщик|получател))|(?:клиент|поставщик)[\s\S]{0,80}(?:главн|крупнейш|основн|ведущ|топ))/iu.test(text); +} function requestsCompactCashflowAnswer(turnMeaning, graph) { const text = normalizeQuestionText([ turnMeaning?.raw_message, @@ -716,6 +751,39 @@ function buildPreviousCounterpartyValueFlowSummary(flow, separateSubject, docume `${basisText} Это не перенос сумм компании на контрагента, а отдельный ранее подтвержденный контрагентский срез.` }; } +function buildBoundarySummaryFromPreviousCounterpartyBundles(entryPoint) { + const turnInput = toRecordObject(entryPoint.turn_input); + const turnMeaning = toRecordObject(turnInput?.turn_meaning_ref); + const graph = toRecordObject(turnInput?.data_need_graph); + const bridge = toRecordObject(entryPoint.bridge); + const pilot = toRecordObject(bridge?.pilot); + const overview = toRecordObject(pilot?.derived_business_overview); + const isBusinessOverview = toNonEmptyString(graph?.business_fact_family) === "business_overview" || + toNonEmptyString(turnMeaning?.asked_domain_family) === "business_overview"; + if (!isBusinessOverview || overview) { + return null; + } + const organizationScope = businessOverviewOrganizationScopeLabel(turnMeaning?.explicit_organization_scope); + const separateSubject = businessOverviewSeparateSubjectLabel(graph, turnMeaning, organizationScope); + const previousCounterpartySummary = buildPreviousCounterpartyValueFlowSummary(toRecordObject(turnMeaning?.previous_counterparty_value_flow_bundle), separateSubject, toRecordObject(turnMeaning?.previous_counterparty_document_bundle)); + if (!separateSubject || !previousCounterpartySummary) { + return null; + } + const lines = organizationScope + ? [ + `Коротко: по компании ${organizationScope} в этом шаге нет нового полного company-level расчета; отдельно по выбранному контрагенту ${separateSubject} есть ранее подтвержденный контрагентский срез.`, + previousCounterpartySummary.line, + `Можно утверждать: по ${separateSubject} отдельно подтверждены входящие/исходящие денежные строки, расчетное нетто и документы из предыдущего контрагентского среза.`, + `Нельзя утверждать: это не подтверждает чистую прибыль, полный оборот или общую бизнес-роль ${separateSubject}; также нельзя смешивать этот контрагентский срез с выводами по компании без отдельного company-level расчета.` + ] + : [ + `Коротко: уточните, по какой компании/организации сравнить выбранного контрагента ${separateSubject}; company-level вывод без организации не подтверждаю.`, + previousCounterpartySummary.line, + `Уже можно утверждать: по ${separateSubject} отдельно подтверждены входящие/исходящие денежные строки, расчетное нетто и документы из предыдущего контрагентского среза.`, + `Нельзя утверждать: это не чистая прибыль, не полный оборот компании и не доказанная бизнес-роль ${separateSubject}; контрагентский срез нельзя смешивать с company-level выводом без выбранной компании.` + ]; + return joinBusinessReplyLines(lines); +} function buildCompactBusinessOverviewReply(entryPoint, draft) { const turnInput = toRecordObject(entryPoint.turn_input); const turnMeaning = toRecordObject(turnInput?.turn_meaning_ref); @@ -773,6 +841,11 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) { : null; const graphReasonCodes = toStringList(graph?.reason_codes); const directMoneyAnswer = graphReasonCodes.includes("data_need_graph_business_overview_direct_money_answer"); + const broadOverviewSurfaceRequested = requestsBroadBusinessOverviewSurface(turnMeaning, graph); + const counterpartyLeaderSurfaceRequested = requestsCounterpartyLeaderSurface(turnMeaning, graph); + const directMoneyOnlyAnswer = directMoneyAnswer && !broadOverviewSurfaceRequested && !counterpartyLeaderSurfaceRequested; + const shouldIncludeCounterpartyLeaders = !directMoneyOnlyAnswer || counterpartyLeaderSurfaceRequested || broadOverviewSurfaceRequested; + const shouldIncludeOverviewSurface = !directMoneyAnswer || broadOverviewSurfaceRequested; const crossScopeExecutiveSummary = Boolean(separateSubject && previousCounterpartySummary); const lines = []; const actionFamily = toNonEmptyString(turnMeaning?.asked_action_family); @@ -781,9 +854,20 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) { const debtDueDateBoundary = actionFamily === "debt_due_date_boundary" || unsupportedFamily === "debt_due_date_boundary"; const vendorRiskBoundary = actionFamily === "vendor_risk_procurement_boundary" || unsupportedFamily === "vendor_risk_procurement_boundary"; const inventoryReserveBoundary = actionFamily === "inventory_reserve_boundary" || unsupportedFamily === "inventory_reserve_liquidation_boundary"; - const compactCashflowRequested = directMoneyAnswer && requestsCompactCashflowAnswer(turnMeaning, graph); + const compactCashflowRequested = directMoneyOnlyAnswer && requestsCompactCashflowAnswer(turnMeaning, graph); const cashflowPolarityRequested = compactCashflowRequested && requestsCashflowPolarityAnswer(turnMeaning, graph); const directAccountingProfitRequested = requestsDirectAccountingProfitAnswer(turnMeaning, graph); + const rawMessage = toNonEmptyString(turnMeaning?.raw_message) ?? toNonEmptyString(turnMeaning?.effective_message); + const rawMessageComparable = compactComparable(rawMessage); + const organizationScopeComparable = compactComparable(organizationScope); + const plainOrganizationClarificationSelection = Boolean(separateSubject && + organizationScope && + rawMessage && + rawMessageComparable && + organizationScopeComparable && + rawMessageComparable.includes(organizationScopeComparable) && + rawMessage.length <= 90 && + !/(?:сравн|подтвержд|деньг|сколько|что\s+|покаж|дай|вывод|нельзя|клиент|поставщик|\?)/iu.test(rawMessage)); if (compactCashflowRequested && !rankingNeed && (incomingAmount || outgoingAmount || netAmount)) { const netDisplay = sentenceAmount(netAmount) ?? netAmount ?? "0 \u0440\u0443\u0431."; const signedNetDisplay = cashflowPolarityRequested && netDisplay && !String(netDisplay).trim().startsWith("-") @@ -798,6 +882,17 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) { : "\u042d\u0442\u043e \u0434\u0435\u043d\u0435\u0436\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a \u043f\u043e \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u043c \u0441\u0442\u0440\u043e\u043a\u0430\u043c 1\u0421, \u043d\u0435 \u0447\u0438\u0441\u0442\u0430\u044f \u043f\u0440\u0438\u0431\u044b\u043b\u044c \u0438 \u043d\u0435 \u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0441\u043a\u0438\u0439 \u0444\u0438\u043d\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442."); return joinBusinessReplyLines(lines); } + if (plainOrganizationClarificationSelection && (incomingAmount || outgoingAmount || netAmount)) { + lines.push(`Коротко: по компании ${organizationScope} ${period} подтвержден company-level денежный срез: входящие ${incomingAmount ?? "0 руб."}, исходящие ${outgoingAmount ?? "0 руб."}, операционное нетто ${sentenceAmount(netAmount) ?? netAmount ?? "0 руб."}.`); + if (previousCounterpartySummary) { + lines.push(previousCounterpartySummary.line); + } + else { + lines.push(`Отдельно по выбранному контрагенту ${separateSubject}: суммы компании на него не переношу; в этом шаге держу только границу, что это отдельный контрагентский контур.`); + } + lines.push(`Нельзя утверждать: чистую прибыль, полноценный финрезультат, юридические роли клиентов/поставщиков и выводы по ${separateSubject} на основе company-level сумм без отдельного контрагентского среза.`); + return joinBusinessReplyLines(lines); + } if (profitMarginBoundary) { const accountingFinancialResult = toRecordObject(overview.accounting_financial_result); if (accountingFinancialResult) { @@ -973,7 +1068,11 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) { lines.push("Проверить нужно отдельно: складской срез на дату, учетную политику резервов, списания и ликвидационную стоимость; косвенные признаки нельзя выдавать за доказанный факт резерва."); return joinBusinessReplyLines(lines); } - if (!separateSubject && !crossScopeExecutiveSummary && (actionFamily === "broad_evaluation" || unsupportedFamily === "broad_business_evaluation")) { + if (!separateSubject && + !crossScopeExecutiveSummary && + !counterpartyLeaderSurfaceRequested && + !rankingNeed && + (actionFamily === "broad_evaluation" || unsupportedFamily === "broad_business_evaluation")) { const subject = organizationScope ?? "компания"; const periodWithoutPrefix = period.replace(/^за\s+/iu, ""); lines.push(`Коротко: по доступным данным ${subject} выглядит как бизнес с крупными контрактными денежными потоками и заметной зависимостью от нескольких крупных контрагентов, а не как равномерный поток мелких продаж.`); @@ -997,6 +1096,10 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) { ? `- крупнейший получатель исходящих денег: ${topSupplier}; это похоже на финансовый контур, не на обычного поставщика;` : `- крупнейший получатель исходящих денег: ${topSupplier};`); } + const taxLine = businessOverviewTaxLine(overview); + if (taxLine) { + lines.push(`- ${localizeLine(taxLine)}`); + } const inventoryLine = businessOverviewInventoryLine(overview); if (inventoryLine) { lines.push(`- ${localizeLine(inventoryLine)}`); @@ -1007,7 +1110,7 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) { } lines.push("Ограничение: это оценка по денежным потокам и найденным срезам 1С, не аудиторское заключение и не подтвержденная чистая прибыль."); const missingOverviewFamilies = []; - if (!businessOverviewTaxLine(overview)) { + if (!taxLine) { missingOverviewFamilies.push("НДС/налоговая позиция без отдельного точного расчета"); } if (!debtLine) { @@ -1040,7 +1143,22 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) { !/(?:все\s+доступное|все\s+время|all\s+time)/iu.test(period) && (incomingAmount || outgoingAmount || netAmount); if (explicitPeriodRankingOverview) { - lines.push(`Коротко: ${organizationPrefix}${period} денежная картина подтверждена по найденным строкам 1С.`); + if (counterpartyLeaderSurfaceRequested) { + const incomingLeaderText = customerName && customerAmount + ? topCustomerLooksFinancial + ? `${customerName} — ${sentenceAmount(customerAmount) ?? customerAmount}; это банк/финансовый контур, не называю его обычной клиентской выручкой без назначения платежа${nonFinancialCustomer ? `; крупнейший небанковский входящий контрагент: ${nonFinancialCustomer}` : ""}` + : `${customerName} — ${sentenceAmount(customerAmount) ?? customerAmount}` + : "не распознан"; + const outgoingLeaderText = topSupplier + ? topSupplierLooksFinancial + ? `${topSupplier}; это банк/финансовый контур, не называю его обычным поставщиком без назначения платежа/договора${nonFinancialSupplier ? `; крупнейший небанковский получатель исходящих денег: ${nonFinancialSupplier}` : ""}` + : topSupplier + : "не распознан"; + lines.push(`Коротко: ${organizationPrefix}${period} больше всего занес ${incomingLeaderText}; больше всего ушло ${outgoingLeaderText}.`); + } + else { + lines.push(`Коротко: ${organizationPrefix}${period} денежная картина подтверждена по найденным строкам 1С.`); + } lines.push(`Деньги: входящие ${incomingAmount ?? "0 руб."}, исходящие ${outgoingAmount ?? "0 руб."}, расчетное операционное нетто ${sentenceAmount(netAmount) ?? netAmount ?? "0 руб."}.`); if (customerName && customerAmount) { lines.push(topCustomerLooksFinancial @@ -1093,7 +1211,7 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) { else if (incomingAmount || outgoingAmount || netAmount) { lines.push(`Коротко: ${organizationPrefix}${period} по подтвержденным строкам 1С получили ${incomingAmount ?? "0 руб."}; исходящие платежи/списания ${outgoingAmount ?? "0 руб."}; ${netDirection} ${sentenceAmount(netAmount) ?? netAmount ?? "0 руб"}${topCustomerLead}${topSupplierLead}${roleBoundaryLead}${separateSubjectLead}.`); lines.push('Метод: "заработали" здесь считаю как операционный денежный показатель по 1С; это не чистая прибыль и не финрезультат.'); - if (!directMoneyAnswer && customerName && customerAmount) { + if (shouldIncludeCounterpartyLeaders && customerName && customerAmount) { lines.push(topCustomerLooksFinancial ? `Крупнейший входящий денежный источник в этом срезе: ${customerName} — ${sentenceAmount(customerAmount) ?? customerAmount}. По названию это банк/финансовая организация, поэтому без назначения платежа не называю это клиентской выручкой.${nonFinancialCustomer ? ` Крупнейший небанковский входящий контрагент: ${nonFinancialCustomer}.` : ""}` : `Крупнейший подтвержденный источник входящих денег в этом срезе: ${customerName} — ${sentenceAmount(customerAmount) ?? customerAmount}.`); @@ -1109,17 +1227,17 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) { lines.push(previousCounterpartySummary?.line ?? `Отдельно по контрагенту ${separateSubject}: этот итог не переносит суммы компании на контрагента. Можно утверждать только разделение контура; нельзя делать вывод о выручке, долге или прибыльности ${separateSubject} без отдельного контрагентского среза документов и движений.`); } - if (!directMoneyAnswer && topSupplier) { + if (shouldIncludeCounterpartyLeaders && topSupplier) { lines.push(topSupplierLooksFinancial ? `Крупнейший получатель исходящих денег: ${topSupplier}. По названию это банк/финансовая организация, поэтому без назначения платежа/договора не считаю это обычным поставщиком.${nonFinancialSupplier ? ` Крупнейший небанковский получатель исходящих денег: ${nonFinancialSupplier}.` : ""}` : `Крупнейший подтвержденный получатель исходящих денег: ${topSupplier}.`); } - if (!directMoneyAnswer && (topCustomer || topSupplier)) { + if (shouldIncludeCounterpartyLeaders && (topCustomer || topSupplier)) { lines.push(topCustomerLooksFinancial || topSupplierLooksFinancial ? "Важно по ролям: текущий денежный срез подтверждает источники и получателей денег, но банковские контрагенты требуют проверки назначения платежа/счетов и не доказывают роль клиента или поставщика." : "Важно по ролям: текущий денежный срез подтверждает денежные источники и получателей, но не доказывает, что это главный клиент или главный поставщик как бизнес-роль."); } - if (!directMoneyAnswer) { + if (shouldIncludeOverviewSurface) { lines.push(`Что подтверждено: денежный срез по компании${organizationScope ? ` ${organizationScope}` : ""}${period ? ` ${period}` : ""}${topCustomer ? ", крупнейший источник входящих денег" : ""}${topSupplier ? ", крупнейший получатель исходящих денег" : ""}.`); const taxLine = businessOverviewTaxLine(overview); if (taxLine) { @@ -1205,6 +1323,10 @@ function buildReplyText(entryPoint, status) { } return null; } + const previousCounterpartyBoundaryReply = buildBoundarySummaryFromPreviousCounterpartyBundles(entryPoint); + if (previousCounterpartyBoundaryReply) { + return previousCounterpartyBoundaryReply; + } const compactBidirectionalValueFlowReply = buildCompactBidirectionalValueFlowReply(entryPoint, draft); if (compactBidirectionalValueFlowReply) { return compactBidirectionalValueFlowReply; diff --git a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryResponsePolicy.js b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryResponsePolicy.js index fa337fc..25d7b7c 100644 --- a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryResponsePolicy.js +++ b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryResponsePolicy.js @@ -361,6 +361,11 @@ function hasExactDocumentListAddressReply(input, entryPoint) { if (source !== "address_query_runtime_v1" && source !== "address_exact" && source !== "address_lane") { return false; } + if (hasValueFlowActionConflictWithDiscoveryTurnMeaning(input, entryPoint) || + hasEvidenceLaneConflictWithDiscoveryTurnMeaning(input, entryPoint) || + hasSemanticConflictWithDiscoveryTurnMeaning(input, entryPoint)) { + return false; + } const detectedIntent = toNonEmptyString(input.addressRuntimeMeta?.detected_intent); const selectedRecipe = toNonEmptyString(input.addressRuntimeMeta?.selected_recipe); const isDocumentIntent = detectedIntent === "list_documents_by_counterparty" || detectedIntent === "list_documents_by_contract"; diff --git a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryRuntimeBridge.js b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryRuntimeBridge.js index c5314cb..7fb12e1 100644 --- a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryRuntimeBridge.js +++ b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryRuntimeBridge.js @@ -271,7 +271,9 @@ async function runAssistantMcpDiscoveryRuntimeBridge(input) { }); const reasonCodes = uniqueStrings([...planner.reason_codes, ...pilot.reason_codes, ...answerDraft.reason_codes]); pushReason(reasonCodes, `runtime_bridge_status_${bridgeStatus}`); - pushReason(reasonCodes, "runtime_bridge_not_wired_to_hot_assistant_answer"); + pushReason(reasonCodes, executionHandoff.can_use_guarded_response + ? "runtime_bridge_wired_to_guarded_hot_assistant_answer" + : "runtime_bridge_not_wired_to_hot_assistant_answer"); pushReason(reasonCodes, `runtime_bridge_loop_state_${loopState.loop_status}`); pushReason(reasonCodes, "runtime_bridge_route_candidate_built"); pushReason(reasonCodes, `runtime_bridge_route_candidate_${routeCandidate.candidate_status}`); diff --git a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryTurnInputAdapter.js b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryTurnInputAdapter.js index f1d3767..ab77ba0 100644 --- a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryTurnInputAdapter.js +++ b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryTurnInputAdapter.js @@ -73,6 +73,7 @@ function isReferentialOrganizationPlaceholder(value) { "этой компании", "этой компанией", "эту компанию", + "в целом", "наша организация", "нашей организации", "нашей компанией" @@ -188,7 +189,10 @@ function normalizeFollowupCounterpartyCandidate(value) { if (!text || isInvalidEntityCandidate(text)) { return null; } - return text; + const cleaned = text + .replace(/^(?:\u043f\u043e\s+)?\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442(?:\u0443|\u0430|\u043e\u043c|\u0435|\u044b|\u0430\u043c|\u0430\u043c\u0438|\u0430\u0445)?\s+/iu, "") + .trim(); + return cleaned && !isInvalidEntityCandidate(cleaned) ? cleaned : text; } function pushScopedEntityCandidate(target, value, groundedFollowupEntity) { const text = candidateValue(value); @@ -543,10 +547,11 @@ function collectFollowupDiscoverySeed(followupContext) { const normalizedDiscoveryEntities = discoveryEntities .map((entity) => normalizeFollowupCounterpartyCandidate(entity)) .filter((entity) => Boolean(entity)); + const normalizedLoopMetadataScopeHint = normalizeFollowupCounterpartyCandidate(loopMetadataScopeHint); const groundedDiscoveryCounterparty = ambiguityBlocksImplicitGrounding || metadataPilotCarriesScopeOnly ? null - : normalizedDiscoveryEntities[0] ?? normalizeFollowupCounterpartyCandidate(loopMetadataScopeHint); - const metadataScopeHint = loopMetadataScopeHint ?? + : normalizedDiscoveryEntities[0] ?? normalizedLoopMetadataScopeHint; + const metadataScopeHint = normalizedLoopMetadataScopeHint ?? (loopSubjectResolutionOptional ? normalizedDiscoveryEntities[0] ?? null : null); const previousFiltersCounterparty = normalizeFollowupCounterpartyCandidate(previousFilters?.counterparty); const rootFiltersCounterparty = normalizeFollowupCounterpartyCandidate(rootFilters?.counterparty); @@ -561,8 +566,10 @@ function collectFollowupDiscoverySeed(followupContext) { (toNonEmptyString(followupContext?.previous_anchor_type) === "organization" ? toNonEmptyString(followupContext?.previous_anchor_value) : null); - const dateScope = collectDateScopeFromFilters(previousFilters) ?? - collectDateScopeFromFilters(rootFilters); + const loopProvidedAllTimeScope = loopProvidedAxes.includes("all_time_scope"); + const dateScope = loopProvidedAllTimeScope + ? "all_time_scope" + : collectDateScopeFromFilters(previousFilters) ?? collectDateScopeFromFilters(rootFilters); return { pilotScope: effectivePilotScope, domain: mapped.domain, @@ -713,7 +720,7 @@ function hasOrganizationLevelSupplierQualityOverviewSignal(text) { return hasSupplierScopeCue && hasSupplierQualityCue && hasCompanyScopeCue; } function hasCrossScopeExecutiveSummarySignal(text) { - return (/(?:\u0441\u043e\u0431\u0435\u0440\p{L}*\s+(?:\u043a\u043e\u0440\u043e\u0442\u043a\p{L}*\s+)?\u0438\u0442\u043e\u0433|\u044d\u043a\u0437\u0435\u043a\u044c\u044e\u0442\u0438\u0432\p{L}*\s+\u0441\u0430\u043c\u043c\u0430\u0440\u0438|executive\s+summary|final\s+summary)/iu.test(text) && + return (/(?:\u0441\u043e\u0431\u0435\u0440\p{L}*\s+(?:\u043a\u043e\u0440\u043e\u0442\u043a\p{L}*\s+)?\u0438\u0442\u043e\u0433|(?:\u043a\u043e\u0440\u043e\u0442\u043a\p{L}*\s+)?\u0441\u0440\u0430\u0432\u043d\p{L}*|\u044d\u043a\u0437\u0435\u043a\u044c\u044e\u0442\u0438\u0432\p{L}*\s+\u0441\u0430\u043c\u043c\u0430\u0440\u0438|executive\s+summary|final\s+summary|brief(?:ly)?\s+compare)/iu.test(text) && /(?:\u0447\u0442\u043e\s+(?:\u043c\u044b\s+)?\u043f\u043e\u0434\u0442\u0432\u0435\u0440\p{L}*|\u043f\u043e\s+\u043a\u043e\u043c\u043f\u0430\u043d\p{L}*|\u043f\u043e\s+\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\p{L}*|confirmed|company|organization)/iu.test(text) && /(?:\u043e\u0442\u0434\u0435\u043b\u044c\u043d\p{L}*\s+\u043f\u043e|\u043f\u043e\s+\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\p{L}*|\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\p{L}*|\u0433\u0440\u0443\u043f\u043f\p{L}*\s+\u0441\u0432\u043a|\u0441\u0432\u043a|counterpart(?:y|ies)?)/iu.test(text) && /(?:\u0447\u0442\u043e\s+\u043c\u043e\u0436\u043d\p{L}*|\u0447\u0442\u043e\s+\u043d\u0435\u043b\u044c\u0437\p{L}*|\u0432\u044b\u0432\u043e\u0434\p{L}*|allowed|forbidden|cannot|can\s+say)/iu.test(text)); @@ -723,6 +730,27 @@ function hasPlainBusinessOverviewSignal(text) { const hasCompanyOrOperatingScopeCue = /(?:\u043e\u043e\u043e|\u0438\u043f|\u0430\u043e|\u043f\u0430\u043e|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0443\s+\u043d\u0430\u0441|\u043d\u0430\u0448\p{L}*|(?:19|20)\d{2}|company|organization|business)/iu.test(text); return hasPlainOverviewCue && hasCompanyOrOperatingScopeCue; } +function countBroadBusinessOverviewAxes(text) { + const axisPatterns = [ + /(?:\u0434\u0435\u043d\p{L}*|\u043e\u0431\u043e\u0440\u043e\u0442|\u0432\u044b\u0440\u0443\u0447\p{L}*|\u043f\u043e\u0441\u0442\u0443\u043f\p{L}*|\u043f\u043b\u0430\u0442\p{L}*|money|cash|revenue|turnover)/iu, + /(?:\u043d\u0434\u0441|vat)/iu, + /(?:\u0434\u043e\u043b\p{L}*|\u0434\u0435\u0431\u0438\u0442\u043e\u0440\p{L}*|\u043a\u0440\u0435\u0434\u0438\u0442\u043e\u0440\p{L}*|receivable|payable|debt)/iu, + /(?:\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u0442\u043e\u0432\u0430\u0440|warehouse|stock|inventory)/iu, + /(?:\u043a\u043b\u0438\u0435\u043d\u0442|\u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b|\u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a|customer|client|buyer)/iu, + /(?:\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a|\u0432\u0435\u043d\u0434\u043e\u0440|\u0437\u0430\u043a\u0443\u043f|supplier|vendor|procurement)/iu, + /(?:\u0433\u0434\u0435[\s\S]{0,80}(?:\u043d\u0435\u043b\u044c\u0437\u044f|\u043d\u0435\s+\u0434\u0435\u043b\u0430\p{L}*|\u043d\u0435\s+\u0445\u0432\u0430\p{L}*)|\u0447\u0442\u043e[\s\S]{0,80}(?:\u043d\u0435\u043b\u044c\u0437\u044f|\u043d\u0435\s+\u0445\u0432\u0430\p{L}*)|cannot|unknown|missing|limitation)/iu + ]; + return axisPatterns.reduce((count, pattern) => count + (pattern.test(text) ? 1 : 0), 0); +} +function hasBroadBusinessOverviewSurfaceSignal(text) { + const normalized = compactLower(text); + if (!normalized) { + return false; + } + const hasBroadCue = /(?:\u043f\u043e[-\s]*\u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\p{L}*|\u0447\u0442\u043e\s+\u043f\u043e\s+\u0431\u0438\u0437\u043d\u0435\u0441\u0443\s+\u0432\u0438\u0434\u043d\p{L}*|\u043f\u043e\u0441\u043c\u043e\u0442\p{L}*[\s\S]{0,100}(?:\u0431\u0438\u0437\u043d\u0435\u0441|\u0434\u0435\u044f\u0442\u0435\u043b\p{L}*)|\u0431\u0438\u0437\u043d\u0435\u0441[\s\S]{0,80}(?:\u0432\u0438\u0434\u043d\p{L}*|\u0432\u044b\u0432\u043e\u0434|\u0441\u0440\u0435\u0437)|human\s+readable\s+business\s+view)/iu.test(normalized); + const hasCompanyScope = /(?:\u043e\u043e\u043e|\u0438\u043f|\u0430\u043e|\u043f\u0430\u043e|\u0437\u0430\u043e|\u043e\u0430\u043e|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+1\s?\u0441|1\s?c|company|organization|business|(?:19|20)\d{2})/iu.test(normalized); + return hasBroadCue && hasCompanyScope && countBroadBusinessOverviewAxes(normalized) >= 3; +} function hasBusinessOverviewSignal(text) { if (hasCrossScopeExecutiveSummarySignal(text) || hasOrganizationLevelEarningsOverviewSignal(text) || @@ -730,6 +758,7 @@ function hasBusinessOverviewSignal(text) { hasOrganizationLevelDebtDueDateOverviewSignal(text) || hasOrganizationLevelInventoryReserveLiquidationOverviewSignal(text) || hasPlainBusinessOverviewSignal(text) || + hasBroadBusinessOverviewSurfaceSignal(text) || hasOrganizationLevelSupplierQualityOverviewSignal(text)) { return true; } @@ -774,6 +803,12 @@ function hasBusinessOverviewSeparateCounterpartySignal(text) { return (/(?:\u043e\u0442\u0434\u0435\u043b\u044c\u043d\p{L}*\s+\u043f\u043e|\u043f\u043e\s+\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\p{L}*|\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\p{L}*|counterpart(?:y|ies)?)/iu.test(text) && /(?:\u043a\u043e\u043c\u043f\u0430\u043d\p{L}*|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\p{L}*|company|organization|\u0438\u0442\u043e\u0433|summary|\u0432\u044b\u0432\u043e\u0434\p{L}*)/iu.test(text)); } +function isGenericSelectedCounterpartyReference(value) { + if (!value) { + return false; + } + return /^(?:(?:\u0432\u044b\u0431\u0440\u0430\u043d\p{L}*|\u044d\u0442\p{L}*|\u0434\u0430\u043d\p{L}*|\u0442\u0435\u043a\u0443\u0449\p{L}*)\s+)?\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\p{L}*$|^(?:selected|chosen|current|this)\s+counterpart(?:y|ies)?$/iu.test(value); +} function businessOverviewSeparateCounterpartyCandidateFromText(text) { const source = (0, addressTextRepair_1.repairAddressMojibakeText)(String(text ?? "")); const patterns = [ @@ -782,7 +817,7 @@ function businessOverviewSeparateCounterpartyCandidateFromText(text) { ]; for (const pattern of patterns) { const candidate = normalizeFollowupCounterpartyCandidate(source.match(pattern)?.[1]); - if (candidate && !isInvalidEntityCandidate(candidate)) { + if (candidate && !isInvalidEntityCandidate(candidate) && !isGenericSelectedCounterpartyReference(candidate)) { return candidate; } } @@ -868,6 +903,9 @@ function normalizeLooseOrganizationAlias(value) { if (hasYearOnlyTimeTail) { return null; } + if (new Set(["в целом", "компания в целом", "организация в целом"]).has(comparable)) { + return null; + } if (/^(?:\u0438|\u0432|\u0432\u043e|\u0437\u0430|\u043d\u0430|\u043f\u043e|\u043a\u0442\u043e|\u0447\u0442\u043e|\u043a\u0430\u043a(?:\u043e\u0439|\u0430\u044f|\u0438\u0435)?|\u0433\u043b\u0430\u0432\u043d\p{L}*)\b/iu.test(comparable)) { return null; } @@ -1370,10 +1408,18 @@ function buildAssistantMcpDiscoveryTurnInput(input) { : "broad_business_evaluation"; const businessOverviewSignal = !businessOverviewCounterpartyValueFlowPivot && (rawBusinessOverviewSignal || seededBusinessOverviewSignal); + const organizationClarificationBusinessOverviewLoop = Boolean(followupSeed.loopStatus === "awaiting_clarification" && + followupSeed.loopSelectedChainId === "business_overview" && + followupSeed.loopPendingAxes.includes("organization") && + currentTurnOrganizationScope && + !rawLifecycleSignal && + !rawMetadataSignal); const businessOverviewSeparateCounterpartySignal = Boolean(businessOverviewSignal && hasBusinessOverviewSeparateCounterpartySignal(rawText)); const businessOverviewSeparateCounterpartyCandidate = businessOverviewSeparateCounterpartySignal ? businessOverviewSeparateCounterpartyCandidateFromText(rawText) - : null; + : organizationClarificationBusinessOverviewLoop + ? followupSeed.counterparty ?? followupSeed.discoveryEntity ?? followupSeed.metadataScopeHint + : null; const explicitIntentCandidate = toNonEmptyString(assistantTurnMeaning?.explicit_intent_candidate); const currentTurnDocumentLaneSignal = rawAction === "list_documents"; const currentTurnMovementLaneSignal = rawAction === "list_movements"; @@ -1397,6 +1443,7 @@ function buildAssistantMcpDiscoveryTurnInput(input) { sameScopedName(followupSeed.counterparty, currentTurnOrganizationScope))); const businessOverviewSuppressesFollowupCounterparty = Boolean(businessOverviewSignal && !businessOverviewSeparateCounterpartySignal && + !organizationClarificationBusinessOverviewLoop && (rawBusinessOverviewSignal || businessOverviewContinuationSignal || broadBusinessEvaluationUnsupported || @@ -1831,7 +1878,8 @@ function buildAssistantMcpDiscoveryTurnInput(input) { } pushScopedEntityCandidate(entityCandidates, rawEntityCandidate, groundedFollowupEntity); } - const businessOverviewSeparateCounterpartyDisplayCandidate = businessOverviewSeparateCounterpartySignal + const shouldPreserveBusinessOverviewSeparateCounterparty = businessOverviewSeparateCounterpartySignal || organizationClarificationBusinessOverviewLoop; + const businessOverviewSeparateCounterpartyDisplayCandidate = shouldPreserveBusinessOverviewSeparateCounterparty ? preferredScopedDisplayName(businessOverviewSeparateCounterpartyCandidate, [ groundedFollowupEntity, effectiveFollowupCounterparty, @@ -1840,7 +1888,21 @@ function buildAssistantMcpDiscoveryTurnInput(input) { rawScopedEntityCandidate, rawEntityCandidate, ...entityCandidates - ]) + ]) ?? + preferredScopedDisplayName(groundedFollowupEntity ?? + effectiveFollowupCounterparty ?? + followupSeed.discoveryEntity ?? + normalizedPredecomposeCounterparty ?? + rawScopedEntityCandidate ?? + rawEntityCandidate, [ + groundedFollowupEntity, + effectiveFollowupCounterparty, + followupSeed.discoveryEntity, + normalizedPredecomposeCounterparty, + rawScopedEntityCandidate, + rawEntityCandidate, + ...entityCandidates + ]) : null; const businessOverviewSeparateEntityCandidates = businessOverviewSeparateCounterpartyDisplayCandidate ? [businessOverviewSeparateCounterpartyDisplayCandidate] @@ -1936,6 +1998,7 @@ function buildAssistantMcpDiscoveryTurnInput(input) { : predecomposeDateScope; const normalizedAssistantTurnMeaningDateScope = rawEntitySearchOverridesStaleScope || suppressNegatedTaxOnlyDateScope || + (organizationClarificationBusinessOverviewLoop && !currentTurnCarriesExplicitPeriod) || (suppressImplicitCurrentDateScope && isImplicitCurrentDateScope(assistantTurnMeaningDateScope)) ? null : assistantTurnMeaningDateScope; @@ -1950,7 +2013,8 @@ function buildAssistantMcpDiscoveryTurnInput(input) { /^\d{4}$/.test(rawDateScope) && normalizedPredecomposeDateScope && normalizedPredecomposeDateScope.startsWith(`${rawDateScope}-`)); - const explicitDateScope = rawAllTimeScopeSignal + const followupAllTimeScopeApplied = normalizedFollowupDateScope === "all_time_scope"; + const explicitDateScope = rawAllTimeScopeSignal || followupAllTimeScopeApplied ? null : normalizedAssistantTurnMeaningDateScope ?? (businessOverviewRawYearOverridesPredecomposeAsOf ? rawDateScope : normalizedPredecomposeDateScope) ?? @@ -1960,7 +2024,8 @@ function buildAssistantMcpDiscoveryTurnInput(input) { !normalizedAssistantTurnMeaningDateScope && !normalizedPredecomposeDateScope && !rawDateScope && - normalizedFollowupDateScope); + normalizedFollowupDateScope && + normalizedFollowupDateScope !== "all_time_scope"); const clarificationLoopSeedApplied = Boolean(followupSeed.loopStatus === "awaiting_clarification" && followupSeed.loopSelectedChainId); const turnMeaning = { raw_message: repairedUserText ?? rawUserText ?? null, @@ -2007,7 +2072,7 @@ function buildAssistantMcpDiscoveryTurnInput(input) { seeded_ranking_need: valueFlowSignal && followupSeed.rankingNeed && !rawEntitySearchOverridesStaleScope ? followupSeed.rankingNeed : undefined, - explicit_entity_candidates: businessOverviewSignal ? [] : entityCandidates, + explicit_entity_candidates: businessOverviewSignal || shouldPreserveBusinessOverviewSeparateCounterparty ? [] : entityCandidates, business_overview_separate_entity_candidates: businessOverviewSeparateEntityCandidates, previous_counterparty_value_flow_bundle: businessOverviewSignal && followupSeed.previousBidirectionalValueFlow ? followupSeed.previousBidirectionalValueFlow @@ -2222,6 +2287,9 @@ function buildAssistantMcpDiscoveryTurnInput(input) { if (rawAllTimeScopeSignal) { pushReason(reasonCodes, "mcp_discovery_all_time_scope_signal_detected"); } + if (followupAllTimeScopeApplied) { + pushReason(reasonCodes, "mcp_discovery_all_time_scope_from_followup_context"); + } if (suppressNegatedTaxOnlyDateScope) { pushReason(reasonCodes, "mcp_discovery_negated_tax_period_scope_suppressed"); } @@ -2324,7 +2392,7 @@ function buildAssistantMcpDiscoveryTurnInput(input) { if (businessOverviewSuppressesFollowupCounterparty) { pushReason(reasonCodes, "mcp_discovery_business_overview_suppressed_stale_counterparty"); } - if (businessOverviewSeparateCounterpartySignal) { + if (shouldPreserveBusinessOverviewSeparateCounterparty) { pushReason(reasonCodes, "mcp_discovery_business_overview_preserved_explicit_counterparty_summary_scope"); } if (businessOverviewSeparateCounterpartyCandidate) { @@ -2346,7 +2414,7 @@ function buildAssistantMcpDiscoveryTurnInput(input) { normalizedPredecomposeCounterparty) { pushReason(reasonCodes, "mcp_discovery_counterparty_from_predecompose"); } - if (rawScopedEntityCandidate && !normalizedPredecomposeCounterparty) { + if (rawScopedEntityCandidate && !normalizedPredecomposeCounterparty && !businessOverviewSignal) { pushReason(reasonCodes, "mcp_discovery_counterparty_from_raw_scope"); } if (effectiveFollowupCounterparty && diff --git a/llm_normalizer/backend/dist/services/assistantTransitionPolicy.js b/llm_normalizer/backend/dist/services/assistantTransitionPolicy.js index fc49355..e462453 100644 --- a/llm_normalizer/backend/dist/services/assistantTransitionPolicy.js +++ b/llm_normalizer/backend/dist/services/assistantTransitionPolicy.js @@ -75,6 +75,19 @@ function createAssistantTransitionPolicy(deps) { } return /(?:документ|счет|счет-фактур|накладн|акт|реализац|document|invoice|receipt)/iu.test(normalized); } + function hasSelectedCounterpartyDocumentFollowupSignal(userMessage, alternateMessage = null) { + return [userMessage, alternateMessage] + .filter((value) => deps.toNonEmptyString(value)) + .map((value) => normalizeFollowupText(value).replace(/С‘/g, "Рµ")) + .some((normalized) => { + if (!normalized) { + return false; + } + const hasDocumentCue = /(?:\u0434\u043e\u043a\p{L}*|\u0441\u0447\p{L}*|\u043d\u0430\u043a\u043b\u0430\u0434\p{L}*|\u0430\u043a\u0442|document|docs?|invoice|receipt)/iu.test(normalized) || hasReadableDocumentsPivotCue(normalized); + const hasSelectedCounterpartyCue = /(?:\u043f\u043e\s+\u043d(?:\u0435\u043c\u0443|\u0435\u0439)|\u043f\u043e\s+\u044d\u0442(?:\u043e\u043c\u0443|\u043e\u0439)|\u0442\u0435\u043a\u0443\u0449\p{L}*\s+\u043e\u0431\u044a\u0435\u043a\p{L}*|\u0432\u044b\u0431\u0440\u0430\u043d\p{L}*\s+(?:\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442|\u043e\u0431\u044a\u0435\u043a\u0442)|selected\s+(?:counterparty|object)|current\s+object)/iu.test(normalized); + return hasDocumentCue && hasSelectedCounterpartyCue; + }); + } function selectSuggestedIntentByPivotCue(suggestedIntents, userMessage, alternateMessage = null) { if (!Array.isArray(suggestedIntents) || suggestedIntents.length === 0) { return null; @@ -298,32 +311,115 @@ function createAssistantTransitionPolicy(deps) { } return flow; } + function readMcpDiscoveryPreviousCounterpartyValueFlowBundle(debug) { + const entryPoint = debug?.assistant_mcp_discovery_entry_point_v1; + const bundle = entryPoint?.turn_input?.turn_meaning_ref?.previous_counterparty_value_flow_bundle; + if (!bundle || typeof bundle !== "object" || Array.isArray(bundle)) { + return null; + } + return bundle; + } + function readMcpDiscoveryPreviousCounterpartyDocumentBundle(debug) { + const entryPoint = debug?.assistant_mcp_discovery_entry_point_v1; + const bundle = entryPoint?.turn_input?.turn_meaning_ref?.previous_counterparty_document_bundle; + if (!bundle || typeof bundle !== "object" || Array.isArray(bundle)) { + return null; + } + return bundle; + } function readCounterpartyDocumentSummaryFromItem(item) { const text = deps.toNonEmptyString(item?.text); if (!text) { return null; } const firstLine = text.split(/\r?\n/).map((line) => line.trim()).find(Boolean) ?? ""; - const match = firstLine.match(/Контрагент:\s*([^.\n]+)\.\s*Найдено документов:\s*(\d+)/iu); - if (!match?.[1] || !match?.[2]) { + const directMatch = firstLine.match(/Контрагент:\s*([^.\n]+)\.\s*Найдено документов:\s*(\d+)/iu); + if (directMatch?.[1] && directMatch?.[2]) { + return { + counterparty: deps.toNonEmptyString(directMatch[1]), + document_count: Number(directMatch[2]), + direct_answer: firstLine + }; + } + const summaryMatch = text.match(/Отдельно\s+по\s+контрагенту\s+([^:\n]+):[\s\S]{0,260}документы\s+по\s+цепочке:\s*найдено\s*(\d+)/iu); + if (!summaryMatch?.[1] || !summaryMatch?.[2]) { + return null; + } + return { + counterparty: deps.toNonEmptyString(summaryMatch[1]), + document_count: Number(summaryMatch[2]), + direct_answer: summaryMatch[0].replace(/\s+/g, " ").trim() + }; + } + function readCounterpartyValueFlowSummaryFromItem(item) { + const text = deps.toNonEmptyString(item?.text); + if (!text) { + return null; + } + const match = text.match(/Отдельно\s+по\s+контрагенту\s+([^:\n]+):\s*подтверждено\s+получили\s+([^,\n]+?руб\.?),\s*заплатили\s+([^,\n]+?руб\.?),\s*расчетное\s+нетто\s+в\s+нашу\s+сторону\s+([^.\n]+?руб\.?)/iu); + if (!match?.[1] || !match?.[2] || !match?.[3] || !match?.[4]) { return null; } return { counterparty: deps.toNonEmptyString(match[1]), - document_count: Number(match[2]), - direct_answer: firstLine + incoming_customer_revenue: { + total_amount_human_ru: deps.toNonEmptyString(match[2]) + }, + outgoing_supplier_payout: { + total_amount_human_ru: deps.toNonEmptyString(match[3]) + }, + net_amount_human_ru: deps.toNonEmptyString(match[4]), + net_direction: "net_incoming", + inference_basis: "parsed_from_previous_confirmed_counterparty_boundary_summary" }; } function findRecentDiscoveryValueFlowBundle(items) { for (let index = Array.isArray(items) ? items.length - 1 : -1; index >= 0; index -= 1) { const item = items[index]; const debug = item?.debug; - if (!item || item.role !== "assistant" || !debug || typeof debug !== "object") { + const isAssistantItem = item?.role === "assistant" || item?.kind === "assistant"; + if (!item || !isAssistantItem) { continue; } - const flow = readMcpDiscoveryBidirectionalValueFlow(debug); - if (flow) { - return flow; + if (debug && typeof debug === "object") { + const flow = readMcpDiscoveryBidirectionalValueFlow(debug); + if (flow) { + return flow; + } + } + const parsedFlow = readCounterpartyValueFlowSummaryFromItem(item); + if (parsedFlow) { + return parsedFlow; + } + } + return null; + } + function sameCounterpartyHint(expected, actual) { + const left = normalizeFollowupText(expected); + const right = normalizeFollowupText(actual); + if (!left || !right) { + return false; + } + return left === right || left.includes(right) || right.includes(left); + } + function findRecentPreviousCounterpartyValueFlowBundle(items, counterpartyHint = null) { + const expectedCounterparty = deps.toNonEmptyString(counterpartyHint); + if (!expectedCounterparty) { + return null; + } + for (let index = Array.isArray(items) ? items.length - 1 : -1; index >= 0; index -= 1) { + const item = items[index]; + const debug = item?.debug; + const isAssistantItem = item?.role === "assistant" || item?.kind === "assistant"; + if (!item || !isAssistantItem || !debug || typeof debug !== "object") { + continue; + } + const bundle = readMcpDiscoveryPreviousCounterpartyValueFlowBundle(debug); + if (!bundle) { + continue; + } + if (sameCounterpartyHint(expectedCounterparty, deps.toNonEmptyString(bundle.counterparty))) { + return bundle; } } return null; @@ -331,7 +427,8 @@ function createAssistantTransitionPolicy(deps) { function findRecentCounterpartyDocumentBundle(items) { for (let index = Array.isArray(items) ? items.length - 1 : -1; index >= 0; index -= 1) { const item = items[index]; - if (!item || item.role !== "assistant" || !item.debug || typeof item.debug !== "object") { + const isAssistantItem = item?.role === "assistant" || item?.kind === "assistant"; + if (!item || !isAssistantItem) { continue; } const summary = readCounterpartyDocumentSummaryFromItem(item); @@ -341,6 +438,28 @@ function createAssistantTransitionPolicy(deps) { } return null; } + function findRecentPreviousCounterpartyDocumentBundle(items, counterpartyHint = null) { + const expectedCounterparty = deps.toNonEmptyString(counterpartyHint); + if (!expectedCounterparty) { + return null; + } + for (let index = Array.isArray(items) ? items.length - 1 : -1; index >= 0; index -= 1) { + const item = items[index]; + const debug = item?.debug; + const isAssistantItem = item?.role === "assistant" || item?.kind === "assistant"; + if (!item || !isAssistantItem || !debug || typeof debug !== "object") { + continue; + } + const bundle = readMcpDiscoveryPreviousCounterpartyDocumentBundle(debug); + if (!bundle) { + continue; + } + if (sameCounterpartyHint(expectedCounterparty, deps.toNonEmptyString(bundle.counterparty))) { + return bundle; + } + } + return null; + } function hasInventoryPurchaseDateVatBridgeSignal(userMessage, alternateMessage, sourceIntentHint, hasInventoryItemFocusHint) { if (sourceIntentHint !== "inventory_purchase_provenance_for_item" && !hasInventoryItemFocusHint && @@ -504,9 +623,15 @@ function createAssistantTransitionPolicy(deps) { ? hasShortValueFlowRetargetCue(String(alternateMessage ?? "")) || hasCompactCashflowFollowupCue(String(alternateMessage ?? "")) : false); + const earlyNavigationSessionState = (0, assistantContinuityPolicy_1.resolveNavigationSessionContextState)(addressNavigationState, deps.toNonEmptyString, deps.normalizeOrganizationScopeValue); + const earlyNavigationFocusObject = earlyNavigationSessionState.focusObject; + const selectedCounterpartyDocumentFollowupSignal = Boolean(deps.toNonEmptyString(earlyNavigationFocusObject?.label) && + deps.toNonEmptyString(earlyNavigationFocusObject?.objectType) === "counterparty" && + hasSelectedCounterpartyDocumentFollowupSignal(userMessage, alternateMessage)); if (assistantTurnMeaning?.stale_replay_forbidden === true && !hasExplicitSummaryBundleReuseSignal(userMessage, alternateMessage) && - !compactCashflowFollowupSignal) { + !compactCashflowFollowupSignal && + !selectedCounterpartyDocumentFollowupSignal) { return null; } const latestAddressItem = deps.findLastAddressAssistantItem(items); @@ -574,7 +699,7 @@ function createAssistantTransitionPolicy(deps) { sourceDiscoveryPilotScopeHint === "counterparty_bidirectional_value_flow_query_movements_v1" || sourceDiscoveryPilotScopeHint === "business_overview_route_template_v1"; const hasBusinessOverviewCarryoverSourceHint = sourceDiscoveryPilotScopeHint === "business_overview_route_template_v1"; - const navigationSessionState = (0, assistantContinuityPolicy_1.resolveNavigationSessionContextState)(addressNavigationState, deps.toNonEmptyString, deps.normalizeOrganizationScopeValue); + const navigationSessionState = earlyNavigationSessionState; const navigationFocusObjectHint = navigationSessionState.focusObject; const hasNavigationInventoryItemFocusHint = Boolean(deps.toNonEmptyString(navigationFocusObjectHint?.label) && deps.toNonEmptyString(navigationFocusObjectHint?.objectType) === "item" && @@ -662,6 +787,7 @@ function createAssistantTransitionPolicy(deps) { Boolean(debtRoleSwapIntent) || shortValueFlowRetargetPrimary || shortValueFlowRetargetAlternate || + selectedCounterpartyDocumentFollowupSignal || businessOverviewBoundaryFollowupPrimary || businessOverviewBoundaryFollowupAlternate || inventoryMarginRankingFollowup || @@ -686,6 +812,7 @@ function createAssistantTransitionPolicy(deps) { Boolean(debtRoleSwapIntent) || shortValueFlowRetargetPrimary || shortValueFlowRetargetAlternate || + selectedCounterpartyDocumentFollowupSignal || businessOverviewBoundaryFollowupPrimary || businessOverviewBoundaryFollowupAlternate || inventoryMarginRankingFollowup || @@ -713,6 +840,7 @@ function createAssistantTransitionPolicy(deps) { !hasInventoryRootRestatementAlternate && !shortValueFlowRetargetPrimary && !shortValueFlowRetargetAlternate && + !selectedCounterpartyDocumentFollowupSignal && !hasImplicitContinuationSignal && !hasSuggestedIntentPivotSignal && !hasOrganizationClarificationContinuation && @@ -729,6 +857,7 @@ function createAssistantTransitionPolicy(deps) { !hasInventoryRootRestatementAlternate && !shortValueFlowRetargetPrimary && !shortValueFlowRetargetAlternate && + !selectedCounterpartyDocumentFollowupSignal && !hasImplicitContinuationSignal && !hasSuggestedIntentPivotSignal && !hasOrganizationClarificationContinuation && @@ -762,8 +891,19 @@ function createAssistantTransitionPolicy(deps) { const sourceDiscoveryLoopSubjectResolutionOptional = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryLoopSubjectResolutionOptional)(carryoverSourceDebug); const sourceDiscoveryRankingNeed = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryRankingNeed)(carryoverSourceDebug, deps.toNonEmptyString); const sourceDiscoveryEntityAmbiguityCandidates = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryEntityAmbiguityCandidates)(carryoverSourceDebug, deps.toNonEmptyString); - const sourceDiscoveryBidirectionalValueFlow = readMcpDiscoveryBidirectionalValueFlow(carryoverSourceDebug) ?? findRecentDiscoveryValueFlowBundle(items); - const sourceDiscoveryDocumentSummary = findRecentCounterpartyDocumentBundle(items); + const sourceDiscoveryCounterpartyHint = sourceDiscoveryLoopMetadataScopeHint ?? + (deps.toNonEmptyString(earlyNavigationFocusObject?.objectType) === "counterparty" + ? deps.toNonEmptyString(earlyNavigationFocusObject?.label) + : null); + const sourceDiscoveryBidirectionalValueFlow = readMcpDiscoveryBidirectionalValueFlow(carryoverSourceDebug) ?? + readMcpDiscoveryPreviousCounterpartyValueFlowBundle(carryoverSourceDebug) ?? + findRecentPreviousCounterpartyValueFlowBundle(items, sourceDiscoveryCounterpartyHint) ?? + readCounterpartyValueFlowSummaryFromItem(previousAddressItem) ?? + findRecentDiscoveryValueFlowBundle(items); + const sourceDiscoveryDocumentSummary = readMcpDiscoveryPreviousCounterpartyDocumentBundle(carryoverSourceDebug) ?? + findRecentPreviousCounterpartyDocumentBundle(items, sourceDiscoveryCounterpartyHint) ?? + readCounterpartyDocumentSummaryFromItem(previousAddressItem) ?? + findRecentCounterpartyDocumentBundle(items); const llmExplicitIntent = deps.toNonEmptyString(llmPreDecomposeMeta?.predecomposeContract?.intent); const llmSelectedObjectScopeDetected = llmPreDecomposeMeta?.predecomposeContract?.semantics?.selected_object_scope_detected === true; const resolvedPrimaryIntent = deps.resolveAddressIntent(deps.repairAddressMojibake(String(userMessage ?? ""))).intent; @@ -917,6 +1057,14 @@ function createAssistantTransitionPolicy(deps) { let resolvedCounterpartyFromDisplay = false; let displayedEntityTargetIntent = null; let previousFilters = (0, assistantContinuityPolicy_1.resolveAddressDebugCarryoverFilters)(carryoverSourceDebug, deps.toNonEmptyString); + const navigationCounterpartyFocus = navigationFocusObjectType === "counterparty" ? navigationFocusObjectLabel : null; + const hasNavigationCounterpartyFocusCarryover = Boolean(navigationCounterpartyFocus && + (hasValueFlowCarryoverSourceHint || + sourceIntentHint === "list_contracts_by_counterparty" || + sourceIntentHint === "list_documents_by_counterparty" || + sourceIntentHint === "bank_operations_by_counterparty" || + sourceIntentHint === "open_items_by_counterparty_or_contract" || + sourceDiscoveryLoopSelectedChainIdHint === "value_flow_comparison")); const shouldBackfillHistoricalPartyAnchors = sourceIntentHint === "list_contracts_by_counterparty" || sourceIntentHint === "list_documents_by_counterparty" || sourceIntentHint === "bank_operations_by_counterparty" || @@ -924,6 +1072,15 @@ function createAssistantTransitionPolicy(deps) { sourceIntentHint === "bank_operations_by_contract" || sourceIntentHint === "open_items_by_counterparty_or_contract"; previousFilters = (0, assistantContinuityPolicy_1.applyHistoricalPartyCarryoverFilters)(previousFilters, shouldBackfillHistoricalPartyAnchors, deps.findRecentAddressFilterValue(items, "contract"), deps.findRecentAddressFilterValue(items, "counterparty"), deps.toNonEmptyString); + if (hasNavigationCounterpartyFocusCarryover && navigationCounterpartyFocus) { + if (!previousAnchor) { + previousAnchorType = "counterparty"; + previousAnchor = navigationCounterpartyFocus; + } + if (!deps.toNonEmptyString(previousFilters.counterparty)) { + previousFilters.counterparty = navigationCounterpartyFocus; + } + } const historicalOrganization = deps.findRecentAddressFilterValue(items, "organization"); const authorityActiveOrganization = deps.normalizeOrganizationScopeValue(organizationAuthority.activeOrganization) ?? deps.normalizeOrganizationScopeValue(organizationAuthority.continuityActiveOrganization); diff --git a/llm_normalizer/backend/src/services/addressIntentResolver.ts b/llm_normalizer/backend/src/services/addressIntentResolver.ts index 1e4e681..c0914d3 100644 --- a/llm_normalizer/backend/src/services/addressIntentResolver.ts +++ b/llm_normalizer/backend/src/services/addressIntentResolver.ts @@ -2152,6 +2152,35 @@ function hasBidirectionalValueFlowComparisonSignal(text: string): boolean { return hasIncomingCue && hasOutgoingCue && hasComparisonCue && (hasValueFlowCue || hasNetAmountCue); } +function countBroadBusinessOverviewBridgeAxes(text: string): number { + const axisPatterns = [ + /(?:\u0434\u0435\u043d\p{L}*|\u043e\u0431\u043e\u0440\u043e\u0442|\u0432\u044b\u0440\u0443\u0447\p{L}*|\u043f\u043e\u0441\u0442\u0443\u043f\p{L}*|\u043f\u043b\u0430\u0442\p{L}*|money|cash|revenue|turnover)/iu, + /(?:\u043d\u0434\u0441|vat)/iu, + /(?:\u0434\u043e\u043b\p{L}*|\u0434\u0435\u0431\u0438\u0442\u043e\u0440\p{L}*|\u043a\u0440\u0435\u0434\u0438\u0442\u043e\u0440\p{L}*|receivable|payable|debt)/iu, + /(?:\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u0442\u043e\u0432\u0430\u0440|warehouse|stock|inventory)/iu, + /(?:\u043a\u043b\u0438\u0435\u043d\u0442|\u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b|\u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a|customer|client|buyer)/iu, + /(?:\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a|\u0432\u0435\u043d\u0434\u043e\u0440|\u0437\u0430\u043a\u0443\u043f|supplier|vendor|procurement)/iu, + /(?:\u0433\u0434\u0435[\s\S]{0,80}(?:\u043d\u0435\u043b\u044c\u0437\u044f|\u043d\u0435\s+\u0434\u0435\u043b\u0430\p{L}*|\u043d\u0435\s+\u0445\u0432\u0430\p{L}*)|\u0447\u0442\u043e[\s\S]{0,80}(?:\u043d\u0435\u043b\u044c\u0437\u044f|\u043d\u0435\s+\u0445\u0432\u0430\p{L}*)|cannot|unknown|missing|limitation)/iu + ]; + return axisPatterns.reduce((count, pattern) => count + (pattern.test(text) ? 1 : 0), 0); +} + +function hasBroadBusinessOverviewBridgeSignal(text: string): boolean { + const normalized = String(text ?? "").trim().toLowerCase(); + if (!normalized) { + return false; + } + const hasBroadCue = + /(?:\u043f\u043e[-\s]*\u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\p{L}*|\u0447\u0442\u043e\s+\u043f\u043e\s+\u0431\u0438\u0437\u043d\u0435\u0441\u0443\s+\u0432\u0438\u0434\u043d\p{L}*|\u043f\u043e\u0441\u043c\u043e\u0442\p{L}*[\s\S]{0,100}(?:\u0431\u0438\u0437\u043d\u0435\u0441|\u0434\u0435\u044f\u0442\u0435\u043b\p{L}*)|\u0431\u0438\u0437\u043d\u0435\u0441[\s\S]{0,80}(?:\u0432\u0438\u0434\u043d\p{L}*|\u0432\u044b\u0432\u043e\u0434|\u0441\u0440\u0435\u0437)|human\s+readable\s+business\s+view)/iu.test( + normalized + ); + const hasCompanyScope = + /(?:\u043e\u043e\u043e|\u0438\u043f|\u0430\u043e|\u043f\u0430\u043e|\u0437\u0430\u043e|\u043e\u0430\u043e|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+1\s?\u0441|1\s?c|company|organization|business|(?:19|20)\d{2})/iu.test( + normalized + ); + return hasBroadCue && hasCompanyScope && countBroadBusinessOverviewBridgeAxes(normalized) >= 3; +} + function hasNomenclatureMarginRankingSignal(text: string): boolean { const normalized = String(text ?? "").trim().toLowerCase(); if (!normalized) { @@ -2357,6 +2386,10 @@ function resolveUnicodeAddressIntentBridge(text: string): AddressIntentResolutio ); } + if (hasBroadBusinessOverviewBridgeSignal(normalized)) { + return unicodeBridgeResolution("unknown", "high", "unicode_business_overview_multi_surface_deferred_to_discovery"); + } + if (hasOrganizationLevelEarningsOverviewBridgeSignal(normalized)) { return unicodeBridgeResolution("unknown", "high", "unicode_business_overview_earnings_deferred_to_discovery"); } diff --git a/llm_normalizer/backend/src/services/addressNavigationState.ts b/llm_normalizer/backend/src/services/addressNavigationState.ts index 8ce68ff..2db05a6 100644 --- a/llm_normalizer/backend/src/services/addressNavigationState.ts +++ b/llm_normalizer/backend/src/services/addressNavigationState.ts @@ -3,7 +3,9 @@ import type { AssistantConversationItem } from "../types/assistant"; import type { AddressIntent } from "../types/addressQuery"; import { readAddressDebugCounterparty, - readAddressDebugItem + readAddressDebugItem, + readAddressDebugOrganization, + readAddressDebugTemporalScope } from "./assistantContinuityPolicy"; import { ADDRESS_NAVIGATION_STATE_SCHEMA_VERSION, @@ -21,7 +23,11 @@ const MAX_RESULT_SETS = 40; const MAX_NAVIGATION_EVENTS = 120; const MAX_ENTITY_REFS_PER_RESULT_SET = 40; +type AddressComparisonScope = NonNullable; +type AddressComparisonProofBundles = NonNullable; + const DISPLAY_ENTITY_TYPE_BY_INTENT: Partial> = { + business_overview: "organization", counterparty_activity_lifecycle: "counterparty", customer_revenue_and_payments: "counterparty", supplier_payouts_profile: "counterparty", @@ -45,6 +51,7 @@ const DISPLAY_ENTITY_TYPE_BY_INTENT: Partial> = { + business_overview: "profile_summary", counterparty_activity_lifecycle: "counterparty_list", customer_revenue_and_payments: "counterparty_list", supplier_payouts_profile: "counterparty_list", @@ -83,6 +90,18 @@ function toObject(value: unknown): Record | null { return value as Record; } +function cloneRecord(value: unknown): Record | null { + const record = toObject(value); + if (!record) { + return null; + } + try { + return JSON.parse(JSON.stringify(record)) as Record; + } catch { + return { ...record }; + } +} + function toNonEmptyString(value: unknown): string | null { if (typeof value !== "string") { return null; @@ -91,6 +110,44 @@ function toNonEmptyString(value: unknown): string | null { return trimmed.length > 0 ? trimmed : null; } +function candidateLabel(value: unknown): string | null { + const direct = toNonEmptyString(value); + if (direct && direct !== "[object Object]") { + return direct; + } + const record = toObject(value); + if (!record) { + return null; + } + return ( + toNonEmptyString(record.value) ?? + toNonEmptyString(record.name) ?? + toNonEmptyString(record.ref) ?? + toNonEmptyString(record.text) + ); +} + +function readNavigationDiscoveryCounterparty(debug: Record): string | null { + const entry = toObject(debug.assistant_mcp_discovery_entry_point_v1); + const turnInput = toObject(entry?.turn_input); + const turnMeaning = toObject(turnInput?.turn_meaning_ref); + const dataNeedGraph = toObject(turnInput?.data_need_graph); + const candidates = [ + ...(Array.isArray(turnMeaning?.business_overview_separate_entity_candidates) + ? turnMeaning.business_overview_separate_entity_candidates + : []), + ...(Array.isArray(turnMeaning?.explicit_entity_candidates) ? turnMeaning.explicit_entity_candidates : []), + ...(Array.isArray(dataNeedGraph?.subject_candidates) ? dataNeedGraph.subject_candidates : []) + ]; + for (const candidate of candidates) { + const label = candidateLabel(candidate); + if (label) { + return label; + } + } + return null; +} + function toAddressFocusObjectType(value: unknown): AddressFocusObjectType { const normalized = toNonEmptyString(value); if (!normalized) { @@ -228,6 +285,26 @@ function cloneFocusObject(value: AddressFocusObject | null): AddressFocusObject }; } +function cloneComparisonProofBundles(value: unknown): AddressComparisonProofBundles | null { + const record = toObject(value); + if (!record) { + return null; + } + const counterpartyValueFlowBundle = cloneRecord( + record.counterparty_value_flow_bundle ?? record.previous_counterparty_value_flow_bundle + ); + const counterpartyDocumentBundle = cloneRecord( + record.counterparty_document_bundle ?? record.previous_counterparty_document_bundle + ); + if (!counterpartyValueFlowBundle && !counterpartyDocumentBundle) { + return null; + } + return { + counterparty_value_flow_bundle: counterpartyValueFlowBundle, + counterparty_document_bundle: counterpartyDocumentBundle + }; +} + function cloneResultSet(input: AddressResultSet): AddressResultSet { return { result_set_id: input.result_set_id, @@ -296,8 +373,71 @@ function buildFocusObject( }; } +function cloneComparisonScope( + value: AddressNavigationState["session_context"]["comparison_scope"] +): AddressNavigationState["session_context"]["comparison_scope"] { + if (!value || typeof value !== "object") { + return null; + } + return { + organization: cloneFocusObject(value.organization), + counterparty: cloneFocusObject(value.counterparty), + proof_bundles: cloneComparisonProofBundles(value.proof_bundles) + }; +} + +function sameBusinessLabel(left: unknown, right: unknown): boolean { + const normalizedLeft = toNonEmptyString(left)?.toLocaleLowerCase("ru-RU"); + const normalizedRight = toNonEmptyString(right)?.toLocaleLowerCase("ru-RU"); + return Boolean(normalizedLeft && normalizedRight && normalizedLeft === normalizedRight); +} + +function readBusinessOverviewComparisonProofBundles(debug: Record): AddressComparisonProofBundles | null { + const entryPoint = toObject(debug.assistant_mcp_discovery_entry_point_v1); + const turnInput = toObject(entryPoint?.turn_input); + const turnMeaning = toObject(turnInput?.turn_meaning_ref); + const bridge = toObject(entryPoint?.bridge); + const pilot = toObject(bridge?.pilot); + const counterpartyValueFlowBundle = + cloneRecord(turnMeaning?.previous_counterparty_value_flow_bundle) ?? + cloneRecord(pilot?.derived_bidirectional_value_flow); + const counterpartyDocumentBundle = cloneRecord(turnMeaning?.previous_counterparty_document_bundle); + const counterparty = + toNonEmptyString(counterpartyValueFlowBundle?.counterparty) ?? + toNonEmptyString(counterpartyDocumentBundle?.counterparty) ?? + readNavigationDiscoveryCounterparty(debug); + if (!counterparty) { + return null; + } + if (!counterpartyValueFlowBundle && !counterpartyDocumentBundle) { + return null; + } + return { + counterparty_value_flow_bundle: counterpartyValueFlowBundle, + counterparty_document_bundle: counterpartyDocumentBundle + }; +} + function buildFocusObjectFromDebug(debug: Record, resultSetId: string, createdAt: string): AddressFocusObject | null { const extractedFilters = toObject(debug.extracted_filters) ?? {}; + const selectedDiscoveryChain = toNonEmptyString(debug.mcp_discovery_selected_chain_id); + if (selectedDiscoveryChain === "business_overview" && debug.mcp_discovery_response_applied === true) { + const counterparty = readAddressDebugCounterparty(debug, toNonEmptyString) ?? readNavigationDiscoveryCounterparty(debug); + if (counterparty) { + return buildFocusObject("counterparty", counterparty, resultSetId, createdAt); + } + const organization = readAddressDebugOrganization(debug, toNonEmptyString); + if (organization) { + return buildFocusObject("organization", organization, resultSetId, createdAt); + } + } + if (selectedDiscoveryChain === "value_flow_comparison" && debug.mcp_discovery_response_applied === true) { + const counterparty = + readAddressDebugCounterparty(debug, toNonEmptyString) ?? readNavigationDiscoveryCounterparty(debug); + if (counterparty) { + return buildFocusObject("counterparty", counterparty, resultSetId, createdAt); + } + } const objectType = toAddressFocusObjectType(debug.anchor_type); const canonicalType = objectType === "unknown" ? inferDisplayEntityType(toAddressIntent(debug.detected_intent)) : objectType; if (canonicalType === "item") { @@ -330,11 +470,13 @@ function capNavigationEvents(events: AddressNavigationEvent[]): AddressNavigatio } function isAddressAssistantItem(item: AssistantConversationItem): boolean { - return ( - item.role === "assistant" && - Boolean(item.debug) && - toNonEmptyString(item.debug?.detected_mode) === "address_query" - ); + if (item.role !== "assistant" || !item.debug) { + return false; + } + if (toNonEmptyString(item.debug.detected_mode) === "address_query") { + return true; + } + return item.debug.mcp_discovery_response_applied === true && Boolean(toNonEmptyString(item.debug.mcp_discovery_selected_chain_id)); } export function createEmptyAddressNavigationState( @@ -348,6 +490,7 @@ export function createEmptyAddressNavigationState( session_context: { active_result_set_id: null, active_focus_object: null, + comparison_scope: null, last_confirmed_route: null, date_scope: { as_of_date: null, @@ -372,6 +515,7 @@ export function cloneAddressNavigationState(value: AddressNavigationState | null session_context: { active_result_set_id: value.session_context.active_result_set_id, active_focus_object: cloneFocusObject(value.session_context.active_focus_object), + comparison_scope: cloneComparisonScope(value.session_context.comparison_scope), last_confirmed_route: value.session_context.last_confirmed_route, date_scope: { as_of_date: value.session_context.date_scope.as_of_date, @@ -406,6 +550,9 @@ export function normalizeAddressNavigationState( session_context: { active_result_set_id: toNonEmptyString(context.active_result_set_id), active_focus_object: cloneFocusObject(context.active_focus_object as AddressFocusObject | null), + comparison_scope: cloneComparisonScope( + context.comparison_scope as AddressNavigationState["session_context"]["comparison_scope"] + ), last_confirmed_route: toNonEmptyString(context.last_confirmed_route), date_scope: { as_of_date: toNonEmptyString(dateScope.as_of_date), @@ -464,20 +611,42 @@ export function evolveAddressNavigationStateWithAssistantItem( return state; } const debug = item.debug as unknown as Record; - const intent = toAddressIntent(debug.detected_intent); - if (intent === "unknown") { + const selectedDiscoveryChain = toNonEmptyString(debug.mcp_discovery_selected_chain_id); + const discoveryIntent = + selectedDiscoveryChain === "business_overview" + ? "business_overview" + : selectedDiscoveryChain === "value_flow_comparison" + ? "customer_revenue_and_payments" + : "unknown"; + const detectedIntent = toNonEmptyString(debug.detected_intent); + const intent = toAddressIntent(detectedIntent && detectedIntent !== "unknown" ? detectedIntent : discoveryIntent); + const trackableDiscoveryTurn = debug.mcp_discovery_response_applied === true && Boolean(selectedDiscoveryChain); + if (intent === "unknown" && !trackableDiscoveryTurn) { return state; } const createdAt = toNonEmptyString(item.created_at) ?? new Date().toISOString(); const resultSetId = `rs-${item.message_id}`; - const routeId = toNonEmptyString(debug.selected_recipe); + const routeId = toNonEmptyString(debug.selected_recipe) ?? selectedDiscoveryChain; const filters = normalizeFilters(debug.extracted_filters); - const derivedOrganizationScope = resolveDerivedOrganizationScope(debug, filters, item.text); + const derivedOrganizationScope = + resolveDerivedOrganizationScope(debug, filters, item.text) ?? readAddressDebugOrganization(debug, toNonEmptyString); + const derivedCounterpartyScope = + selectedDiscoveryChain === "value_flow_comparison" && debug.mcp_discovery_response_applied === true + ? readAddressDebugCounterparty(debug, toNonEmptyString) ?? readNavigationDiscoveryCounterparty(debug) + : null; const filtersWithDerivedScope = derivedOrganizationScope && !toNonEmptyString(filters.organization) ? { ...filters, - organization: derivedOrganizationScope + organization: derivedOrganizationScope, + ...(derivedCounterpartyScope && !toNonEmptyString(filters.counterparty) + ? { counterparty: derivedCounterpartyScope } + : {}) + } + : derivedCounterpartyScope && !toNonEmptyString(filters.counterparty) + ? { + ...filters, + counterparty: derivedCounterpartyScope } : filters; const sourceRefs = routeId ? [routeId] : []; @@ -495,6 +664,41 @@ export function evolveAddressNavigationStateWithAssistantItem( }; const previousResultSetId = state.session_context.active_result_set_id; const focusObject = buildFocusObjectFromDebug(debug, resultSetId, createdAt); + const comparisonCounterparty = + selectedDiscoveryChain === "business_overview" && debug.mcp_discovery_response_applied === true + ? readNavigationDiscoveryCounterparty(debug) + : null; + const comparisonOrganization = + selectedDiscoveryChain === "business_overview" && debug.mcp_discovery_response_applied === true + ? derivedOrganizationScope ?? toNonEmptyString(filtersWithDerivedScope.organization) + : null; + const currentComparisonProofBundles = + selectedDiscoveryChain === "business_overview" && debug.mcp_discovery_response_applied === true + ? readBusinessOverviewComparisonProofBundles(debug) + : null; + const inheritedComparisonScope = state.session_context.comparison_scope; + const inheritedComparisonProofBundles = + comparisonCounterparty && + sameBusinessLabel(inheritedComparisonScope?.counterparty?.label, comparisonCounterparty) + ? cloneComparisonProofBundles(inheritedComparisonScope?.proof_bundles) + : null; + const comparisonProofBundles = currentComparisonProofBundles ?? inheritedComparisonProofBundles; + const comparisonOrganizationObject = + comparisonOrganization + ? buildFocusObject("organization", comparisonOrganization, resultSetId, createdAt) + : cloneFocusObject(inheritedComparisonScope?.organization ?? null); + const comparisonCounterpartyObject = + comparisonCounterparty + ? buildFocusObject("counterparty", comparisonCounterparty, resultSetId, createdAt) + : cloneFocusObject(inheritedComparisonScope?.counterparty ?? null); + const comparisonScope = + comparisonOrganizationObject || comparisonCounterpartyObject || comparisonProofBundles + ? { + organization: comparisonOrganizationObject, + counterparty: comparisonCounterpartyObject, + proof_bundles: comparisonProofBundles + } + : null; const action = resolveNavigationAction(debug, Boolean(focusObject)); const navigationEvent: AddressNavigationEvent = { event_id: `nav-${nanoid(10)}`, @@ -505,10 +709,11 @@ export function evolveAddressNavigationStateWithAssistantItem( turn_index: turnIndex, created_at: createdAt }; + const discoveryTemporalScope = readAddressDebugTemporalScope(debug, toNonEmptyString); const normalizedDateScope = { - as_of_date: toNonEmptyString(filtersWithDerivedScope.as_of_date), - period_from: toNonEmptyString(filtersWithDerivedScope.period_from), - period_to: toNonEmptyString(filtersWithDerivedScope.period_to) + as_of_date: toNonEmptyString(filtersWithDerivedScope.as_of_date) ?? discoveryTemporalScope.asOfDate, + period_from: toNonEmptyString(filtersWithDerivedScope.period_from) ?? discoveryTemporalScope.periodFrom, + period_to: toNonEmptyString(filtersWithDerivedScope.period_to) ?? discoveryTemporalScope.periodTo }; const organizationScope = toNonEmptyString(filtersWithDerivedScope.organization); const nextResultSets = capResultSets( @@ -522,6 +727,7 @@ export function evolveAddressNavigationStateWithAssistantItem( ? { active_result_set_id: resultSetId, active_focus_object: focusObject ?? null, + comparison_scope: comparisonScope, last_confirmed_route: routeId ?? null, date_scope: { as_of_date: normalizedDateScope.as_of_date, @@ -533,6 +739,7 @@ export function evolveAddressNavigationStateWithAssistantItem( : { active_result_set_id: resultSetId, active_focus_object: focusObject ?? state.session_context.active_focus_object, + comparison_scope: comparisonScope ?? state.session_context.comparison_scope, last_confirmed_route: routeId ?? state.session_context.last_confirmed_route, date_scope: { as_of_date: normalizedDateScope.as_of_date ?? state.session_context.date_scope.as_of_date, diff --git a/llm_normalizer/backend/src/services/address_runtime/composeStage.ts b/llm_normalizer/backend/src/services/address_runtime/composeStage.ts index 0c78b36..48bca55 100644 --- a/llm_normalizer/backend/src/services/address_runtime/composeStage.ts +++ b/llm_normalizer/backend/src/services/address_runtime/composeStage.ts @@ -733,6 +733,44 @@ function needsVatCalendarDetails(userMessage: string | null | undefined): boolea return /(?:срок|когда|дата\s+уплат|декларац|дол(?:я|ями)|по\s+частям|платежн(?:ый|ого)\s+график)/iu.test(text); } +function needsVatPurchaseDateAnchorDisclosure(userMessage: string | null | undefined): boolean { + const text = normalizeQuestionText(userMessage); + if (!text) { + return false; + } + return /(?:дата|дату|дате|момент)\s+(?:покуп|закуп)|(?:покуп|закуп)\S*\s+(?:дат|момент)|purchase\s+date|date\s+of\s+purchase/iu.test( + text + ); +} + +function buildVatPurchaseDateAnchorDisclosureLine( + options: ComposeFactualReplyOptions, + periodWindowLabel: string | null +): string | null { + if (!periodWindowLabel || !needsVatPurchaseDateAnchorDisclosure(options.userMessage)) { + return null; + } + + const asOfDate = normalizeIsoDateOnly(options.asOfDate); + const periodFrom = normalizeIsoDateOnly(options.periodFrom); + const periodTo = normalizeIsoDateOnly(options.periodTo); + const asOfTs = toUtcDayTimestamp(asOfDate); + const fromTs = toUtcDayTimestamp(periodFrom); + const toTs = toUtcDayTimestamp(periodTo); + if ( + asOfDate && + asOfTs !== null && + fromTs !== null && + toTs !== null && + asOfTs >= fromTs && + asOfTs <= toTs + ) { + return `- Якорь периода: дата покупки ${formatDateRu(asOfDate)} попадает в налоговый период ${periodWindowLabel}; поэтому расчет ниже взят из книг продаж/покупок за это окно.`; + } + + return `- Якорь периода: дата покупки из вопроса/контекста использована для выбора налогового периода ${periodWindowLabel}; сам расчет ниже взят из книг продаж/покупок за это окно.`; +} + function detectRankingLimit(userMessage: string | null | undefined, fallback = 20): number { const text = normalizeQuestionText(userMessage); if (!text) { @@ -3896,6 +3934,7 @@ function composeFactualReplyBody( const formatConfirmedMoney = (value: number): string => (options.useRubCurrency ? formatMoneyRub(value) : formatMoney(value)); const organizationLabel = normalizeOrganizationScopeValue(options.organizationHint); const organizationScopeLabel = organizationLabel ? ` по организации ${organizationLabel}` : ""; + const purchaseDateAnchorLine = buildVatPurchaseDateAnchorDisclosureLine(options, periodWindowLabel); const lines = [ `Коротко: подтвержденный НДС к уплате за налоговый период${organizationScopeLabel} — ${formatConfirmedMoney(vatToPay)}.`, @@ -3904,6 +3943,7 @@ function composeFactualReplyBody( "Что вошло в расчет:", ...(organizationLabel ? [`- Организация: ${organizationLabel}.`] : []), `- Налоговый период расчета: ${periodWindowLabel ?? "не задан (нужен явный период)"}.`, + ...(purchaseDateAnchorLine ? [purchaseDateAnchorLine] : []), `- НДС по книге продаж: ${formatConfirmedMoney(salesVat)}.`, `- НДС по книге покупок (вычеты): ${formatConfirmedMoney(purchaseVat)}.`, `- Нетто НДС (книга продаж - книга покупок): ${formatConfirmedMoney(netVat)}.` diff --git a/llm_normalizer/backend/src/services/assistantAddressLaneResponseRuntimeAdapter.ts b/llm_normalizer/backend/src/services/assistantAddressLaneResponseRuntimeAdapter.ts index 86f835c..f10a07f 100644 --- a/llm_normalizer/backend/src/services/assistantAddressLaneResponseRuntimeAdapter.ts +++ b/llm_normalizer/backend/src/services/assistantAddressLaneResponseRuntimeAdapter.ts @@ -76,6 +76,141 @@ function normalizeAddressReplyType(value: unknown): AssistantReplyType { return value === "factual" || value === "partial_coverage" ? value : "partial_coverage"; } +function sameBusinessLabel(left: unknown, right: unknown): boolean { + const normalizedLeft = toNullableString(left)?.toLocaleLowerCase("ru-RU").replace(/ё/g, "е"); + const normalizedRight = toNullableString(right)?.toLocaleLowerCase("ru-RU").replace(/ё/g, "е"); + return Boolean( + normalizedLeft && + normalizedRight && + (normalizedLeft === normalizedRight || + normalizedLeft.includes(normalizedRight) || + normalizedRight.includes(normalizedLeft)) + ); +} + +function firstString(values: unknown[]): string | null { + for (const value of values) { + const text = toNullableString(value); + if (text) { + return text; + } + } + return null; +} + +function legalOrganizationLabelFromClarification(value: unknown): string | null { + const text = toNullableString(value); + if (!text) { + return null; + } + const compact = text.replace(/\s+/gu, " ").replace(/[.!?]+$/u, "").trim(); + if (compact.length > 120 || !/^(?:ООО|ПАО|АО|ИП)\s+\S/iu.test(compact)) { + return null; + } + return compact; +} + +function cleanComparisonScopeCompanyLine(line: string, organization: string | null): string { + let clean = String(line ?? "") + .replace(/\bcompany-level\b/giu, "общий по компании") + .replace(/\breusable bundle\b/giu, "сохраненный подтвержденный срез"); + if (organization) { + clean = clean.replace(/по компании\s+Альтернатива Плюс/iu, `по компании ${organization}`); + } + return clean.trim(); +} + +function buildComparisonScopeProofReply(input: { + baseReply: string; + debug: Record; + session: unknown; + userMessage?: unknown; +}): { reply: string; audit: Record } | null { + const entryPoint = toRecordObject(input.debug.assistant_mcp_discovery_entry_point_v1); + const turnInput = toRecordObject(entryPoint?.turn_input); + const turnMeaning = toRecordObject(turnInput?.turn_meaning_ref); + const isBusinessOverview = toNullableString(turnMeaning?.asked_domain_family) === "business_overview"; + if (!isBusinessOverview) { + return null; + } + const separateCandidates = Array.isArray(turnMeaning?.business_overview_separate_entity_candidates) + ? turnMeaning.business_overview_separate_entity_candidates + : []; + const separateSubject = firstString([...separateCandidates, turnMeaning?.metadata_scope_hint]); + if (!separateSubject) { + return null; + } + const sessionRecord = toRecordObject(input.session); + const addressNavigationState = toRecordObject(sessionRecord?.address_navigation_state); + const sessionContext = toRecordObject(addressNavigationState?.session_context); + const comparisonScope = toRecordObject(sessionContext?.comparison_scope); + const comparisonCounterparty = toRecordObject(comparisonScope?.counterparty); + const proofBundles = toRecordObject(comparisonScope?.proof_bundles); + const valueBundle = toRecordObject(proofBundles?.counterparty_value_flow_bundle); + const documentBundle = toRecordObject(proofBundles?.counterparty_document_bundle); + if (!valueBundle || !sameBusinessLabel(separateSubject, valueBundle.counterparty ?? comparisonCounterparty?.label)) { + return null; + } + const incoming = toRecordObject(valueBundle.incoming_customer_revenue); + const outgoing = toRecordObject(valueBundle.outgoing_supplier_payout); + const incomingAmount = toNullableString(incoming?.total_amount_human_ru); + const outgoingAmount = toNullableString(outgoing?.total_amount_human_ru); + const netAmount = toNullableString(valueBundle.net_amount_human_ru); + if (!incomingAmount && !outgoingAmount && !netAmount) { + return null; + } + const organization = legalOrganizationLabelFromClarification(input.userMessage) + ?? toNullableString(turnMeaning?.explicit_organization_scope) + ?? toNullableString(toRecordObject(comparisonScope?.organization)?.label); + const documentCount = Number(toRecordObject(documentBundle)?.document_count); + const documentText = Number.isFinite(documentCount) && documentCount > 0 ? `, документы: ${documentCount}` : ""; + const lines = String(input.baseReply ?? "") + .split(/\r?\n/u) + .map((line) => line.trim()) + .filter(Boolean); + const companyLine = cleanComparisonScopeCompanyLine( + lines[0] ?? `Коротко: по компании ${organization ?? "выбранной организации"} подтвержден общий денежный срез.`, + organization + ); + const netDirection = + valueBundle.net_direction === "net_outgoing" ? "нетто в минус" : "нетто в нашу сторону"; + const counterparty = toNullableString(valueBundle.counterparty) ?? separateSubject; + return { + reply: [ + `${companyLine}; отдельно по ${counterparty}: получили ${incomingAmount ?? "0 руб."}, заплатили ${outgoingAmount ?? "0 руб."}, ${netDirection} ${netAmount ?? "0 руб."}${documentText}.`, + `Отдельно по контрагенту ${counterparty}: это ранее подтвержденный контрагентский срез, а не перенос общих сумм компании на контрагента.`, + `Нельзя утверждать: чистую прибыль, полноценный финрезультат, юридические роли клиентов/поставщиков и выводы по ${counterparty} из общих сумм компании без отдельного контрагентского среза.` + ].join("\n"), + audit: { + applied: true, + source: "address_navigation_state.comparison_scope.proof_bundles", + counterparty, + organization: organization ?? null, + document_count: Number.isFinite(documentCount) && documentCount > 0 ? documentCount : null + } + }; +} + +function buildAppliedMcpDiscoveryRoutePatch( + debug: Record, + applied: boolean +): Record { + if (!applied) { + return {}; + } + const selectedChain = toNullableString(debug.mcp_discovery_selected_chain_id); + if (selectedChain === "business_overview") { + return { + detected_intent: "business_overview", + detected_intent_confidence: "high", + selected_recipe: "business_overview", + response_type: "LIMITED_WITH_REASON", + mcp_discovery_effective_response_route: "business_overview" + }; + } + return {}; +} + function normalizeAddressLaneDebug(value: unknown): AddressExecutionDebug { return (toRecordObject(value) ?? {}) as unknown as AddressExecutionDebug; } @@ -290,18 +425,27 @@ export function runAssistantAddressLaneResponseRuntime | null, + toNonEmptyString: BuildAssistantAddressOrchestrationRuntimeInput["toNonEmptyString"] +): boolean { + if (!followupContext) { + return false; + } + return [ + followupContext.previous_discovery_pilot_scope, + followupContext.previous_discovery_loop_selected_chain_id, + followupContext.previous_discovery_loop_asked_domain_family, + followupContext.previous_intent, + followupContext.target_intent + ] + .map((value) => toNonEmptyString(value)) + .some((value) => value === "business_overview" || value === "business_overview_route_template_v1"); +} + +function businessOverviewCounterpartyHint( + followupContext: Record, + toNonEmptyString: BuildAssistantAddressOrchestrationRuntimeInput["toNonEmptyString"] +): string | null { + const previousFilters = toRecordObject(followupContext.previous_filters); + const rootFilters = toRecordObject(followupContext.root_filters); + return ( + toNonEmptyString(followupContext.previous_discovery_loop_metadata_scope_hint) ?? + (toNonEmptyString(followupContext.previous_anchor_type) === "counterparty" + ? toNonEmptyString(followupContext.previous_anchor_value) + : null) ?? + toNonEmptyString(previousFilters?.counterparty) ?? + toNonEmptyString(rootFilters?.counterparty) + ); +} + +function turnMeaningCounterpartyName( + turnMeaningRef: Record, + valueBundle: Record | null, + documentBundle: Record | null, + toNonEmptyString: BuildAssistantAddressOrchestrationRuntimeInput["toNonEmptyString"] +): string | null { + const separateEntities = Array.isArray(turnMeaningRef.business_overview_separate_entity_candidates) + ? turnMeaningRef.business_overview_separate_entity_candidates + : []; + return ( + toNonEmptyString(valueBundle?.counterparty) ?? + toNonEmptyString(documentBundle?.counterparty) ?? + toNonEmptyString(turnMeaningRef.metadata_scope_hint) ?? + firstString(separateEntities, toNonEmptyString) + ); +} + +function parseBusinessOverviewProofBundlesFromText( + value: unknown, + toNonEmptyString: BuildAssistantAddressOrchestrationRuntimeInput["toNonEmptyString"] +): { valueBundle: Record | null; documentBundle: Record | null } | null { + const text = toNonEmptyString(value); + if (!text) { + return null; + } + const valueMatch = text.match( + /Отдельно\s+по\s+контрагенту\s+([^:\n]+):\s*подтверждено\s+получили\s+([^,\n]+?руб\.?),\s*заплатили\s+([^,\n]+?руб\.?),\s*расчетное\s+нетто\s+в\s+нашу\s+сторону\s+([^.\n]+?руб\.?)/iu + ); + const directDocumentMatch = text.match(/Контрагент:\s*([^.\n]+)\.\s*Найдено\s+документов:\s*(\d+)/iu); + const summaryDocumentMatch = text.match(/документы\s+по\s+цепочке:\s*найдено\s*(\d+)/iu); + const counterparty = + toNonEmptyString(valueMatch?.[1]) ?? toNonEmptyString(directDocumentMatch?.[1]); + if (!counterparty) { + return null; + } + const valueBundle = valueMatch + ? { + counterparty, + incoming_customer_revenue: { + total_amount_human_ru: toNonEmptyString(valueMatch[2]) + }, + outgoing_supplier_payout: { + total_amount_human_ru: toNonEmptyString(valueMatch[3]) + }, + net_amount_human_ru: toNonEmptyString(valueMatch[4]), + net_direction: "net_incoming", + inference_basis: "parsed_from_previous_business_overview_summary" + } + : null; + const documentCount = Number(directDocumentMatch?.[2] ?? summaryDocumentMatch?.[1]); + const documentBundle = Number.isFinite(documentCount) && documentCount > 0 + ? { + counterparty, + document_count: documentCount + } + : null; + return valueBundle || documentBundle ? { valueBundle, documentBundle } : null; +} + +function parseBusinessOverviewProofBundlesFromTextV2( + value: unknown, + counterpartyHint: string | null, + toNonEmptyString: BuildAssistantAddressOrchestrationRuntimeInput["toNonEmptyString"] +): { valueBundle: Record | null; documentBundle: Record | null } | null { + const text = toNonEmptyString(value); + if (!text) { + return null; + } + const comparableHint = comparableEntityName(counterpartyHint); + const lines = text + .split(/\r?\n/u) + .map((line) => line.trim()) + .filter(Boolean); + const candidateLines = comparableHint + ? lines.filter((line) => comparableEntityName(line)?.includes(comparableHint)) + : lines; + const rubAmountPattern = /[0-9][0-9\s.,]*\s*\u0440\u0443\u0431\.?/giu; + const valueLine = candidateLines.find((line) => (line.match(rubAmountPattern) ?? []).length >= 3) ?? null; + const valueAmounts = valueLine?.match(rubAmountPattern) ?? []; + const directDocumentMatch = candidateLines + .map((line) => + line.match( + /\u041a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442:\s*([^.\n]+)\.\s*\u041d\u0430\u0439\u0434\u0435\u043d\u043e\s+\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u043e\u0432:\s*(\d+)/iu + ) + ) + .find(Boolean); + const summaryDocumentMatch = candidateLines + .map((line) => + line.match( + /\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u044b\s+\u043f\u043e\s+\u0446\u0435\u043f\u043e\u0447\u043a\u0435:\s*\u043d\u0430\u0439\u0434\u0435\u043d\u043e\s*(\d+)/iu + ) + ) + .find(Boolean); + const counterparty = counterpartyHint ?? toNonEmptyString(directDocumentMatch?.[1]); + if (!counterparty) { + return null; + } + const valueBundle = valueAmounts.length >= 3 + ? { + counterparty, + incoming_customer_revenue: { + total_amount_human_ru: toNonEmptyString(valueAmounts[0]) + }, + outgoing_supplier_payout: { + total_amount_human_ru: toNonEmptyString(valueAmounts[1]) + }, + net_amount_human_ru: toNonEmptyString(valueAmounts[2]), + net_direction: "net_incoming", + inference_basis: "parsed_from_previous_business_overview_summary" + } + : null; + const documentCount = Number(directDocumentMatch?.[2] ?? summaryDocumentMatch?.[1]); + const documentBundle = Number.isFinite(documentCount) && documentCount > 0 + ? { + counterparty, + document_count: documentCount + } + : null; + return valueBundle || documentBundle ? { valueBundle, documentBundle } : null; +} + +function findRecentBusinessOverviewProofBundles(input: { + sessionItems: unknown[]; + counterpartyHint: string | null; + toNonEmptyString: BuildAssistantAddressOrchestrationRuntimeInput["toNonEmptyString"]; +}): { valueBundle: Record | null; documentBundle: Record | null } | null { + if (!input.counterpartyHint) { + return null; + } + for (let index = input.sessionItems.length - 1; index >= 0; index -= 1) { + const item = toRecordObject(input.sessionItems[index]); + if (input.toNonEmptyString(item?.role) !== "assistant") { + continue; + } + const debug = toRecordObject(item?.debug); + const entryPoint = toRecordObject(debug?.assistant_mcp_discovery_entry_point_v1); + const turnInput = toRecordObject(entryPoint?.turn_input); + const turnMeaningRef = toRecordObject(turnInput?.turn_meaning_ref); + if (turnMeaningRef) { + const valueBundle = toRecordObject(turnMeaningRef.previous_counterparty_value_flow_bundle); + const documentBundle = toRecordObject(turnMeaningRef.previous_counterparty_document_bundle); + if (valueBundle || documentBundle) { + const bundleCounterparty = turnMeaningCounterpartyName( + turnMeaningRef, + valueBundle, + documentBundle, + input.toNonEmptyString + ); + if (sameEntityHint(input.counterpartyHint, bundleCounterparty)) { + return { valueBundle, documentBundle }; + } + } + } + const parsedBundles = + parseBusinessOverviewProofBundlesFromTextV2(item?.text, input.counterpartyHint, input.toNonEmptyString) ?? + parseBusinessOverviewProofBundlesFromText(item?.text, input.toNonEmptyString); + if (!parsedBundles) { + continue; + } + const parsedCounterparty = + input.toNonEmptyString(parsedBundles.valueBundle?.counterparty) ?? + input.toNonEmptyString(parsedBundles.documentBundle?.counterparty); + if (!sameEntityHint(input.counterpartyHint, parsedCounterparty)) { + continue; + } + return parsedBundles; + } + return null; +} + +function mergeBusinessOverviewProofBundlesFromNavigationState(input: { + followupContext: Record | null; + sessionAddressNavigationState: unknown; + predecomposeContract: Record | null; + toNonEmptyString: BuildAssistantAddressOrchestrationRuntimeInput["toNonEmptyString"]; +}): Record | null { + const currentValueBundle = toRecordObject(input.followupContext?.previous_discovery_bidirectional_value_flow); + const currentDocumentBundle = toRecordObject(input.followupContext?.previous_discovery_document_summary); + if (currentValueBundle && currentDocumentBundle) { + return input.followupContext; + } + const state = toRecordObject(input.sessionAddressNavigationState); + const sessionContext = toRecordObject(state?.session_context); + const comparisonScope = toRecordObject(sessionContext?.comparison_scope); + const proofBundles = toRecordObject(comparisonScope?.proof_bundles); + const valueBundle = toRecordObject(proofBundles?.counterparty_value_flow_bundle); + const documentBundle = toRecordObject(proofBundles?.counterparty_document_bundle); + if (!valueBundle && !documentBundle) { + return input.followupContext; + } + const entities = toRecordObject(input.predecomposeContract?.entities); + const hasCurrentOrganizationSelection = Boolean(input.toNonEmptyString(entities?.organization)); + const businessOverviewFollowup = isBusinessOverviewDiscoveryFollowup(input.followupContext, input.toNonEmptyString); + if (!businessOverviewFollowup && !hasCurrentOrganizationSelection) { + return input.followupContext; + } + const comparisonCounterparty = toRecordObject(comparisonScope?.counterparty); + const counterpartyHint = + (input.followupContext ? businessOverviewCounterpartyHint(input.followupContext, input.toNonEmptyString) : null) ?? + input.toNonEmptyString(comparisonCounterparty?.label); + const bundleCounterparty = + input.toNonEmptyString(valueBundle?.counterparty) ?? input.toNonEmptyString(documentBundle?.counterparty); + if (!counterpartyHint || !sameEntityHint(counterpartyHint, bundleCounterparty)) { + return input.followupContext; + } + return { + ...(input.followupContext ?? {}), + previous_intent: input.toNonEmptyString(input.followupContext?.previous_intent) ?? "business_overview", + target_intent: input.toNonEmptyString(input.followupContext?.target_intent) ?? "business_overview", + previous_discovery_pilot_scope: + input.toNonEmptyString(input.followupContext?.previous_discovery_pilot_scope) ?? + "business_overview_route_template_v1", + previous_discovery_loop_status: + input.toNonEmptyString(input.followupContext?.previous_discovery_loop_status) ?? "awaiting_clarification", + previous_discovery_loop_selected_chain_id: + input.toNonEmptyString(input.followupContext?.previous_discovery_loop_selected_chain_id) ?? "business_overview", + previous_discovery_loop_pending_axes: Array.isArray(input.followupContext?.previous_discovery_loop_pending_axes) + ? input.followupContext?.previous_discovery_loop_pending_axes + : ["organization"], + previous_discovery_loop_asked_domain_family: + input.toNonEmptyString(input.followupContext?.previous_discovery_loop_asked_domain_family) ?? "business_overview", + previous_discovery_loop_asked_action_family: + input.toNonEmptyString(input.followupContext?.previous_discovery_loop_asked_action_family) ?? "broad_evaluation", + previous_discovery_loop_metadata_scope_hint: + input.toNonEmptyString(input.followupContext?.previous_discovery_loop_metadata_scope_hint) ?? counterpartyHint, + previous_anchor_type: input.toNonEmptyString(input.followupContext?.previous_anchor_type) ?? "counterparty", + previous_anchor_value: input.toNonEmptyString(input.followupContext?.previous_anchor_value) ?? counterpartyHint, + previous_filters: toRecordObject(input.followupContext?.previous_filters) ?? {}, + previous_discovery_bidirectional_value_flow: currentValueBundle ?? valueBundle ?? undefined, + previous_discovery_document_summary: currentDocumentBundle ?? documentBundle ?? undefined + }; +} + +function mergeBusinessOverviewProofBundlesFromSessionItems(input: { + followupContext: Record | null; + sessionItems: unknown[]; + toNonEmptyString: BuildAssistantAddressOrchestrationRuntimeInput["toNonEmptyString"]; +}): Record | null { + if (!isBusinessOverviewDiscoveryFollowup(input.followupContext, input.toNonEmptyString)) { + return input.followupContext; + } + const currentValueBundle = toRecordObject(input.followupContext?.previous_discovery_bidirectional_value_flow); + const currentDocumentBundle = toRecordObject(input.followupContext?.previous_discovery_document_summary); + if (currentValueBundle && currentDocumentBundle) { + return input.followupContext; + } + const counterpartyHint = input.followupContext + ? businessOverviewCounterpartyHint(input.followupContext, input.toNonEmptyString) + : null; + const proofBundles = findRecentBusinessOverviewProofBundles({ + sessionItems: input.sessionItems, + counterpartyHint, + toNonEmptyString: input.toNonEmptyString + }); + if (!proofBundles) { + return input.followupContext; + } + return { + ...(input.followupContext ?? {}), + previous_discovery_bidirectional_value_flow: + currentValueBundle ?? proofBundles.valueBundle ?? undefined, + previous_discovery_document_summary: currentDocumentBundle ?? proofBundles.documentBundle ?? undefined + }; +} + function hasSelectedObjectInventorySignal(text: string | null): boolean { return /(?:по\s+выбранному\s+объекту|по\s+выбранной\s+позиции|по\s+этой\s+позиции|по\s+этому\s+товару|по\s+ним|selected\s+object)/iu.test( String(text ?? "") @@ -525,6 +851,17 @@ export async function buildAssistantAddressOrchestrationRuntime( sessionItems: input.sessionItems, toNonEmptyString: input.toNonEmptyString }); + const discoveryFollowupContextWithProofBundles = mergeBusinessOverviewProofBundlesFromSessionItems({ + followupContext: discoveryFollowupContext, + sessionItems: input.sessionItems, + toNonEmptyString: input.toNonEmptyString + }); + const discoveryFollowupContextWithStateProofBundles = mergeBusinessOverviewProofBundlesFromNavigationState({ + followupContext: discoveryFollowupContextWithProofBundles, + sessionAddressNavigationState: input.sessionAddressNavigationState, + predecomposeContract, + toNonEmptyString: input.toNonEmptyString + }); const dialogContinuationContract = input.buildAddressDialogContinuationContractV2( input.userMessage, addressInputMessage, @@ -540,7 +877,7 @@ export async function buildAssistantAddressOrchestrationRuntime( effectiveMessage: addressInputMessage, assistantTurnMeaning: toRecordObject(orchestrationContract?.assistant_turn_meaning), predecomposeContract, - followupContext: discoveryFollowupContext, + followupContext: discoveryFollowupContextWithStateProofBundles, knownOrganizations: sessionKnownOrganizations(input.sessionOrganizationScope ?? null) })) as Record; } catch (error) { diff --git a/llm_normalizer/backend/src/services/assistantContinuityPolicy.ts b/llm_normalizer/backend/src/services/assistantContinuityPolicy.ts index a9a2ad0..20cac3e 100644 --- a/llm_normalizer/backend/src/services/assistantContinuityPolicy.ts +++ b/llm_normalizer/backend/src/services/assistantContinuityPolicy.ts @@ -414,6 +414,9 @@ function mapAssistantMcpDiscoveryPilotScopeToAddressIntent( pilotScope: string | null, actionFamily: string | null ): string | null { + if (pilotScope === "business_overview_route_template_v1" || actionFamily === "broad_evaluation") { + return "business_overview"; + } if (pilotScope === "counterparty_lifecycle_query_documents_v1") { return "counterparty_activity_lifecycle"; } diff --git a/llm_normalizer/backend/src/services/assistantLivingChatRuntimeAdapter.ts b/llm_normalizer/backend/src/services/assistantLivingChatRuntimeAdapter.ts index b1c0382..8176e2b 100644 --- a/llm_normalizer/backend/src/services/assistantLivingChatRuntimeAdapter.ts +++ b/llm_normalizer/backend/src/services/assistantLivingChatRuntimeAdapter.ts @@ -131,6 +131,20 @@ function buildDeterministicSmalltalkLeadReply(): string { return "\u041f\u0440\u0438\u0432\u0435\u0442! \u0412\u0441\u0451 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e."; } +function hasFirstTurnSmalltalkGreetingSignal(value: unknown): boolean { + const normalized = String(value ?? "") + .toLowerCase() + .replace(/\u0451/gu, "\u0435") + .replace(/\s+/gu, " ") + .trim(); + if (!normalized) { + return false; + } + return /^(?:привет(?:ик)?|здравствуй(?:те)?|хай|йо|yo|hello|hi|че\s+как|че\s+там)(?:[\s,.!?;:()\-]+(?:как|дела|там|че|что|у\s+тебя|как\s+там|как\s+дела))*[\s,.!?;:()\-]*$/iu.test( + normalized + ); +} + function hasConversationExecutiveSummarySignal(value: unknown): boolean { const normalized = String(value ?? "") .toLowerCase() @@ -215,6 +229,14 @@ export async function runAssistantLivingChatRuntime( let knownOrganizations = [...organizationAuthority.knownOrganizations]; let selectedOrganization = organizationAuthority.selectedOrganization; let activeOrganization = organizationAuthority.activeOrganization; + const shouldHandleFirstTurnSmalltalkDeterministically = + !selectedOrganization && + !activeOrganization && + !continuitySnapshot.hasGroundedAddressContext && + !hasPriorAssistantTurn(input.sessionItems) && + input.modeDecision?.mode === "chat" && + hasFirstTurnSmalltalkGreetingSignal(userMessage) && + input.hasLivingChatSignal(userMessage); const addressRuntimeMeta = (input.addressRuntimeMeta && typeof input.addressRuntimeMeta === "object" ? input.addressRuntimeMeta : {}) as Record; @@ -365,6 +387,27 @@ export async function runAssistantLivingChatRuntime( } else if (capabilityMetaQuery) { chatText = input.buildAssistantCapabilityContractReply(userMessage); livingChatSource = "deterministic_capability_contract"; + } else if (shouldHandleFirstTurnSmalltalkDeterministically) { + const proactiveScopeProbe = await input.resolveDataScopeProbe(); + const mergedKnownOrganizations = input.mergeKnownOrganizations([ + ...knownOrganizations, + ...(Array.isArray(proactiveScopeProbe?.organizations) ? (proactiveScopeProbe.organizations as unknown[]) : []) + ]); + knownOrganizations = mergedKnownOrganizations; + if (!activeOrganization && mergedKnownOrganizations.length === 1) { + activeOrganization = mergedKnownOrganizations[0]; + } + const proactiveOffer = input.buildAssistantProactiveOrganizationOfferReply(proactiveScopeProbe); + chatText = [buildDeterministicSmalltalkLeadReply(), proactiveOffer] + .filter((part) => String(part ?? "").trim().length > 0) + .join(" "); + livingChatProactiveScopeOfferApplied = Boolean(proactiveOffer); + livingChatSource = proactiveOffer + ? "deterministic_smalltalk_with_proactive_scope_offer" + : "deterministic_smalltalk"; + if (!dataScopeProbe) { + dataScopeProbe = proactiveScopeProbe; + } } else { chatText = await input.executeLlmChat(); const scriptGuard = input.applyScriptGuard(chatText, userMessage); @@ -385,36 +428,6 @@ export async function runAssistantLivingChatRuntime( livingChatGroundingGuardReason = groundingGuard.reason; livingChatSource = "llm_chat_grounding_guard"; } - - const shouldOfferProactiveOrganizationScope = - !selectedOrganization && - !activeOrganization && - !continuitySnapshot.hasGroundedAddressContext && - !hasPriorAssistantTurn(input.sessionItems) && - input.modeDecision?.mode === "chat" && - input.hasLivingChatSignal(userMessage); - if (shouldOfferProactiveOrganizationScope) { - const proactiveScopeProbe = await input.resolveDataScopeProbe(); - const mergedKnownOrganizations = input.mergeKnownOrganizations([ - ...knownOrganizations, - ...(Array.isArray(proactiveScopeProbe?.organizations) ? (proactiveScopeProbe.organizations as unknown[]) : []) - ]); - knownOrganizations = mergedKnownOrganizations; - if (!activeOrganization && mergedKnownOrganizations.length === 1) { - activeOrganization = mergedKnownOrganizations[0]; - } - const proactiveOffer = input.buildAssistantProactiveOrganizationOfferReply(proactiveScopeProbe); - if (proactiveOffer) { - chatText = [buildDeterministicSmalltalkLeadReply(), proactiveOffer] - .filter((part) => String(part ?? "").trim().length > 0) - .join(" "); - livingChatProactiveScopeOfferApplied = true; - livingChatSource = "deterministic_smalltalk_with_proactive_scope_offer"; - if (!dataScopeProbe) { - dataScopeProbe = proactiveScopeProbe; - } - } - } } if (!chatText) { diff --git a/llm_normalizer/backend/src/services/assistantMcpDiscoveryExecutionHandoff.ts b/llm_normalizer/backend/src/services/assistantMcpDiscoveryExecutionHandoff.ts index cdf8534..e1a3a54 100644 --- a/llm_normalizer/backend/src/services/assistantMcpDiscoveryExecutionHandoff.ts +++ b/llm_normalizer/backend/src/services/assistantMcpDiscoveryExecutionHandoff.ts @@ -42,7 +42,11 @@ export interface AssistantMcpDiscoveryExecutionHandoffContract { reason_codes: string[]; } -const HOT_HANDOFF_CHAIN_ALLOWLIST: AssistantMcpDiscoveryChainId[] = ["value_flow"]; +const HOT_HANDOFF_CHAIN_ALLOWLIST: AssistantMcpDiscoveryChainId[] = [ + "value_flow", + "value_flow_comparison", + "business_overview" +]; function uniqueStrings(values: string[]): string[] { const result: string[] = []; diff --git a/llm_normalizer/backend/src/services/assistantMcpDiscoveryResponseCandidate.ts b/llm_normalizer/backend/src/services/assistantMcpDiscoveryResponseCandidate.ts index 4ee9469..040b6cb 100644 --- a/llm_normalizer/backend/src/services/assistantMcpDiscoveryResponseCandidate.ts +++ b/llm_normalizer/backend/src/services/assistantMcpDiscoveryResponseCandidate.ts @@ -47,19 +47,66 @@ function normalizeQuestionText(value: unknown): string { .trim(); } -function requestsFinancialCounterpartyBoundary(turnMeaning: Record | null, graph: Record | null): boolean { - const text = normalizeQuestionText([ +function normalizedTurnAndGraphText( + turnMeaning: Record | null, + graph: Record | null +): string { + return normalizeQuestionText([ turnMeaning?.raw_message, turnMeaning?.effective_message, graph?.source_message, graph?.question ].join(" ")); +} + +function requestsFinancialCounterpartyBoundary(turnMeaning: Record | null, graph: Record | null): boolean { + const text = normalizedTurnAndGraphText(turnMeaning, graph); return ( /(?:банк|сбербанк|финанс|кредит|депозит)/iu.test(text) && /(?:клиент|поставщик|выручк|топ|обычн|роль|поток)/iu.test(text) ); } +function requestsBroadBusinessOverviewSurface( + turnMeaning: Record | null, + graph: Record | null +): boolean { + const text = normalizedTurnAndGraphText(turnMeaning, graph); + if (!text) { + return false; + } + if (/(?:не\s+обзор|просто\s+ден\p{L}*|одной\s+строк\p{L}*|только\s+итог|без\s+разбив\p{L}*)/iu.test(text)) { + return false; + } + if (/(?:бизнес[-\s]*обзор|взросл\p{L}{0,10}\s+бизнес|что\s+(?:пока\s+)?нельзя\s+утвержд)/iu.test(text)) { + return true; + } + const markers = [ + /(?:ндс|налог\p{L}*)/iu, + /(?:долг\p{L}*|дебитор|кредитор)/iu, + /(?:склад|остатк|товар\p{L}*)/iu, + /(?:клиент|заказчик|покупател)/iu, + /(?:поставщик|получател)/iu, + /(?:оборот\p{L}*)/iu, + /(?:ограничен|не\s+подтвержд|нельзя\s+утвержд)/iu + ]; + return markers.filter((marker) => marker.test(text)).length >= 3; +} + +function requestsCounterpartyLeaderSurface( + turnMeaning: Record | null, + graph: Record | null +): boolean { + const text = normalizedTurnAndGraphText(turnMeaning, graph); + if (!text) { + return false; + } + if (/(?:кто|кому)[\s\S]{0,60}(?:больше\s+всего|крупнее\s+всего|основн\p{L}*)[\s\S]{0,60}(?:зан[её]с|прин[её]с|платил|ушло|получил|перев[её]л|заплатил|внес|вн[её]с)/iu.test(text)) { + return true; + } + return /(?:(?:кто|как\p{L}*|покаж\p{L}*|назов\p{L}*|раскро\p{L}*)[\s\S]{0,100}(?:главн\p{L}*|крупнейш\p{L}*|основн\p{L}*|ведущ\p{L}*|топ)[\s\S]{0,80}(?:клиент|заказчик|поставщик|получател)|(?:главн\p{L}*|крупнейш\p{L}*|основн\p{L}*|ведущ\p{L}*)[\s\S]{0,80}(?:клиент|заказчик|поставщик|получател)|(?:топ[-\s]*(?:клиент|заказчик|поставщик|получател))|(?:клиент|поставщик)[\s\S]{0,80}(?:главн|крупнейш|основн|ведущ|топ))/iu.test(text); +} + function requestsCompactCashflowAnswer( turnMeaning: Record | null, graph: Record | null @@ -850,6 +897,49 @@ function buildPreviousCounterpartyValueFlowSummary( }; } +function buildBoundarySummaryFromPreviousCounterpartyBundles( + entryPoint: AssistantMcpDiscoveryRuntimeEntryPointContract +): string | null { + const turnInput = toRecordObject(entryPoint.turn_input); + const turnMeaning = toRecordObject(turnInput?.turn_meaning_ref); + const graph = toRecordObject(turnInput?.data_need_graph); + const bridge = toRecordObject(entryPoint.bridge); + const pilot = toRecordObject(bridge?.pilot); + const overview = toRecordObject(pilot?.derived_business_overview); + const isBusinessOverview = + toNonEmptyString(graph?.business_fact_family) === "business_overview" || + toNonEmptyString(turnMeaning?.asked_domain_family) === "business_overview"; + if (!isBusinessOverview || overview) { + return null; + } + + const organizationScope = businessOverviewOrganizationScopeLabel(turnMeaning?.explicit_organization_scope); + const separateSubject = businessOverviewSeparateSubjectLabel(graph, turnMeaning, organizationScope); + const previousCounterpartySummary = buildPreviousCounterpartyValueFlowSummary( + toRecordObject(turnMeaning?.previous_counterparty_value_flow_bundle), + separateSubject, + toRecordObject(turnMeaning?.previous_counterparty_document_bundle) + ); + if (!separateSubject || !previousCounterpartySummary) { + return null; + } + + const lines = organizationScope + ? [ + `Коротко: по компании ${organizationScope} в этом шаге нет нового полного company-level расчета; отдельно по выбранному контрагенту ${separateSubject} есть ранее подтвержденный контрагентский срез.`, + previousCounterpartySummary.line, + `Можно утверждать: по ${separateSubject} отдельно подтверждены входящие/исходящие денежные строки, расчетное нетто и документы из предыдущего контрагентского среза.`, + `Нельзя утверждать: это не подтверждает чистую прибыль, полный оборот или общую бизнес-роль ${separateSubject}; также нельзя смешивать этот контрагентский срез с выводами по компании без отдельного company-level расчета.` + ] + : [ + `Коротко: уточните, по какой компании/организации сравнить выбранного контрагента ${separateSubject}; company-level вывод без организации не подтверждаю.`, + previousCounterpartySummary.line, + `Уже можно утверждать: по ${separateSubject} отдельно подтверждены входящие/исходящие денежные строки, расчетное нетто и документы из предыдущего контрагентского среза.`, + `Нельзя утверждать: это не чистая прибыль, не полный оборот компании и не доказанная бизнес-роль ${separateSubject}; контрагентский срез нельзя смешивать с company-level выводом без выбранной компании.` + ]; + return joinBusinessReplyLines(lines); +} + function buildCompactBusinessOverviewReply( entryPoint: AssistantMcpDiscoveryRuntimeEntryPointContract, draft: Record @@ -921,6 +1011,13 @@ function buildCompactBusinessOverviewReply( : null; const graphReasonCodes = toStringList(graph?.reason_codes); const directMoneyAnswer = graphReasonCodes.includes("data_need_graph_business_overview_direct_money_answer"); + const broadOverviewSurfaceRequested = requestsBroadBusinessOverviewSurface(turnMeaning, graph); + const counterpartyLeaderSurfaceRequested = requestsCounterpartyLeaderSurface(turnMeaning, graph); + const directMoneyOnlyAnswer = + directMoneyAnswer && !broadOverviewSurfaceRequested && !counterpartyLeaderSurfaceRequested; + const shouldIncludeCounterpartyLeaders = + !directMoneyOnlyAnswer || counterpartyLeaderSurfaceRequested || broadOverviewSurfaceRequested; + const shouldIncludeOverviewSurface = !directMoneyAnswer || broadOverviewSurfaceRequested; const crossScopeExecutiveSummary = Boolean(separateSubject && previousCounterpartySummary); const lines: string[] = []; const actionFamily = toNonEmptyString(turnMeaning?.asked_action_family); @@ -931,9 +1028,22 @@ function buildCompactBusinessOverviewReply( actionFamily === "vendor_risk_procurement_boundary" || unsupportedFamily === "vendor_risk_procurement_boundary"; const inventoryReserveBoundary = actionFamily === "inventory_reserve_boundary" || unsupportedFamily === "inventory_reserve_liquidation_boundary"; - const compactCashflowRequested = directMoneyAnswer && requestsCompactCashflowAnswer(turnMeaning, graph); + const compactCashflowRequested = directMoneyOnlyAnswer && requestsCompactCashflowAnswer(turnMeaning, graph); const cashflowPolarityRequested = compactCashflowRequested && requestsCashflowPolarityAnswer(turnMeaning, graph); const directAccountingProfitRequested = requestsDirectAccountingProfitAnswer(turnMeaning, graph); + const rawMessage = toNonEmptyString(turnMeaning?.raw_message) ?? toNonEmptyString(turnMeaning?.effective_message); + const rawMessageComparable = compactComparable(rawMessage); + const organizationScopeComparable = compactComparable(organizationScope); + const plainOrganizationClarificationSelection = Boolean( + separateSubject && + organizationScope && + rawMessage && + rawMessageComparable && + organizationScopeComparable && + rawMessageComparable.includes(organizationScopeComparable) && + rawMessage.length <= 90 && + !/(?:сравн|подтвержд|деньг|сколько|что\s+|покаж|дай|вывод|нельзя|клиент|поставщик|\?)/iu.test(rawMessage) + ); if (compactCashflowRequested && !rankingNeed && (incomingAmount || outgoingAmount || netAmount)) { const netDisplay = sentenceAmount(netAmount) ?? netAmount ?? "0 \u0440\u0443\u0431."; @@ -955,6 +1065,23 @@ function buildCompactBusinessOverviewReply( return joinBusinessReplyLines(lines); } + if (plainOrganizationClarificationSelection && (incomingAmount || outgoingAmount || netAmount)) { + lines.push( + `Коротко: по компании ${organizationScope} ${period} подтвержден company-level денежный срез: входящие ${incomingAmount ?? "0 руб."}, исходящие ${outgoingAmount ?? "0 руб."}, операционное нетто ${sentenceAmount(netAmount) ?? netAmount ?? "0 руб."}.` + ); + if (previousCounterpartySummary) { + lines.push(previousCounterpartySummary.line); + } else { + lines.push( + `Отдельно по выбранному контрагенту ${separateSubject}: суммы компании на него не переношу; в этом шаге держу только границу, что это отдельный контрагентский контур.` + ); + } + lines.push( + `Нельзя утверждать: чистую прибыль, полноценный финрезультат, юридические роли клиентов/поставщиков и выводы по ${separateSubject} на основе company-level сумм без отдельного контрагентского среза.` + ); + return joinBusinessReplyLines(lines); + } + if (profitMarginBoundary) { const accountingFinancialResult = toRecordObject(overview.accounting_financial_result); if (accountingFinancialResult) { @@ -1178,7 +1305,13 @@ function buildCompactBusinessOverviewReply( return joinBusinessReplyLines(lines); } - if (!separateSubject && !crossScopeExecutiveSummary && (actionFamily === "broad_evaluation" || unsupportedFamily === "broad_business_evaluation")) { + if ( + !separateSubject && + !crossScopeExecutiveSummary && + !counterpartyLeaderSurfaceRequested && + !rankingNeed && + (actionFamily === "broad_evaluation" || unsupportedFamily === "broad_business_evaluation") + ) { const subject = organizationScope ?? "компания"; const periodWithoutPrefix = period.replace(/^за\s+/iu, ""); lines.push( @@ -1208,6 +1341,10 @@ function buildCompactBusinessOverviewReply( : `- крупнейший получатель исходящих денег: ${topSupplier};` ); } + const taxLine = businessOverviewTaxLine(overview); + if (taxLine) { + lines.push(`- ${localizeLine(taxLine)}`); + } const inventoryLine = businessOverviewInventoryLine(overview); if (inventoryLine) { lines.push(`- ${localizeLine(inventoryLine)}`); @@ -1220,7 +1357,7 @@ function buildCompactBusinessOverviewReply( "Ограничение: это оценка по денежным потокам и найденным срезам 1С, не аудиторское заключение и не подтвержденная чистая прибыль." ); const missingOverviewFamilies: string[] = []; - if (!businessOverviewTaxLine(overview)) { + if (!taxLine) { missingOverviewFamilies.push("НДС/налоговая позиция без отдельного точного расчета"); } if (!debtLine) { @@ -1264,9 +1401,26 @@ function buildCompactBusinessOverviewReply( !/(?:все\s+доступное|все\s+время|all\s+time)/iu.test(period) && (incomingAmount || outgoingAmount || netAmount); if (explicitPeriodRankingOverview) { - lines.push( - `Коротко: ${organizationPrefix}${period} денежная картина подтверждена по найденным строкам 1С.` - ); + if (counterpartyLeaderSurfaceRequested) { + const incomingLeaderText = + customerName && customerAmount + ? topCustomerLooksFinancial + ? `${customerName} — ${sentenceAmount(customerAmount) ?? customerAmount}; это банк/финансовый контур, не называю его обычной клиентской выручкой без назначения платежа${nonFinancialCustomer ? `; крупнейший небанковский входящий контрагент: ${nonFinancialCustomer}` : ""}` + : `${customerName} — ${sentenceAmount(customerAmount) ?? customerAmount}` + : "не распознан"; + const outgoingLeaderText = topSupplier + ? topSupplierLooksFinancial + ? `${topSupplier}; это банк/финансовый контур, не называю его обычным поставщиком без назначения платежа/договора${nonFinancialSupplier ? `; крупнейший небанковский получатель исходящих денег: ${nonFinancialSupplier}` : ""}` + : topSupplier + : "не распознан"; + lines.push( + `Коротко: ${organizationPrefix}${period} больше всего занес ${incomingLeaderText}; больше всего ушло ${outgoingLeaderText}.` + ); + } else { + lines.push( + `Коротко: ${organizationPrefix}${period} денежная картина подтверждена по найденным строкам 1С.` + ); + } lines.push( `Деньги: входящие ${incomingAmount ?? "0 руб."}, исходящие ${outgoingAmount ?? "0 руб."}, расчетное операционное нетто ${sentenceAmount(netAmount) ?? netAmount ?? "0 руб."}.` ); @@ -1332,7 +1486,7 @@ function buildCompactBusinessOverviewReply( `Коротко: ${organizationPrefix}${period} по подтвержденным строкам 1С получили ${incomingAmount ?? "0 руб."}; исходящие платежи/списания ${outgoingAmount ?? "0 руб."}; ${netDirection} ${sentenceAmount(netAmount) ?? netAmount ?? "0 руб"}${topCustomerLead}${topSupplierLead}${roleBoundaryLead}${separateSubjectLead}.` ); lines.push('Метод: "заработали" здесь считаю как операционный денежный показатель по 1С; это не чистая прибыль и не финрезультат.'); - if (!directMoneyAnswer && customerName && customerAmount) { + if (shouldIncludeCounterpartyLeaders && customerName && customerAmount) { lines.push( topCustomerLooksFinancial ? `Крупнейший входящий денежный источник в этом срезе: ${customerName} — ${sentenceAmount(customerAmount) ?? customerAmount}. По названию это банк/финансовая организация, поэтому без назначения платежа не называю это клиентской выручкой.${nonFinancialCustomer ? ` Крупнейший небанковский входящий контрагент: ${nonFinancialCustomer}.` : ""}` @@ -1353,21 +1507,21 @@ function buildCompactBusinessOverviewReply( ); } - if (!directMoneyAnswer && topSupplier) { + if (shouldIncludeCounterpartyLeaders && topSupplier) { lines.push( topSupplierLooksFinancial ? `Крупнейший получатель исходящих денег: ${topSupplier}. По названию это банк/финансовая организация, поэтому без назначения платежа/договора не считаю это обычным поставщиком.${nonFinancialSupplier ? ` Крупнейший небанковский получатель исходящих денег: ${nonFinancialSupplier}.` : ""}` : `Крупнейший подтвержденный получатель исходящих денег: ${topSupplier}.` ); } - if (!directMoneyAnswer && (topCustomer || topSupplier)) { + if (shouldIncludeCounterpartyLeaders && (topCustomer || topSupplier)) { lines.push( topCustomerLooksFinancial || topSupplierLooksFinancial ? "Важно по ролям: текущий денежный срез подтверждает источники и получателей денег, но банковские контрагенты требуют проверки назначения платежа/счетов и не доказывают роль клиента или поставщика." : "Важно по ролям: текущий денежный срез подтверждает денежные источники и получателей, но не доказывает, что это главный клиент или главный поставщик как бизнес-роль." ); } - if (!directMoneyAnswer) { + if (shouldIncludeOverviewSurface) { lines.push( `Что подтверждено: денежный срез по компании${organizationScope ? ` ${organizationScope}` : ""}${period ? ` ${period}` : ""}${topCustomer ? ", крупнейший источник входящих денег" : ""}${topSupplier ? ", крупнейший получатель исходящих денег" : ""}.` ); @@ -1466,6 +1620,11 @@ function buildReplyText(entryPoint: AssistantMcpDiscoveryRuntimeEntryPointContra return null; } + const previousCounterpartyBoundaryReply = buildBoundarySummaryFromPreviousCounterpartyBundles(entryPoint); + if (previousCounterpartyBoundaryReply) { + return previousCounterpartyBoundaryReply; + } + const compactBidirectionalValueFlowReply = buildCompactBidirectionalValueFlowReply(entryPoint, draft); if (compactBidirectionalValueFlowReply) { return compactBidirectionalValueFlowReply; diff --git a/llm_normalizer/backend/src/services/assistantMcpDiscoveryResponsePolicy.ts b/llm_normalizer/backend/src/services/assistantMcpDiscoveryResponsePolicy.ts index 2b71b16..7ec0edb 100644 --- a/llm_normalizer/backend/src/services/assistantMcpDiscoveryResponsePolicy.ts +++ b/llm_normalizer/backend/src/services/assistantMcpDiscoveryResponsePolicy.ts @@ -510,6 +510,13 @@ function hasExactDocumentListAddressReply( if (source !== "address_query_runtime_v1" && source !== "address_exact" && source !== "address_lane") { return false; } + if ( + hasValueFlowActionConflictWithDiscoveryTurnMeaning(input, entryPoint) || + hasEvidenceLaneConflictWithDiscoveryTurnMeaning(input, entryPoint) || + hasSemanticConflictWithDiscoveryTurnMeaning(input, entryPoint) + ) { + return false; + } const detectedIntent = toNonEmptyString(input.addressRuntimeMeta?.detected_intent); const selectedRecipe = toNonEmptyString(input.addressRuntimeMeta?.selected_recipe); const isDocumentIntent = diff --git a/llm_normalizer/backend/src/services/assistantMcpDiscoveryRuntimeBridge.ts b/llm_normalizer/backend/src/services/assistantMcpDiscoveryRuntimeBridge.ts index e26d064..31672f7 100644 --- a/llm_normalizer/backend/src/services/assistantMcpDiscoveryRuntimeBridge.ts +++ b/llm_normalizer/backend/src/services/assistantMcpDiscoveryRuntimeBridge.ts @@ -432,7 +432,12 @@ export async function runAssistantMcpDiscoveryRuntimeBridge( const reasonCodes = uniqueStrings([...planner.reason_codes, ...pilot.reason_codes, ...answerDraft.reason_codes]); pushReason(reasonCodes, `runtime_bridge_status_${bridgeStatus}`); - pushReason(reasonCodes, "runtime_bridge_not_wired_to_hot_assistant_answer"); + pushReason( + reasonCodes, + executionHandoff.can_use_guarded_response + ? "runtime_bridge_wired_to_guarded_hot_assistant_answer" + : "runtime_bridge_not_wired_to_hot_assistant_answer" + ); pushReason(reasonCodes, `runtime_bridge_loop_state_${loopState.loop_status}`); pushReason(reasonCodes, "runtime_bridge_route_candidate_built"); pushReason(reasonCodes, `runtime_bridge_route_candidate_${routeCandidate.candidate_status}`); diff --git a/llm_normalizer/backend/src/services/assistantMcpDiscoveryTurnInputAdapter.ts b/llm_normalizer/backend/src/services/assistantMcpDiscoveryTurnInputAdapter.ts index d055750..51c790b 100644 --- a/llm_normalizer/backend/src/services/assistantMcpDiscoveryTurnInputAdapter.ts +++ b/llm_normalizer/backend/src/services/assistantMcpDiscoveryTurnInputAdapter.ts @@ -117,6 +117,7 @@ function isReferentialOrganizationPlaceholder(value: string | null): boolean { "этой компании", "этой компанией", "эту компанию", + "в целом", "наша организация", "нашей организации", "нашей компанией" @@ -250,7 +251,13 @@ function normalizeFollowupCounterpartyCandidate(value: unknown): string | null { if (!text || isInvalidEntityCandidate(text)) { return null; } - return text; + const cleaned = text + .replace( + /^(?:\u043f\u043e\s+)?\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442(?:\u0443|\u0430|\u043e\u043c|\u0435|\u044b|\u0430\u043c|\u0430\u043c\u0438|\u0430\u0445)?\s+/iu, + "" + ) + .trim(); + return cleaned && !isInvalidEntityCandidate(cleaned) ? cleaned : text; } function pushScopedEntityCandidate( @@ -702,12 +709,13 @@ function collectFollowupDiscoverySeed(followupContext: Record | const normalizedDiscoveryEntities = discoveryEntities .map((entity) => normalizeFollowupCounterpartyCandidate(entity)) .filter((entity): entity is string => Boolean(entity)); + const normalizedLoopMetadataScopeHint = normalizeFollowupCounterpartyCandidate(loopMetadataScopeHint); const groundedDiscoveryCounterparty = ambiguityBlocksImplicitGrounding || metadataPilotCarriesScopeOnly ? null - : normalizedDiscoveryEntities[0] ?? normalizeFollowupCounterpartyCandidate(loopMetadataScopeHint); + : normalizedDiscoveryEntities[0] ?? normalizedLoopMetadataScopeHint; const metadataScopeHint = - loopMetadataScopeHint ?? + normalizedLoopMetadataScopeHint ?? (loopSubjectResolutionOptional ? normalizedDiscoveryEntities[0] ?? null : null); const previousFiltersCounterparty = normalizeFollowupCounterpartyCandidate(previousFilters?.counterparty); const rootFiltersCounterparty = normalizeFollowupCounterpartyCandidate(rootFilters?.counterparty); @@ -724,9 +732,10 @@ function collectFollowupDiscoverySeed(followupContext: Record | (toNonEmptyString(followupContext?.previous_anchor_type) === "organization" ? toNonEmptyString(followupContext?.previous_anchor_value) : null); - const dateScope = - collectDateScopeFromFilters(previousFilters) ?? - collectDateScopeFromFilters(rootFilters); + const loopProvidedAllTimeScope = loopProvidedAxes.includes("all_time_scope"); + const dateScope = loopProvidedAllTimeScope + ? "all_time_scope" + : collectDateScopeFromFilters(previousFilters) ?? collectDateScopeFromFilters(rootFilters); return { pilotScope: effectivePilotScope, domain: mapped.domain, @@ -986,7 +995,7 @@ function hasOrganizationLevelSupplierQualityOverviewSignal(text: string): boolea function hasCrossScopeExecutiveSummarySignal(text: string): boolean { return ( - /(?:\u0441\u043e\u0431\u0435\u0440\p{L}*\s+(?:\u043a\u043e\u0440\u043e\u0442\u043a\p{L}*\s+)?\u0438\u0442\u043e\u0433|\u044d\u043a\u0437\u0435\u043a\u044c\u044e\u0442\u0438\u0432\p{L}*\s+\u0441\u0430\u043c\u043c\u0430\u0440\u0438|executive\s+summary|final\s+summary)/iu.test( + /(?:\u0441\u043e\u0431\u0435\u0440\p{L}*\s+(?:\u043a\u043e\u0440\u043e\u0442\u043a\p{L}*\s+)?\u0438\u0442\u043e\u0433|(?:\u043a\u043e\u0440\u043e\u0442\u043a\p{L}*\s+)?\u0441\u0440\u0430\u0432\u043d\p{L}*|\u044d\u043a\u0437\u0435\u043a\u044c\u044e\u0442\u0438\u0432\p{L}*\s+\u0441\u0430\u043c\u043c\u0430\u0440\u0438|executive\s+summary|final\s+summary|brief(?:ly)?\s+compare)/iu.test( text ) && /(?:\u0447\u0442\u043e\s+(?:\u043c\u044b\s+)?\u043f\u043e\u0434\u0442\u0432\u0435\u0440\p{L}*|\u043f\u043e\s+\u043a\u043e\u043c\u043f\u0430\u043d\p{L}*|\u043f\u043e\s+\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\p{L}*|confirmed|company|organization)/iu.test( @@ -1013,6 +1022,35 @@ function hasPlainBusinessOverviewSignal(text: string): boolean { return hasPlainOverviewCue && hasCompanyOrOperatingScopeCue; } +function countBroadBusinessOverviewAxes(text: string): number { + const axisPatterns = [ + /(?:\u0434\u0435\u043d\p{L}*|\u043e\u0431\u043e\u0440\u043e\u0442|\u0432\u044b\u0440\u0443\u0447\p{L}*|\u043f\u043e\u0441\u0442\u0443\u043f\p{L}*|\u043f\u043b\u0430\u0442\p{L}*|money|cash|revenue|turnover)/iu, + /(?:\u043d\u0434\u0441|vat)/iu, + /(?:\u0434\u043e\u043b\p{L}*|\u0434\u0435\u0431\u0438\u0442\u043e\u0440\p{L}*|\u043a\u0440\u0435\u0434\u0438\u0442\u043e\u0440\p{L}*|receivable|payable|debt)/iu, + /(?:\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u0442\u043e\u0432\u0430\u0440|warehouse|stock|inventory)/iu, + /(?:\u043a\u043b\u0438\u0435\u043d\u0442|\u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b|\u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a|customer|client|buyer)/iu, + /(?:\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a|\u0432\u0435\u043d\u0434\u043e\u0440|\u0437\u0430\u043a\u0443\u043f|supplier|vendor|procurement)/iu, + /(?:\u0433\u0434\u0435[\s\S]{0,80}(?:\u043d\u0435\u043b\u044c\u0437\u044f|\u043d\u0435\s+\u0434\u0435\u043b\u0430\p{L}*|\u043d\u0435\s+\u0445\u0432\u0430\p{L}*)|\u0447\u0442\u043e[\s\S]{0,80}(?:\u043d\u0435\u043b\u044c\u0437\u044f|\u043d\u0435\s+\u0445\u0432\u0430\p{L}*)|cannot|unknown|missing|limitation)/iu + ]; + return axisPatterns.reduce((count, pattern) => count + (pattern.test(text) ? 1 : 0), 0); +} + +function hasBroadBusinessOverviewSurfaceSignal(text: string): boolean { + const normalized = compactLower(text); + if (!normalized) { + return false; + } + const hasBroadCue = + /(?:\u043f\u043e[-\s]*\u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\p{L}*|\u0447\u0442\u043e\s+\u043f\u043e\s+\u0431\u0438\u0437\u043d\u0435\u0441\u0443\s+\u0432\u0438\u0434\u043d\p{L}*|\u043f\u043e\u0441\u043c\u043e\u0442\p{L}*[\s\S]{0,100}(?:\u0431\u0438\u0437\u043d\u0435\u0441|\u0434\u0435\u044f\u0442\u0435\u043b\p{L}*)|\u0431\u0438\u0437\u043d\u0435\u0441[\s\S]{0,80}(?:\u0432\u0438\u0434\u043d\p{L}*|\u0432\u044b\u0432\u043e\u0434|\u0441\u0440\u0435\u0437)|human\s+readable\s+business\s+view)/iu.test( + normalized + ); + const hasCompanyScope = + /(?:\u043e\u043e\u043e|\u0438\u043f|\u0430\u043e|\u043f\u0430\u043e|\u0437\u0430\u043e|\u043e\u0430\u043e|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+1\s?\u0441|1\s?c|company|organization|business|(?:19|20)\d{2})/iu.test( + normalized + ); + return hasBroadCue && hasCompanyScope && countBroadBusinessOverviewAxes(normalized) >= 3; +} + function hasBusinessOverviewSignal(text: string): boolean { if ( hasCrossScopeExecutiveSummarySignal(text) || @@ -1021,6 +1059,7 @@ function hasBusinessOverviewSignal(text: string): boolean { hasOrganizationLevelDebtDueDateOverviewSignal(text) || hasOrganizationLevelInventoryReserveLiquidationOverviewSignal(text) || hasPlainBusinessOverviewSignal(text) || + hasBroadBusinessOverviewSurfaceSignal(text) || hasOrganizationLevelSupplierQualityOverviewSignal(text) ) { return true; @@ -1101,6 +1140,15 @@ function hasBusinessOverviewSeparateCounterpartySignal(text: string): boolean { ); } +function isGenericSelectedCounterpartyReference(value: string | null): boolean { + if (!value) { + return false; + } + return /^(?:(?:\u0432\u044b\u0431\u0440\u0430\u043d\p{L}*|\u044d\u0442\p{L}*|\u0434\u0430\u043d\p{L}*|\u0442\u0435\u043a\u0443\u0449\p{L}*)\s+)?\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\p{L}*$|^(?:selected|chosen|current|this)\s+counterpart(?:y|ies)?$/iu.test( + value + ); +} + function businessOverviewSeparateCounterpartyCandidateFromText(text: string): string | null { const source = repairAddressMojibakeText(String(text ?? "")); const patterns = [ @@ -1109,7 +1157,7 @@ function businessOverviewSeparateCounterpartyCandidateFromText(text: string): st ]; for (const pattern of patterns) { const candidate = normalizeFollowupCounterpartyCandidate(source.match(pattern)?.[1]); - if (candidate && !isInvalidEntityCandidate(candidate)) { + if (candidate && !isInvalidEntityCandidate(candidate) && !isGenericSelectedCounterpartyReference(candidate)) { return candidate; } } @@ -1245,6 +1293,9 @@ function normalizeLooseOrganizationAlias(value: string | null): string | null { if (hasYearOnlyTimeTail) { return null; } + if (new Set(["в целом", "компания в целом", "организация в целом"]).has(comparable)) { + return null; + } if (/^(?:\u0438|\u0432|\u0432\u043e|\u0437\u0430|\u043d\u0430|\u043f\u043e|\u043a\u0442\u043e|\u0447\u0442\u043e|\u043a\u0430\u043a(?:\u043e\u0439|\u0430\u044f|\u0438\u0435)?|\u0433\u043b\u0430\u0432\u043d\p{L}*)\b/iu.test(comparable)) { return null; } @@ -1910,11 +1961,21 @@ export function buildAssistantMcpDiscoveryTurnInput( const businessOverviewSignal = !businessOverviewCounterpartyValueFlowPivot && (rawBusinessOverviewSignal || seededBusinessOverviewSignal); + const organizationClarificationBusinessOverviewLoop = Boolean( + followupSeed.loopStatus === "awaiting_clarification" && + followupSeed.loopSelectedChainId === "business_overview" && + followupSeed.loopPendingAxes.includes("organization") && + currentTurnOrganizationScope && + !rawLifecycleSignal && + !rawMetadataSignal + ); const businessOverviewSeparateCounterpartySignal = Boolean( businessOverviewSignal && hasBusinessOverviewSeparateCounterpartySignal(rawText) ); const businessOverviewSeparateCounterpartyCandidate = businessOverviewSeparateCounterpartySignal ? businessOverviewSeparateCounterpartyCandidateFromText(rawText) + : organizationClarificationBusinessOverviewLoop + ? followupSeed.counterparty ?? followupSeed.discoveryEntity ?? followupSeed.metadataScopeHint : null; const explicitIntentCandidate = toNonEmptyString(assistantTurnMeaning?.explicit_intent_candidate); const currentTurnDocumentLaneSignal = rawAction === "list_documents"; @@ -1944,6 +2005,7 @@ export function buildAssistantMcpDiscoveryTurnInput( const businessOverviewSuppressesFollowupCounterparty = Boolean( businessOverviewSignal && !businessOverviewSeparateCounterpartySignal && + !organizationClarificationBusinessOverviewLoop && (rawBusinessOverviewSignal || businessOverviewContinuationSignal || broadBusinessEvaluationUnsupported || @@ -2452,7 +2514,9 @@ export function buildAssistantMcpDiscoveryTurnInput( } pushScopedEntityCandidate(entityCandidates, rawEntityCandidate, groundedFollowupEntity); } - const businessOverviewSeparateCounterpartyDisplayCandidate = businessOverviewSeparateCounterpartySignal + const shouldPreserveBusinessOverviewSeparateCounterparty = + businessOverviewSeparateCounterpartySignal || organizationClarificationBusinessOverviewLoop; + const businessOverviewSeparateCounterpartyDisplayCandidate = shouldPreserveBusinessOverviewSeparateCounterparty ? preferredScopedDisplayName(businessOverviewSeparateCounterpartyCandidate, [ groundedFollowupEntity, effectiveFollowupCounterparty, @@ -2461,7 +2525,24 @@ export function buildAssistantMcpDiscoveryTurnInput( rawScopedEntityCandidate, rawEntityCandidate, ...entityCandidates - ]) + ]) ?? + preferredScopedDisplayName( + groundedFollowupEntity ?? + effectiveFollowupCounterparty ?? + followupSeed.discoveryEntity ?? + normalizedPredecomposeCounterparty ?? + rawScopedEntityCandidate ?? + rawEntityCandidate, + [ + groundedFollowupEntity, + effectiveFollowupCounterparty, + followupSeed.discoveryEntity, + normalizedPredecomposeCounterparty, + rawScopedEntityCandidate, + rawEntityCandidate, + ...entityCandidates + ] + ) : null; const businessOverviewSeparateEntityCandidates = businessOverviewSeparateCounterpartyDisplayCandidate ? [businessOverviewSeparateCounterpartyDisplayCandidate] @@ -2586,6 +2667,7 @@ export function buildAssistantMcpDiscoveryTurnInput( const normalizedAssistantTurnMeaningDateScope = rawEntitySearchOverridesStaleScope || suppressNegatedTaxOnlyDateScope || + (organizationClarificationBusinessOverviewLoop && !currentTurnCarriesExplicitPeriod) || (suppressImplicitCurrentDateScope && isImplicitCurrentDateScope(assistantTurnMeaningDateScope)) ? null : assistantTurnMeaningDateScope; @@ -2603,8 +2685,9 @@ export function buildAssistantMcpDiscoveryTurnInput( normalizedPredecomposeDateScope && normalizedPredecomposeDateScope.startsWith(`${rawDateScope}-`) ); + const followupAllTimeScopeApplied = normalizedFollowupDateScope === "all_time_scope"; const explicitDateScope = - rawAllTimeScopeSignal + rawAllTimeScopeSignal || followupAllTimeScopeApplied ? null : normalizedAssistantTurnMeaningDateScope ?? (businessOverviewRawYearOverridesPredecomposeAsOf ? rawDateScope : normalizedPredecomposeDateScope) ?? @@ -2615,7 +2698,8 @@ export function buildAssistantMcpDiscoveryTurnInput( !normalizedAssistantTurnMeaningDateScope && !normalizedPredecomposeDateScope && !rawDateScope && - normalizedFollowupDateScope + normalizedFollowupDateScope && + normalizedFollowupDateScope !== "all_time_scope" ); const clarificationLoopSeedApplied = Boolean( followupSeed.loopStatus === "awaiting_clarification" && followupSeed.loopSelectedChainId @@ -2668,7 +2752,8 @@ export function buildAssistantMcpDiscoveryTurnInput( valueFlowSignal && followupSeed.rankingNeed && !rawEntitySearchOverridesStaleScope ? followupSeed.rankingNeed : undefined, - explicit_entity_candidates: businessOverviewSignal ? [] : entityCandidates, + explicit_entity_candidates: + businessOverviewSignal || shouldPreserveBusinessOverviewSeparateCounterparty ? [] : entityCandidates, business_overview_separate_entity_candidates: businessOverviewSeparateEntityCandidates, previous_counterparty_value_flow_bundle: businessOverviewSignal && followupSeed.previousBidirectionalValueFlow @@ -2897,6 +2982,9 @@ export function buildAssistantMcpDiscoveryTurnInput( if (rawAllTimeScopeSignal) { pushReason(reasonCodes, "mcp_discovery_all_time_scope_signal_detected"); } + if (followupAllTimeScopeApplied) { + pushReason(reasonCodes, "mcp_discovery_all_time_scope_from_followup_context"); + } if (suppressNegatedTaxOnlyDateScope) { pushReason(reasonCodes, "mcp_discovery_negated_tax_period_scope_suppressed"); } @@ -2999,7 +3087,7 @@ export function buildAssistantMcpDiscoveryTurnInput( if (businessOverviewSuppressesFollowupCounterparty) { pushReason(reasonCodes, "mcp_discovery_business_overview_suppressed_stale_counterparty"); } - if (businessOverviewSeparateCounterpartySignal) { + if (shouldPreserveBusinessOverviewSeparateCounterparty) { pushReason(reasonCodes, "mcp_discovery_business_overview_preserved_explicit_counterparty_summary_scope"); } if (businessOverviewSeparateCounterpartyCandidate) { @@ -3023,7 +3111,7 @@ export function buildAssistantMcpDiscoveryTurnInput( ) { pushReason(reasonCodes, "mcp_discovery_counterparty_from_predecompose"); } - if (rawScopedEntityCandidate && !normalizedPredecomposeCounterparty) { + if (rawScopedEntityCandidate && !normalizedPredecomposeCounterparty && !businessOverviewSignal) { pushReason(reasonCodes, "mcp_discovery_counterparty_from_raw_scope"); } if ( diff --git a/llm_normalizer/backend/src/services/assistantTransitionPolicy.ts b/llm_normalizer/backend/src/services/assistantTransitionPolicy.ts index 224cb0c..a13f2c1 100644 --- a/llm_normalizer/backend/src/services/assistantTransitionPolicy.ts +++ b/llm_normalizer/backend/src/services/assistantTransitionPolicy.ts @@ -136,6 +136,26 @@ export function createAssistantTransitionPolicy(deps) { return /(?:документ|счет|счет-фактур|накладн|акт|реализац|document|invoice|receipt)/iu.test(normalized); } + function hasSelectedCounterpartyDocumentFollowupSignal(userMessage, alternateMessage = null) { + return [userMessage, alternateMessage] + .filter((value) => deps.toNonEmptyString(value)) + .map((value) => normalizeFollowupText(value).replace(/С‘/g, "Рµ")) + .some((normalized) => { + if (!normalized) { + return false; + } + const hasDocumentCue = + /(?:\u0434\u043e\u043a\p{L}*|\u0441\u0447\p{L}*|\u043d\u0430\u043a\u043b\u0430\u0434\p{L}*|\u0430\u043a\u0442|document|docs?|invoice|receipt)/iu.test( + normalized + ) || hasReadableDocumentsPivotCue(normalized); + const hasSelectedCounterpartyCue = + /(?:\u043f\u043e\s+\u043d(?:\u0435\u043c\u0443|\u0435\u0439)|\u043f\u043e\s+\u044d\u0442(?:\u043e\u043c\u0443|\u043e\u0439)|\u0442\u0435\u043a\u0443\u0449\p{L}*\s+\u043e\u0431\u044a\u0435\u043a\p{L}*|\u0432\u044b\u0431\u0440\u0430\u043d\p{L}*\s+(?:\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442|\u043e\u0431\u044a\u0435\u043a\u0442)|selected\s+(?:counterparty|object)|current\s+object)/iu.test( + normalized + ); + return hasDocumentCue && hasSelectedCounterpartyCue; + }); + } + function selectSuggestedIntentByPivotCue(suggestedIntents, userMessage, alternateMessage = null) { if (!Array.isArray(suggestedIntents) || suggestedIntents.length === 0) { return null; @@ -425,20 +445,71 @@ export function createAssistantTransitionPolicy(deps) { return flow; } + function readMcpDiscoveryPreviousCounterpartyValueFlowBundle(debug) { + const entryPoint = debug?.assistant_mcp_discovery_entry_point_v1; + const bundle = entryPoint?.turn_input?.turn_meaning_ref?.previous_counterparty_value_flow_bundle; + if (!bundle || typeof bundle !== "object" || Array.isArray(bundle)) { + return null; + } + return bundle; + } + + function readMcpDiscoveryPreviousCounterpartyDocumentBundle(debug) { + const entryPoint = debug?.assistant_mcp_discovery_entry_point_v1; + const bundle = entryPoint?.turn_input?.turn_meaning_ref?.previous_counterparty_document_bundle; + if (!bundle || typeof bundle !== "object" || Array.isArray(bundle)) { + return null; + } + return bundle; + } + function readCounterpartyDocumentSummaryFromItem(item) { const text = deps.toNonEmptyString(item?.text); if (!text) { return null; } const firstLine = text.split(/\r?\n/).map((line) => line.trim()).find(Boolean) ?? ""; - const match = firstLine.match(/Контрагент:\s*([^.\n]+)\.\s*Найдено документов:\s*(\d+)/iu); - if (!match?.[1] || !match?.[2]) { + const directMatch = firstLine.match(/Контрагент:\s*([^.\n]+)\.\s*Найдено документов:\s*(\d+)/iu); + if (directMatch?.[1] && directMatch?.[2]) { + return { + counterparty: deps.toNonEmptyString(directMatch[1]), + document_count: Number(directMatch[2]), + direct_answer: firstLine + }; + } + const summaryMatch = text.match(/Отдельно\s+по\s+контрагенту\s+([^:\n]+):[\s\S]{0,260}документы\s+по\s+цепочке:\s*найдено\s*(\d+)/iu); + if (!summaryMatch?.[1] || !summaryMatch?.[2]) { + return null; + } + return { + counterparty: deps.toNonEmptyString(summaryMatch[1]), + document_count: Number(summaryMatch[2]), + direct_answer: summaryMatch[0].replace(/\s+/g, " ").trim() + }; + } + + function readCounterpartyValueFlowSummaryFromItem(item) { + const text = deps.toNonEmptyString(item?.text); + if (!text) { + return null; + } + const match = text.match( + /Отдельно\s+по\s+контрагенту\s+([^:\n]+):\s*подтверждено\s+получили\s+([^,\n]+?руб\.?),\s*заплатили\s+([^,\n]+?руб\.?),\s*расчетное\s+нетто\s+в\s+нашу\s+сторону\s+([^.\n]+?руб\.?)/iu + ); + if (!match?.[1] || !match?.[2] || !match?.[3] || !match?.[4]) { return null; } return { counterparty: deps.toNonEmptyString(match[1]), - document_count: Number(match[2]), - direct_answer: firstLine + incoming_customer_revenue: { + total_amount_human_ru: deps.toNonEmptyString(match[2]) + }, + outgoing_supplier_payout: { + total_amount_human_ru: deps.toNonEmptyString(match[3]) + }, + net_amount_human_ru: deps.toNonEmptyString(match[4]), + net_direction: "net_incoming", + inference_basis: "parsed_from_previous_confirmed_counterparty_boundary_summary" }; } @@ -446,12 +517,51 @@ export function createAssistantTransitionPolicy(deps) { for (let index = Array.isArray(items) ? items.length - 1 : -1; index >= 0; index -= 1) { const item = items[index]; const debug = item?.debug; - if (!item || item.role !== "assistant" || !debug || typeof debug !== "object") { + const isAssistantItem = item?.role === "assistant" || item?.kind === "assistant"; + if (!item || !isAssistantItem) { continue; } - const flow = readMcpDiscoveryBidirectionalValueFlow(debug); - if (flow) { - return flow; + if (debug && typeof debug === "object") { + const flow = readMcpDiscoveryBidirectionalValueFlow(debug); + if (flow) { + return flow; + } + } + const parsedFlow = readCounterpartyValueFlowSummaryFromItem(item); + if (parsedFlow) { + return parsedFlow; + } + } + return null; + } + + function sameCounterpartyHint(expected, actual) { + const left = normalizeFollowupText(expected); + const right = normalizeFollowupText(actual); + if (!left || !right) { + return false; + } + return left === right || left.includes(right) || right.includes(left); + } + + function findRecentPreviousCounterpartyValueFlowBundle(items, counterpartyHint = null) { + const expectedCounterparty = deps.toNonEmptyString(counterpartyHint); + if (!expectedCounterparty) { + return null; + } + for (let index = Array.isArray(items) ? items.length - 1 : -1; index >= 0; index -= 1) { + const item = items[index]; + const debug = item?.debug; + const isAssistantItem = item?.role === "assistant" || item?.kind === "assistant"; + if (!item || !isAssistantItem || !debug || typeof debug !== "object") { + continue; + } + const bundle = readMcpDiscoveryPreviousCounterpartyValueFlowBundle(debug); + if (!bundle) { + continue; + } + if (sameCounterpartyHint(expectedCounterparty, deps.toNonEmptyString(bundle.counterparty))) { + return bundle; } } return null; @@ -460,7 +570,8 @@ export function createAssistantTransitionPolicy(deps) { function findRecentCounterpartyDocumentBundle(items) { for (let index = Array.isArray(items) ? items.length - 1 : -1; index >= 0; index -= 1) { const item = items[index]; - if (!item || item.role !== "assistant" || !item.debug || typeof item.debug !== "object") { + const isAssistantItem = item?.role === "assistant" || item?.kind === "assistant"; + if (!item || !isAssistantItem) { continue; } const summary = readCounterpartyDocumentSummaryFromItem(item); @@ -471,6 +582,29 @@ export function createAssistantTransitionPolicy(deps) { return null; } + function findRecentPreviousCounterpartyDocumentBundle(items, counterpartyHint = null) { + const expectedCounterparty = deps.toNonEmptyString(counterpartyHint); + if (!expectedCounterparty) { + return null; + } + for (let index = Array.isArray(items) ? items.length - 1 : -1; index >= 0; index -= 1) { + const item = items[index]; + const debug = item?.debug; + const isAssistantItem = item?.role === "assistant" || item?.kind === "assistant"; + if (!item || !isAssistantItem || !debug || typeof debug !== "object") { + continue; + } + const bundle = readMcpDiscoveryPreviousCounterpartyDocumentBundle(debug); + if (!bundle) { + continue; + } + if (sameCounterpartyHint(expectedCounterparty, deps.toNonEmptyString(bundle.counterparty))) { + return bundle; + } + } + return null; + } + function hasInventoryPurchaseDateVatBridgeSignal(userMessage, alternateMessage, sourceIntentHint, hasInventoryItemFocusHint) { if ( sourceIntentHint !== "inventory_purchase_provenance_for_item" && @@ -681,10 +815,22 @@ export function createAssistantTransitionPolicy(deps) { ? hasShortValueFlowRetargetCue(String(alternateMessage ?? "")) || hasCompactCashflowFollowupCue(String(alternateMessage ?? "")) : false); + const earlyNavigationSessionState = resolveNavigationSessionContextState( + addressNavigationState, + deps.toNonEmptyString, + deps.normalizeOrganizationScopeValue + ); + const earlyNavigationFocusObject = earlyNavigationSessionState.focusObject; + const selectedCounterpartyDocumentFollowupSignal = Boolean( + deps.toNonEmptyString(earlyNavigationFocusObject?.label) && + deps.toNonEmptyString(earlyNavigationFocusObject?.objectType) === "counterparty" && + hasSelectedCounterpartyDocumentFollowupSignal(userMessage, alternateMessage) + ); if ( assistantTurnMeaning?.stale_replay_forbidden === true && !hasExplicitSummaryBundleReuseSignal(userMessage, alternateMessage) && - !compactCashflowFollowupSignal + !compactCashflowFollowupSignal && + !selectedCounterpartyDocumentFollowupSignal ) { return null; } @@ -784,11 +930,7 @@ export function createAssistantTransitionPolicy(deps) { sourceDiscoveryPilotScopeHint === "business_overview_route_template_v1"; const hasBusinessOverviewCarryoverSourceHint = sourceDiscoveryPilotScopeHint === "business_overview_route_template_v1"; - const navigationSessionState = resolveNavigationSessionContextState( - addressNavigationState, - deps.toNonEmptyString, - deps.normalizeOrganizationScopeValue - ); + const navigationSessionState = earlyNavigationSessionState; const navigationFocusObjectHint = navigationSessionState.focusObject; const hasNavigationInventoryItemFocusHint = Boolean( deps.toNonEmptyString(navigationFocusObjectHint?.label) && @@ -912,6 +1054,7 @@ export function createAssistantTransitionPolicy(deps) { Boolean(debtRoleSwapIntent) || shortValueFlowRetargetPrimary || shortValueFlowRetargetAlternate || + selectedCounterpartyDocumentFollowupSignal || businessOverviewBoundaryFollowupPrimary || businessOverviewBoundaryFollowupAlternate || inventoryMarginRankingFollowup || @@ -937,6 +1080,7 @@ export function createAssistantTransitionPolicy(deps) { Boolean(debtRoleSwapIntent) || shortValueFlowRetargetPrimary || shortValueFlowRetargetAlternate || + selectedCounterpartyDocumentFollowupSignal || businessOverviewBoundaryFollowupPrimary || businessOverviewBoundaryFollowupAlternate || inventoryMarginRankingFollowup || @@ -969,6 +1113,7 @@ export function createAssistantTransitionPolicy(deps) { !hasInventoryRootRestatementAlternate && !shortValueFlowRetargetPrimary && !shortValueFlowRetargetAlternate && + !selectedCounterpartyDocumentFollowupSignal && !hasImplicitContinuationSignal && !hasSuggestedIntentPivotSignal && !hasOrganizationClarificationContinuation && @@ -987,6 +1132,7 @@ export function createAssistantTransitionPolicy(deps) { !hasInventoryRootRestatementAlternate && !shortValueFlowRetargetPrimary && !shortValueFlowRetargetAlternate && + !selectedCounterpartyDocumentFollowupSignal && !hasImplicitContinuationSignal && !hasSuggestedIntentPivotSignal && !hasOrganizationClarificationContinuation && @@ -1062,9 +1208,22 @@ export function createAssistantTransitionPolicy(deps) { carryoverSourceDebug, deps.toNonEmptyString ); + const sourceDiscoveryCounterpartyHint = + sourceDiscoveryLoopMetadataScopeHint ?? + (deps.toNonEmptyString(earlyNavigationFocusObject?.objectType) === "counterparty" + ? deps.toNonEmptyString(earlyNavigationFocusObject?.label) + : null); const sourceDiscoveryBidirectionalValueFlow = - readMcpDiscoveryBidirectionalValueFlow(carryoverSourceDebug) ?? findRecentDiscoveryValueFlowBundle(items); - const sourceDiscoveryDocumentSummary = findRecentCounterpartyDocumentBundle(items); + readMcpDiscoveryBidirectionalValueFlow(carryoverSourceDebug) ?? + readMcpDiscoveryPreviousCounterpartyValueFlowBundle(carryoverSourceDebug) ?? + findRecentPreviousCounterpartyValueFlowBundle(items, sourceDiscoveryCounterpartyHint) ?? + readCounterpartyValueFlowSummaryFromItem(previousAddressItem) ?? + findRecentDiscoveryValueFlowBundle(items); + const sourceDiscoveryDocumentSummary = + readMcpDiscoveryPreviousCounterpartyDocumentBundle(carryoverSourceDebug) ?? + findRecentPreviousCounterpartyDocumentBundle(items, sourceDiscoveryCounterpartyHint) ?? + readCounterpartyDocumentSummaryFromItem(previousAddressItem) ?? + findRecentCounterpartyDocumentBundle(items); const llmExplicitIntent = deps.toNonEmptyString(llmPreDecomposeMeta?.predecomposeContract?.intent); const llmSelectedObjectScopeDetected = llmPreDecomposeMeta?.predecomposeContract?.semantics?.selected_object_scope_detected === true; @@ -1240,6 +1399,17 @@ export function createAssistantTransitionPolicy(deps) { let resolvedCounterpartyFromDisplay = false; let displayedEntityTargetIntent = null; let previousFilters = resolveAddressDebugCarryoverFilters(carryoverSourceDebug, deps.toNonEmptyString); + const navigationCounterpartyFocus = + navigationFocusObjectType === "counterparty" ? navigationFocusObjectLabel : null; + const hasNavigationCounterpartyFocusCarryover = Boolean( + navigationCounterpartyFocus && + (hasValueFlowCarryoverSourceHint || + sourceIntentHint === "list_contracts_by_counterparty" || + sourceIntentHint === "list_documents_by_counterparty" || + sourceIntentHint === "bank_operations_by_counterparty" || + sourceIntentHint === "open_items_by_counterparty_or_contract" || + sourceDiscoveryLoopSelectedChainIdHint === "value_flow_comparison") + ); const shouldBackfillHistoricalPartyAnchors = sourceIntentHint === "list_contracts_by_counterparty" || sourceIntentHint === "list_documents_by_counterparty" || @@ -1254,6 +1424,15 @@ export function createAssistantTransitionPolicy(deps) { deps.findRecentAddressFilterValue(items, "counterparty"), deps.toNonEmptyString ); + if (hasNavigationCounterpartyFocusCarryover && navigationCounterpartyFocus) { + if (!previousAnchor) { + previousAnchorType = "counterparty"; + previousAnchor = navigationCounterpartyFocus; + } + if (!deps.toNonEmptyString(previousFilters.counterparty)) { + previousFilters.counterparty = navigationCounterpartyFocus; + } + } const historicalOrganization = deps.findRecentAddressFilterValue(items, "organization"); const authorityActiveOrganization = deps.normalizeOrganizationScopeValue(organizationAuthority.activeOrganization) ?? diff --git a/llm_normalizer/backend/src/types/addressNavigation.ts b/llm_normalizer/backend/src/types/addressNavigation.ts index 71e72a5..375594c 100644 --- a/llm_normalizer/backend/src/types/addressNavigation.ts +++ b/llm_normalizer/backend/src/types/addressNavigation.ts @@ -65,6 +65,14 @@ export interface AddressNavigationEvent { export interface AddressNavigationSessionContext { active_result_set_id: string | null; active_focus_object: AddressFocusObject | null; + comparison_scope: { + organization: AddressFocusObject | null; + counterparty: AddressFocusObject | null; + proof_bundles: { + counterparty_value_flow_bundle: Record | null; + counterparty_document_bundle: Record | null; + } | null; + } | null; last_confirmed_route: string | null; date_scope: { as_of_date: string | null; diff --git a/llm_normalizer/backend/src/types/addressQuery.ts b/llm_normalizer/backend/src/types/addressQuery.ts index c109dea..cdc394f 100644 --- a/llm_normalizer/backend/src/types/addressQuery.ts +++ b/llm_normalizer/backend/src/types/addressQuery.ts @@ -7,6 +7,7 @@ import type { } from "./assistantRuntimeContracts"; export type AddressIntent = + | "business_overview" | "period_coverage_profile" | "document_type_and_account_section_profile" | "counterparty_population_and_roles" diff --git a/llm_normalizer/backend/src/types/assistant.ts b/llm_normalizer/backend/src/types/assistant.ts index 0c40065..9cc2dd5 100644 --- a/llm_normalizer/backend/src/types/assistant.ts +++ b/llm_normalizer/backend/src/types/assistant.ts @@ -529,6 +529,11 @@ export interface AssistantDebugPayload { fa_live_route_audit?: FaLiveRouteAuditDebug; eligibility_time_basis?: GroundedAnswerEligibilityGuardDebug["eligibility_time_basis"]; grounded_answer_eligibility_guard?: GroundedAnswerEligibilityGuardDebug; + mcp_discovery_response_applied?: boolean; + mcp_discovery_selected_chain_id?: string | null; + mcp_discovery_effective_response_route?: string | null; + assistant_mcp_discovery_entry_point_v1?: unknown; + mcp_discovery_response_candidate_v1?: unknown; followup_state_usage?: FollowupStateUsageDebug; problem_centric_answer_applied?: boolean; problem_units_used_count?: number; diff --git a/llm_normalizer/backend/tests/addressIntentResolverRegression.test.ts b/llm_normalizer/backend/tests/addressIntentResolverRegression.test.ts index 7562f37..95239b5 100644 --- a/llm_normalizer/backend/tests/addressIntentResolverRegression.test.ts +++ b/llm_normalizer/backend/tests/addressIntentResolverRegression.test.ts @@ -72,6 +72,15 @@ describe("addressIntentResolver regression bridges", () => { expect(result.reasons).toContain("unicode_business_overview_debt_position_deferred_to_discovery"); }); + it("defers colloquial multi-surface company overview to discovery before exact VAT", () => { + const result = resolveAddressIntent( + "\u041f\u043e-\u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438 \u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441 \u0437\u0430 2020: \u0447\u0442\u043e \u043f\u043e \u0431\u0438\u0437\u043d\u0435\u0441\u0443 \u0432\u0438\u0434\u043d\u043e \u0432 1\u0421 \u043f\u043e \u0434\u0435\u043d\u044c\u0433\u0430\u043c, \u041d\u0414\u0421, \u0434\u043e\u043b\u0433\u0430\u043c, \u0441\u043a\u043b\u0430\u0434\u0443, \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c/\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\u0430\u043c \u0438 \u0433\u0434\u0435 \u043f\u043e\u043a\u0430 \u043d\u0435\u043b\u044c\u0437\u044f \u0434\u0435\u043b\u0430\u0442\u044c \u0432\u044b\u0432\u043e\u0434?" + ); + + expect(result.intent).toBe("unknown"); + expect(result.reasons).toContain("unicode_business_overview_multi_surface_deferred_to_discovery"); + }); + it("detects specific counterparty turnover wording as revenue profile", () => { const result = resolveAddressIntent( "\u043a\u0430\u043a\u043e\u0439 \u043e\u0431\u043e\u0440\u043e\u0442 \u0431\u044b\u043b \u0441\u0432\u043a" diff --git a/llm_normalizer/backend/tests/addressNavigationState.test.ts b/llm_normalizer/backend/tests/addressNavigationState.test.ts index fdf87b5..d14586a 100644 --- a/llm_normalizer/backend/tests/addressNavigationState.test.ts +++ b/llm_normalizer/backend/tests/addressNavigationState.test.ts @@ -55,6 +55,231 @@ describe("address navigation state", () => { expect(evolved.navigation_history[0]?.action).toBe("open"); }); + it("captures organization focus from applied business overview discovery turns", () => { + const base = createEmptyAddressNavigationState("asst-bo", "2026-04-12T10:00:00.000Z"); + const assistantItem = { + message_id: "msg-bo1", + session_id: "asst-bo", + role: "assistant", + text: "Коротко: по данным ООО Альтернатива Плюс за 2020 подтвержден бизнес-обзор.", + reply_type: "partial_coverage", + created_at: "2026-04-12T10:10:00.000Z", + trace_id: "address-bo", + debug: { + detected_mode: "address_query", + detected_intent: "unknown", + selected_recipe: null, + extracted_filters: {}, + anchor_type: "unknown", + mcp_discovery_response_applied: true, + mcp_discovery_selected_chain_id: "business_overview", + assistant_mcp_discovery_entry_point_v1: { + schema_version: "assistant_mcp_discovery_runtime_entry_point_v1", + entry_status: "bridge_executed", + turn_input: { + turn_meaning_ref: { + explicit_organization_scope: "ООО Альтернатива Плюс", + explicit_date_scope: "2020" + } + }, + bridge: { + bridge_status: "answer_draft_ready", + answer_draft: { + answer_mode: "confirmed_with_bounded_inference" + } + } + }, + dialog_continuation_contract_v2: { + decision: "new_topic" + } + } + } as any; + + const evolved = evolveAddressNavigationStateWithAssistantItem(base, assistantItem, 2); + expect(evolved.result_sets[0]?.route_id).toBe("business_overview"); + expect(evolved.result_sets[0]?.filters.organization).toBe("ООО Альтернатива Плюс"); + expect(evolved.session_context.active_focus_object?.object_type).toBe("organization"); + expect(evolved.session_context.active_focus_object?.label).toBe("ООО Альтернатива Плюс"); + expect(evolved.session_context.organization_scope).toBe("ООО Альтернатива Плюс"); + expect(evolved.session_context.date_scope.period_from).toBe("2020-01-01"); + expect(evolved.session_context.date_scope.period_to).toBe("2020-12-31"); + }); + + it("captures counterparty focus from applied discovery turns even when the response stayed in chat mode", () => { + const base = createEmptyAddressNavigationState("asst-vf", "2026-04-12T10:00:00.000Z"); + const assistantItem = { + message_id: "msg-vf1", + session_id: "asst-vf", + role: "assistant", + text: "\u041f\u043e \u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a \u0437\u0430 2020 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u044b \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0438 \u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0434\u0435\u043d\u044c\u0433\u0438.", + reply_type: "partial_coverage", + created_at: "2026-04-12T10:12:00.000Z", + trace_id: "chat-vf", + debug: { + detected_mode: "chat", + detected_intent: "unknown", + selected_recipe: null, + extracted_filters: {}, + anchor_type: "unknown", + mcp_discovery_response_applied: true, + mcp_discovery_selected_chain_id: "value_flow_comparison", + assistant_mcp_discovery_entry_point_v1: { + schema_version: "assistant_mcp_discovery_runtime_entry_point_v1", + entry_status: "bridge_executed", + turn_input: { + turn_meaning_ref: { + asked_domain_family: "counterparty_value", + asked_action_family: "compare_incoming_outgoing", + explicit_entity_candidates: ["\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a"], + stale_replay_forbidden: true, + explicit_date_scope: "2020" + } + }, + bridge: { + bridge_status: "answer_draft_ready", + answer_draft: { + answer_mode: "confirmed_factual" + } + } + }, + dialog_continuation_contract_v2: { + decision: "new_topic" + } + } + } as any; + + const evolved = evolveAddressNavigationStateWithAssistantItem(base, assistantItem, 2); + expect(evolved.result_sets[0]?.route_id).toBe("value_flow_comparison"); + expect(evolved.result_sets[0]?.intent).toBe("customer_revenue_and_payments"); + expect(evolved.result_sets[0]?.filters.counterparty).toBe("\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a"); + expect(evolved.session_context.active_focus_object?.object_type).toBe("counterparty"); + expect(evolved.session_context.active_focus_object?.label).toBe("\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a"); + expect(evolved.session_context.date_scope.period_from).toBe("2020-01-01"); + expect(evolved.session_context.date_scope.period_to).toBe("2020-12-31"); + }); + + it("keeps selected counterparty focus for company boundary summaries", () => { + const initial = createEmptyAddressNavigationState("asst-boundary", "2026-04-12T10:00:00.000Z"); + const assistantItem = { + message_id: "msg-boundary", + session_id: "asst-boundary", + role: "assistant", + text: + "Коротко: по компании Альтернатива Плюс подтвержден company-level денежный срез.\n" + + "Отдельно по выбранному контрагенту Группа СВК: суммы компании на него не переношу.", + created_at: "2026-04-12T10:05:00.000Z", + debug: { + detected_intent: "unknown", + mcp_discovery_selected_chain_id: "business_overview", + mcp_discovery_response_applied: true, + extracted_filters: { + organization: "Альтернатива Плюс" + }, + assistant_mcp_discovery_entry_point_v1: { + turn_input: { + turn_meaning_ref: { + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + business_overview_separate_entity_candidates: ["Группа СВК"], + explicit_organization_scope: "Альтернатива Плюс" + }, + data_need_graph: { + business_fact_family: "business_overview", + subject_candidates: [] + } + } + } + } + } as any; + + const evolved = evolveAddressNavigationStateWithAssistantItem(initial, assistantItem, 1); + + expect(evolved.session_context.organization_scope).toBe("Альтернатива Плюс"); + expect(evolved.session_context.active_focus_object?.object_type).toBe("counterparty"); + expect(evolved.session_context.active_focus_object?.label).toBe("Группа СВК"); + expect(evolved.session_context.comparison_scope?.organization?.label).toBe("Альтернатива Плюс"); + expect(evolved.session_context.comparison_scope?.counterparty?.label).toBe("Группа СВК"); + expect(evolved.navigation_history[0]?.target_object_id).toBe("counterparty:группа свк"); + }); + + it("carries comparison proof bundles through organization clarification", () => { + const org = "\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441"; + const counterparty = "\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a"; + const valueFlowBundle = { + counterparty, + incoming_customer_revenue: { total_amount_human_ru: "20 653 490 руб." }, + outgoing_supplier_payout: { total_amount_human_ru: "2 129 651 руб." }, + net_amount_human_ru: "18 523 839 руб." + }; + const documentBundle = { counterparty, document_count: 19 }; + const initial = createEmptyAddressNavigationState("asst-proof", "2026-04-12T10:00:00.000Z"); + const boundaryItem = { + message_id: "msg-boundary-proof", + session_id: "asst-proof", + role: "assistant", + text: `Коротко: уточните организацию для сравнения ${counterparty}.`, + created_at: "2026-04-12T10:05:00.000Z", + debug: { + detected_intent: "unknown", + mcp_discovery_selected_chain_id: "business_overview", + mcp_discovery_response_applied: true, + extracted_filters: {}, + assistant_mcp_discovery_entry_point_v1: { + turn_input: { + turn_meaning_ref: { + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + business_overview_separate_entity_candidates: [counterparty], + previous_counterparty_value_flow_bundle: valueFlowBundle, + previous_counterparty_document_bundle: documentBundle + } + } + } + } + } as any; + + const afterBoundary = evolveAddressNavigationStateWithAssistantItem(initial, boundaryItem, 1); + expect(afterBoundary.session_context.comparison_scope?.organization).toBeNull(); + expect(afterBoundary.session_context.comparison_scope?.counterparty?.label).toBe(counterparty); + expect(afterBoundary.session_context.comparison_scope?.proof_bundles?.counterparty_value_flow_bundle).toEqual( + valueFlowBundle + ); + + const clarifiedItem = { + message_id: "msg-boundary-org", + session_id: "asst-proof", + role: "assistant", + text: `Коротко: по компании ${org} подтвержден company-level срез. Отдельно по ${counterparty}: границу не теряю.`, + created_at: "2026-04-12T10:06:00.000Z", + debug: { + detected_intent: "business_overview", + mcp_discovery_selected_chain_id: "business_overview", + mcp_discovery_response_applied: true, + extracted_filters: { organization: org }, + assistant_mcp_discovery_entry_point_v1: { + turn_input: { + turn_meaning_ref: { + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + business_overview_separate_entity_candidates: [counterparty], + explicit_organization_scope: org + } + } + } + } + } as any; + + const afterClarification = evolveAddressNavigationStateWithAssistantItem(afterBoundary, clarifiedItem, 2); + expect(afterClarification.session_context.comparison_scope?.organization?.label).toBe(org); + expect(afterClarification.session_context.comparison_scope?.counterparty?.label).toBe(counterparty); + expect(afterClarification.session_context.comparison_scope?.proof_bundles?.counterparty_value_flow_bundle).toEqual( + valueFlowBundle + ); + expect(afterClarification.session_context.comparison_scope?.proof_bundles?.counterparty_document_bundle).toEqual( + documentBundle + ); + }); + it("tracks drilldown event for follow-up continuation turn", () => { const initial = normalizeAddressNavigationState( { diff --git a/llm_normalizer/backend/tests/addressQueryRuntimeM23.test.ts b/llm_normalizer/backend/tests/addressQueryRuntimeM23.test.ts index e881557..0e03d7d 100644 --- a/llm_normalizer/backend/tests/addressQueryRuntimeM23.test.ts +++ b/llm_normalizer/backend/tests/addressQueryRuntimeM23.test.ts @@ -2145,6 +2145,43 @@ describe("address compose stage utf8 headers", () => { expect(reply.semantics?.balance_confirmed).toBe(true); }); + it("explains purchase-date anchor for confirmed VAT tax-period reply", () => { + const reply = composeFactualReply( + "vat_liability_confirmed_for_tax_period", + [ + { + period: "2015-02-28T23:59:59Z", + registrator: "VAT_BOOK_SALES", + account_dt: "68.02", + account_kt: "", + amount: 3500000, + analytics: [] + }, + { + period: "2015-02-28T23:59:59Z", + registrator: "VAT_BOOK_PURCHASES", + account_dt: "19", + account_kt: "", + amount: 868612, + analytics: [] + } + ], + { + userMessage: "ндс можешь прикинуть на дату покупки рабочей станции?", + periodFrom: "2015-02-01", + periodTo: "2015-02-28", + asOfDate: "2016-03-31", + organizationHint: "ООО Альтернатива Плюс", + useRubCurrency: true + } + ); + + expect(reply.responseType).toBe("FACTUAL_SUMMARY"); + expect(reply.text).toContain("Якорь периода: дата покупки из вопроса/контекста"); + expect(reply.text).toContain("01.02.2015..28.02.2015"); + expect(reply.text).toContain("книг продаж/покупок"); + }); + it("formats VAT forecast amounts in rubles and emphasizes numbers when requested", () => { const reply = composeFactualReply( "vat_payable_forecast", diff --git a/llm_normalizer/backend/tests/assistantAddressLaneResponseRuntimeAdapter.test.ts b/llm_normalizer/backend/tests/assistantAddressLaneResponseRuntimeAdapter.test.ts index afb09e0..898c015 100644 --- a/llm_normalizer/backend/tests/assistantAddressLaneResponseRuntimeAdapter.test.ts +++ b/llm_normalizer/backend/tests/assistantAddressLaneResponseRuntimeAdapter.test.ts @@ -236,6 +236,216 @@ describe("assistant address lane response runtime adapter", () => { expect(String((runtime.response as any).assistant_reply)).toContain("исходящих платежей/списаний"); }); + it("aligns final route metadata when a business-overview discovery candidate replaces a stale exact reply", () => { + const finalizeAddressTurn = vi.fn((input) => ({ + response: { + ok: true, + assistant_reply: input.assistantReply, + reply_type: input.replyType, + debug: input.debug + } + })); + + const runtime = runAssistantAddressLaneResponseRuntime({ + sessionId: "asst-business-overview-address", + userMessage: "Собери короткий бизнес-итог по компании и отдельно по СВК.", + effectiveAddressUserMessage: "Собери короткий бизнес-итог по компании и отдельно по СВК.", + addressLane: { + handled: true, + reply_text: "Контрагент: Группа СВК. Найдено документов: 19.", + reply_type: "factual", + debug: { + detected_intent: "list_documents_by_counterparty", + selected_recipe: "address_documents_by_counterparty_v1", + response_type: "FACTUAL_LIST" + } + }, + llmPreDecomposeMeta: { + mcpDiscoveryRuntimeEntryPoint: { + schema_version: "assistant_mcp_discovery_runtime_entry_point_v1", + policy_owner: "assistantMcpDiscoveryRuntimeEntryPoint", + entry_status: "bridge_executed", + hot_runtime_wired: false, + discovery_attempted: true, + turn_input: { + adapter_status: "ready", + should_run_discovery: true, + turn_meaning_ref: { + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + explicit_organization_scope: "ООО Альтернатива Плюс", + explicit_date_scope: "2020", + raw_message: "Собери короткий бизнес-итог по компании и отдельно по СВК." + }, + data_need_graph: { + business_fact_family: "business_overview", + reason_codes: ["data_need_graph_family_business_overview"] + } + }, + bridge: { + bridge_status: "answer_draft_ready", + user_facing_response_allowed: true, + business_fact_answer_allowed: true, + requires_user_clarification: false, + planner: { + selected_chain_id: "business_overview" + }, + pilot: { + pilot_scope: "business_overview_route_template_v1", + derived_business_overview: { + period_scope: "2020", + incoming_customer_revenue: { + total_amount_human_ru: "47 628 853,03 руб." + }, + outgoing_supplier_payout: { + total_amount_human_ru: "43 763 351,53 руб." + }, + net_amount_human_ru: "3 865 501,50 руб.", + net_direction: "net_incoming" + } + }, + answer_draft: { + answer_mode: "confirmed_with_bounded_inference", + headline: "Business overview answer", + confirmed_lines: ["Confirmed company business overview facts"], + inference_lines: [], + unknown_lines: ["Pure profit is not proven"], + limitation_lines: [], + next_step_line: null + } + }, + reason_codes: ["runtime_entry_point_bridge_executed"] + } + }, + knownOrganizations: [], + activeOrganization: null, + sanitizeOutgoingAssistantText: (text) => String(text ?? ""), + buildAddressDebugPayload: (debug) => ({ ...(debug as Record) }), + buildAddressFollowupOffer: () => null, + mergeKnownOrganizations: (items) => items, + toNonEmptyString: (value) => (typeof value === "string" && value.trim() ? value.trim() : null), + appendItem: () => {}, + getSession: () => ({ session_id: "asst-business-overview-address", updated_at: "", items: [], investigation_state: null } as any), + persistSession: () => {}, + cloneConversation: (items) => items, + logEvent: () => {}, + messageIdFactory: () => "msg-business-overview-address", + finalizeAddressTurn + }); + + expect((runtime.response as any).debug).toEqual( + expect.objectContaining({ + mcp_discovery_response_applied: true, + detected_intent: "business_overview", + selected_recipe: "business_overview", + mcp_discovery_effective_response_route: "business_overview" + }) + ); + expect(String((runtime.response as any).assistant_reply)).toContain("47 628 853,03"); + }); + + it("keeps comparison-scope proof augmentation business-facing for organization clarification", () => { + const finalizeAddressTurn = vi.fn((input) => ({ + response: { + ok: true, + assistant_reply: input.assistantReply, + reply_type: input.replyType, + debug: input.debug + } + })); + + const runtime = runAssistantAddressLaneResponseRuntime({ + sessionId: "asst-comparison-proof", + userMessage: "ООО Альтернатива Плюс", + effectiveAddressUserMessage: "ООО Альтернатива Плюс", + addressLane: { + handled: true, + reply_text: + "Коротко: по компании Альтернатива Плюс подтвержден company-level денежный срез: входящие 285 819 547,57 руб.", + reply_type: "partial_coverage", + debug: {} + }, + llmPreDecomposeMeta: { + mcpDiscoveryRuntimeEntryPoint: { + schema_version: "assistant_mcp_discovery_runtime_entry_point_v1", + policy_owner: "assistantMcpDiscoveryRuntimeEntryPoint", + entry_status: "bridge_executed", + hot_runtime_wired: true, + discovery_attempted: true, + turn_input: { + turn_meaning_ref: { + asked_domain_family: "business_overview", + business_overview_separate_entity_candidates: ["Группа СВК"], + explicit_organization_scope: "Альтернатива Плюс" + } + }, + bridge: { + bridge_status: "not_applicable", + user_facing_response_allowed: false, + business_fact_answer_allowed: false, + requires_user_clarification: false + }, + reason_codes: [] + } + }, + knownOrganizations: [], + activeOrganization: null, + sanitizeOutgoingAssistantText: (text) => String(text ?? ""), + buildAddressDebugPayload: () => ({}), + buildAddressFollowupOffer: () => null, + mergeKnownOrganizations: (items) => items, + toNonEmptyString: (value) => (typeof value === "string" && value.trim() ? value.trim() : null), + appendItem: () => {}, + getSession: () => + ({ + session_id: "asst-comparison-proof", + updated_at: "", + items: [], + investigation_state: null, + address_navigation_state: { + session_context: { + comparison_scope: { + organization: { label: "Альтернатива Плюс" }, + counterparty: { label: "Группа СВК" }, + proof_bundles: { + counterparty_value_flow_bundle: { + counterparty: "Группа СВК", + incoming_customer_revenue: { total_amount_human_ru: "20 653 490 руб." }, + outgoing_supplier_payout: { total_amount_human_ru: "2 129 651 руб." }, + net_amount_human_ru: "18 523 839 руб.", + net_direction: "net_incoming" + }, + counterparty_document_bundle: { + document_count: 19 + } + } + } + } + } + }) as any, + persistSession: () => {}, + cloneConversation: (items) => items, + logEvent: () => {}, + messageIdFactory: () => "msg-comparison-proof", + finalizeAddressTurn + }); + + const reply = String((runtime.response as any).assistant_reply); + expect(reply).toContain("по компании ООО Альтернатива Плюс"); + expect(reply).toContain("получили 20 653 490 руб."); + expect(reply).toContain("документы: 19"); + expect(reply).not.toContain("company-level"); + expect(reply).not.toContain("reusable bundle"); + expect((runtime.response as any).debug.comparison_scope_response_augmentation_v1).toEqual( + expect.objectContaining({ + applied: true, + organization: "ООО Альтернатива Плюс", + counterparty: "Группа СВК", + document_count: 19 + }) + ); + }); + it("keeps debug bounded to shadow contracts when optional enrichment is absent", () => { const runtime = runAssistantAddressLaneResponseRuntime({ sessionId: "asst-2", diff --git a/llm_normalizer/backend/tests/assistantAddressOrchestrationRuntimeAdapter.test.ts b/llm_normalizer/backend/tests/assistantAddressOrchestrationRuntimeAdapter.test.ts index a170a5f..f1e2527 100644 --- a/llm_normalizer/backend/tests/assistantAddressOrchestrationRuntimeAdapter.test.ts +++ b/llm_normalizer/backend/tests/assistantAddressOrchestrationRuntimeAdapter.test.ts @@ -307,6 +307,320 @@ describe("assistant address orchestration runtime adapter", () => { ); }); + it("recovers business overview proof bundles from session history before MCP discovery", async () => { + const valueFlowBundle = { + counterparty: "Group SVK", + incoming_total: 20653490, + outgoing_total: 2129651, + net_amount: 18523839 + }; + const documentBundle = { + counterparty: "Group SVK", + document_count: 19 + }; + const runMcpDiscoveryRuntimeEntryPoint = vi.fn(async () => ({ + schema_version: "assistant_mcp_discovery_runtime_entry_point_v1", + policy_owner: "assistantMcpDiscoveryRuntimeEntryPoint", + entry_status: "bridge_executed", + hot_runtime_wired: false, + discovery_attempted: true + })); + const input = buildInput({ + userMessage: "Alt Plus", + sessionItems: [ + { + role: "assistant", + debug: { + assistant_mcp_discovery_entry_point_v1: { + turn_input: { + turn_meaning_ref: { + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + business_overview_separate_entity_candidates: ["Group SVK"], + previous_counterparty_value_flow_bundle: valueFlowBundle, + previous_counterparty_document_bundle: documentBundle, + metadata_scope_hint: "Group SVK" + } + } + } + } + } + ], + runAddressLlmPreDecompose: vi.fn(async () => ({ + attempted: true, + applied: false, + effectiveMessage: "Alt Plus", + reason: "raw_kept", + predecomposeContract: { + mode: "unsupported", + intent: "unknown", + entities: { organization: "Alt Plus" }, + semantics: { anchor_kind: "organization", anchor_value: "Alt Plus" } + } + })), + resolveAddressFollowupCarryoverContext: vi.fn(() => ({ + followupContext: { + previous_intent: "business_overview", + target_intent: "business_overview", + previous_discovery_pilot_scope: "business_overview_route_template_v1", + previous_discovery_loop_status: "awaiting_clarification", + previous_discovery_loop_selected_chain_id: "business_overview", + previous_discovery_loop_metadata_scope_hint: "Group SVK", + previous_anchor_type: "counterparty", + previous_anchor_value: "Group SVK", + previous_filters: {} + } + })), + resolveAssistantOrchestrationDecision: vi.fn(() => ({ + runAddressLane: true, + livingMode: "address_data", + livingReason: "address_lane_triggered", + toolGateDecision: "run_address_lane", + toolGateReason: "followup_context_detected", + orchestrationContract: { + schema_version: "assistant_orchestration_contract_v1", + assistant_turn_meaning: { + schema_version: "assistant_turn_meaning_v1", + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + unsupported_but_understood_family: "broad_business_evaluation" + } + } + })), + runMcpDiscoveryRuntimeEntryPoint + }); + + await buildAssistantAddressOrchestrationRuntime(input); + + expect(runMcpDiscoveryRuntimeEntryPoint).toHaveBeenCalledWith( + expect.objectContaining({ + followupContext: expect.objectContaining({ + previous_discovery_bidirectional_value_flow: valueFlowBundle, + previous_discovery_document_summary: documentBundle + }) + }) + ); + }); + + it("recovers business overview proof bundles from previous assistant summary text", async () => { + const runMcpDiscoveryRuntimeEntryPoint = vi.fn(async () => ({ + schema_version: "assistant_mcp_discovery_runtime_entry_point_v1", + policy_owner: "assistantMcpDiscoveryRuntimeEntryPoint", + entry_status: "bridge_executed", + hot_runtime_wired: false, + discovery_attempted: true + })); + const input = buildInput({ + userMessage: "Alt Plus", + sessionItems: [ + { + role: "assistant", + text: + "\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0443 Group SVK: " + + "\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 20 653 490 \u0440\u0443\u0431., " + + "\u0437\u0430\u043f\u043b\u0430\u0442\u0438\u043b\u0438 2 129 651 \u0440\u0443\u0431., " + + "\u0440\u0430\u0441\u0447\u0435\u0442\u043d\u043e\u0435 \u043d\u0435\u0442\u0442\u043e \u0432 \u043d\u0430\u0448\u0443 \u0441\u0442\u043e\u0440\u043e\u043d\u0443 18 523 839 \u0440\u0443\u0431. " + + "\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u044b \u043f\u043e \u0446\u0435\u043f\u043e\u0447\u043a\u0435: \u043d\u0430\u0439\u0434\u0435\u043d\u043e 19." + } + ], + runAddressLlmPreDecompose: vi.fn(async () => ({ + attempted: true, + applied: false, + effectiveMessage: "Alt Plus", + reason: "raw_kept", + predecomposeContract: { + mode: "unsupported", + intent: "unknown", + entities: { organization: "Alt Plus" } + } + })), + resolveAddressFollowupCarryoverContext: vi.fn(() => ({ + followupContext: { + previous_intent: "business_overview", + target_intent: "business_overview", + previous_discovery_pilot_scope: "business_overview_route_template_v1", + previous_discovery_loop_selected_chain_id: "business_overview", + previous_discovery_loop_metadata_scope_hint: "Group SVK", + previous_anchor_type: "counterparty", + previous_anchor_value: "Group SVK", + previous_filters: {} + } + })), + resolveAssistantOrchestrationDecision: vi.fn(() => ({ + runAddressLane: true, + livingMode: "address_data", + livingReason: "address_lane_triggered", + toolGateDecision: "run_address_lane", + toolGateReason: "followup_context_detected", + orchestrationContract: { + schema_version: "assistant_orchestration_contract_v1", + assistant_turn_meaning: { + schema_version: "assistant_turn_meaning_v1", + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation" + } + } + })), + runMcpDiscoveryRuntimeEntryPoint + }); + + await buildAssistantAddressOrchestrationRuntime(input); + + expect(runMcpDiscoveryRuntimeEntryPoint).toHaveBeenCalledWith( + expect.objectContaining({ + followupContext: expect.objectContaining({ + previous_discovery_bidirectional_value_flow: expect.objectContaining({ + counterparty: "Group SVK", + incoming_customer_revenue: { total_amount_human_ru: "20 653 490 \u0440\u0443\u0431." }, + outgoing_supplier_payout: { total_amount_human_ru: "2 129 651 \u0440\u0443\u0431." }, + net_amount_human_ru: "18 523 839 \u0440\u0443\u0431." + }), + previous_discovery_document_summary: expect.objectContaining({ + counterparty: "Group SVK", + document_count: 19 + }) + }) + }) + ); + }); + + it("recovers business overview proof bundles from navigation comparison state", async () => { + const valueFlowBundle = { + counterparty: "Group SVK", + incoming_customer_revenue: { total_amount_human_ru: "20 653 490 руб." }, + outgoing_supplier_payout: { total_amount_human_ru: "2 129 651 руб." }, + net_amount_human_ru: "18 523 839 руб." + }; + const documentBundle = { counterparty: "Group SVK", document_count: 19 }; + const runMcpDiscoveryRuntimeEntryPoint = vi.fn(async () => ({ + schema_version: "assistant_mcp_discovery_runtime_entry_point_v1", + policy_owner: "assistantMcpDiscoveryRuntimeEntryPoint", + entry_status: "bridge_executed", + hot_runtime_wired: false, + discovery_attempted: true + })); + const input = buildInput({ + userMessage: "Alt Plus", + sessionAddressNavigationState: { + session_context: { + comparison_scope: { + organization: null, + counterparty: { label: "Group SVK" }, + proof_bundles: { + counterparty_value_flow_bundle: valueFlowBundle, + counterparty_document_bundle: documentBundle + } + } + } + }, + runAddressLlmPreDecompose: vi.fn(async () => ({ + attempted: true, + applied: false, + effectiveMessage: "Alt Plus", + reason: "raw_kept", + predecomposeContract: { + mode: "unsupported", + intent: "unknown", + entities: { organization: "Alt Plus" } + } + })), + resolveAddressFollowupCarryoverContext: vi.fn(() => ({ followupContext: null })), + resolveAssistantOrchestrationDecision: vi.fn(() => ({ + runAddressLane: true, + livingMode: "address_data", + livingReason: "address_lane_triggered", + toolGateDecision: "run_address_lane", + toolGateReason: "followup_context_detected", + orchestrationContract: { + schema_version: "assistant_orchestration_contract_v1", + assistant_turn_meaning: { + schema_version: "assistant_turn_meaning_v1", + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation" + } + } + })), + runMcpDiscoveryRuntimeEntryPoint + }); + + await buildAssistantAddressOrchestrationRuntime(input); + + expect(runMcpDiscoveryRuntimeEntryPoint).toHaveBeenCalledWith( + expect.objectContaining({ + followupContext: expect.objectContaining({ + previous_discovery_loop_selected_chain_id: "business_overview", + previous_discovery_loop_pending_axes: ["organization"], + previous_discovery_loop_metadata_scope_hint: "Group SVK", + previous_discovery_bidirectional_value_flow: valueFlowBundle, + previous_discovery_document_summary: documentBundle + }) + }) + ); + }); + + it("does not infer a counterparty proof bundle from company-only overview totals", async () => { + const runMcpDiscoveryRuntimeEntryPoint = vi.fn(async () => ({ + schema_version: "assistant_mcp_discovery_runtime_entry_point_v1", + policy_owner: "assistantMcpDiscoveryRuntimeEntryPoint", + entry_status: "bridge_executed", + hot_runtime_wired: false, + discovery_attempted: true + })); + const input = buildInput({ + userMessage: "who brought money", + sessionItems: [ + { + role: "assistant", + text: + "Деньги: входящие 47 628 853,03 руб., исходящие 43 763 351,53 руб., расчетное операционное нетто 3 865 501,50 руб.\n" + + "НДС: продажи 2 002 138,93 руб., покупки 1 784 850,48 руб., НДС к уплате 217 288,45 руб." + } + ], + runAddressLlmPreDecompose: vi.fn(async () => ({ + attempted: true, + applied: false, + effectiveMessage: "who brought money", + reason: "raw_kept", + predecomposeContract: { + mode: "unsupported", + intent: "unknown", + entities: { organization: "Alt Plus" } + } + })), + resolveAddressFollowupCarryoverContext: vi.fn(() => ({ + followupContext: { + previous_intent: "business_overview", + target_intent: "business_overview", + previous_discovery_pilot_scope: "business_overview_route_template_v1", + previous_discovery_loop_selected_chain_id: "business_overview", + previous_filters: { organization: "Alt Plus" } + } + })), + resolveAssistantOrchestrationDecision: vi.fn(() => ({ + runAddressLane: true, + livingMode: "address_data", + livingReason: "address_lane_triggered", + toolGateDecision: "run_address_lane", + toolGateReason: "followup_context_detected", + orchestrationContract: { + schema_version: "assistant_orchestration_contract_v1", + assistant_turn_meaning: { + schema_version: "assistant_turn_meaning_v1", + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation" + } + } + })), + runMcpDiscoveryRuntimeEntryPoint + }); + + await buildAssistantAddressOrchestrationRuntime(input); + + const call = runMcpDiscoveryRuntimeEntryPoint.mock.calls[0]?.[0] as any; + expect(call.followupContext.previous_discovery_bidirectional_value_flow).toBeUndefined(); + expect(call.followupContext.previous_discovery_document_summary).toBeUndefined(); + }); + it("passes grounded discovery follow-up carryover into MCP discovery entry point for a short year switch", async () => { const runMcpDiscoveryRuntimeEntryPoint = vi.fn(async () => ({ schema_version: "assistant_mcp_discovery_runtime_entry_point_v1", diff --git a/llm_normalizer/backend/tests/assistantLivingChatRuntimeAdapter.test.ts b/llm_normalizer/backend/tests/assistantLivingChatRuntimeAdapter.test.ts index 1dc3f6b..94ebcc0 100644 --- a/llm_normalizer/backend/tests/assistantLivingChatRuntimeAdapter.test.ts +++ b/llm_normalizer/backend/tests/assistantLivingChatRuntimeAdapter.test.ts @@ -176,6 +176,31 @@ describe("assistant living chat runtime adapter", () => { expect(executeLlmChat).toHaveBeenCalledTimes(1); }); + it("handles first-turn smalltalk deterministically without relying on LLM", async () => { + const resolveDataScopeProbe = vi.fn(async () => ({ + status: "resolved", + channel: "default", + organizations: [], + error: null + })); + const input = buildRuntimeInput({ + userMessage: "приветик - че как там дела", + resolveDataScopeProbe, + buildAssistantProactiveOrganizationOfferReply: () => "" + }); + + const output = await runAssistantLivingChatRuntime(input); + + expect(output.handled).toBe(true); + expect(output.chatText).toContain("Привет! Всё нормально."); + expect(output.chatText).not.toContain("llm-text"); + expect(output.debug?.living_chat_response_source).toBe("deterministic_smalltalk"); + expect(output.debug?.living_chat_proactive_scope_offer_applied).toBe(false); + expect(output.debug?.living_chat_data_scope_probe_org_count).toBe(0); + expect(input.__spies.executeLlmChat).not.toHaveBeenCalled(); + expect(resolveDataScopeProbe).toHaveBeenCalledTimes(1); + }); + it("builds deterministic broad business evaluation summary from grounded continuity instead of replaying lifecycle noise", async () => { const executeLlmChat = vi.fn(async () => "raw-llm"); const input = buildRuntimeInput({ @@ -438,6 +463,7 @@ describe("assistant living chat runtime adapter", () => { "ООО Лайсвуд", "РАЙМ" ]); + expect(input.__spies.executeLlmChat).not.toHaveBeenCalled(); }); it("does not add proactive organization offer after the session already has assistant context", async () => { diff --git a/llm_normalizer/backend/tests/assistantMcpDiscoveryResponseCandidate.test.ts b/llm_normalizer/backend/tests/assistantMcpDiscoveryResponseCandidate.test.ts index 6b1afa7..533bb52 100644 --- a/llm_normalizer/backend/tests/assistantMcpDiscoveryResponseCandidate.test.ts +++ b/llm_normalizer/backend/tests/assistantMcpDiscoveryResponseCandidate.test.ts @@ -475,6 +475,7 @@ describe("assistant MCP discovery response candidate", () => { effective_message: "Дать краткий обзор ООО Альтернатива Плюс за 2020: входящие, исходящие, нетто и банковскую границу.", explicit_organization_scope: "ООО Альтернатива Плюс" + ,asked_action_family: "broad_evaluation" }, data_need_graph: { business_fact_family: "business_overview", @@ -778,6 +779,199 @@ describe("assistant MCP discovery response candidate", () => { expect(candidate.reply_text).not.toContain("wide overview"); }); + it("keeps broad overview layers when direct-money reason is present", () => { + const candidate = buildAssistantMcpDiscoveryResponseCandidate( + entryPoint({ + turn_input: { + adapter_status: "ready", + turn_meaning_ref: { + raw_message: + "Дай взрослый бизнес-обзор ООО Альтернатива Плюс за 2020 год: деньги, нетто, НДС, долги, склад, клиенты, поставщики и что нельзя утверждать.", + asked_action_family: "broad_evaluation", + unsupported_but_understood_family: "broad_business_evaluation", + explicit_organization_scope: "ООО Альтернатива Плюс", + explicit_date_scope: "2020" + }, + data_need_graph: { + business_fact_family: "business_overview", + ranking_need: null, + reason_codes: [ + "data_need_graph_family_business_overview", + "data_need_graph_business_overview_direct_money_answer" + ] + } + }, + bridge: { + bridge_status: "answer_draft_ready", + user_facing_response_allowed: true, + business_fact_answer_allowed: true, + requires_user_clarification: false, + pilot: { + pilot_scope: "business_overview_route_template_v1", + derived_business_overview: { + period_scope: "2020", + incoming_customer_revenue: { + total_amount_human_ru: "47 628 853,03 руб." + }, + outgoing_supplier_payout: { + total_amount_human_ru: "43 763 351,53 руб." + }, + net_amount_human_ru: "3 865 501,50 руб.", + net_direction: "net_incoming", + top_customers: [ + { + axis_value: "СБЕРБАНК, ПАО", + total_amount_human_ru: "12 792 194,31 руб.", + is_likely_financial_institution: true + }, + { + axis_value: "Группа СВК", + total_amount_human_ru: "12 093 465 руб." + } + ], + top_suppliers: [ + { + axis_value: "Департамент капитального ремонта города Москвы", + total_amount_human_ru: "9 612 904,90 руб." + } + ], + tax_position: { + sales_vat_amount_human_ru: "2 717 288,45 руб.", + purchase_vat_amount_human_ru: "2 500 000 руб.", + net_vat_amount_human_ru: "217 288,45 руб.", + net_vat_direction: "vat_to_pay" + }, + debt_position: { + receivables: { total_amount_human_ru: "25 000 000 руб." }, + payables: { total_amount_human_ru: "3 318 824,40 руб." }, + net_debt_position_amount_human_ru: "21 681 175,60 руб.", + net_debt_position_direction: "net_receivable" + }, + inventory_position: { + total_amount_human_ru: "716 418,33 руб.", + rows_matched: 34 + } + } + }, + answer_draft: { + answer_mode: "confirmed_with_bounded_inference", + headline: "wide overview should not leak", + confirmed_lines: [], + inference_lines: [], + unknown_lines: [], + limitation_lines: [], + next_step_line: null + } + } + }) + ); + + expect(candidate.reply_text).toContain("Что видно:"); + expect(candidate.reply_text).toContain("НДС:"); + expect(candidate.reply_text).toContain("Долги:"); + expect(candidate.reply_text).toContain("Склад:"); + expect(candidate.reply_text).toContain("Группа СВК"); + expect(candidate.reply_text).not.toContain("по деньгам плюс"); + expect(candidate.reply_text).not.toContain("wide overview"); + }); + + it("keeps counterparty leaders for money followups instead of compact cashflow", () => { + const candidate = buildAssistantMcpDiscoveryResponseCandidate( + entryPoint({ + turn_input: { + adapter_status: "ready", + turn_meaning_ref: { + raw_message: + "Раскрой деньги подробнее: сколько получили, сколько заплатили, какой чистый денежный поток, кто главный клиент и главный поставщик в 2020.", + asked_action_family: "broad_evaluation", + unsupported_but_understood_family: "broad_business_evaluation", + explicit_organization_scope: "ООО Альтернатива Плюс", + explicit_date_scope: "2020" + }, + data_need_graph: { + business_fact_family: "business_overview", + ranking_need: null, + reason_codes: [ + "data_need_graph_family_business_overview", + "data_need_graph_business_overview_direct_money_answer" + ] + } + }, + bridge: { + bridge_status: "answer_draft_ready", + user_facing_response_allowed: true, + business_fact_answer_allowed: true, + requires_user_clarification: false, + pilot: { + pilot_scope: "business_overview_route_template_v1", + derived_business_overview: { + period_scope: "2020", + incoming_customer_revenue: { + total_amount_human_ru: "47 628 853,03 руб." + }, + outgoing_supplier_payout: { + total_amount_human_ru: "43 763 351,53 руб." + }, + net_amount_human_ru: "3 865 501,50 руб.", + net_direction: "net_incoming", + top_customers: [ + { + axis_value: "СБЕРБАНК, ПАО", + total_amount_human_ru: "12 792 194,31 руб.", + is_likely_financial_institution: true + }, + { + axis_value: "Группа СВК", + total_amount_human_ru: "12 093 465 руб." + } + ], + top_suppliers: [ + { + axis_value: "Департамент капитального ремонта города Москвы", + total_amount_human_ru: "9 612 904,90 руб." + } + ], + tax_position: { + net_vat_amount_human_ru: "217 288,45 руб.", + net_vat_direction: "vat_to_pay" + }, + debt_position: { + receivables: { total_amount_human_ru: "25 000 000 руб." }, + payables: { total_amount_human_ru: "3 318 824,40 руб." }, + net_debt_position_amount_human_ru: "21 681 175,60 руб.", + net_debt_position_direction: "net_receivable" + }, + inventory_position: { + total_amount_human_ru: "716 418,33 руб.", + rows_matched: 34 + } + } + }, + answer_draft: { + answer_mode: "confirmed_with_bounded_inference", + headline: "wide overview should not leak", + confirmed_lines: [], + inference_lines: [], + unknown_lines: [], + limitation_lines: [], + next_step_line: null + } + } + }) + ); + + expect(candidate.reply_text).toContain("47 628 853,03"); + expect(candidate.reply_text).toContain("43 763 351,53"); + expect(candidate.reply_text).toContain("3 865 501,50"); + expect(candidate.reply_text).toContain("СБЕРБАНК, ПАО"); + expect(candidate.reply_text).toContain("Группа СВК"); + expect(candidate.reply_text).toContain("Департамент капитального ремонта города Москвы"); + expect(candidate.reply_text).not.toContain("по деньгам плюс"); + expect(candidate.reply_text).not.toContain("НДС:"); + expect(candidate.reply_text).not.toContain("Склад:"); + expect(candidate.reply_text).not.toContain("wide overview"); + }); + it("labels organization-scoped bidirectional value-flow continuations as company scope", () => { const candidate = buildAssistantMcpDiscoveryResponseCandidate( entryPoint({ @@ -902,6 +1096,83 @@ describe("assistant MCP discovery response candidate", () => { expect(candidate.reply_text).not.toContain("Самый крупный подтвержденный клиент"); }); + it("answers colloquial money leader follow-ups with leaders first", () => { + const candidate = buildAssistantMcpDiscoveryResponseCandidate( + entryPoint({ + turn_input: { + adapter_status: "ready", + turn_meaning_ref: { + raw_message: + "А по деньгам в этом же году кто больше всего занес и кому больше всего ушло? Банк не называй обычным клиентом без оговорки.", + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + explicit_organization_scope: "ООО Альтернатива Плюс", + explicit_date_scope: "2020" + }, + data_need_graph: { + business_fact_family: "business_overview", + ranking_need: "top_desc", + reason_codes: [ + "data_need_graph_family_business_overview", + "data_need_graph_business_overview_direct_money_answer" + ] + } + }, + bridge: { + bridge_status: "answer_draft_ready", + user_facing_response_allowed: true, + business_fact_answer_allowed: true, + requires_user_clarification: false, + pilot: { + pilot_scope: "business_overview_route_template_v1", + derived_business_overview: { + period_scope: "2020", + incoming_customer_revenue: { total_amount_human_ru: "47 628 853,03 руб." }, + outgoing_supplier_payout: { total_amount_human_ru: "43 763 351,53 руб." }, + net_amount_human_ru: "3 865 501,50 руб.", + net_direction: "net_incoming", + top_customers: [ + { + axis_value: "СБЕРБАНК, ПАО", + total_amount_human_ru: "12 792 194,31 руб.", + counterparty_role_hint: "financial_institution" + }, + { + axis_value: "Группа СВК", + total_amount_human_ru: "12 093 465 руб.", + counterparty_role_hint: "ordinary_counterparty" + } + ], + top_suppliers: [ + { + axis_value: "Департамент капитального ремонта города Москвы.", + total_amount_human_ru: "9 612 904,90 руб." + } + ], + yearly_breakdown: [] + } + }, + answer_draft: { + answer_mode: "confirmed_with_bounded_inference", + headline: "Company summary.", + confirmed_lines: [], + inference_lines: [], + unknown_lines: [], + limitation_lines: [], + next_step_line: null + } + } + }) + ); + + const firstLine = candidate.reply_text?.split("\n")[0] ?? ""; + expect(firstLine).toContain("больше всего занес СБЕРБАНК, ПАО"); + expect(firstLine).toContain("не называю его обычной клиентской выручкой"); + expect(firstLine).toContain("крупнейший небанковский входящий контрагент: Группа СВК"); + expect(firstLine).toContain("больше всего ушло Департамент капитального ремонта города Москвы."); + expect(firstLine).not.toContain("выглядит как бизнес"); + }); + it("mentions separate counterparty scope in company plus counterparty business summaries", () => { const candidate = buildAssistantMcpDiscoveryResponseCandidate( entryPoint({ @@ -1107,6 +1378,128 @@ describe("assistant MCP discovery response candidate", () => { expect(candidate.reply_text).toContain("ранее подтвержденный контрагентский срез"); }); + it("answers selected counterparty boundary summaries from previous bundles without asking for organization", () => { + const candidate = buildAssistantMcpDiscoveryResponseCandidate( + entryPoint({ + turn_input: { + adapter_status: "ready", + turn_meaning_ref: { + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + business_overview_separate_entity_candidates: ["Группа СВК"], + previous_counterparty_value_flow_bundle: { + counterparty: "Группа СВК", + incoming_customer_revenue: { + total_amount_human_ru: "20 653 490 руб.", + rows_with_amount: 26, + rows_matched: 26 + }, + outgoing_supplier_payout: { + total_amount_human_ru: "2 129 651 руб.", + rows_with_amount: 1, + rows_matched: 1 + }, + net_amount_human_ru: "18 523 839 руб.", + net_direction: "net_incoming" + }, + previous_counterparty_document_bundle: { + counterparty: "Группа СВК", + document_count: 19 + } + }, + data_need_graph: { + business_fact_family: "business_overview", + subject_candidates: [], + clarification_gaps: ["organization"], + reason_codes: ["data_need_graph_family_business_overview", "data_need_graph_has_clarification_gaps"] + } + }, + bridge: { + bridge_status: "needs_clarification", + user_facing_response_allowed: true, + business_fact_answer_allowed: false, + requires_user_clarification: true, + answer_draft: { + answer_mode: "needs_clarification", + headline: "Нужно уточнить контекст перед поиском в 1С.", + confirmed_lines: [], + inference_lines: [], + unknown_lines: [], + limitation_lines: [], + next_step_line: "Уточните организацию." + } + } + }) + ); + + expect(candidate.candidate_status).toBe("clarification_candidate"); + expect(candidate.reply_text).toContain("уточните, по какой компании"); + expect(candidate.reply_text).toContain("Группа СВК"); + expect(candidate.reply_text).toContain("20 653 490 руб."); + expect(candidate.reply_text).toContain("документы по цепочке: найдено 19"); + expect(candidate.reply_text).toContain("Нельзя утверждать"); + expect(candidate.reply_text).not.toContain("перед поиском"); + }); + + it("keeps organization clarification boundary summaries compact", () => { + const candidate = buildAssistantMcpDiscoveryResponseCandidate( + entryPoint({ + turn_input: { + adapter_status: "ready", + turn_meaning_ref: { + raw_message: "ООО Альтернатива Плюс", + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + business_overview_separate_entity_candidates: ["Группа СВК"], + explicit_organization_scope: "Альтернатива Плюс" + }, + data_need_graph: { + business_fact_family: "business_overview", + subject_candidates: [], + metadata_scope_hint: "Группа СВК", + reason_codes: ["data_need_graph_family_business_overview"] + } + }, + bridge: { + bridge_status: "answer_draft_ready", + user_facing_response_allowed: true, + business_fact_answer_allowed: true, + requires_user_clarification: false, + pilot: { + pilot_scope: "business_overview_route_template_v1", + derived_business_overview: { + period_scope: "all_time", + incoming_customer_revenue: { total_amount_human_ru: "285 819 547,57 руб." }, + outgoing_supplier_payout: { total_amount_human_ru: "137 963 720,37 руб." }, + net_amount_human_ru: "147 855 827,20 руб.", + net_direction: "net_incoming", + top_customers: [{ axis_value: "Комитет государственных услуг г. Москвы", total_amount_human_ru: "133 839 880,82 руб." }], + top_suppliers: [{ axis_value: "ГТК-Интер, ООО", total_amount_human_ru: "44 943 460 руб." }] + } + }, + answer_draft: { + answer_mode: "confirmed_with_bounded_inference", + headline: "Company summary.", + confirmed_lines: [], + inference_lines: [], + unknown_lines: [], + limitation_lines: [], + next_step_line: null + } + } + }) + ); + + const lines = candidate.reply_text?.split("\n").filter(Boolean) ?? []; + expect(lines.length).toBeLessThanOrEqual(3); + expect(lines[0]).toContain("по компании Альтернатива Плюс"); + expect(lines[0]).toContain("285 819 547,57"); + expect(candidate.reply_text).toContain("Отдельно по выбранному контрагенту Группа СВК"); + expect(candidate.reply_text).toContain("Нельзя утверждать"); + expect(candidate.reply_text).not.toContain("Метод:"); + expect(candidate.reply_text).not.toContain("Для ответа именно про чистую прибыль"); + }); + it("localizes value-flow evidence without leaking pilot mechanics", () => { const candidate = buildAssistantMcpDiscoveryResponseCandidate( entryPoint({ diff --git a/llm_normalizer/backend/tests/assistantMcpDiscoveryResponsePolicy.test.ts b/llm_normalizer/backend/tests/assistantMcpDiscoveryResponsePolicy.test.ts index 6eef701..c385c13 100644 --- a/llm_normalizer/backend/tests/assistantMcpDiscoveryResponsePolicy.test.ts +++ b/llm_normalizer/backend/tests/assistantMcpDiscoveryResponsePolicy.test.ts @@ -310,6 +310,67 @@ describe("assistant MCP discovery response policy", () => { expect(result.reason_codes).not.toContain("mcp_discovery_response_policy_keep_exact_matched_factual_address_reply"); }); + it("overrides exact document-list replies for explicit counterparty received-paid-net questions", () => { + const result = applyAssistantMcpDiscoveryResponsePolicy({ + currentReply: "Контрагент: Группа СВК. Найдено документов: 19.", + currentReplySource: "address_query_runtime_v1", + currentReplyType: "factual", + addressRuntimeMeta: { + detected_intent: "list_documents_by_counterparty", + selected_recipe: "address_documents_by_counterparty_v1", + mcp_call_status: "matched_non_empty", + truth_mode: "confirmed", + capability_binding_status: "bound", + capability_binding_violations: [], + answer_shape_contract: { + reply_type: "factual", + capability_contract_id: "documents_drilldown" + }, + assistant_mcp_discovery_entry_point_v1: entryPoint({ + turn_input: { + adapter_status: "ready", + should_run_discovery: true, + data_need_graph: { + business_fact_family: "value_flow", + subject_candidates: ["Группа СВК"], + reason_codes: ["data_need_graph_built", "data_need_graph_bidirectional_value_flow"] + }, + turn_meaning_ref: { + asked_domain_family: "counterparty_value", + asked_action_family: "net_value_flow", + explicit_entity_candidates: ["Группа СВК"], + unsupported_but_understood_family: "counterparty_bidirectional_value_flow_or_netting" + } + }, + bridge: { + bridge_status: "answer_draft_ready", + user_facing_response_allowed: true, + business_fact_answer_allowed: true, + requires_user_clarification: false, + answer_draft: { + answer_mode: "confirmed_with_bounded_inference", + headline: "Группа СВК: получили 20 653 490 руб., заплатили 2 129 651 руб.; нетто 18 523 839 руб. в нашу сторону.", + confirmed_lines: ["получили 20 653 490 руб.; заплатили 2 129 651 руб.; нетто 18 523 839 руб."], + inference_lines: [], + unknown_lines: [], + limitation_lines: ["Это денежный срез, не бухгалтерская прибыль."], + next_step_line: null + } + } + }) + } + }); + + expect(result.applied).toBe(true); + expect(result.decision).toBe("apply_candidate"); + expect(result.reply_source).toBe("mcp_discovery_response_candidate_guarded"); + expect(result.reply_text).toContain("20 653 490"); + expect(result.reply_text).toContain("2 129 651"); + expect(result.reason_codes).toContain("mcp_discovery_response_policy_value_flow_action_conflict_allows_candidate_override"); + expect(result.reason_codes).toContain("mcp_discovery_response_policy_semantic_conflict_allows_candidate_override"); + expect(result.reason_codes).not.toContain("mcp_discovery_response_policy_keep_exact_document_list_address_reply"); + }); + it("keeps exact matched inventory address replies over stale metadata discovery candidates", () => { const result = applyAssistantMcpDiscoveryResponsePolicy({ currentReply: "По товару Шкаф картотечный 1000*400*2100 цепочка поставки и продажи подтверждена.", diff --git a/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeBridge.test.ts b/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeBridge.test.ts index aa246b6..ac372ed 100644 --- a/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeBridge.test.ts +++ b/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeBridge.test.ts @@ -328,8 +328,17 @@ describe("assistant MCP discovery runtime bridge", () => { }); expect(result.bridge_status).toBe("answer_draft_ready"); + expect(result.hot_runtime_wired).toBe(true); expect(result.business_fact_answer_allowed).toBe(true); expect(result.planner.selected_chain_id).toBe("value_flow_comparison"); + expect(result.hot_runtime_wired).toBe(true); + expect(result.execution_handoff).toMatchObject({ + handoff_status: "ready_for_guarded_response", + selected_chain_id: "value_flow_comparison", + allowed_hot_chain: true, + can_use_guarded_response: true + }); + expect(result.reason_codes).toContain("runtime_bridge_wired_to_guarded_hot_assistant_answer"); expect(result.pilot.derived_bidirectional_value_flow).toMatchObject({ period_scope: "2020", incoming_customer_revenue: { @@ -389,6 +398,14 @@ describe("assistant MCP discovery runtime bridge", () => { expect(result.requires_user_clarification).toBe(false); expect(result.business_fact_answer_allowed).toBe(true); expect(result.planner.selected_chain_id).toBe("value_flow_comparison"); + expect(result.hot_runtime_wired).toBe(true); + expect(result.execution_handoff).toMatchObject({ + handoff_status: "ready_for_guarded_response", + selected_chain_id: "value_flow_comparison", + allowed_hot_chain: true, + can_use_guarded_response: true + }); + expect(result.reason_codes).toContain("runtime_bridge_wired_to_guarded_hot_assistant_answer"); expect(result.planner.required_axes).toContain("all_time_scope"); expect(result.pilot.mcp_execution_performed).toBe(true); expect(result.pilot.derived_bidirectional_value_flow).toMatchObject({ @@ -581,6 +598,11 @@ describe("assistant MCP discovery runtime bridge", () => { executable_now: true, enablement_reason: null }); + expect(result.execution_handoff).toMatchObject({ + handoff_status: "ready_for_guarded_response", + allowed_hot_chain: true, + can_use_guarded_response: true + }); expect(result.pilot.derived_business_overview?.inventory_quality_events?.evidence_status).toBe( "reviewed_no_quality_events_found" ); diff --git a/llm_normalizer/backend/tests/assistantMcpDiscoveryTurnInputAdapter.test.ts b/llm_normalizer/backend/tests/assistantMcpDiscoveryTurnInputAdapter.test.ts index 6b370ae..6549469 100644 --- a/llm_normalizer/backend/tests/assistantMcpDiscoveryTurnInputAdapter.test.ts +++ b/llm_normalizer/backend/tests/assistantMcpDiscoveryTurnInputAdapter.test.ts @@ -166,6 +166,34 @@ describe("assistant MCP discovery turn input adapter", () => { expect(result.reason_codes).toContain("mcp_discovery_bidirectional_value_flow_signal_detected"); }); + it("normalizes role-prefixed counterparty carryover before document discovery", () => { + const result = buildAssistantMcpDiscoveryTurnInput({ + userMessage: "Покажи документы по этой цепочке и не смешивай Группа СВК с организацией ООО Альтернатива Плюс.", + assistantTurnMeaning: { + asked_domain_family: "counterparty", + asked_action_family: "list_documents", + explicit_intent_candidate: "list_documents_by_counterparty" + }, + predecomposeContract: { + entities: { counterparty: null, organization: null }, + period: { scope: "unspecified", period_from: null, period_to: null } + }, + followupContext: { + previous_intent: "customer_revenue_and_payments", + target_intent: "list_documents_by_counterparty", + previous_discovery_pilot_scope: "counterparty_bidirectional_value_flow_query_movements_v1", + previous_discovery_loop_metadata_scope_hint: "контрагенту группа свк", + previous_anchor_type: "counterparty", + previous_anchor_value: "контрагенту группа свк", + previous_filters: { counterparty: "контрагенту группа свк" } + } + }); + + expect(result.turn_meaning_ref?.explicit_entity_candidates).toEqual(["группа свк"]); + expect(result.turn_meaning_ref?.metadata_scope_hint).toBe("группа свк"); + expect(result.data_need_graph?.subject_candidates).toEqual(["группа свк"]); + }); + it("extracts compact scoped counterparty from net follow-up wording when LLM entities are empty", () => { const orgName = "ООО Альтернатива Плюс"; const result = buildAssistantMcpDiscoveryTurnInput({ @@ -1653,6 +1681,7 @@ describe("assistant MCP discovery turn input adapter", () => { expect(result.should_run_discovery).toBe(true); expect(result.semantic_data_need).toBe("business overview evidence with bounded analyst interpretation"); expect(result.data_need_graph?.business_fact_family).toBe("business_overview"); + expect(result.data_need_graph?.subject_candidates).toEqual([]); expect(result.data_need_graph?.time_scope_need).toBe("all_time_scope"); expect(result.data_need_graph?.clarification_gaps).toEqual([]); expect(result.turn_meaning_ref).toMatchObject({ @@ -1699,6 +1728,22 @@ describe("assistant MCP discovery turn input adapter", () => { expect(result.reason_codes).not.toContain("mcp_discovery_value_flow_signal_detected"); }); + it("routes colloquial multi-surface company overview into business overview over exact VAT", () => { + const result = buildAssistantMcpDiscoveryTurnInput({ + userMessage: + "\u041f\u043e-\u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438 \u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441 \u0437\u0430 2020: \u0447\u0442\u043e \u043f\u043e \u0431\u0438\u0437\u043d\u0435\u0441\u0443 \u0432\u0438\u0434\u043d\u043e \u0432 1\u0421 \u043f\u043e \u0434\u0435\u043d\u044c\u0433\u0430\u043c, \u041d\u0414\u0421, \u0434\u043e\u043b\u0433\u0430\u043c, \u0441\u043a\u043b\u0430\u0434\u0443, \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c/\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\u0430\u043c \u0438 \u0433\u0434\u0435 \u043f\u043e\u043a\u0430 \u043d\u0435\u043b\u044c\u0437\u044f \u0434\u0435\u043b\u0430\u0442\u044c \u0432\u044b\u0432\u043e\u0434?", + assistantTurnMeaning: { + explicit_intent_candidate: "vat_liability_confirmed_for_tax_period", + explicit_organization_scope: "\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441" + } + }); + + expect(result.semantic_data_need).toBe("business overview evidence with bounded analyst interpretation"); + expect(result.data_need_graph?.business_fact_family).toBe("business_overview"); + expect(result.turn_meaning_ref?.asked_action_family).toBe("broad_evaluation"); + expect(result.turn_meaning_ref?.explicit_intent_candidate).toBeUndefined(); + }); + it("keeps explicit year out of the organization scope for raw business overview wording", () => { const result = buildAssistantMcpDiscoveryTurnInput({ userMessage: @@ -1789,6 +1834,36 @@ describe("assistant MCP discovery turn input adapter", () => { expect(result.reason_codes).not.toContain("mcp_discovery_counterparty_from_predecompose"); }); + it("keeps previous organization scope when all-time business overview says company in general", () => { + const result = buildAssistantMcpDiscoveryTurnInput({ + userMessage: + "Теперь за все доступное время дай обзор компании в целом, но не тащи НДС за 2020 как подтвержденную общую налоговую позицию.", + assistantTurnMeaning: { + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + explicit_organization_scope: "в целом", + unsupported_but_understood_family: "broad_business_evaluation", + stale_replay_forbidden: true + }, + followupContext: { + previous_discovery_pilot_scope: "business_overview_route_template_v1", + previous_discovery_loop_provided_axes: ["organization"], + previous_filters: { + organization: "ООО Альтернатива Плюс", + period_from: "2020-01-01", + period_to: "2020-12-31" + } + } + }); + + expect(result.adapter_status).toBe("ready"); + expect(result.data_need_graph?.business_fact_family).toBe("business_overview"); + expect(result.data_need_graph?.time_scope_need).toBe("all_time_scope"); + expect(result.turn_meaning_ref?.explicit_organization_scope).toBe("ООО Альтернатива Плюс"); + expect(result.reason_codes).toContain("mcp_discovery_all_time_scope_signal_detected"); + expect(result.reason_codes).not.toContain("mcp_discovery_organization_scope_from_semantic_text"); + }); + it("grounds organization aliases from known organizations for clean-session earnings questions", () => { const result = buildAssistantMcpDiscoveryTurnInput({ userMessage: "скока денег альтернатива заработала за 20 год?", @@ -3690,6 +3765,135 @@ describe("assistant MCP discovery turn input adapter", () => { expect(result.reason_codes).not.toContain("mcp_discovery_not_applicable_for_supported_exact_turn"); }); + it("routes brief compare boundary wording to business overview without implicit current date", () => { + const today = new Date().toISOString().slice(0, 10); + const orgName = + "\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441"; + const counterpartyName = "\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a"; + const valueFlowBundle = { + counterparty: counterpartyName, + incoming_total: 20653490, + outgoing_total: 2129651, + net_amount: 18523839 + }; + const documentBundle = { + counterparty: counterpartyName, + document_count: 19 + }; + + const result = buildAssistantMcpDiscoveryTurnInput({ + userMessage: + "\u0418 \u043a\u043e\u0440\u043e\u0442\u043a\u043e \u0441\u0440\u0430\u0432\u043d\u0438: \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043e \u043f\u043e \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438, \u0447\u0442\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c\u0443 \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0443, \u0438 \u043a\u0430\u043a\u0438\u0435 \u0432\u044b\u0432\u043e\u0434\u044b \u043d\u0435\u043b\u044c\u0437\u044f \u0434\u0435\u043b\u0430\u0442\u044c?", + assistantTurnMeaning: { + asked_domain_family: "counterparty_value", + asked_action_family: "turnover", + explicit_intent_candidate: "list_documents_by_counterparty", + explicit_entity_candidates: ["\u043d\u0430\u0441 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043e"] + }, + followupContext: { + previous_discovery_pilot_scope: "counterparty_document_evidence_query_documents_v1", + previous_intent: "list_documents_by_counterparty", + target_intent: "list_documents_by_counterparty", + previous_filters: { + organization: orgName, + counterparty: counterpartyName, + as_of_date: today + }, + previous_anchor_type: "counterparty", + previous_anchor_value: counterpartyName, + previous_discovery_bidirectional_value_flow: valueFlowBundle, + previous_discovery_document_summary: documentBundle + } + }); + + expect(result.adapter_status).toBe("ready"); + expect(result.should_run_discovery).toBe(true); + expect(result.semantic_data_need).toBe("business overview evidence with bounded analyst interpretation"); + expect(result.data_need_graph?.business_fact_family).toBe("business_overview"); + expect(result.data_need_graph?.subject_candidates).toEqual([]); + expect(result.turn_meaning_ref).toMatchObject({ + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + business_overview_separate_entity_candidates: [counterpartyName], + previous_counterparty_value_flow_bundle: valueFlowBundle, + previous_counterparty_document_bundle: documentBundle, + explicit_organization_scope: orgName, + unsupported_but_understood_family: "broad_business_evaluation", + stale_replay_forbidden: true + }); + expect(result.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined(); + expect(result.turn_meaning_ref?.explicit_date_scope).toBeUndefined(); + expect(result.reason_codes).toContain( + "mcp_discovery_business_overview_preserved_explicit_counterparty_summary_scope" + ); + expect(result.reason_codes).not.toContain("mcp_discovery_counterparty_from_raw_scope"); + }); + + it("continues business overview organization clarification without current-date reset", () => { + const today = new Date().toISOString().slice(0, 10); + const orgName = "ООО Альтернатива Плюс"; + const counterpartyName = "Группа СВК"; + const valueFlowBundle = { + counterparty: counterpartyName, + incoming_total: 20653490, + outgoing_total: 2129651, + net_amount: 18523839 + }; + const documentBundle = { + counterparty: counterpartyName, + document_count: 19 + }; + + const result = buildAssistantMcpDiscoveryTurnInput({ + userMessage: orgName, + assistantTurnMeaning: { + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + explicit_date_scope: today, + stale_replay_forbidden: true + }, + predecomposeContract: { + entities: { organization: orgName }, + period: { as_of_date: today } + }, + followupContext: { + previous_discovery_loop_status: "awaiting_clarification", + previous_discovery_loop_selected_chain_id: "business_overview", + previous_discovery_loop_pending_axes: ["organization"], + previous_discovery_loop_provided_axes: ["all_time_scope", "metadata_scope"], + previous_discovery_loop_asked_domain_family: "business_overview", + previous_discovery_loop_asked_action_family: "broad_evaluation", + previous_discovery_loop_unsupported_family: "broad_business_evaluation", + previous_discovery_loop_metadata_scope_hint: counterpartyName, + previous_anchor_type: "counterparty", + previous_anchor_value: counterpartyName, + previous_discovery_bidirectional_value_flow: valueFlowBundle, + previous_discovery_document_summary: documentBundle + } + }); + + expect(result.source_signal).toBe("assistant_turn_meaning"); + expect(result.data_need_graph?.business_fact_family).toBe("business_overview"); + expect(result.data_need_graph?.time_scope_need).toBe("all_time_scope"); + expect(result.turn_meaning_ref).toMatchObject({ + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + business_overview_separate_entity_candidates: [counterpartyName], + previous_counterparty_value_flow_bundle: valueFlowBundle, + previous_counterparty_document_bundle: documentBundle, + explicit_organization_scope: orgName, + unsupported_but_understood_family: "broad_business_evaluation", + stale_replay_forbidden: true + }); + expect(result.turn_meaning_ref?.explicit_date_scope).toBeUndefined(); + expect(result.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined(); + expect(result.reason_codes).toContain("mcp_discovery_all_time_scope_from_followup_context"); + expect(result.reason_codes).toContain( + "mcp_discovery_business_overview_preserved_explicit_counterparty_summary_scope" + ); + expect(result.reason_codes).not.toContain("mcp_discovery_date_scope_from_followup_context"); + }); + it("preserves explicit counterparty scope for company plus counterparty business summaries", () => { const orgName = "ООО Альтернатива Плюс"; const counterpartyName = "Группа СВК"; diff --git a/llm_normalizer/backend/tests/assistantTransitionPolicy.test.ts b/llm_normalizer/backend/tests/assistantTransitionPolicy.test.ts index 9e5d917..c57a06e 100644 --- a/llm_normalizer/backend/tests/assistantTransitionPolicy.test.ts +++ b/llm_normalizer/backend/tests/assistantTransitionPolicy.test.ts @@ -339,6 +339,71 @@ describe("assistantTransitionPolicy", () => { expect(carryover?.followupContext?.previous_anchor_value).toBe("Workstation Focus"); }); + it("keeps selected counterparty document follow-up through stale discovery guard", () => { + const policy = buildPolicy({ + findLastAddressAssistantItem: () => ({ + text: "Confirmed value-flow profile for SVK Group.", + debug: { + detected_intent: "customer_revenue_and_payments", + extracted_filters: { + organization: "ACME", + period_from: "2017-01-01", + period_to: "2017-12-31" + }, + assistant_mcp_discovery_entry_point_v1: { + bridge: { + loop_state: { + selected_chain_id: "value_flow_comparison" + } + } + } + } + }), + resolveAssistantTurnMeaning: () => ({ + stale_replay_forbidden: true, + explicit_intent_candidate: "list_documents_by_counterparty" + }), + resolveAddressIntent: () => ({ intent: "list_documents_by_counterparty" }), + resolveAddressIntentFamily: (intent: unknown) => + ["customer_revenue_and_payments", "list_documents_by_counterparty"].includes(String(intent ?? "")) + ? "counterparty" + : toNonEmptyString(intent), + hasAddressFollowupContextSignal: () => false, + hasReferentialPointer: () => false, + findRecentInventoryRootFrame: () => null, + findRecentAddressFilterValue: () => null + }); + + const carryover = policy.resolveAddressFollowupCarryoverContext( + "Show docs for selected counterparty", + [], + null, + { + predecomposeContract: { + intent: "list_documents_by_counterparty" + } + }, + { + session_context: { + active_focus_object: { + object_type: "counterparty", + label: "SVK Group" + } + } + } + ); + + expect(carryover?.followupContext?.target_intent).toBe("list_documents_by_counterparty"); + expect(carryover?.followupContext?.previous_anchor_type).toBe("counterparty"); + expect(carryover?.followupContext?.previous_anchor_value).toBe("SVK Group"); + expect(carryover?.followupContext?.previous_filters).toMatchObject({ + organization: "ACME", + counterparty: "SVK Group", + period_from: "2017-01-01", + period_to: "2017-12-31" + }); + }); + it("hydrates follow-up organization from shared assistant authority when local history filters are empty", () => { const policy = buildPolicy({ findLastAddressAssistantItem: () => ({ @@ -1628,6 +1693,164 @@ describe("assistantTransitionPolicy", () => { expect(carryover?.followupContext?.target_intent).toBe("customer_revenue_and_payments"); }); + it("carries selected counterparty proof bundles through business overview organization clarification", () => { + const orgName = "ООО Альтернатива Плюс"; + const counterpartyName = "Группа СВК"; + const valueFlowBundle = { + counterparty: counterpartyName, + incoming_total: 20653490, + outgoing_total: 2129651, + net_amount: 18523839 + }; + const documentBundle = { + counterparty: counterpartyName, + document_count: 19 + }; + const policy = buildPolicy({ + findLastAddressAssistantItem: () => ({ + role: "assistant", + text: "Коротко: уточните, по какой компании/организации сравнить выбранного контрагента Группа СВК.", + debug: { + execution_lane: "living_chat", + detected_intent: "business_overview", + mcp_discovery_response_applied: true, + assistant_mcp_discovery_entry_point_v1: { + schema_version: "assistant_mcp_discovery_runtime_entry_point_v1", + entry_status: "bridge_executed", + turn_input: { + turn_meaning_ref: { + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + business_overview_separate_entity_candidates: [counterpartyName], + previous_counterparty_value_flow_bundle: valueFlowBundle, + previous_counterparty_document_bundle: documentBundle, + metadata_scope_hint: counterpartyName, + unsupported_but_understood_family: "broad_business_evaluation", + stale_replay_forbidden: true + } + }, + bridge: { + bridge_status: "needs_clarification", + business_fact_answer_allowed: false, + pilot: { + pilot_scope: "business_overview_route_template_v1" + }, + loop_state: { + schema_version: "assistant_mcp_discovery_loop_state_v1", + loop_status: "awaiting_clarification", + selected_chain_id: "business_overview", + pilot_scope: "business_overview_route_template_v1", + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + unsupported_but_understood_family: "broad_business_evaluation", + pending_axes: ["organization"], + provided_axes: ["all_time_scope", "metadata_scope"], + metadata_scope_hint: counterpartyName + } + } + } + } + }), + resolveOrganizationSelectionFromMessage: (message: string) => + String(message ?? "").includes("Альтернатива") ? orgName : null, + hasAddressFollowupContextSignal: () => false + }); + + const carryover = policy.resolveAddressFollowupCarryoverContext( + orgName, + [], + null, + { + predecomposeContract: { + mode: "unsupported", + intent: "unknown", + entities: { organization: orgName }, + semantics: { anchor_kind: "organization", anchor_value: orgName } + } + }, + null + ); + + expect(carryover?.followupContext?.previous_discovery_loop_status).toBe("awaiting_clarification"); + expect(carryover?.followupContext?.previous_discovery_loop_selected_chain_id).toBe("business_overview"); + expect(carryover?.followupContext?.previous_discovery_loop_provided_axes).toEqual([ + "all_time_scope", + "metadata_scope" + ]); + expect(carryover?.followupContext?.previous_discovery_loop_metadata_scope_hint).toBe(counterpartyName); + expect(carryover?.followupContext?.previous_discovery_bidirectional_value_flow).toEqual(valueFlowBundle); + expect(carryover?.followupContext?.previous_discovery_document_summary).toEqual(documentBundle); + }); + + it("recovers selected counterparty proof bundles from prior boundary-summary text", () => { + const orgName = "ООО Альтернатива Плюс"; + const counterpartyName = "Группа СВК"; + const policy = buildPolicy({ + findLastAddressAssistantItem: () => ({ + role: "assistant", + text: + "Коротко: уточните, по какой компании/организации сравнить выбранного контрагента Группа СВК.\n" + + "Отдельно по контрагенту Группа СВК: подтверждено получили 20 653 490 руб., заплатили 2 129 651 руб., расчетное нетто в нашу сторону 18 523 839 руб. Основа: проверенные входящие платежи и исходящие платежи и документы по цепочке: найдено 19.", + debug: { + execution_lane: "living_chat", + detected_intent: "business_overview", + mcp_discovery_response_applied: true, + assistant_mcp_discovery_entry_point_v1: { + schema_version: "assistant_mcp_discovery_runtime_entry_point_v1", + entry_status: "bridge_executed", + bridge: { + bridge_status: "needs_clarification", + business_fact_answer_allowed: false, + pilot: { + pilot_scope: "business_overview_route_template_v1" + }, + loop_state: { + schema_version: "assistant_mcp_discovery_loop_state_v1", + loop_status: "awaiting_clarification", + selected_chain_id: "business_overview", + pilot_scope: "business_overview_route_template_v1", + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + pending_axes: ["organization"], + provided_axes: ["all_time_scope", "metadata_scope"], + metadata_scope_hint: counterpartyName + } + } + } + } + }), + resolveOrganizationSelectionFromMessage: (message: string) => + String(message ?? "").includes("Альтернатива") ? orgName : null, + hasAddressFollowupContextSignal: () => false + }); + + const carryover = policy.resolveAddressFollowupCarryoverContext( + orgName, + [], + null, + { + predecomposeContract: { + mode: "unsupported", + intent: "unknown", + entities: { organization: orgName }, + semantics: { anchor_kind: "organization", anchor_value: orgName } + } + }, + null + ); + + expect(carryover?.followupContext?.previous_discovery_bidirectional_value_flow).toMatchObject({ + counterparty: counterpartyName, + incoming_customer_revenue: { total_amount_human_ru: "20 653 490 руб." }, + outgoing_supplier_payout: { total_amount_human_ru: "2 129 651 руб." }, + net_amount_human_ru: "18 523 839 руб." + }); + expect(carryover?.followupContext?.previous_discovery_document_summary).toMatchObject({ + counterparty: counterpartyName, + document_count: 19 + }); + }); + it("carries grounded metadata downstream route hints into followup context", () => { const policy = buildPolicy({ findLastAddressAssistantItem: () => null, diff --git a/llm_normalizer/data/autorun_generators/history.json b/llm_normalizer/data/autorun_generators/history.json index d09a27f..f1d01ce 100644 --- a/llm_normalizer/data/autorun_generators/history.json +++ b/llm_normalizer/data/autorun_generators/history.json @@ -1,4 +1,61 @@ [ + { + "generation_id": "gen-ag05242306-7b49ab", + "created_at": "2026-05-24T23:06:41+00:00", + "mode": "saved_user_sessions", + "title": "AGENT | Бизнес-обзор компании и СВК accepted replay 2026-05-24", + "count": 13, + "domain": "agent_business_overview_counterparty_reliability", + "questions": [ + "Дай взрослый бизнес-обзор ООО Альтернатива Плюс за 2020 год по данным 1С: обороты, входящие и исходящие деньги, нетто, НДС, долги, склад, клиенты, поставщики и что пока нельзя утверждать.", + "Раскрой деньги подробнее: сколько получили, сколько заплатили, какой чистый денежный поток, кто главный клиент и главный поставщик в 2020.", + "Что с НДС за 2020 год по ООО Альтернатива Плюс: какая позиция видна, на чем она основана и чего не хватает для налогового вывода?", + "Теперь за все доступное время дай обзор компании в целом, но не тащи НДС за 2020 как подтвержденную общую налоговую позицию.", + "Отдельно по контрагенту Группа СВК, без опоры на прошлый диалог: сколько денег прошло, что входящее, что исходящее и есть ли документы или движения, на которых это основано?", + "Покажи документы по этой цепочке и не смешивай Группа СВК с организацией ООО Альтернатива Плюс.", + "Собери короткий итог: что мы подтвердили по компании, что отдельно по Группа СВК, какие выводы можно делать и какие нельзя.", + "По-человечески посмотри ООО Альтернатива Плюс за 2020: что по бизнесу видно в 1С по деньгам, НДС, долгам, складу, клиентам/поставщикам и где пока нельзя делать вывод?", + "А по деньгам в этом же году кто больше всего занес и кому больше всего ушло? Банк не называй обычным клиентом без оговорки.", + "Возьми как выбранного контрагента Группа СВК: сколько по нему входящих денег, исходящих денег и расчетное нетто, на чем это основано?", + "Теперь по нему покажи документы и не переключайся на организацию.", + "И коротко сравни: что у нас подтверждено по компании, что отдельно по выбранному контрагенту, и какие выводы нельзя делать?", + "ООО Альтернатива Плюс" + ], + "generated_by": "codex_agent", + "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260524230641_gen-ag05242306-7b49ab.json", + "context": { + "llm_provider": null, + "model": null, + "assistant_prompt_version": null, + "decomposition_prompt_version": null, + "prompt_fingerprint": null, + "autogen_personality_id": null, + "autogen_personality_prompt": null, + "source_session_id": null, + "saved_session_file": "assistant_saved_session_20260524230641_gen-ag05242306-7b49ab.json", + "saved_case_set_kind": "agent_semantic_scenario", + "agent_run": true, + "agent_focus": "Accepted proof pack for company business overview, SVK counterparty money/documents, selected-object carryover, org clarification, and all-time scope reset", + "architecture_phase": "agent_reliability_uplift_business_overview_counterparty", + "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\agent_business_overview_counterparty_reliability_20260524.json", + "scenario_id": null, + "semantic_tags": [ + "business_overview", + "colloquial", + "counterparty", + "debt", + "documents", + "inventory", + "money", + "organization_clarification", + "pronoun_followup", + "scope_guard", + "selected_object", + "vat" + ], + "latest_acceptance": null + } + }, { "generation_id": "gen-ag05231912-4420c2", "created_at": "2026-05-23T19:12:34+00:00", @@ -60,89 +117,7 @@ "settlements_account_60", "settlements_receivables" ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_autonomy_selected_object_mix_live_accepted_20260523", - "saved_after_validated_replay": true - } - }, - { - "generation_id": "gen-ag05231858-323f86", - "created_at": "2026-05-23T18:58:48+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Autonomy business quality pack", - "count": 15, - "domain": "autonomy_business_quality", - "questions": [ - "Сколько входящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?", - "Сколько исходящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?", - "А всего сколько денег пришло в ООО Альтернатива Плюс за 2020, без топов и без контрагентов?", - "Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток.", - "скока денег альтернатива заработала за 20 год?", - "а это чистая прибыль?", - "Какая чистая прибыль по ООО Альтернатива Плюс за 2020?", - "А отдельно по СБЕРБАНКУ: он для нас клиент, поставщик или финансовый поток? Дай коротко по подтвержденным строкам.", - "какое нетто по деньгам с Группа СВК за 2020 год: сколько получили и сколько заплатили?", - "кому мы должны на конец 2020?", - "а нам кто должен на конец 2020?", - "сколько НДС надо заплатить в налоговую за декабрь 2019?", - "Как ты оценишь деятельность компании?", - "Какая номенклатура товара реализована с высокой прибылью какая с низкой?", - "май 2020" - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260523185848_gen-ag05231858-323f86.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260523185848_gen-ag05231858-323f86.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "Expanded targeted AGENT replay for the autonomy milestone: value-flow, business overview, debts, VAT, profit/cashflow distinction, nomenclature margin boundary, and final answer quality must survive realistic business questions.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\agent_autonomy_business_quality_20260523.json", - "scenario_id": "agent_autonomy_business_quality_20260523", - "semantic_tags": [ - "autonomy_core", - "bank_boundary", - "bank_classification", - "business_answer_quality", - "business_evaluation", - "business_overview", - "cashflow_overview", - "cashflow_vs_profit", - "clarification", - "colloquial_money", - "colloquial_total", - "counterparty_value_flow", - "debt_answer_quality", - "direct_profit", - "domain_purity", - "followup_context", - "incoming_total", - "limit_honesty", - "limited_answer", - "net_flow", - "next_action", - "no_profit_substitution", - "no_top_guard", - "nomenclature_margin", - "outgoing_total", - "payables", - "profit_vs_cashflow", - "receivables", - "technical_garbage_guard", - "value_flow", - "vat" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_autonomy_business_quality_live_semantic_gate_accepted_20260523", - "saved_after_validated_replay": true + "latest_acceptance": null } }, { @@ -189,9 +164,7 @@ "only_total", "temporal_carryover" ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_cashflow_compact_display_variants_live5", - "saved_after_validated_replay": true + "latest_acceptance": null } }, { @@ -238,9 +211,7 @@ "temporal_carryover", "tops_allowed" ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_cashflow_no_tops_live1", - "saved_after_validated_replay": true + "latest_acceptance": null } }, { @@ -280,9 +251,7 @@ "followup", "profit_boundary" ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_profit_direct_answer_live1", - "saved_after_validated_replay": true + "latest_acceptance": null } }, { @@ -329,9 +298,7 @@ "period_expansion", "period_followup" ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_inventory_margin_ranking_live5", - "saved_after_validated_replay": true + "latest_acceptance": null } }, { @@ -391,9 +358,7 @@ "slang_wording", "temporal_carryover" ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_cashflow_profit_directness_live11", - "saved_after_validated_replay": true + "latest_acceptance": null } }, { @@ -469,91 +434,7 @@ "value_flow", "vat" ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_autonomy_business_quality_live4", - "saved_after_validated_replay": true - } - }, - { - "generation_id": "gen-ag05221957-713bbd", - "created_at": "2026-05-22T19:57:37+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Hot value-flow discovery handoff", - "count": 3, - "domain": "autonomy_hot_value_flow_handoff", - "questions": [ - "Сколько входящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?", - "Сколько исходящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?", - "А всего сколько денег пришло в ООО Альтернатива Плюс за 2020, без топов и без контрагентов?" - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260522195737_gen-ag05221957-713bbd.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260522195737_gen-ag05221957-713bbd.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "Targeted AGENT replay for the current Autonomy Core slice: organization-scoped value-flow questions must be answered through guarded MCP discovery response with hot handoff, not through stale exact fallback or a counterparty-only route.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\agent_hot_value_flow_handoff_20260522.json", - "scenario_id": "agent_hot_value_flow_handoff_20260522", - "semantic_tags": [ - "autonomy_core", - "colloquial_total", - "guarded_response", - "hot_handoff", - "incoming_total", - "outgoing_total", - "value_flow" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_hot_value_flow_handoff_live5", - "saved_after_validated_replay": true - } - }, - { - "generation_id": "gen-ag05221319-4035f5", - "created_at": "2026-05-22T13:19:31+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Inventory margin-ranking accepted replay 2026-05-22", - "count": 5, - "domain": "inventory_margin_ranking", - "questions": [ - "Какая номеклатура товара реализована с высокой прибылью какая с низкой", - "сентябрь 2017", - "покажи найденные строки себестоимостной базы", - "расширь до 2017 года", - "анализ по 41 счету а не 01" - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260522131931_gen-ag05221319-4035f5.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260522131931_gen-ag05221319-4035f5.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "inventory_margin_ranking_followup_and_business_modes", - "architecture_phase": "Business Answer Contract / margin-ranking safety gate", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\inventory_margin_ranking_agent_loop_20260522.json", - "scenario_id": "inventory_margin_ranking_agent_loop_20260522", - "semantic_tags": [], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\inventory_margin_ranking_agent_loop_live7", - "saved_after_validated_replay": true + "latest_acceptance": null } }, { @@ -622,754 +503,6 @@ "vat_continuity", "warehouse_not_required" ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase105_mixed_schema_primitive_closure_live3", - "saved_after_validated_replay": true - } - }, - { - "generation_id": "gen-ag05131226-630ddf", - "created_at": "2026-05-13T12:26:18+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 104 generic role-tail anchor hygiene replay", - "count": 4, - "domain": "address_phase104_generic_role_tail_anchor_hygiene", - "questions": [ - "Альтернатива Плюс", - "Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток, если по назначению он не обычный клиент или поставщик.", - "А отдельно по СБЕРБАНКУ: он для нас клиент, поставщик или финансовый поток? Дай коротко по подтвержденным строкам.", - "А теперь по поставщику Группа СВК за 2020: сколько мы ему заплатили и какой общий денежный смысл?" - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260513122618_gen-ag05131226-630ddf.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260513122618_gen-ag05131226-630ddf.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "phase104 generic role-tail anchor hygiene", - "architecture_phase": "Open-World Schema/Primitive Discovery", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase104_generic_role_tail_anchor_hygiene.json", - "scenario_id": "address_truth_harness_phase104_generic_role_tail_anchor_hygiene", - "semantic_tags": [ - "bank_like_counterparty", - "bare_org_scope", - "business_overview", - "counterparty_net_cash_flow", - "financial_role_purpose", - "generic_role_tail_anchor_hygiene", - "phase102_canary", - "post_overview_anchor_integrity", - "stale_scope_guard", - "supplier_prefix_canary" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase104_generic_role_tail_anchor_hygiene_live2", - "saved_after_validated_replay": true - } - }, - { - "generation_id": "gen-ag05131200-0ed59a", - "created_at": "2026-05-13T12:00:47+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 103 financial role and purpose arbitration replay", - "count": 6, - "domain": "address_phase103_financial_role_purpose_arbitration", - "questions": [ - "Альтернатива Плюс", - "По СБЕРБАНКУ за 2020 покажи коротко: сколько денег входило и уходило, и что это по смыслу в 1С — клиентская выручка, поставщик, комиссия, кредит или другой финансовый поток?", - "Если СБЕРБАНК есть во входящих поступлениях, можно ли считать его нашим клиентом и выручкой? Скажи по подтвержденным строкам, без притягивания.", - "А если деньги уходили в СБЕРБАНК, это наш поставщик или финансовые списания? Раздели по смыслу и покажи основание.", - "Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток, если по назначению он не обычный клиент или поставщик.", - "А теперь отдельно по Группа СВК за 2020: сколько денег получили, сколько заплатили и какое нетто?" - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260513120047_gen-ag05131200-0ed59a.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260513120047_gen-ag05131200-0ed59a.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "phase103 financial role and purpose arbitration", - "architecture_phase": "Open-World Schema/Primitive Discovery", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase103_financial_role_purpose_arbitration.json", - "scenario_id": "address_truth_harness_phase103_financial_role_purpose_arbitration", - "semantic_tags": [ - "bank_like_counterparty", - "bank_like_customer_boundary", - "bank_like_supplier_boundary", - "bank_operations_by_counterparty", - "bare_org_scope", - "business_overview", - "canary", - "counterparty_net_cash_flow", - "customer_revenue_and_payments", - "financial_role_purpose", - "phase102_canary", - "stale_scope_guard", - "supplier_payouts_profile" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase103_financial_role_purpose_arbitration_live3", - "saved_after_validated_replay": true - } - }, - { - "generation_id": "gen-ag05131121-8c41ab", - "created_at": "2026-05-13T11:21:52+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 102 debt mirror clean-scope polarity replay", - "count": 6, - "domain": "address_phase102_debt_mirror_clean_scope_polarity", - "questions": [ - "Альтернатива Плюс", - "мы кому реально должны денег на сегодня? коротко, чистый долг к оплате, без встречных обеспечений как основного долга", - "а Комитету государственных услуг мы реально должны эти 3,6 млн или это встречное обеспечение/зачет? объясни именно по смыслу долга", - "а нам Комитет государственных услуг тоже должен 3,6 млн? это же та же сумма — скажи честно, это дебиторка или встречная часть?", - "тогда кто нам реально должен денег на сегодня? именно чистая дебиторка", - "а мы кому?" - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260513112152_gen-ag05131121-8c41ab.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260513112152_gen-ag05131121-8c41ab.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "phase102 debt mirror clean-scope polarity", - "architecture_phase": "Open-World Schema/Primitive Discovery", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase102_debt_mirror_clean_scope_polarity.json", - "scenario_id": "address_truth_harness_phase102_debt_mirror_clean_scope_polarity", - "semantic_tags": [ - "company_selected", - "debt_mirror_clean_scope", - "direct_answer_first", - "organization_scope", - "payables_counterparty_check", - "payables_snapshot", - "polarity_honesty", - "receivables_counterparty_check", - "receivables_snapshot", - "settlements_mirror_followup" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase102_debt_mirror_clean_scope_polarity_live3", - "saved_after_validated_replay": true - } - }, - { - "generation_id": "gen-ag05131044-cbe2ff", - "created_at": "2026-05-13T10:44:38+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 101 inventory root scope without warehouse clarification replay", - "count": 7, - "domain": "address_phase101_inventory_root_scope_no_warehouse_clarification", - "questions": [ - "приветик - че как там дела", - "расскажи что можешь интересного", - "кайф - что там на складе по остаткам?", - "АЛЬТЕРНАТИВА", - "а исторические остатки на другие даты умеешь?", - "давай на июнь 2017", - "март 2016" - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260513104438_gen-ag05131044-cbe2ff.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260513104438_gen-ag05131044-cbe2ff.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "Focused semantic replay for the manual assistant-stage1-hyh1A1WR3j signal: after a broad stock-on-hand question and organization clarification, the assistant must resume the root inventory snapshot for the selected company across available warehouses instead of asking the user to name a warehouse, item, category, or material.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase101_inventory_root_scope_no_warehouse_clarification.json", - "scenario_id": "address_truth_harness_phase101_inventory_root_scope_no_warehouse_clarification", - "semantic_tags": [ - "capability_meta", - "clarification_required", - "clarification_resume", - "date_followup", - "historical_inventory", - "human_answer_quality", - "inventory_capability_meta", - "inventory_root", - "smalltalk_entry", - "warehouse_not_required" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase101_inventory_root_scope_no_warehouse_clarification_live1", - "saved_after_validated_replay": true - } - }, - { - "generation_id": "gen-ag05131028-234e5e", - "created_at": "2026-05-13T10:28:45+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 100 large-query continuation UX replay", - "count": 3, - "domain": "address_phase100_large_query_continuation_ux", - "questions": [ - "Дай общий бизнес-обзор ООО Альтернатива Плюс за весь доступный период: входящие, исходящие, нетто, лучший год. Если срез слишком широкий, не выдумывай полный итог, а скажи как безопасно дособрать.", - "Ок, тогда дособери конкретно 2020: входящие, исходящие и расчетное денежное нетто.", - "Это можно считать прибылью за 2020 или нет? Ответь коротко и по делу." - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260513102845_gen-ag05131028-234e5e.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260513102845_gen-ag05131028-234e5e.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "Focused semantic replay for all-time or very broad business overview questions: the assistant should answer from checked evidence, disclose row-limit coverage honestly, offer a safe period-narrowing continuation path, and then recover the explicit-year follow-up through chunked evidence without leaking technical mechanics.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase100_large_query_continuation_ux.json", - "scenario_id": "address_truth_harness_phase100_large_query_continuation_ux", - "semantic_tags": [ - "business_language", - "business_overview", - "followup_continuation", - "followup_directness", - "large_query_budget", - "large_query_continuation", - "limit_honesty", - "profit_boundary" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase100_large_query_continuation_ux_live2", - "saved_after_validated_replay": true - } - }, - { - "generation_id": "gen-ag05131009-f08174", - "created_at": "2026-05-13T10:09:01+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 99 large-query budget and continuation policy replay", - "count": 4, - "domain": "address_phase99_large_query_budget_continuation", - "questions": [ - "Дай взрослый бизнес-обзор ООО Альтернатива Плюс за 2020: входящие, исходящие, нетто, кто основные источники денег и где важные ограничения.", - "То есть это можно считать прибылью за 2020 или нет? Коротко.", - "А кто за 2020 принес больше всего денег, и если там банк, не называй его обычным клиентом.", - "По исходящим за 2020 есть зависимость от одного поставщика или это только денежная концентрация?" - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260513100901_gen-ag05131009-f08174.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260513100901_gen-ag05131009-f08174.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "Focused semantic replay for explicit-year large business questions: the assistant should use chunked 1C evidence where available, answer direct-first, avoid fake profit claims, keep bank/counterparty boundaries, and not collapse into row-limit refusal wording when yearly money coverage can be recovered.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase99_large_query_budget_continuation.json", - "scenario_id": "address_truth_harness_phase99_large_query_budget_continuation", - "semantic_tags": [ - "business_language", - "business_overview", - "context_continuity", - "direct_answer_first", - "financial_counterparty_flow_hint", - "followup_directness", - "large_query_budget", - "profit_boundary", - "vendor_risk_procurement_quality" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase99_large_query_budget_continuation_live2", - "saved_after_validated_replay": true - } - }, - { - "generation_id": "gen-ag05122315-f1e27c", - "created_at": "2026-05-12T23:15:48+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 98 limit honesty and business-language replay", - "count": 6, - "domain": "address_phase98_limit_honesty_business_language", - "questions": [ - "По ООО Альтернатива Плюс на конец 2020 можно точно понять, какая дебиторка просрочена?", - "То есть просрочку доказать нельзя, коротко почему?", - "НДС за 2020 по ООО Альтернатива Плюс какой?", - "А кто принес больше всего денег за 2020?", - "По ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?", - "А зависимость от одного поставщика за 2020 можно точно оценить?" - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260512231548_gen-ag05122315-f1e27c.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260512231548_gen-ag05122315-f1e27c.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "Focused semantic replay from assistant-stage1-v2qsm_R0fF: answers may be bounded, but they must stay business-readable, direct-first, and must not leak MCP/proxy/route/debug wording when explaining row limits, incomplete coverage, debt due-date proof, inventory reserve proof, supplier dependency, VAT, or bank-like counterparties.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase98_limit_honesty_business_language.json", - "scenario_id": "address_truth_harness_phase98_limit_honesty_business_language", - "semantic_tags": [ - "business_language", - "customer_revenue_and_payments", - "debt_due_date_aging_quality", - "debug_leak_guard", - "financial_counterparty_flow_hint", - "followup_directness", - "inventory_reserve_liquidation_quality", - "limit_honesty", - "vat", - "vendor_risk_procurement_quality" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase98_limit_honesty_business_language_live3", - "saved_after_validated_replay": true - } - }, - { - "generation_id": "gen-ag05122250-4451a8", - "created_at": "2026-05-12T22:50:23+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 97 financial counterparty flow hints replay", - "count": 4, - "domain": "address_phase97_financial_counterparty_flow_hints", - "questions": [ - "По ООО Альтернатива Плюс за 2020 отдельно посмотри платежи в СБЕРБАНК: это обычный поставщик или банковский/финансовый поток? Дай коротко и по проверенным данным 1С.", - "А если по этой же компании СБЕРБАНК встречается во входящих поступлениях, это клиентская выручка или там может быть кредитный/депозитный банковский смысл? Не притягивай, скажи что подтверждено.", - "Теперь дай взрослый краткий обзор ООО Альтернатива Плюс за 2020: входящие, исходящие, нетто и отдельно отметь, если в топах есть банк, почему его нельзя читать как обычного клиента или поставщика.", - "А теперь отдельно по Группа СВК за 2020: сколько денег получили, сколько заплатили и какое нетто?" - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260512225023_gen-ag05122250-4451a8.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260512225023_gen-ag05122250-4451a8.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "Focused semantic replay for the Open-World Schema/Primitive Discovery slice: bank-like counterparties must not be described as ordinary suppliers/customers when operation, payment purpose, contract, or comment fields indicate banking commission, credit, deposit, tax/budget, or payroll-like flows. The replay also keeps a normal counterparty value-flow canary.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase97_financial_counterparty_flow_hints.json", - "scenario_id": "address_truth_harness_phase97_financial_counterparty_flow_hints", - "semantic_tags": [ - "bank_like_customer_boundary", - "bank_like_supplier_boundary", - "business_overview", - "canary", - "counterparty_net_cash_flow", - "customer_revenue_and_payments", - "financial_counterparty_flow_hint", - "profit_margin_boundary", - "stale_scope_guard", - "supplier_payouts_profile" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase97_financial_counterparty_flow_hints_live4", - "saved_after_validated_replay": true - } - }, - { - "generation_id": "gen-ag05122057-c9786e", - "created_at": "2026-05-12T20:57:28+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 96 inventory reserve/liquidation quality-events", - "count": 2, - "domain": "address_phase96_inventory_reserve_liquidation_quality", - "questions": [ - "По ООО Альтернатива Плюс за 2020 год проверь склад: были ли списания товаров, оприходования/корректировки, инвентаризации, переоценки, резервы под неликвиды или ликвидационная стоимость? Скажи коротко и честно, что подтверждено 1С, а что нельзя утверждать.", - "А по этим же данным можно сказать, что склад ликвидный и неликвидов нет?" - ], - "generated_by": "Codex", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260512205728_gen-ag05122057-c9786e.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260512205728_gen-ag05122057-c9786e.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "inventory_reserve_liquidation_quality", - "architecture_phase": "Route-Candidate-Driven Enablement Loop", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase96_inventory_reserve_liquidation_quality.json", - "scenario_id": "address_truth_harness_phase96_inventory_reserve_liquidation_quality", - "semantic_tags": [ - "direct_answer_first", - "followup_context_carryover", - "inventory_liquidity_boundary", - "inventory_reserve_liquidation_quality", - "no_inventory_health_overclaim", - "no_market_liquidation_overclaim", - "reviewed_inventory_quality_events" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase96_inventory_reserve_liquidation_quality_rerun", - "saved_after_validated_replay": true - } - }, - { - "generation_id": "gen-ag05121628-50ea6c", - "created_at": "2026-05-12T16:28:41+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Phase20 continuity/ranking/self-scope accepted replay 2026-05-12", - "count": 6, - "domain": "address_phase20_continuity_stabilization", - "questions": [ - "кто у нас самый доходный клиент за все время?", - "какой у нас самый доходный год?", - "кто нам должен денег на май 2017?", - "а какой ндс мы должны примерно заплатить за этот период?", - "мы должны комуто денег на сегодня?", - "а нам?" - ], - "generated_by": "Codex", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260512162841_gen-ag05121628-50ea6c.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260512162841_gen-ag05121628-50ea6c.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "ranking catalog alignment, self-scope pronoun, compact debt answers", - "architecture_phase": "MCP автономка / semantic integrity", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase20_continuity_stabilization.json", - "scenario_id": "address_truth_harness_phase20_continuity_stabilization", - "semantic_tags": [ - "exact_not_overwritten", - "garbage_anchor_forbidden", - "payables_snapshot", - "period_carryover", - "pronoun_followup", - "receivables_snapshot", - "temporal_tail_not_entity", - "value_flow_ranking", - "vat_followup", - "year_tail_not_entity" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase20_continuity_stabilization_rerun_planner_ranking_fix", - "saved_after_validated_replay": true - } - }, - { - "generation_id": "gen-ag05121357-9ea5d6", - "created_at": "2026-05-12T13:57:26+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 95 vendor/procurement quality reviewed route", - "count": 7, - "domain": "address_phase95_vendor_procurement_quality_reviewed_route", - "questions": [ - "по ООО Альтернатива Плюс за 2020 есть ли риск, что мы зависим от одного поставщика?", - "а банк из этого ответа считать обычным поставщиком?", - "по этой же компании на конец 2020 можно точно понять, какая дебиторка просрочена?", - "а чистая прибыль и маржа за 2020 какие?", - "НДС за 2020 по ООО Альтернатива Плюс какой?", - "а кто принес больше всего денег за 2020?", - "по ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?" - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260512135726_gen-ag05121357-9ea5d6.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260512135726_gen-ag05121357-9ea5d6.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "Focused semantic replay for promoting vendor_risk_procurement_quality from proxy-only enablement to reviewed procurement-concentration evidence while preserving debt, profit, VAT, value-flow, and inventory reserve canaries.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase95_vendor_procurement_quality_reviewed_route.json", - "scenario_id": "address_truth_harness_phase95_vendor_procurement_quality_reviewed_route", - "semantic_tags": [ - "accounting_profit_margin", - "business_overview", - "canary", - "context_carryover", - "debt_due_date_boundary", - "financial_institution_boundary", - "inventory_reserve_boundary", - "missing_proof_families", - "profit_margin_boundary", - "ready_for_reviewed_execution", - "value_flow_ranking", - "vat_continuity", - "vendor_risk_procurement_boundary", - "vendor_risk_procurement_quality" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase95_vendor_procurement_quality_reviewed_route_live2", - "saved_after_validated_replay": true - } - }, - { - "generation_id": "gen-ag05101319-c04f79", - "created_at": "2026-05-10T13:19:22+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 94 debt due-date aging reviewed route", - "count": 7, - "domain": "address_phase94_debt_due_date_aging_reviewed_route", - "questions": [ - "по ООО Альтернатива Плюс на конец 2020 можно точно понять, какая дебиторка просрочена?", - "то есть просрочку доказать нельзя, коротко почему?", - "а чистая прибыль и маржа за 2020 по этой же компании какие?", - "НДС за 2020 по ООО Альтернатива Плюс какой?", - "а кто принес больше всего денег за 2020?", - "по ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?", - "а зависимость от одного поставщика за 2020 можно точно оценить?" - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260510131922_gen-ag05101319-c04f79.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260510131922_gen-ag05101319-c04f79.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "Focused semantic replay for promoting debt_due_date_aging_quality from proxy-only enablement to a reviewed payment-term/open-balance route while preserving profit, VAT, inventory, and vendor-risk boundaries.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase94_debt_due_date_aging_reviewed_route.json", - "scenario_id": "address_truth_harness_phase94_debt_due_date_aging_reviewed_route", - "semantic_tags": [ - "accounting_profit_margin", - "business_overview", - "canary", - "checked_negative", - "context_carryover", - "debt_due_date_aging_quality", - "debt_due_date_boundary", - "inventory_reserve_boundary", - "missing_proof_families", - "profit_margin_boundary", - "ready_for_reviewed_execution", - "value_flow_ranking", - "vat_continuity", - "vendor_risk_procurement_boundary" - ], - "latest_acceptance": null - } - }, - { - "generation_id": "gen-ag05101213-596d99", - "created_at": "2026-05-10T12:13:26+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 93 accounting profit-margin reviewed route", - "count": 6, - "domain": "address_phase93_accounting_profit_margin_reviewed_route", - "questions": [ - "по ООО Альтернатива Плюс за 2020 можно точно сказать чистую прибыль и маржу?", - "а это прибыль или убыток, коротко?", - "по этой же компании на конец 2020 можно точно понять, какая дебиторка просрочена?", - "тогда НДС за 2020 по ООО Альтернатива Плюс какой?", - "а какой контрагент принес больше всего денег за 2020?", - "по ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?" - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260510121326_gen-ag05101213-596d99.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260510121326_gen-ag05101213-596d99.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "accounting profit-margin reviewed route", - "architecture_phase": "Route-Candidate-Driven Enablement Loop", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase93_accounting_profit_margin_reviewed_route.json", - "scenario_id": "address_truth_harness_phase93_accounting_profit_margin_reviewed_route", - "semantic_tags": [ - "accounting_profit_margin", - "business_overview", - "context_carryover", - "debt_due_date_boundary", - "inventory_reserve_boundary", - "missing_proof_families", - "needs_route_enablement", - "profit_margin_boundary", - "ready_for_reviewed_execution", - "value_flow_ranking", - "vat_continuity" - ], - "latest_acceptance": null - } - }, - { - "generation_id": "gen-ag05100949-2a5ed8", - "created_at": "2026-05-10T09:49:21+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 91 route-candidate-driven enablement loop canary", - "count": 5, - "domain": "address_phase91_route_candidate_driven_enablement_loop", - "questions": [ - "какой контрагент принес больше всего денег за 2020 год?", - "ООО Альтернатива Плюс", - "а теперь сколько лет мы работаем с Группа СВК?", - "покажи движения по НДС за 2020 по ООО Альтернатива Плюс", - "можно ли по этим данным точно подтвердить резерв под неликвиды на складе?" - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260510094921_gen-ag05100949-2a5ed8.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260510094921_gen-ag05100949-2a5ed8.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "route candidate repair-target grouping + handoff canary", - "architecture_phase": "Route-Candidate-Driven Enablement Loop", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase91_route_candidate_driven_enablement_loop.json", - "scenario_id": "address_truth_harness_phase91_route_candidate_driven_enablement_loop", - "semantic_tags": [ - "clarification_recovery", - "counterparty_lifecycle", - "inventory_reserve_boundary", - "metadata_scope", - "movement_evidence", - "needs_user_scope", - "no_overclaim", - "open_organization_scope", - "ready_for_reviewed_execution", - "route_candidate_handoff", - "stale_scope_guard", - "unreviewed_proof_family", - "value_flow_ranking", - "vat" - ], - "latest_acceptance": null - } - }, - { - "generation_id": "gen-ag05091830-062fc9", - "created_at": "2026-05-09T18:30:50+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Agentic semantic development loop dogfood gate", - "count": 12, - "domain": "agentic_semantic_development_loop_control", - "questions": [ - "Дай взрослый бизнес-обзор ООО Альтернатива Плюс за 2020 год по данным 1С: обороты, входящие и исходящие деньги, нетто, НДС, долги, склад, клиенты, поставщики и что пока нельзя утверждать.", - "Раскрой деньги подробнее: сколько получили, сколько заплатили, какой чистый денежный поток, кто главный клиент и главный поставщик в 2020.", - "А если смотреть за все доступное время, какой самый доходный год по подтвержденным оборотам и почему? Не называй это бухгалтерской прибылью, если чистой прибыли нет.", - "Что с НДС за 2020 год по ООО Альтернатива Плюс: какая позиция видна, на чем она основана и чего не хватает для налогового вывода?", - "Теперь за все доступное время дай обзор компании в целом, но не тащи НДС за 2020 как подтвержденную общую налоговую позицию.", - "Отдельно по контрагенту Группа СВК, без опоры на прошлый диалог: сколько денег прошло, что входящее, что исходящее и есть ли документы или движения, на которых это основано?", - "Покажи документы по этой цепочке и не смешивай Группа СВК с организацией ООО Альтернатива Плюс.", - "Собери короткий итог: что мы подтвердили по компании, что отдельно по Группа СВК, какие выводы можно делать и какие нельзя.", - "Сделай короткий стартовый чек контекста: есть ли уже выбранная компания или контрагент в текущем диалоге; если нет, скажи честно и не выдумывай память про Группа СВК.", - "Покажи хвосты по счету 60 на август 2020 по ООО Альтернатива Плюс; если точных данных нет, скажи это прямо и не подменяй ответ общим обзором.", - "Что было на складе на март 2021 по доступным данным? Дай прямой ответ и не уводи его в контрагента Группа СВК.", - "Вернись к ООО Альтернатива Плюс: сколько всего денег получили и заплатили по всем подтвержденным данным, но не смешивай это с отдельной цепочкой Группа СВК и не называй оборот чистой прибылью." - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260509183050_gen-ag05091830-062fc9.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260509183050_gen-ag05091830-062fc9.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "Automate stage question review, live semantic replay, strong business audit, Lead Codex repair handoff, rerun validation, and final human confirmation.", - "architecture_phase": "turnaround_11_agentic_semantic_development_loop", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\agentic_semantic_development_loop_stage_pack.json", - "scenario_id": null, - "semantic_tags": [ - "business_overview", - "counterparty", - "debt", - "documents", - "inventory", - "memory", - "money", - "scope_guard", - "vat" - ], "latest_acceptance": null } }, @@ -1648,63 +781,6 @@ "latest_acceptance": null } }, - { - "generation_id": "gen-ag04241710-bdb248", - "created_at": "2026-04-24T17:10:31+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Post-F ручные провалы VAT revenue item-flow live3", - "count": 11, - "domain": "address_post_f_manual_failures", - "questions": [ - "кайф - что там на складе по остаткам?", - "АЛЬТЕРНАТИВА", - "март 2016", - "По выбранному объекту \"Рабочая станция универсального специалиста (индивидуальное изготовление)\": где взяли это?", - "ндс можешь прикинуть на дату покупки рабочей станции?", - "прикинь какой ндс нам надо заплатить на февраль 2017", - "кто у нас самый доходный клиент за все время", - "по чепурнову покажи все доки", - "а по свк", - "а сейчас у нас есть что на складе?", - "что нам отгружал чепурнов? какой товар или услугу?" - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260424171031_gen-ag04241710-bdb248.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260424171031_gen-ag04241710-bdb248.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "manual failures 11/13/14/26 from assistant-stage1-9liEOh-7JP", - "architecture_phase": "Post-F Semantic Integrity Hardening", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_post_f_manual_failures_20260424.json", - "scenario_id": "address_truth_harness_post_f_manual_failures_20260424", - "semantic_tags": [ - "counterparty_grounding", - "counterparty_retarget", - "inventory_context", - "item_flow_failure_26", - "manual_9liEOh", - "materialization_gap", - "organization_scope", - "purchase_date_context", - "revenue_ranking_failure_14", - "selected_object_purchase", - "stale_inventory_scope", - "stale_scope_guard", - "vat_failure_11", - "vat_failure_13" - ], - "latest_acceptance": null - } - }, { "generation_id": "gen-ag04241610-84c8bb", "created_at": "2026-04-24T16:10:22+00:00", @@ -1798,99 +874,6 @@ "latest_acceptance": null } }, - { - "generation_id": "gen-ag04241406-abe4d8", - "created_at": "2026-04-24T14:06:30+00:00", - "mode": "saved_user_sessions", - "title": "AGENT | Post-F cross-stage semantic integrity canary", - "count": 24, - "domain": "address_post_f_cross_stage_canary_agent", - "questions": [ - "Мне нужно понять, где в 1С по НДС вообще лежат данные. Какие объекты стоит смотреть по НДС?", - "Хорошо, тогда покажи движения по ООО Альтернатива Плюс.", - "За 2020 год.", - "А теперь по документам?", - "А теперь за 2021 год?", - "А теперь за все время?", - "С НДС закончили. Новая тема: покажи документы по Жуковке 51.", - "Хорошо, а теперь платежи по нему тоже покажи.", - "А по нему договоры?", - "А по нему документы?", - "А за 2021?", - "С Жуковкой закончили. Теперь другая задача: быстрый денежный срез по одной организации. Если для ответа нужна организация, просто уточни ее. Сколько вообще входящих денег было за 2020 год?", - "По ООО Альтернатива Плюс.", - "Понял, тогда за все время.", - "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?", - "И кто больше всего принес денег этой организации в 2020 году?", - "А в 2021 году?", - "Теперь отдельная тема по конкретному контрагенту. Найди в 1С Группу СВК.", - "Сколько получили по нему за 2020 год?", - "А теперь сколько заплатили?", - "А какое нетто?", - "А по документам?", - "А по движениям?", - "А теперь тот же смысл за 2021 год." - ], - "generated_by": "codex_agent", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260424140630_gen-ag04241406-abe4d8.json", - "context": { - "llm_provider": null, - "model": null, - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": null, - "saved_session_file": "assistant_saved_session_20260424140630_gen-ag04241406-abe4d8.json", - "saved_case_set_kind": "agent_semantic_scenario", - "agent_run": true, - "agent_focus": "cross-stage canary: VAT metadata, numeric counterparty suffix, open organization value-flow, SVK grounded reset", - "architecture_phase": "Post-F Semantic Integrity Hardening", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_post_f_cross_stage_canary_agent_20260424.json", - "scenario_id": "address_truth_harness_post_f_cross_stage_canary_agent_20260424", - "semantic_tags": [ - "account_injection_guard", - "all_time_followup", - "bidirectional_value_flow", - "clarification_resume", - "contracts_followup", - "counterparty_pronoun_resolution", - "cross_stage_canary", - "document_lane_continuity", - "document_pivot_after_movement", - "documents_followup", - "documents_pivot", - "grounded_counterparty", - "incoming_value_flow", - "legacy_phase39", - "legacy_phase64", - "legacy_phase67", - "metadata_surface", - "movement_execution", - "movement_lane_after_metadata", - "movements_pivot", - "net_value_flow", - "numeric_counterparty_suffix", - "open_scope_total", - "organization_clarification", - "organization_scope", - "payments_followup", - "payout_value_flow", - "period_clarification_resume", - "post_f", - "repeated_pivot", - "scope_reuse", - "topic_reset", - "value_flow_ranking", - "vat_orientation", - "year_switch", - "year_switch_after_document_pivot", - "year_switch_after_repeated_pivot" - ], - "latest_acceptance": null - } - }, { "generation_id": "gen-mo6rqcw8-kuswg6b", "created_at": "2026-04-20T05:42:42.633Z", @@ -1937,50 +920,6 @@ "latest_acceptance": null } }, - { - "generation_id": "gen-mo2kcds2-tlqmvng", - "created_at": "2026-04-17T07:04:48.581Z", - "mode": "saved_user_sessions", - "title": "Ручная сессия 17.04.2026, 10:04:19 ТЕМП", - "count": 13, - "domain": null, - "questions": [ - "покажи все документы по чепурнову", - "что нам отгружал чепурнов, какой товар или услугу?", - "какие остатки на складе на сегодня?", - "хвосты по счету 60 на август 2022", - "какие остатки на складе на март 2021", - "По выбранному объекту \"Столешница 600*3050*26 альмандин\": кто нам это поставил?", - "По выбранному объекту \"Столешница 600*3050*26 альмандин\": покажи документы по этой позиции", - "покажи еще раз остатки на эту же дату", - "какие остатки на складе на март 2016", - "на июль 2019", - "на сентябрь", - "а на март", - "это по общей базе" - ], - "generated_by": "manual_reviewer", - "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260417070448_gen-mo2kcds2-tlqmvng.json", - "context": { - "llm_provider": "local", - "model": "unsloth/qwen3-30b-a3b-instruct-2507", - "assistant_prompt_version": "address_query_runtime_v1", - "decomposition_prompt_version": "normalizer_v2_0_2", - "prompt_fingerprint": "Ты semantic-normalizer для бухгалтерского ассистента NDC.\nТвоя роль: только нормализация запроса пользователя в строгий JSON-контракт.\n\nЖесткие правила:\n1) Не давай бухгалтерский ответ по сути вопроса.\n2) Возвращай только JSON без markdown и пояснений.\n3) JSON обязан соответствовать переданной schema normalized_query_v1.\n4) Если период не указан, не выдумывай его; отмечай ambiguity.\n5) Для цепочек документов/проводок/оплат поднимай causal и cross-entity признаки.\n6) Для точечного object trace (номер/строка/ref) поднимай needs_exact_object_trace=true.\n7) Используй терминологию NDC.||You are semantic-normalizer for accounting assistant NDC.\nReturn strict JSON only, no markdown, no comments.\n\nTarget schema: normalized_query_v2_0_2.\n\nCore behavior (v2.0.2):\n1. Decompose message into semantic fragments.\n2. Classify fragment domain relevance and business scope.\n3. Fill route-critical flags and candidate labels.\n4. For each fragment set execution state fields:\n - execution_readiness\n - clarification_reason\n - soft_assumption_used\n - route_status\n - no_route_reason\n5. Clarification must be rare and justified.\n\nExecution-state policy:\n- Every in-scope fragment must produce a consistent execution state.\n- If a fragment is routable, mark it as executable or executable_with_soft_assumptions.\n- Do not leave routable fragments in unresolved state.\n- If a fragment cannot be routed, set route_status=no_route and provide explicit no_route_reason.\n\nReadiness values:\n- executable\n- executable_with_soft_assumptions\n- needs_clarification\n- no_route\n\nRoute status values:\n- routed\n- no_route\n\nNo-route reason values:\n- out_of_scope\n- insufficient_specificity\n- missing_mapping\n- unsupported_fragment_type\n\nDo not over-require formality:\n- Do not require document IDs, exact periods, or exact object references for scan/review/anomaly/rule-check requests.\n- Colloquial accounting phrases like \"что висит\", \"что подозрительно\", \"что не сходится\", \"что криво\", \"что аукнется\" are executable if accounting area is understandable.\n\nFragment required fields:\n- fragment_id\n- raw_fragment_text\n- normalized_fragment_text\n- domain_relevance\n- business_scope\n- entity_hints\n- account_hints\n- document_hints\n- register_hints\n- time_scope\n- flags\n- candidate_labels\n- confidence\n- execution_readiness\n- clarification_reason\n- soft_assumption_used\n- route_status\n- no_route_reason\n\nSoft assumptions (`soft_assumption_used`) allowed values:\n- period_from_session_context\n- company_scope_defaulted\n- problem_scan_mode_enabled\n\nGlobal notes:\n- global_notes.needs_clarification should be true only when execution is truly blocked for all in-scope fragments.\n- global_notes.clarification_reason must explain the blocker.\n\nSchema version must be:\n- \"schema_version\": \"normalized_query_v2_0_2\"||Контекст домена: бухгалтерия 1С/NDC.\n\nКлючевые счета:\n- 01, 02, 10, 41, 51, 60, 62, 68.02, 90, 97.\n\nТиповые сущности:\n- контрагент, договор, документ реализации, документ поступления, оплата, проводка, регистр, закрывающий документ.\n\nЛексика causal и сверки (сильные сигналы для cross_entity):\n- \"не бьется\", \"не сходится\", \"не видно\", \"не собралось\", \"повисло\", \"хвост\";\n- \"разложи по документам/оплатам/закрывающим\";\n- \"чем подтверждается\", \"где ошибка в цепочке\", \"что пошло криво\".\n\nЛексика точечного drilldown:\n- \"документ №...\", \"ref\", \"строка проводки\", \"покажи конкретную операцию\", \"точный source-of-record\".\n\nЛексика rule-based контроля:\n- \"проверь настройки\", \"ошибка срока/даты\", \"контроль 97/10/ОС\", \"нарушение правила учета\".\n\nЛексика обзорной аналитики:\n- \"рейтинг\", \"топ рисков\", \"в целом по компании\", \"перед закрытием периода\", \"приоритизация проверок\".\n\nВажное правило:\nЕсли в одном вопросе есть и риск-лексика, и цепочка document/payment/posting, не понижать задачу до чистого `store_feature_risk`.\nПриоритет у causal cross-entity семантики.||v2.0.2: execution-state hardening + explicit route_status/no_route_reason. Схема normalized_query_v2_0_2.||Q: По каким поставщикам висят хвосты по 60, что подозрительно по цепочке оплат?\nA: in_scope fragment, execution_readiness=executable_with_soft_assumptions, route_status=routed, no_route_reason=null.\n\nQ: Покажи записи по 97, которые повисли и могут аукнуться.\nA: in_scope fragment, execution_readiness=executable_with_soft_assumptions, route_status=routed, no_route_reason=null.\n\nQ: Чекни, что у нас не так.\nA: unclear/in_scope fragment, execution_readiness=needs_clarification, route_status=no_route, no_route_reason=insufficient_specificity.\n\nQ: Как вообще по ФСБУ правильно?\nA: out_of_scope fragment, execution_readiness=no_route, route_status=no_route, no_route_reason=out_of_scope.", - "autogen_personality_id": null, - "autogen_personality_prompt": null, - "source_session_id": "asst-kBU5iS0mEt", - "saved_session_file": "assistant_saved_session_20260417070448_gen-mo2kcds2-tlqmvng.json", - "saved_case_set_kind": "assistant_session_scenario", - "agent_run": null, - "agent_focus": null, - "architecture_phase": null, - "source_spec_file": null, - "scenario_id": null, - "semantic_tags": null, - "latest_acceptance": null - } - }, { "generation_id": "gen-mo1t93wq-jy0453e", "created_at": "2026-04-16T18:26:26.191Z", @@ -2560,4 +1499,4 @@ "latest_acceptance": null } } -] +] \ No newline at end of file diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260417070448_gen-mo2kcds2-tlqmvng.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260417070448_gen-mo2kcds2-tlqmvng.json deleted file mode 100644 index 9f35ce0..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260417070448_gen-mo2kcds2-tlqmvng.json +++ /dev/null @@ -1,9242 +0,0 @@ -{ - "saved_at": "2026-04-17T07:04:48.578Z", - "generation_id": "gen-mo2kcds2-tlqmvng", - "mode": "saved_user_sessions", - "title": "Ручная сессия 17.04.2026, 10:04:19 ТЕМП", - "source_session_id": "asst-kBU5iS0mEt", - "questions": [ - "покажи все документы по чепурнову", - "что нам отгружал чепурнов, какой товар или услугу?", - "какие остатки на складе на сегодня?", - "хвосты по счету 60 на август 2022", - "какие остатки на складе на март 2021", - "По выбранному объекту \"Столешница 600*3050*26 альмандин\": кто нам это поставил?", - "По выбранному объекту \"Столешница 600*3050*26 альмандин\": покажи документы по этой позиции", - "покажи еще раз остатки на эту же дату", - "какие остатки на складе на март 2016", - "на июль 2019", - "на сентябрь", - "а на март", - "это по общей базе" - ], - "session": { - "session_id": "asst-kBU5iS0mEt", - "updated_at": "2026-04-17T07:04:19.453Z", - "items": [ - { - "message_id": "msg-SK5XOEQmHz", - "session_id": "asst-kBU5iS0mEt", - "role": "user", - "text": "покажи все документы по чепурнову", - "reply_type": null, - "created_at": "2026-04-17T06:59:00.190Z", - "trace_id": null, - "debug": null - }, - { - "message_id": "msg-FbPrdbojCb", - "session_id": "asst-kBU5iS0mEt", - "role": "assistant", - "text": "Контрагент: Чепурнов П.Д. Найдено документов: 1.\nКонтрагент: Чепурнов П.Д.\n1. 2022-01-20T12:00:03Z | Поступление на расчетный счет 00000000001 от 20.01.2022 12:00:03 | 0 / 0 | 890660 | аналитика: Чепурнов П.Д.; Договор № 11/1 от 25.11.2020 г.", - "reply_type": "factual", - "created_at": "2026-04-17T06:59:13.677Z", - "trace_id": "address-FB16cxDHD5", - "debug": { - "trace_id": "address-FB16cxDHD5", - "prompt_version": "address_query_runtime_v1", - "schema_version": "address_query_runtime_v1", - "fallback_type": "none", - "route_summary": null, - "fragments": [], - "requirements_extracted": [], - "coverage_report": { - "requirements_total": 0, - "requirements_covered": 0, - "requirements_uncovered": [], - "requirements_partially_covered": [], - "clarification_needed_for": [], - "out_of_scope_requirements": [] - }, - "routes": [], - "retrieval_status": [], - "retrieval_results": [], - "answer_grounding_check": { - "status": "grounded", - "route_subject_match": true, - "missing_requirements": [], - "reasons": [ - "docs_or_bank_signal_detected", - "anchor_like_token_detected", - "document_list_signal_detected", - "documents_by_counterparty_signal_detected" - ], - "why_included_summary": [], - "selection_reason_summary": [] - }, - "dropped_intent_segments": [], - "detected_mode": "address_query", - "detected_mode_confidence": "medium", - "query_shape": "DOCUMENT_LIST", - "query_shape_confidence": "medium", - "detected_intent": "list_documents_by_counterparty", - "detected_intent_confidence": "medium", - "extracted_filters": { - "sort": "period_desc", - "limit": 20, - "counterparty": "Чепурнов П.Д." - }, - "missing_required_filters": [], - "selected_recipe": "address_documents_by_counterparty_v1", - "mcp_call_status_legacy": "matched_non_empty", - "account_scope_mode": "preferred", - "account_scope_fallback_applied": false, - "anchor_type": "counterparty", - "anchor_value_raw": "чепурнов", - "anchor_value_resolved": "Чепурнов П.Д.", - "resolver_confidence": "medium", - "ambiguity_count": 0, - "match_failure_stage": "none", - "match_failure_reason": null, - "mcp_call_status": "matched_non_empty", - "rows_fetched": 1000, - "raw_rows_received": 1000, - "rows_after_account_scope": 124, - "rows_after_recipe_filter": 1, - "rows_materialized": 124, - "rows_matched": 1, - "raw_row_keys_sample": [ - "Период", - "Регистратор", - "СчетДт", - "СчетКт", - "Сумма", - "Контрагент", - "Договор", - "Period", - "Registrator", - "Amount" - ], - "materialization_drop_reason": "none", - "account_token_raw": null, - "account_token_normalized": null, - "account_scope_fields_checked": [ - "account_dt", - "account_kt", - "registrator", - "analytics" - ], - "account_scope_match_strategy": "account_code_regex_plus_alias_map_v1", - "account_scope_drop_reason": "not_applicable", - "runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS", - "limited_reason_category": null, - "response_type": "FACTUAL_LIST", - "capability_id": "documents_drilldown", - "capability_layer": "navigation", - "capability_route_mode": "exact", - "capability_route_enabled": true, - "capability_route_reason": "drilldown_route_enabled", - "shadow_route_status": "skipped", - "route_expectation_status": "matched", - "route_expectation_reason": "route_expectation_matched", - "route_expectation_expected_selected_recipes": [ - "address_documents_by_counterparty_v1" - ], - "route_expectation_expected_requested_result_modes": [], - "route_expectation_expected_result_modes": [ - "heuristic_candidates", - "confirmed_balance" - ], - "execution_lane": "address_query", - "llm_decomposition_applied": true, - "llm_decomposition_attempted": true, - "llm_provider_used": "local", - "llm_decomposition_trace_id": "-Avqj4zSSt7qV3", - "llm_decomposition_effective_message": "документы по контрагенту чепурнову", - "llm_decomposition_reason": "fallback_rule_preferred_over_llm_candidate_anchor_quality", - "llm_canonical_candidate_detected": true, - "llm_predecompose_contract": { - "schema_version": "address_llm_predecompose_contract_v1", - "source_message": "покажи все документы по чепурнову", - "canonical_message": "документы по контрагенту чепурнову", - "mode": "address_query", - "mode_confidence": "medium", - "query_shape": "DOCUMENT_LIST", - "query_shape_confidence": "medium", - "intent": "list_documents_by_counterparty", - "intent_confidence": "medium", - "entities": { - "account": null, - "counterparty": "чепурнов", - "contract": null, - "document_type": null, - "document_ref": null, - "organization": null - }, - "period": { - "scope": "unspecified", - "period_from": null, - "period_to": null, - "as_of_date": null, - "has_explicit_period": false - }, - "semantics": { - "scope_kind": "explicit_anchor", - "anchor_kind": "counterparty", - "anchor_value": "чепурнов", - "date_scope_kind": "implicit_current", - "date_basis_hint": "implicit_current_snapshot", - "self_scope_detected": false, - "selected_object_scope_detected": false - }, - "aggregation_profile": "list_lookup" - }, - "fallback_rule_hit": "documents_counterparty_rewrite", - "sanitized_user_message": "покажи все документы по чепурнову", - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "orchestration_contract_v1": { - "schema_version": "assistant_orchestration_contract_v1", - "hard_meta_mode": null, - "address_mode": "address_query", - "address_mode_confidence": "medium", - "address_intent": "list_documents_by_counterparty", - "address_intent_confidence": "medium", - "strong_data_signal_detected": true, - "data_retrieval_signal_detected": true, - "semantic_contract_valid": true, - "semantic_apply_canonical_recommended": true, - "semantic_reason_codes": [], - "semantic_route_arbitration": { - "supported_address_intent_detected": true, - "strict_deep_investigation_bypass_allowed": false, - "semantic_deep_investigation_hint_detected": false, - "semantic_aggregate_shape_detected": false, - "followup_semantic_override_to_deep_allowed": false - }, - "followup_context_detected": false, - "unsupported_address_intent_fallback_to_deep": false, - "deep_analysis_signal_fallback_to_deep": false, - "aggregate_analytics_signal_fallback_to_deep": false, - "deep_session_continuation_fallback_to_deep": false, - "final_decision": { - "run_address_lane": true, - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "living_mode": "address_data", - "living_reason": "address_lane_triggered" - } - }, - "dialog_continuation_contract_v2": { - "schema_version": "address_dialog_continuation_contract_v2", - "source_message": "покажи все документы по чепурнову", - "effective_message": "документы по контрагенту чепурнову", - "decision": "new_topic", - "decision_reasons": [ - "effective_message_rewritten_by_predecompose", - "llm_contract_intent_available" - ], - "followup_context_applied": false, - "previous_intent": null, - "target_intent": "list_documents_by_counterparty", - "intent_selection_mode": null, - "anchor_type": null, - "anchor_value": null, - "implicit_continuation_signal": false - }, - "address_retry_audit": { - "attempted": false, - "reason": null, - "initial_limited_category": null, - "retry_message": null, - "retry_used_followup_context": false, - "retry_result_category": null - }, - "answer_structure_v11": null, - "investigation_state_snapshot": null, - "normalized": null, - "normalizer_output": { - "trace_id": "-Avqj4zSSt7qV3", - "prompt_version": "normalizer_v2_0_2", - "applied": true, - "effective_message": "документы по контрагенту чепурнову" - }, - "address_followup_offer": { - "enabled": true, - "source_intent": "list_documents_by_counterparty", - "anchor_type": "counterparty", - "anchor_value": "Чепурнов П.Д.", - "suggested_intents": [ - "bank_operations_by_counterparty", - "list_contracts_by_counterparty" - ] - }, - "assistant_runtime_contract_v1": { - "schema_version": "assistant_runtime_contracts_v1", - "transition_contract_id": null, - "transition_contract_title": null, - "transition_contract_reason": [ - "transition_contract_not_resolved" - ], - "capability_contract_id": null, - "capability_contract_reason": [ - "debug_capability_id_has_no_contract" - ], - "truth_gate_contract_status": "full_confirmed", - "carryover_eligibility": "none" - }, - "transition_contract_id": null, - "capability_contract_id": null, - "truth_gate_contract_status": "full_confirmed", - "assistant_truth_answer_policy_v1": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "truth_gate": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "none", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "route_expectation_matched", - "docs_or_bank_signal_detected", - "anchor_like_token_detected", - "document_list_signal_detected", - "documents_by_counterparty_signal_detected" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": null, - "transition_contract_id": null, - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": false, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - } - }, - "coverage_gate_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "none", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "route_expectation_matched", - "docs_or_bank_signal_detected", - "anchor_like_token_detected", - "document_list_signal_detected", - "documents_by_counterparty_signal_detected" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": null, - "transition_contract_id": null, - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": false, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - }, - "truth_mode": "confirmed", - "carryover_eligibility": "none", - "answer_shape": "confirmed_factual", - "assistant_state_transition_v1": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": null, - "transition_title": null, - "application_status": "unresolved", - "declared_carryover_depth": null, - "truth_gate_carryover_depth": "none", - "effective_carryover_depth": "none", - "required_prior_state": [], - "expected_answer_mode": null, - "state_mutations": [], - "forbidden_carryover": [ - "implicit_followup_reuse" - ], - "state_actions": { - "living_mode_state": "none", - "root_frame_state": "none", - "selected_object_frame_state": "none", - "meta_frame_state": "none", - "clarification_state": "none", - "coverage_gate_state": "none", - "answer_context_state": "none" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "none", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "route_expectation_matched", - "docs_or_bank_signal_detected", - "anchor_like_token_detected", - "document_list_signal_detected", - "documents_by_counterparty_signal_detected" - ] - }, - "reason_codes": [ - "transition_status_unresolved", - "transition_unresolved", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "docs_or_bank_signal_detected", - "anchor_like_token_detected", - "document_list_signal_detected", - "documents_by_counterparty_signal_detected" - ] - }, - "state_transition_contract": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": null, - "transition_title": null, - "application_status": "unresolved", - "declared_carryover_depth": null, - "truth_gate_carryover_depth": "none", - "effective_carryover_depth": "none", - "required_prior_state": [], - "expected_answer_mode": null, - "state_mutations": [], - "forbidden_carryover": [ - "implicit_followup_reuse" - ], - "state_actions": { - "living_mode_state": "none", - "root_frame_state": "none", - "selected_object_frame_state": "none", - "meta_frame_state": "none", - "clarification_state": "none", - "coverage_gate_state": "none", - "answer_context_state": "none" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "none", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "route_expectation_matched", - "docs_or_bank_signal_detected", - "anchor_like_token_detected", - "document_list_signal_detected", - "documents_by_counterparty_signal_detected" - ] - }, - "reason_codes": [ - "transition_status_unresolved", - "transition_unresolved", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "docs_or_bank_signal_detected", - "anchor_like_token_detected", - "document_list_signal_detected", - "documents_by_counterparty_signal_detected" - ] - }, - "state_transition_id": null, - "state_transition_status": "unresolved", - "effective_carryover_depth": "none", - "assistant_capability_binding_v1": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "documents_drilldown", - "capability_contract_id": null, - "binding_status": "contract_missing", - "binding_action": "observe_only", - "runtime_lane_expected": null, - "runtime_lane_observed": "address_exact", - "execution_adapter": null, - "transition_id": null, - "transition_allowed": false, - "required_anchors": [], - "provided_anchors": [ - "sort", - "limit", - "counterparty" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": null, - "answer_object_shape": null, - "truth_gate_behavior": null, - "truth_fallback_allowed": null, - "answer_shape_compatible": false, - "violations": [ - "capability_contract_missing" - ], - "reason_codes": [ - "binding_status_contract_missing", - "binding_action_observe_only", - "capability_contract_missing", - "transition_status_unresolved", - "transition_unresolved", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "docs_or_bank_signal_detected", - "anchor_like_token_detected", - "document_list_signal_detected", - "documents_by_counterparty_signal_detected" - ] - }, - "capability_binding_contract": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "documents_drilldown", - "capability_contract_id": null, - "binding_status": "contract_missing", - "binding_action": "observe_only", - "runtime_lane_expected": null, - "runtime_lane_observed": "address_exact", - "execution_adapter": null, - "transition_id": null, - "transition_allowed": false, - "required_anchors": [], - "provided_anchors": [ - "sort", - "limit", - "counterparty" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": null, - "answer_object_shape": null, - "truth_gate_behavior": null, - "truth_fallback_allowed": null, - "answer_shape_compatible": false, - "violations": [ - "capability_contract_missing" - ], - "reason_codes": [ - "binding_status_contract_missing", - "binding_action_observe_only", - "capability_contract_missing", - "transition_status_unresolved", - "transition_unresolved", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "docs_or_bank_signal_detected", - "anchor_like_token_detected", - "document_list_signal_detected", - "documents_by_counterparty_signal_detected" - ] - }, - "capability_binding_status": "contract_missing", - "capability_binding_action": "observe_only", - "capability_binding_violations": [ - "capability_contract_missing" - ], - "capability_binding_response_guard": { - "schema_version": "assistant_capability_binding_response_guard_v1", - "guard_owner": "assistantCapabilityBindingResponseGuard", - "applied": false, - "action": "observe_only", - "original_reply_type": "factual", - "guarded_reply_type": "factual", - "reason_codes": [ - "binding_status_contract_missing", - "binding_action_observe_only", - "capability_contract_missing", - "transition_status_unresolved", - "transition_unresolved", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "docs_or_bank_signal_detected", - "anchor_like_token_detected", - "document_list_signal_detected", - "documents_by_counterparty_signal_detected" - ] - } - } - }, - { - "message_id": "msg-31gb2_Ca-t", - "session_id": "asst-kBU5iS0mEt", - "role": "user", - "text": "что нам отгружал чепурнов, какой товар или услугу?", - "reply_type": null, - "created_at": "2026-04-17T06:59:14.857Z", - "trace_id": null, - "debug": null - }, - { - "message_id": "msg-F31DDcZwOL", - "session_id": "asst-kBU5iS0mEt", - "role": "assistant", - "text": "Контрагент: Чепурнов П.Д. Подтвержденных поставок товаров или услуг не найдено.\nПозиции: подтвержденных поставок товаров или услуг не найдено.\nПо связанным расчетам с контрагентом найдено возвратов от поставщика: 1 на 890 660,00 ₽.\nДоговор: Договор № 11/1 от 25.11.2020 г..\nВозвраты от поставщика:\n1. Поступление на расчетный счет 00000000001 от 20.01.2022 12:00:03 | дата: 2022-01-20T12:00:03Z | сумма: 890 660,00 ₽ | договор: Договор № 11/1 от 25.11.2020 г.", - "reply_type": "factual", - "created_at": "2026-04-17T06:59:28.924Z", - "trace_id": "address-_x0DkTrgTY", - "debug": { - "trace_id": "address-_x0DkTrgTY", - "prompt_version": "address_query_runtime_v1", - "schema_version": "address_query_runtime_v1", - "fallback_type": "none", - "route_summary": null, - "fragments": [], - "requirements_extracted": [], - "coverage_report": { - "requirements_total": 0, - "requirements_covered": 0, - "requirements_uncovered": [], - "requirements_partially_covered": [], - "clarification_needed_for": [], - "out_of_scope_requirements": [] - }, - "routes": [], - "retrieval_status": [], - "retrieval_results": [], - "answer_grounding_check": { - "status": "grounded", - "route_subject_match": true, - "missing_requirements": [], - "reasons": [ - "address_action_detected", - "address_entity_detected", - "object_signal_detected", - "counterparty_item_flow_signal_detected", - "counterparty_item_flow_query_override_to_purchase_documents", - "counterparty_item_flow_no_supply_but_bank_activity_explained" - ], - "why_included_summary": [], - "selection_reason_summary": [] - }, - "dropped_intent_segments": [], - "detected_mode": "address_query", - "detected_mode_confidence": "high", - "query_shape": "OBJECT_LOOKUP", - "query_shape_confidence": "medium", - "detected_intent": "list_documents_by_counterparty", - "detected_intent_confidence": "medium", - "extracted_filters": { - "sort": "period_desc", - "limit": 20, - "counterparty": "Чепурнов П.Д." - }, - "missing_required_filters": [], - "selected_recipe": "address_documents_by_counterparty_v1", - "mcp_call_status_legacy": "no_raw_rows", - "account_scope_mode": "preferred", - "account_scope_fallback_applied": false, - "anchor_type": "counterparty", - "anchor_value_raw": "Чепурновым", - "anchor_value_resolved": "Чепурнов П.Д.", - "resolver_confidence": "medium", - "ambiguity_count": 0, - "match_failure_stage": "none", - "match_failure_reason": null, - "mcp_call_status": "no_raw_rows", - "rows_fetched": 0, - "raw_rows_received": 0, - "rows_after_account_scope": 0, - "rows_after_recipe_filter": 0, - "rows_materialized": 0, - "rows_matched": 0, - "raw_row_keys_sample": [], - "materialization_drop_reason": "none", - "account_token_raw": null, - "account_token_normalized": null, - "account_scope_fields_checked": [ - "account_dt", - "account_kt", - "registrator", - "analytics" - ], - "account_scope_match_strategy": "account_code_regex_plus_alias_map_v1", - "account_scope_drop_reason": "not_applicable", - "runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS", - "limited_reason_category": null, - "response_type": "FACTUAL_SUMMARY", - "capability_id": "documents_drilldown", - "capability_layer": "navigation", - "capability_route_mode": "exact", - "capability_route_enabled": true, - "capability_route_reason": "drilldown_route_enabled", - "shadow_route_status": "skipped", - "route_expectation_status": "matched", - "route_expectation_reason": "route_expectation_matched", - "route_expectation_expected_selected_recipes": [ - "address_documents_by_counterparty_v1" - ], - "route_expectation_expected_requested_result_modes": [], - "route_expectation_expected_result_modes": [ - "heuristic_candidates", - "confirmed_balance" - ], - "execution_lane": "address_query", - "llm_decomposition_applied": true, - "llm_decomposition_attempted": true, - "llm_provider_used": "local", - "llm_decomposition_trace_id": "YmU_wxWYUMaSm6", - "llm_decomposition_effective_message": "Узнать, какие товары или услуги были отгружены нашей компании контрагентом Чепурновым", - "llm_decomposition_reason": "normalized_fragment_applied", - "llm_canonical_candidate_detected": true, - "llm_predecompose_contract": { - "schema_version": "address_llm_predecompose_contract_v1", - "source_message": "что нам отгружал чепурнов, какой товар или услугу?", - "canonical_message": "Узнать, какие товары или услуги были отгружены нашей компании контрагентом Чепурновым", - "mode": "address_query", - "mode_confidence": "high", - "query_shape": "OBJECT_LOOKUP", - "query_shape_confidence": "medium", - "intent": "list_documents_by_counterparty", - "intent_confidence": "medium", - "entities": { - "account": null, - "counterparty": "Чепурновым", - "contract": null, - "document_type": null, - "document_ref": null, - "organization": null - }, - "period": { - "scope": "unspecified", - "period_from": null, - "period_to": null, - "as_of_date": null, - "has_explicit_period": false - }, - "semantics": { - "scope_kind": "implicit_self_scope", - "anchor_kind": "self_scope", - "anchor_value": null, - "date_scope_kind": "implicit_current", - "date_basis_hint": "implicit_current_snapshot", - "self_scope_detected": true, - "selected_object_scope_detected": false - }, - "aggregation_profile": "list_lookup" - }, - "fallback_rule_hit": null, - "sanitized_user_message": "что нам отгружал чепурнов, какой товар или услугу?", - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "orchestration_contract_v1": { - "schema_version": "assistant_orchestration_contract_v1", - "hard_meta_mode": null, - "address_mode": "address_query", - "address_mode_confidence": "high", - "address_intent": "list_documents_by_counterparty", - "address_intent_confidence": "medium", - "strong_data_signal_detected": true, - "data_retrieval_signal_detected": true, - "semantic_contract_valid": true, - "semantic_apply_canonical_recommended": true, - "semantic_reason_codes": [], - "semantic_route_arbitration": { - "supported_address_intent_detected": true, - "strict_deep_investigation_bypass_allowed": false, - "semantic_deep_investigation_hint_detected": false, - "semantic_aggregate_shape_detected": false, - "followup_semantic_override_to_deep_allowed": false - }, - "followup_context_detected": false, - "unsupported_address_intent_fallback_to_deep": false, - "deep_analysis_signal_fallback_to_deep": false, - "aggregate_analytics_signal_fallback_to_deep": false, - "deep_session_continuation_fallback_to_deep": false, - "final_decision": { - "run_address_lane": true, - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "living_mode": "address_data", - "living_reason": "address_lane_triggered" - } - }, - "dialog_continuation_contract_v2": { - "schema_version": "address_dialog_continuation_contract_v2", - "source_message": "что нам отгружал чепурнов, какой товар или услугу?", - "effective_message": "Узнать, какие товары или услуги были отгружены нашей компании контрагентом Чепурновым", - "decision": "new_topic", - "decision_reasons": [ - "effective_message_rewritten_by_predecompose", - "llm_contract_intent_available" - ], - "followup_context_applied": false, - "previous_intent": null, - "target_intent": "list_documents_by_counterparty", - "intent_selection_mode": null, - "anchor_type": null, - "anchor_value": null, - "implicit_continuation_signal": false - }, - "address_retry_audit": { - "attempted": false, - "reason": null, - "initial_limited_category": null, - "retry_message": null, - "retry_used_followup_context": false, - "retry_result_category": null - }, - "answer_structure_v11": null, - "investigation_state_snapshot": null, - "normalized": null, - "normalizer_output": { - "trace_id": "YmU_wxWYUMaSm6", - "prompt_version": "normalizer_v2_0_2", - "applied": true, - "effective_message": "Узнать, какие товары или услуги были отгружены нашей компании контрагентом Чепурновым" - }, - "address_followup_offer": { - "enabled": true, - "source_intent": "list_documents_by_counterparty", - "anchor_type": "counterparty", - "anchor_value": "Чепурнов П.Д.", - "suggested_intents": [ - "bank_operations_by_counterparty", - "list_contracts_by_counterparty" - ] - }, - "assistant_runtime_contract_v1": { - "schema_version": "assistant_runtime_contracts_v1", - "transition_contract_id": null, - "transition_contract_title": null, - "transition_contract_reason": [ - "transition_contract_not_resolved" - ], - "capability_contract_id": null, - "capability_contract_reason": [ - "debug_capability_id_has_no_contract" - ], - "truth_gate_contract_status": "full_confirmed", - "carryover_eligibility": "none" - }, - "transition_contract_id": null, - "capability_contract_id": null, - "truth_gate_contract_status": "full_confirmed", - "assistant_truth_answer_policy_v1": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "truth_gate": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "none", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "object_signal_detected", - "counterparty_item_flow_signal_detected", - "counterparty_item_flow_query_override_to_purchase_documents", - "counterparty_item_flow_no_supply_but_bank_activity_explained" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": null, - "transition_contract_id": null, - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": false, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - } - }, - "coverage_gate_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "none", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "object_signal_detected", - "counterparty_item_flow_signal_detected", - "counterparty_item_flow_query_override_to_purchase_documents", - "counterparty_item_flow_no_supply_but_bank_activity_explained" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": null, - "transition_contract_id": null, - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": false, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - }, - "truth_mode": "confirmed", - "carryover_eligibility": "none", - "answer_shape": "confirmed_factual", - "assistant_state_transition_v1": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": null, - "transition_title": null, - "application_status": "unresolved", - "declared_carryover_depth": null, - "truth_gate_carryover_depth": "none", - "effective_carryover_depth": "none", - "required_prior_state": [], - "expected_answer_mode": null, - "state_mutations": [], - "forbidden_carryover": [ - "implicit_followup_reuse" - ], - "state_actions": { - "living_mode_state": "none", - "root_frame_state": "none", - "selected_object_frame_state": "none", - "meta_frame_state": "none", - "clarification_state": "none", - "coverage_gate_state": "none", - "answer_context_state": "none" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "none", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "object_signal_detected", - "counterparty_item_flow_signal_detected", - "counterparty_item_flow_query_override_to_purchase_documents", - "counterparty_item_flow_no_supply_but_bank_activity_explained" - ] - }, - "reason_codes": [ - "transition_status_unresolved", - "transition_unresolved", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "object_signal_detected", - "counterparty_item_flow_signal_detected", - "counterparty_item_flow_query_override_to_purchase_documents", - "counterparty_item_flow_no_supply_but_bank_activity_explained" - ] - }, - "state_transition_contract": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": null, - "transition_title": null, - "application_status": "unresolved", - "declared_carryover_depth": null, - "truth_gate_carryover_depth": "none", - "effective_carryover_depth": "none", - "required_prior_state": [], - "expected_answer_mode": null, - "state_mutations": [], - "forbidden_carryover": [ - "implicit_followup_reuse" - ], - "state_actions": { - "living_mode_state": "none", - "root_frame_state": "none", - "selected_object_frame_state": "none", - "meta_frame_state": "none", - "clarification_state": "none", - "coverage_gate_state": "none", - "answer_context_state": "none" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "none", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "object_signal_detected", - "counterparty_item_flow_signal_detected", - "counterparty_item_flow_query_override_to_purchase_documents", - "counterparty_item_flow_no_supply_but_bank_activity_explained" - ] - }, - "reason_codes": [ - "transition_status_unresolved", - "transition_unresolved", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "object_signal_detected", - "counterparty_item_flow_signal_detected", - "counterparty_item_flow_query_override_to_purchase_documents", - "counterparty_item_flow_no_supply_but_bank_activity_explained" - ] - }, - "state_transition_id": null, - "state_transition_status": "unresolved", - "effective_carryover_depth": "none", - "assistant_capability_binding_v1": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "documents_drilldown", - "capability_contract_id": null, - "binding_status": "contract_missing", - "binding_action": "observe_only", - "runtime_lane_expected": null, - "runtime_lane_observed": "address_exact", - "execution_adapter": null, - "transition_id": null, - "transition_allowed": false, - "required_anchors": [], - "provided_anchors": [ - "sort", - "limit", - "counterparty" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": null, - "answer_object_shape": null, - "truth_gate_behavior": null, - "truth_fallback_allowed": null, - "answer_shape_compatible": false, - "violations": [ - "capability_contract_missing" - ], - "reason_codes": [ - "binding_status_contract_missing", - "binding_action_observe_only", - "capability_contract_missing", - "transition_status_unresolved", - "transition_unresolved", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "object_signal_detected", - "counterparty_item_flow_signal_detected", - "counterparty_item_flow_query_override_to_purchase_documents", - "counterparty_item_flow_no_supply_but_bank_activity_explained" - ] - }, - "capability_binding_contract": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "documents_drilldown", - "capability_contract_id": null, - "binding_status": "contract_missing", - "binding_action": "observe_only", - "runtime_lane_expected": null, - "runtime_lane_observed": "address_exact", - "execution_adapter": null, - "transition_id": null, - "transition_allowed": false, - "required_anchors": [], - "provided_anchors": [ - "sort", - "limit", - "counterparty" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": null, - "answer_object_shape": null, - "truth_gate_behavior": null, - "truth_fallback_allowed": null, - "answer_shape_compatible": false, - "violations": [ - "capability_contract_missing" - ], - "reason_codes": [ - "binding_status_contract_missing", - "binding_action_observe_only", - "capability_contract_missing", - "transition_status_unresolved", - "transition_unresolved", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "object_signal_detected", - "counterparty_item_flow_signal_detected", - "counterparty_item_flow_query_override_to_purchase_documents", - "counterparty_item_flow_no_supply_but_bank_activity_explained" - ] - }, - "capability_binding_status": "contract_missing", - "capability_binding_action": "observe_only", - "capability_binding_violations": [ - "capability_contract_missing" - ], - "capability_binding_response_guard": { - "schema_version": "assistant_capability_binding_response_guard_v1", - "guard_owner": "assistantCapabilityBindingResponseGuard", - "applied": false, - "action": "observe_only", - "original_reply_type": "factual", - "guarded_reply_type": "factual", - "reason_codes": [ - "binding_status_contract_missing", - "binding_action_observe_only", - "capability_contract_missing", - "transition_status_unresolved", - "transition_unresolved", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "object_signal_detected", - "counterparty_item_flow_signal_detected", - "counterparty_item_flow_query_override_to_purchase_documents", - "counterparty_item_flow_no_supply_but_bank_activity_explained" - ] - } - } - }, - { - "message_id": "msg-ob_ucrIz0e", - "session_id": "asst-kBU5iS0mEt", - "role": "user", - "text": "какие остатки на складе на сегодня?", - "reply_type": null, - "created_at": "2026-04-17T06:59:38.991Z", - "trace_id": null, - "debug": null - }, - { - "message_id": "msg-3BxJ--X0gY", - "session_id": "asst-kBU5iS0mEt", - "role": "assistant", - "text": "На 17.04.2026 на складе подтверждено 11 позиций с остатком на 716.418,33 ₽.\n\nПозиции:\n1. Модуль прямоугольый 1400*110*750 | склад: Основной склад | количество: 22,000 | стоимость: 148.261,67 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2026-04-17T23:59:59Z\n2. Конструкция трансформер рабочей станции 1300*900*2000 | склад: Основной склад | количество: 3,000 | стоимость: 498.472,50 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2026-04-17T23:59:59Z\n3. Диван трехместный | склад: Основной склад | количество: 1,000 | стоимость: 34.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2026-04-17T23:59:59Z\n4. Кресло орион | склад: Основной склад | количество: 1,000 | стоимость: 13.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2026-04-17T23:59:59Z\n5. Зеркало для инвалидов поворотное травмобезопасное | склад: Основной склад | количество: 1,000 | стоимость: 7.250,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2026-04-17T23:59:59Z\n6. Пуф арий | склад: Основной склад | количество: 1,000 | стоимость: 6.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2026-04-17T23:59:59Z\n7. Столешница 600*3050*26 дуб ниагара | склад: Основной склад | количество: 1,000 | стоимость: 3.724,17 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2026-04-17T23:59:59Z\n8. Столешница 600*3050*26 альмандин | склад: Основной склад | количество: 1,000 | стоимость: 3.075,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2026-04-17T23:59:59Z\n9. Четки Пост (84*117) | склад: Основной склад | количество: 1,000 | стоимость: 833,33 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2026-04-17T23:59:59Z\n10. Кромка с клеем 33 альмандин 137 м | склад: Основной склад | количество: 1,000 | стоимость: 165,83 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2026-04-17T23:59:59Z\n11. Кромка с клеем 33 дуб ниагара 137 м | склад: Основной склад | количество: 1,000 | стоимость: 165,83 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2026-04-17T23:59:59Z\n\nПодтверждение:\n- Дата среза: 17.04.2026.\n- Контур: остатки по счету 41.01 «Товары на складах».\n- Уникальных товаров: 11.\n- Уникальных складов: 1.\n- Суммарное количество: 34,000.", - "reply_type": "factual", - "created_at": "2026-04-17T06:59:50.036Z", - "trace_id": "address-Ov7Sfq7RCk", - "debug": { - "trace_id": "address-Ov7Sfq7RCk", - "prompt_version": "address_query_runtime_v1", - "schema_version": "address_query_runtime_v1", - "fallback_type": "none", - "route_summary": null, - "fragments": [], - "requirements_extracted": [], - "coverage_report": { - "requirements_total": 0, - "requirements_covered": 0, - "requirements_uncovered": [], - "requirements_partially_covered": [], - "clarification_needed_for": [], - "out_of_scope_requirements": [] - }, - "routes": [], - "retrieval_status": [], - "retrieval_results": [], - "answer_grounding_check": { - "status": "grounded", - "route_subject_match": true, - "missing_requirements": [], - "reasons": [ - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "confirmed_balance_exact_inventory_intent", - "organization_grounded_from_observed_rows" - ], - "why_included_summary": [], - "selection_reason_summary": [] - }, - "dropped_intent_segments": [], - "detected_mode": "address_query", - "detected_mode_confidence": "high", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "detected_intent": "inventory_on_hand_as_of_date", - "detected_intent_confidence": "high", - "extracted_filters": { - "sort": "period_desc", - "as_of_date": "2026-04-17", - "organization": "ООО \\Альтернатива Плюс\\" - }, - "missing_required_filters": [], - "selected_recipe": "address_inventory_on_hand_as_of_date_v1", - "mcp_call_status_legacy": "matched_non_empty", - "account_scope_mode": "strict", - "account_scope_fallback_applied": false, - "anchor_type": "unknown", - "anchor_value_raw": null, - "anchor_value_resolved": null, - "resolver_confidence": "low", - "ambiguity_count": 0, - "match_failure_stage": "none", - "match_failure_reason": null, - "mcp_call_status": "matched_non_empty", - "rows_fetched": 11, - "raw_rows_received": 11, - "rows_after_account_scope": 11, - "rows_after_recipe_filter": 11, - "rows_materialized": 11, - "rows_matched": 11, - "raw_row_keys_sample": [ - "Период", - "Регистратор", - "СчетДт", - "СчетКт", - "Сумма", - "Номенклатура", - "Склад", - "Организация", - "Количество", - "Period", - "Registrator", - "AccountDt", - "Amount" - ], - "materialization_drop_reason": "none", - "account_token_raw": null, - "account_token_normalized": null, - "account_scope_fields_checked": [ - "account_dt", - "account_kt", - "registrator", - "analytics" - ], - "account_scope_match_strategy": "account_code_regex_plus_alias_map_v1", - "account_scope_drop_reason": "not_applicable", - "runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS", - "limited_reason_category": null, - "response_type": "FACTUAL_LIST", - "requested_result_mode": "confirmed_balance", - "result_mode": "confirmed_balance", - "evidence_strength": "strong", - "balance_confirmed": true, - "as_of_date_basis": "implicit_current_snapshot", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_layer": "compute", - "capability_route_mode": "exact", - "capability_route_enabled": true, - "capability_route_reason": "inventory_on_hand_route_enabled", - "shadow_route_status": "skipped", - "route_expectation_status": "matched", - "route_expectation_reason": "route_expectation_matched", - "route_expectation_expected_selected_recipes": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "route_expectation_expected_requested_result_modes": [ - "confirmed_balance" - ], - "route_expectation_expected_result_modes": [ - "confirmed_balance" - ], - "execution_lane": "address_query", - "llm_decomposition_applied": true, - "llm_decomposition_attempted": true, - "llm_provider_used": "local", - "llm_decomposition_trace_id": "07SeIS--6iv3ys", - "llm_decomposition_effective_message": "Какие остатки по складу на текущую дату?", - "llm_decomposition_reason": "normalized_fragment_applied", - "llm_canonical_candidate_detected": true, - "llm_predecompose_contract": { - "schema_version": "address_llm_predecompose_contract_v1", - "source_message": "какие остатки на складе на сегодня?", - "canonical_message": "Какие остатки по складу на текущую дату?", - "mode": "address_query", - "mode_confidence": "high", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "intent": "inventory_on_hand_as_of_date", - "intent_confidence": "high", - "entities": { - "account": null, - "counterparty": null, - "contract": null, - "document_type": null, - "document_ref": null, - "organization": null - }, - "period": { - "scope": "as_of", - "period_from": null, - "period_to": null, - "as_of_date": "2026-04-17", - "has_explicit_period": false - }, - "semantics": { - "scope_kind": "implicit_self_scope", - "anchor_kind": "self_scope", - "anchor_value": null, - "date_scope_kind": "implicit_current", - "date_basis_hint": "implicit_current_snapshot", - "self_scope_detected": true, - "selected_object_scope_detected": false - }, - "aggregation_profile": "unknown" - }, - "fallback_rule_hit": null, - "sanitized_user_message": "какие остатки на складе на сегодня?", - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "orchestration_contract_v1": { - "schema_version": "assistant_orchestration_contract_v1", - "hard_meta_mode": null, - "address_mode": "address_query", - "address_mode_confidence": "high", - "address_intent": "inventory_on_hand_as_of_date", - "address_intent_confidence": "high", - "strong_data_signal_detected": true, - "data_retrieval_signal_detected": true, - "semantic_contract_valid": true, - "semantic_apply_canonical_recommended": true, - "semantic_reason_codes": [], - "semantic_route_arbitration": { - "supported_address_intent_detected": true, - "strict_deep_investigation_bypass_allowed": false, - "semantic_deep_investigation_hint_detected": false, - "semantic_aggregate_shape_detected": false, - "followup_semantic_override_to_deep_allowed": false - }, - "followup_context_detected": false, - "unsupported_address_intent_fallback_to_deep": false, - "deep_analysis_signal_fallback_to_deep": false, - "aggregate_analytics_signal_fallback_to_deep": false, - "deep_session_continuation_fallback_to_deep": false, - "final_decision": { - "run_address_lane": true, - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "living_mode": "address_data", - "living_reason": "address_lane_triggered" - } - }, - "dialog_continuation_contract_v2": { - "schema_version": "address_dialog_continuation_contract_v2", - "source_message": "какие остатки на складе на сегодня?", - "effective_message": "Какие остатки по складу на текущую дату?", - "decision": "new_topic", - "decision_reasons": [ - "effective_message_rewritten_by_predecompose", - "llm_contract_intent_available" - ], - "followup_context_applied": false, - "previous_intent": null, - "target_intent": "inventory_on_hand_as_of_date", - "intent_selection_mode": null, - "anchor_type": null, - "anchor_value": null, - "implicit_continuation_signal": false - }, - "address_retry_audit": { - "attempted": false, - "reason": null, - "initial_limited_category": null, - "retry_message": null, - "retry_used_followup_context": false, - "retry_result_category": null - }, - "answer_structure_v11": null, - "investigation_state_snapshot": null, - "normalized": null, - "normalizer_output": { - "trace_id": "07SeIS--6iv3ys", - "prompt_version": "normalizer_v2_0_2", - "applied": true, - "effective_message": "Какие остатки по складу на текущую дату?" - }, - "assistant_active_organization": "ООО \\Альтернатива Плюс\\", - "assistant_runtime_contract_v1": { - "schema_version": "assistant_runtime_contracts_v1", - "transition_contract_id": "T1", - "transition_contract_title": "Root Query Entry", - "transition_contract_reason": [ - "capability_contract_root_or_new_entry" - ], - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_reason": [ - "debug_capability_id_matched_contract" - ], - "truth_gate_contract_status": "full_confirmed", - "carryover_eligibility": "root_only" - }, - "transition_contract_id": "T1", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "truth_gate_contract_status": "full_confirmed", - "assistant_truth_answer_policy_v1": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "truth_gate": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "confirmed_balance_exact_inventory_intent", - "organization_grounded_from_observed_rows" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T1", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - } - }, - "coverage_gate_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "confirmed_balance_exact_inventory_intent", - "organization_grounded_from_observed_rows" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T1", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - }, - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "answer_shape": "confirmed_factual", - "assistant_state_transition_v1": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T1", - "transition_title": "Root Query Entry", - "application_status": "applied", - "declared_carryover_depth": "none", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "none", - "required_prior_state": [ - "living_mode_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "create_root_frame_state", - "clear_selected_object_frame_state", - "create_coverage_gate_state" - ], - "forbidden_carryover": [ - "stale_focus_object", - "stale_object_intent", - "implicit_followup_reuse" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "create", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "confirmed_balance_exact_inventory_intent", - "organization_grounded_from_observed_rows" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T1", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "confirmed_balance_exact_inventory_intent", - "organization_grounded_from_observed_rows" - ] - }, - "state_transition_contract": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T1", - "transition_title": "Root Query Entry", - "application_status": "applied", - "declared_carryover_depth": "none", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "none", - "required_prior_state": [ - "living_mode_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "create_root_frame_state", - "clear_selected_object_frame_state", - "create_coverage_gate_state" - ], - "forbidden_carryover": [ - "stale_focus_object", - "stale_object_intent", - "implicit_followup_reuse" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "create", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "confirmed_balance_exact_inventory_intent", - "organization_grounded_from_observed_rows" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T1", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "confirmed_balance_exact_inventory_intent", - "organization_grounded_from_observed_rows" - ] - }, - "state_transition_id": "T1", - "state_transition_status": "applied", - "effective_carryover_depth": "none", - "assistant_capability_binding_v1": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T1", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "as_of_date", - "organization" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T1", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "confirmed_balance_exact_inventory_intent", - "organization_grounded_from_observed_rows" - ] - }, - "capability_binding_contract": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T1", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "as_of_date", - "organization" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T1", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "confirmed_balance_exact_inventory_intent", - "organization_grounded_from_observed_rows" - ] - }, - "capability_binding_status": "bound", - "capability_binding_action": "allow", - "capability_binding_violations": [], - "capability_binding_response_guard": { - "schema_version": "assistant_capability_binding_response_guard_v1", - "guard_owner": "assistantCapabilityBindingResponseGuard", - "applied": false, - "action": "allow", - "original_reply_type": "factual", - "guarded_reply_type": "factual", - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T1", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "confirmed_balance_exact_inventory_intent", - "organization_grounded_from_observed_rows" - ] - } - } - }, - { - "message_id": "msg-2xDanycewl", - "session_id": "asst-kBU5iS0mEt", - "role": "user", - "text": "хвосты по счету 60 на август 2022", - "reply_type": null, - "created_at": "2026-04-17T07:00:02.181Z", - "trace_id": null, - "debug": null - }, - { - "message_id": "msg-MXOH4cg-7h", - "session_id": "asst-kBU5iS0mEt", - "role": "assistant", - "text": "По счету 60 за период 2022-08-01..2022-08-31 открытых остатков не найдено.\nОрганизация: ООО \\Альтернатива Плюс\\.", - "reply_type": "factual", - "created_at": "2026-04-17T07:00:16.065Z", - "trace_id": "address-K5uGp--oGV", - "debug": { - "trace_id": "address-K5uGp--oGV", - "prompt_version": "address_query_runtime_v1", - "schema_version": "address_query_runtime_v1", - "fallback_type": "none", - "route_summary": null, - "fragments": [], - "requirements_extracted": [], - "coverage_report": { - "requirements_total": 0, - "requirements_covered": 0, - "requirements_uncovered": [], - "requirements_partially_covered": [], - "clarification_needed_for": [], - "out_of_scope_requirements": [] - }, - "routes": [], - "retrieval_status": [], - "retrieval_results": [], - "answer_grounding_check": { - "status": "grounded", - "route_subject_match": true, - "missing_requirements": [], - "reasons": [ - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "open_items_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_unavailable_fallback_to_heuristic_candidates", - "open_items_account_query_override_to_movements", - "open_items_account_exact_negative_response" - ], - "why_included_summary": [], - "selection_reason_summary": [] - }, - "dropped_intent_segments": [], - "detected_mode": "address_query", - "detected_mode_confidence": "high", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "detected_intent": "open_items_by_counterparty_or_contract", - "detected_intent_confidence": "medium", - "extracted_filters": { - "sort": "period_desc", - "limit": 20, - "account": "60", - "period_from": "2022-08-01", - "period_to": "2022-08-31", - "as_of_date": "2022-08-31", - "organization": "ООО \\Альтернатива Плюс\\" - }, - "missing_required_filters": [], - "selected_recipe": "address_open_items_by_party_or_contract_v1", - "mcp_call_status_legacy": "no_raw_rows", - "account_scope_mode": "strict", - "account_scope_fallback_applied": false, - "anchor_type": "organization", - "anchor_value_raw": "ООО \\Альтернатива Плюс\\", - "anchor_value_resolved": "ООО \\Альтернатива Плюс\\", - "resolver_confidence": "medium", - "ambiguity_count": 0, - "match_failure_stage": "none", - "match_failure_reason": null, - "mcp_call_status": "no_raw_rows", - "rows_fetched": 0, - "raw_rows_received": 0, - "rows_after_account_scope": 0, - "rows_after_recipe_filter": 0, - "rows_materialized": 0, - "rows_matched": 0, - "raw_row_keys_sample": [], - "materialization_drop_reason": "none", - "account_token_raw": "60", - "account_token_normalized": "60", - "account_scope_fields_checked": [ - "account_dt", - "account_kt", - "registrator", - "analytics" - ], - "account_scope_match_strategy": "account_code_regex_plus_alias_map_v1", - "account_scope_drop_reason": "not_applicable", - "runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS", - "limited_reason_category": null, - "response_type": "FACTUAL_SUMMARY", - "requested_result_mode": "confirmed_balance", - "result_mode": "heuristic_candidates", - "evidence_strength": "weak", - "balance_confirmed": false, - "as_of_date_basis": "period_range", - "capability_id": "address_open_items_by_counterparty_or_contract", - "capability_layer": "compute", - "capability_route_mode": "heuristic", - "capability_route_enabled": true, - "capability_route_reason": "receivables_heuristic_route_enabled", - "shadow_route_status": "skipped", - "route_expectation_status": "not_found", - "route_expectation_reason": "route_expectation_not_defined_for_intent", - "route_expectation_expected_selected_recipes": [], - "route_expectation_expected_requested_result_modes": [], - "route_expectation_expected_result_modes": [], - "execution_lane": "address_query", - "llm_decomposition_applied": true, - "llm_decomposition_attempted": true, - "llm_provider_used": "local", - "llm_decomposition_trace_id": "pawnDc0VTNs75s", - "llm_decomposition_effective_message": "поиск хвостов по счету 60 за август 2022 года", - "llm_decomposition_reason": "normalized_fragment_applied", - "llm_canonical_candidate_detected": true, - "llm_predecompose_contract": { - "schema_version": "address_llm_predecompose_contract_v1", - "source_message": "хвосты по счету 60 на август 2022", - "canonical_message": "поиск хвостов по счету 60 за август 2022 года", - "mode": "address_query", - "mode_confidence": "high", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "intent": "open_items_by_counterparty_or_contract", - "intent_confidence": "medium", - "entities": { - "account": "60", - "counterparty": null, - "contract": null, - "document_type": null, - "document_ref": null, - "organization": null - }, - "period": { - "scope": "as_of", - "period_from": "2022-08-01", - "period_to": "2022-08-31", - "as_of_date": "2022-08-31", - "has_explicit_period": true - }, - "semantics": { - "scope_kind": "implicit_self_scope", - "anchor_kind": "self_scope", - "anchor_value": null, - "date_scope_kind": "explicit", - "date_basis_hint": "period_range", - "self_scope_detected": true, - "selected_object_scope_detected": false - }, - "aggregation_profile": "open_items" - }, - "fallback_rule_hit": null, - "sanitized_user_message": "хвосты по счету 60 на август 2022", - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "orchestration_contract_v1": { - "schema_version": "assistant_orchestration_contract_v1", - "hard_meta_mode": null, - "address_mode": "address_query", - "address_mode_confidence": "high", - "address_intent": "open_items_by_counterparty_or_contract", - "address_intent_confidence": "medium", - "strong_data_signal_detected": true, - "data_retrieval_signal_detected": false, - "semantic_contract_valid": true, - "semantic_apply_canonical_recommended": true, - "semantic_reason_codes": [ - "deep_investigation_signal_detected" - ], - "semantic_route_arbitration": { - "supported_address_intent_detected": true, - "strict_deep_investigation_bypass_allowed": false, - "semantic_deep_investigation_hint_detected": true, - "semantic_aggregate_shape_detected": false, - "followup_semantic_override_to_deep_allowed": false - }, - "followup_context_detected": false, - "unsupported_address_intent_fallback_to_deep": false, - "deep_analysis_signal_fallback_to_deep": false, - "aggregate_analytics_signal_fallback_to_deep": false, - "deep_session_continuation_fallback_to_deep": false, - "final_decision": { - "run_address_lane": true, - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "living_mode": "address_data", - "living_reason": "address_lane_triggered" - } - }, - "dialog_continuation_contract_v2": { - "schema_version": "address_dialog_continuation_contract_v2", - "source_message": "хвосты по счету 60 на август 2022", - "effective_message": "поиск хвостов по счету 60 за август 2022 года", - "decision": "new_topic", - "decision_reasons": [ - "effective_message_rewritten_by_predecompose", - "llm_contract_intent_available" - ], - "followup_context_applied": false, - "previous_intent": null, - "target_intent": "open_items_by_counterparty_or_contract", - "intent_selection_mode": null, - "anchor_type": null, - "anchor_value": null, - "implicit_continuation_signal": false - }, - "address_retry_audit": { - "attempted": false, - "reason": null, - "initial_limited_category": null, - "retry_message": null, - "retry_used_followup_context": false, - "retry_result_category": null - }, - "answer_structure_v11": null, - "investigation_state_snapshot": null, - "normalized": null, - "normalizer_output": { - "trace_id": "pawnDc0VTNs75s", - "prompt_version": "normalizer_v2_0_2", - "applied": true, - "effective_message": "поиск хвостов по счету 60 за август 2022 года" - }, - "address_followup_offer": { - "enabled": true, - "source_intent": "open_items_by_counterparty_or_contract", - "anchor_type": "organization", - "anchor_value": "ООО \\Альтернатива Плюс\\", - "suggested_intents": [ - "list_documents_by_counterparty", - "bank_operations_by_counterparty" - ] - }, - "assistant_known_organizations": [ - "ООО \\Альтернатива Плюс\\" - ], - "assistant_active_organization": "ООО \\Альтернатива Плюс\\", - "assistant_runtime_contract_v1": { - "schema_version": "assistant_runtime_contracts_v1", - "transition_contract_id": null, - "transition_contract_title": null, - "transition_contract_reason": [ - "transition_contract_not_resolved" - ], - "capability_contract_id": null, - "capability_contract_reason": [ - "debug_capability_id_has_no_contract" - ], - "truth_gate_contract_status": "unknown", - "carryover_eligibility": "none" - }, - "transition_contract_id": null, - "capability_contract_id": null, - "truth_gate_contract_status": "unknown", - "assistant_truth_answer_policy_v1": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "truth_gate": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "blocked", - "evidence_grade": "weak", - "grounding_status": "grounded", - "truth_mode": "unsupported", - "carryover_eligibility": "none", - "reason_codes": [ - "truth_gate_unknown", - "truth_mode_unsupported", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "route_expectation_not_defined_for_intent", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "open_items_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_unavailable_fallback_to_heuristic_candidates", - "open_items_account_query_override_to_movements", - "open_items_account_exact_negative_response" - ], - "source_truth_gate_status": "unknown", - "blocked_or_limited_explanation": "truth_gate_not_confirmed" - }, - "answer_shape": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "blocked_no_answer", - "reply_type": "factual", - "capability_contract_id": null, - "transition_contract_id": null, - "may_state_confirmed_facts": false, - "must_include_limitation": true, - "may_power_followup": false, - "required_sections": [ - "blocked_reason", - "safe_next_step" - ], - "downgrade_only": true - } - }, - "coverage_gate_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "blocked", - "evidence_grade": "weak", - "grounding_status": "grounded", - "truth_mode": "unsupported", - "carryover_eligibility": "none", - "reason_codes": [ - "truth_gate_unknown", - "truth_mode_unsupported", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "route_expectation_not_defined_for_intent", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "open_items_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_unavailable_fallback_to_heuristic_candidates", - "open_items_account_query_override_to_movements", - "open_items_account_exact_negative_response" - ], - "source_truth_gate_status": "unknown", - "blocked_or_limited_explanation": "truth_gate_not_confirmed" - }, - "answer_shape_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "blocked_no_answer", - "reply_type": "factual", - "capability_contract_id": null, - "transition_contract_id": null, - "may_state_confirmed_facts": false, - "must_include_limitation": true, - "may_power_followup": false, - "required_sections": [ - "blocked_reason", - "safe_next_step" - ], - "downgrade_only": true - }, - "truth_mode": "unsupported", - "carryover_eligibility": "none", - "answer_shape": "blocked_no_answer", - "assistant_state_transition_v1": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": null, - "transition_title": null, - "application_status": "unresolved", - "declared_carryover_depth": null, - "truth_gate_carryover_depth": "none", - "effective_carryover_depth": "none", - "required_prior_state": [], - "expected_answer_mode": null, - "state_mutations": [], - "forbidden_carryover": [ - "implicit_followup_reuse" - ], - "state_actions": { - "living_mode_state": "none", - "root_frame_state": "none", - "selected_object_frame_state": "none", - "meta_frame_state": "none", - "clarification_state": "none", - "coverage_gate_state": "none", - "answer_context_state": "none" - }, - "coverage_gate_state": { - "coverage_status": "blocked", - "evidence_grade": "weak", - "grounding_status": "grounded", - "truth_mode": "unsupported", - "carryover_eligibility": "none", - "reason_codes": [ - "truth_gate_unknown", - "truth_mode_unsupported", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "route_expectation_not_defined_for_intent", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "open_items_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_unavailable_fallback_to_heuristic_candidates", - "open_items_account_query_override_to_movements", - "open_items_account_exact_negative_response" - ] - }, - "reason_codes": [ - "transition_status_unresolved", - "transition_unresolved", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "truth_gate_unknown", - "truth_mode_unsupported", - "route_expectation_not_defined_for_intent", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "open_items_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_unavailable_fallback_to_heuristic_candidates", - "open_items_account_query_override_to_movements", - "open_items_account_exact_negative_response" - ] - }, - "state_transition_contract": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": null, - "transition_title": null, - "application_status": "unresolved", - "declared_carryover_depth": null, - "truth_gate_carryover_depth": "none", - "effective_carryover_depth": "none", - "required_prior_state": [], - "expected_answer_mode": null, - "state_mutations": [], - "forbidden_carryover": [ - "implicit_followup_reuse" - ], - "state_actions": { - "living_mode_state": "none", - "root_frame_state": "none", - "selected_object_frame_state": "none", - "meta_frame_state": "none", - "clarification_state": "none", - "coverage_gate_state": "none", - "answer_context_state": "none" - }, - "coverage_gate_state": { - "coverage_status": "blocked", - "evidence_grade": "weak", - "grounding_status": "grounded", - "truth_mode": "unsupported", - "carryover_eligibility": "none", - "reason_codes": [ - "truth_gate_unknown", - "truth_mode_unsupported", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "route_expectation_not_defined_for_intent", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "open_items_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_unavailable_fallback_to_heuristic_candidates", - "open_items_account_query_override_to_movements", - "open_items_account_exact_negative_response" - ] - }, - "reason_codes": [ - "transition_status_unresolved", - "transition_unresolved", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "truth_gate_unknown", - "truth_mode_unsupported", - "route_expectation_not_defined_for_intent", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "open_items_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_unavailable_fallback_to_heuristic_candidates", - "open_items_account_query_override_to_movements", - "open_items_account_exact_negative_response" - ] - }, - "state_transition_id": null, - "state_transition_status": "unresolved", - "effective_carryover_depth": "none", - "assistant_capability_binding_v1": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "address_open_items_by_counterparty_or_contract", - "capability_contract_id": null, - "binding_status": "contract_missing", - "binding_action": "observe_only", - "runtime_lane_expected": null, - "runtime_lane_observed": "unknown", - "execution_adapter": null, - "transition_id": null, - "transition_allowed": false, - "required_anchors": [], - "provided_anchors": [ - "sort", - "limit", - "account", - "period_from", - "period_to", - "as_of_date", - "organization" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": null, - "answer_object_shape": null, - "truth_gate_behavior": null, - "truth_fallback_allowed": null, - "answer_shape_compatible": false, - "violations": [ - "capability_contract_missing" - ], - "reason_codes": [ - "binding_status_contract_missing", - "binding_action_observe_only", - "capability_contract_missing", - "transition_status_unresolved", - "transition_unresolved", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "truth_gate_unknown", - "truth_mode_unsupported", - "route_expectation_not_defined_for_intent", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "open_items_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_unavailable_fallback_to_heuristic_candidates", - "open_items_account_query_override_to_movements", - "open_items_account_exact_negative_response" - ] - }, - "capability_binding_contract": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "address_open_items_by_counterparty_or_contract", - "capability_contract_id": null, - "binding_status": "contract_missing", - "binding_action": "observe_only", - "runtime_lane_expected": null, - "runtime_lane_observed": "unknown", - "execution_adapter": null, - "transition_id": null, - "transition_allowed": false, - "required_anchors": [], - "provided_anchors": [ - "sort", - "limit", - "account", - "period_from", - "period_to", - "as_of_date", - "organization" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": null, - "answer_object_shape": null, - "truth_gate_behavior": null, - "truth_fallback_allowed": null, - "answer_shape_compatible": false, - "violations": [ - "capability_contract_missing" - ], - "reason_codes": [ - "binding_status_contract_missing", - "binding_action_observe_only", - "capability_contract_missing", - "transition_status_unresolved", - "transition_unresolved", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "truth_gate_unknown", - "truth_mode_unsupported", - "route_expectation_not_defined_for_intent", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "open_items_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_unavailable_fallback_to_heuristic_candidates", - "open_items_account_query_override_to_movements", - "open_items_account_exact_negative_response" - ] - }, - "capability_binding_status": "contract_missing", - "capability_binding_action": "observe_only", - "capability_binding_violations": [ - "capability_contract_missing" - ], - "capability_binding_response_guard": { - "schema_version": "assistant_capability_binding_response_guard_v1", - "guard_owner": "assistantCapabilityBindingResponseGuard", - "applied": false, - "action": "observe_only", - "original_reply_type": "factual", - "guarded_reply_type": "factual", - "reason_codes": [ - "binding_status_contract_missing", - "binding_action_observe_only", - "capability_contract_missing", - "transition_status_unresolved", - "transition_unresolved", - "transition_contract_not_resolved", - "debug_capability_id_has_no_contract", - "truth_gate_unknown", - "truth_mode_unsupported", - "route_expectation_not_defined_for_intent", - "address_action_detected", - "address_entity_detected", - "shape_not_detected", - "open_items_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_unavailable_fallback_to_heuristic_candidates", - "open_items_account_query_override_to_movements", - "open_items_account_exact_negative_response" - ] - } - } - }, - { - "message_id": "msg-bWwgVggGD1", - "session_id": "asst-kBU5iS0mEt", - "role": "user", - "text": "какие остатки на складе на март 2021", - "reply_type": null, - "created_at": "2026-04-17T07:00:36.924Z", - "trace_id": null, - "debug": null - }, - { - "message_id": "msg-yllv_YMGcL", - "session_id": "asst-kBU5iS0mEt", - "role": "assistant", - "text": "На 31.03.2021 на складе подтверждено 11 позиций с остатком на 716.418,33 ₽.\n\nПозиции:\n1. Модуль прямоугольый 1400*110*750 | склад: Основной склад | количество: 22,000 | стоимость: 148.261,67 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2021-03-31T23:59:59Z\n2. Конструкция трансформер рабочей станции 1300*900*2000 | склад: Основной склад | количество: 3,000 | стоимость: 498.472,50 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2021-03-31T23:59:59Z\n3. Диван трехместный | склад: Основной склад | количество: 1,000 | стоимость: 34.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2021-03-31T23:59:59Z\n4. Кресло орион | склад: Основной склад | количество: 1,000 | стоимость: 13.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2021-03-31T23:59:59Z\n5. Зеркало для инвалидов поворотное травмобезопасное | склад: Основной склад | количество: 1,000 | стоимость: 7.250,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2021-03-31T23:59:59Z\n6. Пуф арий | склад: Основной склад | количество: 1,000 | стоимость: 6.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2021-03-31T23:59:59Z\n7. Столешница 600*3050*26 дуб ниагара | склад: Основной склад | количество: 1,000 | стоимость: 3.724,17 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2021-03-31T23:59:59Z\n8. Столешница 600*3050*26 альмандин | склад: Основной склад | количество: 1,000 | стоимость: 3.075,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2021-03-31T23:59:59Z\n9. Четки Пост (84*117) | склад: Основной склад | количество: 1,000 | стоимость: 833,33 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2021-03-31T23:59:59Z\n10. Кромка с клеем 33 альмандин 137 м | склад: Основной склад | количество: 1,000 | стоимость: 165,83 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2021-03-31T23:59:59Z\n11. Кромка с клеем 33 дуб ниагара 137 м | склад: Основной склад | количество: 1,000 | стоимость: 165,83 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2021-03-31T23:59:59Z\n\nПодтверждение:\n- Дата среза: 31.03.2021.\n- Контур: остатки по счету 41.01 «Товары на складах».\n- Уникальных товаров: 11.\n- Уникальных складов: 1.\n- Суммарное количество: 34,000.", - "reply_type": "factual", - "created_at": "2026-04-17T07:00:49.064Z", - "trace_id": "address-ldgT4KtD3f", - "debug": { - "trace_id": "address-ldgT4KtD3f", - "prompt_version": "address_query_runtime_v1", - "schema_version": "address_query_runtime_v1", - "fallback_type": "none", - "route_summary": null, - "fragments": [], - "requirements_extracted": [], - "coverage_report": { - "requirements_total": 0, - "requirements_covered": 0, - "requirements_uncovered": [], - "requirements_partially_covered": [], - "clarification_needed_for": [], - "out_of_scope_requirements": [] - }, - "routes": [], - "retrieval_status": [], - "retrieval_results": [], - "answer_grounding_check": { - "status": "grounded", - "route_subject_match": true, - "missing_requirements": [], - "reasons": [ - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "why_included_summary": [], - "selection_reason_summary": [] - }, - "dropped_intent_segments": [], - "detected_mode": "address_query", - "detected_mode_confidence": "medium", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "detected_intent": "inventory_on_hand_as_of_date", - "detected_intent_confidence": "high", - "extracted_filters": { - "sort": "period_desc", - "period_from": "2021-03-01", - "period_to": "2021-03-31", - "as_of_date": "2021-03-31", - "organization": "ООО \\Альтернатива Плюс\\" - }, - "missing_required_filters": [], - "selected_recipe": "address_inventory_on_hand_as_of_date_v1", - "mcp_call_status_legacy": "matched_non_empty", - "account_scope_mode": "strict", - "account_scope_fallback_applied": false, - "anchor_type": "organization", - "anchor_value_raw": "ООО \\Альтернатива Плюс\\", - "anchor_value_resolved": "ООО \\Альтернатива Плюс\\", - "resolver_confidence": "medium", - "ambiguity_count": 0, - "match_failure_stage": "none", - "match_failure_reason": null, - "mcp_call_status": "matched_non_empty", - "rows_fetched": 11, - "raw_rows_received": 11, - "rows_after_account_scope": 11, - "rows_after_recipe_filter": 11, - "rows_materialized": 11, - "rows_matched": 11, - "raw_row_keys_sample": [ - "Период", - "Регистратор", - "СчетДт", - "СчетКт", - "Сумма", - "Номенклатура", - "Склад", - "Организация", - "Количество", - "Period", - "Registrator", - "AccountDt", - "Amount" - ], - "materialization_drop_reason": "none", - "account_token_raw": null, - "account_token_normalized": null, - "account_scope_fields_checked": [ - "account_dt", - "account_kt", - "registrator", - "analytics" - ], - "account_scope_match_strategy": "account_code_regex_plus_alias_map_v1", - "account_scope_drop_reason": "not_applicable", - "runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS", - "limited_reason_category": null, - "response_type": "FACTUAL_LIST", - "requested_result_mode": "confirmed_balance", - "result_mode": "confirmed_balance", - "evidence_strength": "strong", - "balance_confirmed": true, - "as_of_date_basis": "period_range", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_layer": "compute", - "capability_route_mode": "exact", - "capability_route_enabled": true, - "capability_route_reason": "inventory_on_hand_route_enabled", - "shadow_route_status": "skipped", - "route_expectation_status": "matched", - "route_expectation_reason": "route_expectation_matched", - "route_expectation_expected_selected_recipes": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "route_expectation_expected_requested_result_modes": [ - "confirmed_balance" - ], - "route_expectation_expected_result_modes": [ - "confirmed_balance" - ], - "execution_lane": "address_query", - "llm_decomposition_applied": true, - "llm_decomposition_attempted": true, - "llm_provider_used": "local", - "llm_decomposition_trace_id": "n10pc0MALsnCY9", - "llm_decomposition_effective_message": "получить остатки по складу за март 2021 года", - "llm_decomposition_reason": "normalized_fragment_applied", - "llm_canonical_candidate_detected": true, - "llm_predecompose_contract": { - "schema_version": "address_llm_predecompose_contract_v1", - "source_message": "какие остатки на складе на март 2021", - "canonical_message": "получить остатки по складу за март 2021 года", - "mode": "address_query", - "mode_confidence": "medium", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "intent": "inventory_on_hand_as_of_date", - "intent_confidence": "high", - "entities": { - "account": null, - "counterparty": null, - "contract": null, - "document_type": null, - "document_ref": null, - "organization": null - }, - "period": { - "scope": "as_of", - "period_from": "2021-03-01", - "period_to": "2021-03-31", - "as_of_date": "2021-03-31", - "has_explicit_period": true - }, - "semantics": { - "scope_kind": "implicit_self_scope", - "anchor_kind": "self_scope", - "anchor_value": null, - "date_scope_kind": "explicit", - "date_basis_hint": "period_range", - "self_scope_detected": true, - "selected_object_scope_detected": false - }, - "aggregation_profile": "unknown" - }, - "fallback_rule_hit": null, - "sanitized_user_message": "какие остатки на складе на март 2021", - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "orchestration_contract_v1": { - "schema_version": "assistant_orchestration_contract_v1", - "hard_meta_mode": null, - "address_mode": "address_query", - "address_mode_confidence": "medium", - "address_intent": "inventory_on_hand_as_of_date", - "address_intent_confidence": "high", - "strong_data_signal_detected": true, - "data_retrieval_signal_detected": true, - "semantic_contract_valid": true, - "semantic_apply_canonical_recommended": true, - "semantic_reason_codes": [], - "semantic_route_arbitration": { - "supported_address_intent_detected": true, - "strict_deep_investigation_bypass_allowed": false, - "semantic_deep_investigation_hint_detected": false, - "semantic_aggregate_shape_detected": false, - "followup_semantic_override_to_deep_allowed": false - }, - "followup_context_detected": false, - "unsupported_address_intent_fallback_to_deep": false, - "deep_analysis_signal_fallback_to_deep": false, - "aggregate_analytics_signal_fallback_to_deep": false, - "deep_session_continuation_fallback_to_deep": false, - "final_decision": { - "run_address_lane": true, - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "living_mode": "address_data", - "living_reason": "address_lane_triggered" - } - }, - "dialog_continuation_contract_v2": { - "schema_version": "address_dialog_continuation_contract_v2", - "source_message": "какие остатки на складе на март 2021", - "effective_message": "получить остатки по складу за март 2021 года", - "decision": "new_topic", - "decision_reasons": [ - "effective_message_rewritten_by_predecompose", - "llm_contract_intent_available" - ], - "followup_context_applied": false, - "previous_intent": null, - "target_intent": "inventory_on_hand_as_of_date", - "intent_selection_mode": null, - "anchor_type": null, - "anchor_value": null, - "implicit_continuation_signal": false - }, - "address_retry_audit": { - "attempted": false, - "reason": null, - "initial_limited_category": null, - "retry_message": null, - "retry_used_followup_context": false, - "retry_result_category": null - }, - "answer_structure_v11": null, - "investigation_state_snapshot": null, - "normalized": null, - "normalizer_output": { - "trace_id": "n10pc0MALsnCY9", - "prompt_version": "normalizer_v2_0_2", - "applied": true, - "effective_message": "получить остатки по складу за март 2021 года" - }, - "assistant_known_organizations": [ - "ООО \\Альтернатива Плюс\\" - ], - "assistant_active_organization": "ООО \\Альтернатива Плюс\\", - "assistant_runtime_contract_v1": { - "schema_version": "assistant_runtime_contracts_v1", - "transition_contract_id": "T1", - "transition_contract_title": "Root Query Entry", - "transition_contract_reason": [ - "capability_contract_root_or_new_entry" - ], - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_reason": [ - "debug_capability_id_matched_contract" - ], - "truth_gate_contract_status": "full_confirmed", - "carryover_eligibility": "root_only" - }, - "transition_contract_id": "T1", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "truth_gate_contract_status": "full_confirmed", - "assistant_truth_answer_policy_v1": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "truth_gate": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T1", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - } - }, - "coverage_gate_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T1", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - }, - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "answer_shape": "confirmed_factual", - "assistant_state_transition_v1": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T1", - "transition_title": "Root Query Entry", - "application_status": "applied", - "declared_carryover_depth": "none", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "none", - "required_prior_state": [ - "living_mode_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "create_root_frame_state", - "clear_selected_object_frame_state", - "create_coverage_gate_state" - ], - "forbidden_carryover": [ - "stale_focus_object", - "stale_object_intent", - "implicit_followup_reuse" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "create", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T1", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_contract": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T1", - "transition_title": "Root Query Entry", - "application_status": "applied", - "declared_carryover_depth": "none", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "none", - "required_prior_state": [ - "living_mode_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "create_root_frame_state", - "clear_selected_object_frame_state", - "create_coverage_gate_state" - ], - "forbidden_carryover": [ - "stale_focus_object", - "stale_object_intent", - "implicit_followup_reuse" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "create", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T1", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_id": "T1", - "state_transition_status": "applied", - "effective_carryover_depth": "none", - "assistant_capability_binding_v1": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T1", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "period_from", - "period_to", - "as_of_date", - "organization" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T1", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_contract": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T1", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "period_from", - "period_to", - "as_of_date", - "organization" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T1", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_status": "bound", - "capability_binding_action": "allow", - "capability_binding_violations": [], - "capability_binding_response_guard": { - "schema_version": "assistant_capability_binding_response_guard_v1", - "guard_owner": "assistantCapabilityBindingResponseGuard", - "applied": false, - "action": "allow", - "original_reply_type": "factual", - "guarded_reply_type": "factual", - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T1", - "capability_contract_root_or_new_entry", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - } - } - }, - { - "message_id": "msg-Ghjyg-PlaW", - "session_id": "asst-kBU5iS0mEt", - "role": "user", - "text": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": кто нам это поставил?", - "reply_type": null, - "created_at": "2026-04-17T07:00:58.621Z", - "trace_id": null, - "debug": null - }, - { - "message_id": "msg-ursK5G5ZoO", - "session_id": "asst-kBU5iS0mEt", - "role": "assistant", - "text": "На 31.03.2021 на складе подтверждено 2 позиций с остатком на 3.240,83 ₽.\n\nПозиции:\n1. Столешница 600*3050*26 альмандин | склад: Основной склад | количество: 1,000 | стоимость: 3.075,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2021-03-31T23:59:59Z\n2. Кромка с клеем 33 альмандин 137 м | склад: Основной склад | количество: 1,000 | стоимость: 165,83 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2021-03-31T23:59:59Z\n\nПодтверждение:\n- Дата среза: 31.03.2021.\n- Контур: остатки по счету 41.01 «Товары на складах».\n- Уникальных товаров: 2.\n- Уникальных складов: 1.\n- Суммарное количество: 2,000.", - "reply_type": "factual", - "created_at": "2026-04-17T07:01:11.435Z", - "trace_id": "address-QYcF1mkhg2", - "debug": { - "trace_id": "address-QYcF1mkhg2", - "prompt_version": "address_query_runtime_v1", - "schema_version": "address_query_runtime_v1", - "fallback_type": "none", - "route_summary": null, - "fragments": [], - "requirements_extracted": [], - "coverage_report": { - "requirements_total": 0, - "requirements_covered": 0, - "requirements_uncovered": [], - "requirements_partially_covered": [], - "clarification_needed_for": [], - "out_of_scope_requirements": [] - }, - "routes": [], - "retrieval_status": [], - "retrieval_results": [], - "answer_grounding_check": { - "status": "grounded", - "route_subject_match": true, - "missing_requirements": [], - "reasons": [ - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "item_from_explicit_quote", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "why_included_summary": [], - "selection_reason_summary": [] - }, - "dropped_intent_segments": [], - "detected_mode": "address_query", - "detected_mode_confidence": "medium", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "detected_intent": "inventory_on_hand_as_of_date", - "detected_intent_confidence": "low", - "extracted_filters": { - "sort": "period_desc", - "as_of_date": "2021-03-31", - "organization": "ООО \\Альтернатива Плюс\\", - "item": "Столешница 600*3050*26 альмандин", - "period_from": "2021-03-01", - "period_to": "2021-03-31" - }, - "missing_required_filters": [], - "selected_recipe": "address_inventory_on_hand_as_of_date_v1", - "mcp_call_status_legacy": "matched_non_empty", - "account_scope_mode": "strict", - "account_scope_fallback_applied": false, - "anchor_type": "organization", - "anchor_value_raw": "ООО \\Альтернатива Плюс\\", - "anchor_value_resolved": "ООО \\Альтернатива Плюс\\", - "resolver_confidence": "medium", - "ambiguity_count": 0, - "match_failure_stage": "none", - "match_failure_reason": null, - "mcp_call_status": "matched_non_empty", - "rows_fetched": 11, - "raw_rows_received": 11, - "rows_after_account_scope": 11, - "rows_after_recipe_filter": 2, - "rows_materialized": 11, - "rows_matched": 2, - "raw_row_keys_sample": [ - "Период", - "Регистратор", - "СчетДт", - "СчетКт", - "Сумма", - "Номенклатура", - "Склад", - "Организация", - "Количество", - "Period", - "Registrator", - "AccountDt", - "Amount" - ], - "materialization_drop_reason": "none", - "account_token_raw": null, - "account_token_normalized": null, - "account_scope_fields_checked": [ - "account_dt", - "account_kt", - "registrator", - "analytics" - ], - "account_scope_match_strategy": "account_code_regex_plus_alias_map_v1", - "account_scope_drop_reason": "not_applicable", - "runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS", - "limited_reason_category": null, - "response_type": "FACTUAL_LIST", - "requested_result_mode": "confirmed_balance", - "result_mode": "confirmed_balance", - "evidence_strength": "strong", - "balance_confirmed": true, - "as_of_date_basis": "implicit_current_snapshot", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_layer": "compute", - "capability_route_mode": "exact", - "capability_route_enabled": true, - "capability_route_reason": "inventory_on_hand_route_enabled", - "shadow_route_status": "skipped", - "route_expectation_status": "matched", - "route_expectation_reason": "route_expectation_matched", - "route_expectation_expected_selected_recipes": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "route_expectation_expected_requested_result_modes": [ - "confirmed_balance" - ], - "route_expectation_expected_result_modes": [ - "confirmed_balance" - ], - "execution_lane": "address_query", - "llm_decomposition_applied": false, - "llm_decomposition_attempted": true, - "llm_provider_used": "local", - "llm_decomposition_trace_id": "Ha4-mqbgDCE638", - "llm_decomposition_effective_message": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": кто нам это поставил?", - "llm_decomposition_reason": "followup_raw_message_preferred_over_llm_rewrite", - "llm_canonical_candidate_detected": true, - "llm_predecompose_contract": { - "schema_version": "address_llm_predecompose_contract_v1", - "source_message": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": кто нам это поставил?", - "canonical_message": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": кто нам это поставил?", - "mode": "address_query", - "mode_confidence": "medium", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "intent": "unknown", - "intent_confidence": "low", - "entities": { - "account": null, - "counterparty": null, - "contract": null, - "document_type": null, - "document_ref": null, - "organization": null - }, - "period": { - "scope": "unspecified", - "period_from": null, - "period_to": null, - "as_of_date": null, - "has_explicit_period": false - }, - "semantics": { - "scope_kind": "none", - "anchor_kind": "none", - "anchor_value": null, - "date_scope_kind": "none", - "date_basis_hint": null, - "self_scope_detected": false, - "selected_object_scope_detected": true - }, - "aggregation_profile": "unknown" - }, - "fallback_rule_hit": null, - "sanitized_user_message": "по выбранному объекту \"столешница 600*3050*26 альмандин\": кто нам это поставил?", - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "orchestration_contract_v1": { - "schema_version": "assistant_orchestration_contract_v1", - "hard_meta_mode": null, - "address_mode": "address_query", - "address_mode_confidence": "medium", - "address_intent": "unknown", - "address_intent_confidence": "low", - "strong_data_signal_detected": false, - "data_retrieval_signal_detected": false, - "semantic_contract_valid": true, - "semantic_apply_canonical_recommended": true, - "semantic_reason_codes": [ - "unsupported_low_confidence_contract", - "rewrite_without_structured_gain" - ], - "semantic_route_arbitration": { - "supported_address_intent_detected": false, - "strict_deep_investigation_bypass_allowed": false, - "semantic_deep_investigation_hint_detected": false, - "semantic_aggregate_shape_detected": false, - "followup_semantic_override_to_deep_allowed": false - }, - "followup_context_detected": true, - "unsupported_address_intent_fallback_to_deep": false, - "deep_analysis_signal_fallback_to_deep": false, - "aggregate_analytics_signal_fallback_to_deep": false, - "deep_session_continuation_fallback_to_deep": false, - "final_decision": { - "run_address_lane": true, - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "living_mode": "address_data", - "living_reason": "address_lane_triggered" - } - }, - "dialog_continuation_contract_v2": { - "schema_version": "address_dialog_continuation_contract_v2", - "source_message": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": кто нам это поставил?", - "effective_message": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": кто нам это поставил?", - "decision": "continue_previous", - "decision_reasons": [ - "followup_context_detected" - ], - "followup_context_applied": true, - "previous_intent": "inventory_on_hand_as_of_date", - "target_intent": "inventory_on_hand_as_of_date", - "intent_selection_mode": "carry_previous_intent", - "anchor_type": "organization", - "anchor_value": "ООО \\Альтернатива Плюс\\", - "implicit_continuation_signal": false - }, - "address_retry_audit": { - "attempted": false, - "reason": null, - "initial_limited_category": null, - "retry_message": null, - "retry_used_followup_context": false, - "retry_result_category": null - }, - "answer_structure_v11": null, - "investigation_state_snapshot": null, - "normalized": null, - "normalizer_output": { - "trace_id": "Ha4-mqbgDCE638", - "prompt_version": "normalizer_v2_0_2", - "applied": false, - "effective_message": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": кто нам это поставил?" - }, - "assistant_known_organizations": [ - "ООО \\Альтернатива Плюс\\" - ], - "assistant_active_organization": "ООО \\Альтернатива Плюс\\", - "address_root_frame_context": { - "root_intent": "inventory_on_hand_as_of_date", - "current_frame_kind": "inventory_root", - "organization": "ООО \\Альтернатива Плюс\\", - "as_of_date": "2021-03-31", - "period_from": "2021-03-01", - "period_to": "2021-03-31" - }, - "assistant_runtime_contract_v1": { - "schema_version": "assistant_runtime_contracts_v1", - "transition_contract_id": "T2", - "transition_contract_title": "Root Follow-Up With Date Or Scope Change", - "transition_contract_reason": [ - "root_followup_continue_previous" - ], - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_reason": [ - "debug_capability_id_matched_contract" - ], - "truth_gate_contract_status": "full_confirmed", - "carryover_eligibility": "root_only" - }, - "transition_contract_id": "T2", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "truth_gate_contract_status": "full_confirmed", - "assistant_truth_answer_policy_v1": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "truth_gate": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "item_from_explicit_quote", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T2", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - } - }, - "coverage_gate_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "item_from_explicit_quote", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T2", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - }, - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "answer_shape": "confirmed_factual", - "assistant_state_transition_v1": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T2", - "transition_title": "Root Follow-Up With Date Or Scope Change", - "application_status": "applied", - "declared_carryover_depth": "root_only", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "root_only", - "required_prior_state": [ - "root_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "update_root_frame_state", - "run_exact_route", - "refresh_coverage_gate_state" - ], - "forbidden_carryover": [ - "incompatible_selected_object_route" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "update", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "item_from_explicit_quote", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "item_from_explicit_quote", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_contract": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T2", - "transition_title": "Root Follow-Up With Date Or Scope Change", - "application_status": "applied", - "declared_carryover_depth": "root_only", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "root_only", - "required_prior_state": [ - "root_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "update_root_frame_state", - "run_exact_route", - "refresh_coverage_gate_state" - ], - "forbidden_carryover": [ - "incompatible_selected_object_route" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "update", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "item_from_explicit_quote", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "item_from_explicit_quote", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_id": "T2", - "state_transition_status": "applied", - "effective_carryover_depth": "root_only", - "assistant_capability_binding_v1": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T2", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "as_of_date", - "organization", - "item", - "period_from", - "period_to" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "item_from_explicit_quote", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_contract": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T2", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "as_of_date", - "organization", - "item", - "period_from", - "period_to" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "item_from_explicit_quote", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_status": "bound", - "capability_binding_action": "allow", - "capability_binding_violations": [], - "capability_binding_response_guard": { - "schema_version": "assistant_capability_binding_response_guard_v1", - "guard_owner": "assistantCapabilityBindingResponseGuard", - "applied": false, - "action": "allow", - "original_reply_type": "factual", - "guarded_reply_type": "factual", - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "item_from_explicit_quote", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - } - } - }, - { - "message_id": "msg-BXkKSt1eQw", - "session_id": "asst-kBU5iS0mEt", - "role": "user", - "text": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": покажи документы по этой позиции", - "reply_type": null, - "created_at": "2026-04-17T07:01:39.623Z", - "trace_id": null, - "debug": null - }, - { - "message_id": "msg-3JlrNX8e49", - "session_id": "asst-kBU5iS0mEt", - "role": "assistant", - "text": "По позиции Столешница 600*3050*26 альмандин найдено 1 подтвержденных документов закупки до 17.04.2026.\n\nПодтверждение:\n- Дата верхней границы: 17.04.2026.\n- Операций поступления в выборке: 1.\n- Поставщик: Торговый дом \\Союз\n\nДокументы:\n1. Поступление товаров и услуг 00000000003 от 12.02.2019 0:00:00 | дата: 12.02.2019 | сумма: 3.690,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | контрагент: Торговый дом \\Союз", - "reply_type": "factual", - "created_at": "2026-04-17T07:01:52.029Z", - "trace_id": "address-ICvNYuY0ps", - "debug": { - "trace_id": "address-ICvNYuY0ps", - "prompt_version": "address_query_runtime_v1", - "schema_version": "address_query_runtime_v1", - "fallback_type": "none", - "route_summary": null, - "fragments": [], - "requirements_extracted": [], - "coverage_report": { - "requirements_total": 0, - "requirements_covered": 0, - "requirements_uncovered": [], - "requirements_partially_covered": [], - "clarification_needed_for": [], - "out_of_scope_requirements": [] - }, - "routes": [], - "retrieval_status": [], - "retrieval_results": [], - "answer_grounding_check": { - "status": "grounded", - "route_subject_match": true, - "missing_requirements": [], - "reasons": [ - "address_action_detected", - "address_entity_detected", - "document_list_signal_detected", - "inventory_selected_object_purchase_documents_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied" - ], - "why_included_summary": [], - "selection_reason_summary": [] - }, - "dropped_intent_segments": [], - "detected_mode": "address_query", - "detected_mode_confidence": "high", - "query_shape": "DOCUMENT_LIST", - "query_shape_confidence": "medium", - "detected_intent": "inventory_purchase_documents_for_item", - "detected_intent_confidence": "medium", - "extracted_filters": { - "sort": "period_desc", - "item": "Столешница 600*3050*26 альмандин", - "organization": "ООО \\Альтернатива Плюс\\" - }, - "missing_required_filters": [], - "selected_recipe": "address_inventory_purchase_documents_for_item_v1", - "mcp_call_status_legacy": "matched_non_empty", - "account_scope_mode": "strict", - "account_scope_fallback_applied": false, - "anchor_type": "item", - "anchor_value_raw": "Столешница 600*3050*26 альмандин", - "anchor_value_resolved": "Столешница 600*3050*26 альмандин", - "resolver_confidence": "medium", - "ambiguity_count": 0, - "match_failure_stage": "none", - "match_failure_reason": null, - "mcp_call_status": "matched_non_empty", - "rows_fetched": 1, - "raw_rows_received": 1, - "rows_after_account_scope": 1, - "rows_after_recipe_filter": 1, - "rows_materialized": 1, - "rows_matched": 1, - "raw_row_keys_sample": [ - "Период", - "Регистратор", - "СчетДт", - "СчетКт", - "Сумма", - "Номенклатура", - "Контрагент", - "Договор", - "Организация", - "Количество", - "Period", - "Registrator", - "AccountDt", - "Amount" - ], - "materialization_drop_reason": "none", - "account_token_raw": null, - "account_token_normalized": null, - "account_scope_fields_checked": [ - "account_dt", - "account_kt", - "registrator", - "analytics" - ], - "account_scope_match_strategy": "account_code_regex_plus_alias_map_v1", - "account_scope_drop_reason": "not_applicable", - "runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS", - "limited_reason_category": null, - "response_type": "FACTUAL_LIST", - "requested_result_mode": "confirmed_balance", - "result_mode": "confirmed_balance", - "evidence_strength": "strong", - "balance_confirmed": true, - "as_of_date_basis": "implicit_current_snapshot", - "capability_id": "inventory_inventory_purchase_documents_for_item", - "capability_layer": "compute", - "capability_route_mode": "exact", - "capability_route_enabled": true, - "capability_route_reason": "inventory_trace_route_enabled", - "shadow_route_status": "skipped", - "route_expectation_status": "matched", - "route_expectation_reason": "route_expectation_matched", - "route_expectation_expected_selected_recipes": [ - "address_inventory_purchase_documents_for_item_v1" - ], - "route_expectation_expected_requested_result_modes": [ - "confirmed_balance" - ], - "route_expectation_expected_result_modes": [ - "confirmed_balance" - ], - "execution_lane": "address_query", - "llm_decomposition_applied": false, - "llm_decomposition_attempted": true, - "llm_provider_used": "local", - "llm_decomposition_trace_id": "kLmPDN9bcU-wyu", - "llm_decomposition_effective_message": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": покажи документы по этой позиции", - "llm_decomposition_reason": "normalized_fragment_rejected_intent_conflict", - "llm_canonical_candidate_detected": true, - "llm_predecompose_contract": { - "schema_version": "address_llm_predecompose_contract_v1", - "source_message": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": покажи документы по этой позиции", - "canonical_message": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": покажи документы по этой позиции", - "mode": "address_query", - "mode_confidence": "high", - "query_shape": "DOCUMENT_LIST", - "query_shape_confidence": "medium", - "intent": "inventory_purchase_documents_for_item", - "intent_confidence": "medium", - "entities": { - "account": null, - "counterparty": null, - "contract": null, - "document_type": null, - "document_ref": null, - "organization": null - }, - "period": { - "scope": "unspecified", - "period_from": null, - "period_to": null, - "as_of_date": null, - "has_explicit_period": false - }, - "semantics": { - "scope_kind": "selected_object_scope", - "anchor_kind": "item", - "anchor_value": "Столешница 600*3050*26 альмандин", - "date_scope_kind": "implicit_current", - "date_basis_hint": "implicit_current_snapshot", - "self_scope_detected": false, - "selected_object_scope_detected": true - }, - "aggregation_profile": "list_lookup" - }, - "fallback_rule_hit": null, - "sanitized_user_message": "по выбранному объекту \"столешница 600*3050*26 альмандин\": покажи документы по этой позиции", - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "orchestration_contract_v1": { - "schema_version": "assistant_orchestration_contract_v1", - "hard_meta_mode": null, - "address_mode": "address_query", - "address_mode_confidence": "high", - "address_intent": "inventory_purchase_documents_for_item", - "address_intent_confidence": "medium", - "strong_data_signal_detected": true, - "data_retrieval_signal_detected": true, - "semantic_contract_valid": true, - "semantic_apply_canonical_recommended": true, - "semantic_reason_codes": [], - "semantic_route_arbitration": { - "supported_address_intent_detected": true, - "strict_deep_investigation_bypass_allowed": true, - "semantic_deep_investigation_hint_detected": false, - "semantic_aggregate_shape_detected": false, - "followup_semantic_override_to_deep_allowed": false - }, - "followup_context_detected": true, - "unsupported_address_intent_fallback_to_deep": false, - "deep_analysis_signal_fallback_to_deep": false, - "aggregate_analytics_signal_fallback_to_deep": false, - "deep_session_continuation_fallback_to_deep": false, - "final_decision": { - "run_address_lane": true, - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "living_mode": "address_data", - "living_reason": "address_lane_triggered" - } - }, - "dialog_continuation_contract_v2": { - "schema_version": "address_dialog_continuation_contract_v2", - "source_message": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": покажи документы по этой позиции", - "effective_message": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": покажи документы по этой позиции", - "decision": "continue_previous", - "decision_reasons": [ - "followup_context_detected", - "llm_contract_intent_available" - ], - "followup_context_applied": true, - "previous_intent": "inventory_on_hand_as_of_date", - "target_intent": "inventory_purchase_documents_for_item", - "intent_selection_mode": "carry_previous_intent", - "anchor_type": "organization", - "anchor_value": "ООО \\Альтернатива Плюс\\", - "implicit_continuation_signal": false - }, - "address_retry_audit": { - "attempted": false, - "reason": null, - "initial_limited_category": null, - "retry_message": null, - "retry_used_followup_context": false, - "retry_result_category": null - }, - "answer_structure_v11": null, - "investigation_state_snapshot": null, - "normalized": null, - "normalizer_output": { - "trace_id": "kLmPDN9bcU-wyu", - "prompt_version": "normalizer_v2_0_2", - "applied": false, - "effective_message": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": покажи документы по этой позиции" - }, - "assistant_known_organizations": [ - "ООО \\Альтернатива Плюс\\" - ], - "assistant_active_organization": "ООО \\Альтернатива Плюс\\", - "address_root_frame_context": { - "root_intent": "inventory_on_hand_as_of_date", - "current_frame_kind": "inventory_root", - "organization": "ООО \\Альтернатива Плюс\\", - "as_of_date": "2021-03-31", - "period_from": "2021-03-01", - "period_to": "2021-03-31" - }, - "assistant_runtime_contract_v1": { - "schema_version": "assistant_runtime_contracts_v1", - "transition_contract_id": "T4", - "transition_contract_title": "Short Action Follow-Up On Selected Object", - "transition_contract_reason": [ - "selected_object_capability_continue_previous" - ], - "capability_contract_id": "inventory_inventory_purchase_documents_for_item", - "capability_contract_reason": [ - "debug_capability_id_matched_contract" - ], - "truth_gate_contract_status": "full_confirmed", - "carryover_eligibility": "object_only" - }, - "transition_contract_id": "T4", - "capability_contract_id": "inventory_inventory_purchase_documents_for_item", - "truth_gate_contract_status": "full_confirmed", - "assistant_truth_answer_policy_v1": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "truth_gate": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "object_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "selected_object_capability_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "document_list_signal_detected", - "inventory_selected_object_purchase_documents_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "inventory_inventory_purchase_documents_for_item", - "transition_contract_id": "T4", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - } - }, - "coverage_gate_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "object_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "selected_object_capability_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "document_list_signal_detected", - "inventory_selected_object_purchase_documents_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "inventory_inventory_purchase_documents_for_item", - "transition_contract_id": "T4", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - }, - "truth_mode": "confirmed", - "carryover_eligibility": "object_only", - "answer_shape": "confirmed_factual", - "assistant_state_transition_v1": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T4", - "transition_title": "Short Action Follow-Up On Selected Object", - "application_status": "applied", - "declared_carryover_depth": "object_only", - "truth_gate_carryover_depth": "object_only", - "effective_carryover_depth": "object_only", - "required_prior_state": [ - "selected_object_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "reuse_selected_object_frame_state", - "route_to_compatible_item_action" - ], - "forbidden_carryover": [ - "generic_chat_fallback", - "data_scope_selection_fallback", - "object_focus_reset" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "preserve", - "selected_object_frame_state": "reuse", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "object_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "selected_object_capability_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "document_list_signal_detected", - "inventory_selected_object_purchase_documents_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T4", - "selected_object_capability_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "document_list_signal_detected", - "inventory_selected_object_purchase_documents_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied" - ] - }, - "state_transition_contract": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T4", - "transition_title": "Short Action Follow-Up On Selected Object", - "application_status": "applied", - "declared_carryover_depth": "object_only", - "truth_gate_carryover_depth": "object_only", - "effective_carryover_depth": "object_only", - "required_prior_state": [ - "selected_object_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "reuse_selected_object_frame_state", - "route_to_compatible_item_action" - ], - "forbidden_carryover": [ - "generic_chat_fallback", - "data_scope_selection_fallback", - "object_focus_reset" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "preserve", - "selected_object_frame_state": "reuse", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "object_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "selected_object_capability_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "document_list_signal_detected", - "inventory_selected_object_purchase_documents_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T4", - "selected_object_capability_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "document_list_signal_detected", - "inventory_selected_object_purchase_documents_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied" - ] - }, - "state_transition_id": "T4", - "state_transition_status": "applied", - "effective_carryover_depth": "object_only", - "assistant_capability_binding_v1": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "inventory_inventory_purchase_documents_for_item", - "capability_contract_id": "inventory_inventory_purchase_documents_for_item", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T4", - "transition_allowed": true, - "required_anchors": [ - "item" - ], - "provided_anchors": [ - "sort", - "item", - "organization" - ], - "missing_anchors": [], - "requires_focus_object": true, - "focus_object_binding_status": "inferred_from_anchor", - "result_shape": "purchase_document_list_for_selected_item", - "answer_object_shape": "inventory_purchase_documents_bundle", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T4", - "selected_object_capability_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "document_list_signal_detected", - "inventory_selected_object_purchase_documents_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied" - ] - }, - "capability_binding_contract": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "inventory_inventory_purchase_documents_for_item", - "capability_contract_id": "inventory_inventory_purchase_documents_for_item", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T4", - "transition_allowed": true, - "required_anchors": [ - "item" - ], - "provided_anchors": [ - "sort", - "item", - "organization" - ], - "missing_anchors": [], - "requires_focus_object": true, - "focus_object_binding_status": "inferred_from_anchor", - "result_shape": "purchase_document_list_for_selected_item", - "answer_object_shape": "inventory_purchase_documents_bundle", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T4", - "selected_object_capability_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "document_list_signal_detected", - "inventory_selected_object_purchase_documents_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied" - ] - }, - "capability_binding_status": "bound", - "capability_binding_action": "allow", - "capability_binding_violations": [], - "capability_binding_response_guard": { - "schema_version": "assistant_capability_binding_response_guard_v1", - "guard_owner": "assistantCapabilityBindingResponseGuard", - "applied": false, - "action": "allow", - "original_reply_type": "factual", - "guarded_reply_type": "factual", - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T4", - "selected_object_capability_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "address_action_detected", - "address_entity_detected", - "document_list_signal_detected", - "inventory_selected_object_purchase_documents_signal_detected", - "organization_from_followup_context", - "address_followup_context_applied" - ] - } - } - }, - { - "message_id": "msg-keO-4TDjD_", - "session_id": "asst-kBU5iS0mEt", - "role": "user", - "text": "покажи еще раз остатки на эту же дату", - "reply_type": null, - "created_at": "2026-04-17T07:02:07.766Z", - "trace_id": null, - "debug": null - }, - { - "message_id": "msg-G6BtQFSdJv", - "session_id": "asst-kBU5iS0mEt", - "role": "assistant", - "text": "Не могу надежно подтвердить ответ в текущем контексте.\nПроверка сценария остановила ответ: transition_not_supported_by_capability.\nЛучше уточнить объект или перезапустить вопрос от корневого запроса, чем выдавать это как подтвержденный факт.", - "reply_type": "partial_coverage", - "created_at": "2026-04-17T07:02:19.571Z", - "trace_id": "address-cCylCuneeR", - "debug": { - "trace_id": "address-cCylCuneeR", - "prompt_version": "address_query_runtime_v1", - "schema_version": "address_query_runtime_v1", - "fallback_type": "none", - "route_summary": null, - "fragments": [], - "requirements_extracted": [], - "coverage_report": { - "requirements_total": 0, - "requirements_covered": 0, - "requirements_uncovered": [], - "requirements_partially_covered": [], - "clarification_needed_for": [], - "out_of_scope_requirements": [] - }, - "routes": [], - "retrieval_status": [], - "retrieval_results": [], - "answer_grounding_check": { - "status": "grounded", - "route_subject_match": true, - "missing_requirements": [], - "reasons": [ - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "compound_signal_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "why_included_summary": [], - "selection_reason_summary": [] - }, - "dropped_intent_segments": [], - "detected_mode": "address_query", - "detected_mode_confidence": "medium", - "query_shape": "COMPOUND_FACTUAL_QUERY", - "query_shape_confidence": "medium", - "detected_intent": "inventory_on_hand_as_of_date", - "detected_intent_confidence": "low", - "extracted_filters": { - "sort": "period_desc", - "as_of_date": "2021-03-31", - "organization": "ООО \\Альтернатива Плюс\\", - "period_from": "2021-03-01", - "period_to": "2021-03-31" - }, - "missing_required_filters": [], - "selected_recipe": "address_inventory_on_hand_as_of_date_v1", - "mcp_call_status_legacy": "matched_non_empty", - "account_scope_mode": "strict", - "account_scope_fallback_applied": false, - "anchor_type": "organization", - "anchor_value_raw": "ООО \\Альтернатива Плюс\\", - "anchor_value_resolved": "ООО \\Альтернатива Плюс\\", - "resolver_confidence": "medium", - "ambiguity_count": 0, - "match_failure_stage": "none", - "match_failure_reason": null, - "mcp_call_status": "matched_non_empty", - "rows_fetched": 11, - "raw_rows_received": 11, - "rows_after_account_scope": 11, - "rows_after_recipe_filter": 11, - "rows_materialized": 11, - "rows_matched": 11, - "raw_row_keys_sample": [ - "Период", - "Регистратор", - "СчетДт", - "СчетКт", - "Сумма", - "Номенклатура", - "Склад", - "Организация", - "Количество", - "Period", - "Registrator", - "AccountDt", - "Amount" - ], - "materialization_drop_reason": "none", - "account_token_raw": null, - "account_token_normalized": null, - "account_scope_fields_checked": [ - "account_dt", - "account_kt", - "registrator", - "analytics" - ], - "account_scope_match_strategy": "account_code_regex_plus_alias_map_v1", - "account_scope_drop_reason": "not_applicable", - "runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS", - "limited_reason_category": null, - "response_type": "FACTUAL_LIST", - "requested_result_mode": "confirmed_balance", - "result_mode": "confirmed_balance", - "evidence_strength": "strong", - "balance_confirmed": true, - "as_of_date_basis": "implicit_current_snapshot", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_layer": "compute", - "capability_route_mode": "exact", - "capability_route_enabled": true, - "capability_route_reason": "inventory_on_hand_route_enabled", - "shadow_route_status": "skipped", - "route_expectation_status": "matched", - "route_expectation_reason": "route_expectation_matched", - "route_expectation_expected_selected_recipes": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "route_expectation_expected_requested_result_modes": [ - "confirmed_balance" - ], - "route_expectation_expected_result_modes": [ - "confirmed_balance" - ], - "execution_lane": "address_query", - "llm_decomposition_applied": false, - "llm_decomposition_attempted": true, - "llm_provider_used": "local", - "llm_decomposition_trace_id": "iIkIedvfxgUuUF", - "llm_decomposition_effective_message": "покажи еще раз остатки на эту же дату", - "llm_decomposition_reason": "normalized_fragment_rejected_semantic_guard", - "llm_canonical_candidate_detected": true, - "llm_predecompose_contract": { - "schema_version": "address_llm_predecompose_contract_v1", - "source_message": "покажи еще раз остатки на эту же дату", - "canonical_message": "покажи еще раз остатки на эту же дату", - "mode": "unsupported", - "mode_confidence": "low", - "query_shape": "COMPOUND_FACTUAL_QUERY", - "query_shape_confidence": "medium", - "intent": "unknown", - "intent_confidence": "low", - "entities": { - "account": null, - "counterparty": null, - "contract": null, - "document_type": null, - "document_ref": null, - "organization": null - }, - "period": { - "scope": "unspecified", - "period_from": null, - "period_to": null, - "as_of_date": null, - "has_explicit_period": false - }, - "semantics": { - "scope_kind": "implicit_self_scope", - "anchor_kind": "self_scope", - "anchor_value": null, - "date_scope_kind": "implicit_current", - "date_basis_hint": "implicit_current_snapshot", - "self_scope_detected": true, - "selected_object_scope_detected": false - }, - "aggregation_profile": "unknown" - }, - "fallback_rule_hit": null, - "sanitized_user_message": "покажи еще раз остатки на эту же дату", - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_signal_detected", - "orchestration_contract_v1": { - "schema_version": "assistant_orchestration_contract_v1", - "hard_meta_mode": null, - "address_mode": "unsupported", - "address_mode_confidence": "low", - "address_intent": "unknown", - "address_intent_confidence": "low", - "strong_data_signal_detected": true, - "data_retrieval_signal_detected": true, - "semantic_contract_valid": false, - "semantic_apply_canonical_recommended": false, - "semantic_reason_codes": [ - "unsupported_low_confidence_contract" - ], - "semantic_route_arbitration": { - "supported_address_intent_detected": false, - "strict_deep_investigation_bypass_allowed": false, - "semantic_deep_investigation_hint_detected": false, - "semantic_aggregate_shape_detected": false, - "followup_semantic_override_to_deep_allowed": true - }, - "followup_context_detected": true, - "unsupported_address_intent_fallback_to_deep": false, - "deep_analysis_signal_fallback_to_deep": false, - "aggregate_analytics_signal_fallback_to_deep": false, - "deep_session_continuation_fallback_to_deep": false, - "final_decision": { - "run_address_lane": true, - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_signal_detected", - "living_mode": "address_data", - "living_reason": "address_lane_triggered" - } - }, - "dialog_continuation_contract_v2": { - "schema_version": "address_dialog_continuation_contract_v2", - "source_message": "покажи еще раз остатки на эту же дату", - "effective_message": "покажи еще раз остатки на эту же дату", - "decision": "continue_previous", - "decision_reasons": [ - "followup_context_detected" - ], - "followup_context_applied": true, - "previous_intent": "inventory_purchase_documents_for_item", - "target_intent": "inventory_purchase_documents_for_item", - "intent_selection_mode": "carry_previous_intent", - "anchor_type": "item", - "anchor_value": "Столешница 600*3050*26 альмандин", - "implicit_continuation_signal": false - }, - "address_retry_audit": { - "attempted": false, - "reason": null, - "initial_limited_category": null, - "retry_message": null, - "retry_used_followup_context": false, - "retry_result_category": null - }, - "answer_structure_v11": null, - "investigation_state_snapshot": null, - "normalized": null, - "normalizer_output": { - "trace_id": "iIkIedvfxgUuUF", - "prompt_version": "normalizer_v2_0_2", - "applied": false, - "effective_message": "покажи еще раз остатки на эту же дату" - }, - "assistant_known_organizations": [ - "ООО \\Альтернатива Плюс\\" - ], - "assistant_active_organization": "ООО \\Альтернатива Плюс\\", - "address_root_frame_context": { - "root_intent": "inventory_on_hand_as_of_date", - "current_frame_kind": "inventory_drilldown", - "organization": "ООО \\Альтернатива Плюс\\", - "as_of_date": "2021-03-31", - "period_from": "2021-03-01", - "period_to": "2021-03-31" - }, - "assistant_runtime_contract_v1": { - "schema_version": "assistant_runtime_contracts_v1", - "transition_contract_id": "T6", - "transition_contract_title": "Domain Pivot With Root-Only Carryover", - "transition_contract_reason": [ - "root_context_reused_after_drilldown_context" - ], - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_reason": [ - "debug_capability_id_matched_contract" - ], - "truth_gate_contract_status": "full_confirmed", - "carryover_eligibility": "root_only" - }, - "transition_contract_id": "T6", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "truth_gate_contract_status": "full_confirmed", - "assistant_truth_answer_policy_v1": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "truth_gate": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_context_reused_after_drilldown_context", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "compound_signal_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T6", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - } - }, - "coverage_gate_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_context_reused_after_drilldown_context", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "compound_signal_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T6", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - }, - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "answer_shape": "confirmed_factual", - "assistant_state_transition_v1": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T6", - "transition_title": "Domain Pivot With Root-Only Carryover", - "application_status": "applied", - "declared_carryover_depth": "root_only", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "root_only", - "required_prior_state": [ - "root_frame_state", - "selected_object_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "preserve_root_frame_state", - "drop_selected_object_frame_state" - ], - "forbidden_carryover": [ - "object_route_replay_into_new_domain" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "preserve", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_context_reused_after_drilldown_context", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "compound_signal_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T6", - "root_context_reused_after_drilldown_context", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "compound_signal_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_contract": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T6", - "transition_title": "Domain Pivot With Root-Only Carryover", - "application_status": "applied", - "declared_carryover_depth": "root_only", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "root_only", - "required_prior_state": [ - "root_frame_state", - "selected_object_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "preserve_root_frame_state", - "drop_selected_object_frame_state" - ], - "forbidden_carryover": [ - "object_route_replay_into_new_domain" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "preserve", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_context_reused_after_drilldown_context", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "compound_signal_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T6", - "root_context_reused_after_drilldown_context", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "compound_signal_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_id": "T6", - "state_transition_status": "applied", - "effective_carryover_depth": "root_only", - "assistant_capability_binding_v1": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "blocked", - "binding_action": "block", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T6", - "transition_allowed": false, - "required_anchors": [], - "provided_anchors": [ - "sort", - "as_of_date", - "organization", - "period_from", - "period_to", - "selected_object" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [ - "transition_not_supported_by_capability" - ], - "reason_codes": [ - "binding_status_blocked", - "binding_action_block", - "transition_not_supported_by_capability", - "transition_status_applied", - "transition_T6", - "root_context_reused_after_drilldown_context", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "compound_signal_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_contract": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "blocked", - "binding_action": "block", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T6", - "transition_allowed": false, - "required_anchors": [], - "provided_anchors": [ - "sort", - "as_of_date", - "organization", - "period_from", - "period_to", - "selected_object" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [ - "transition_not_supported_by_capability" - ], - "reason_codes": [ - "binding_status_blocked", - "binding_action_block", - "transition_not_supported_by_capability", - "transition_status_applied", - "transition_T6", - "root_context_reused_after_drilldown_context", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "compound_signal_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_status": "blocked", - "capability_binding_action": "block", - "capability_binding_violations": [ - "transition_not_supported_by_capability" - ], - "capability_binding_response_guard": { - "schema_version": "assistant_capability_binding_response_guard_v1", - "guard_owner": "assistantCapabilityBindingResponseGuard", - "applied": true, - "action": "block", - "original_reply_type": "factual", - "guarded_reply_type": "partial_coverage", - "reason_codes": [ - "binding_status_blocked", - "binding_action_block", - "transition_not_supported_by_capability", - "transition_status_applied", - "transition_T6", - "root_context_reused_after_drilldown_context", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "compound_signal_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent", - "capability_binding_guard_blocked_reply" - ] - } - } - }, - { - "message_id": "msg-6yaObspNjm", - "session_id": "asst-kBU5iS0mEt", - "role": "user", - "text": "какие остатки на складе на март 2016", - "reply_type": null, - "created_at": "2026-04-17T07:02:49.149Z", - "trace_id": null, - "debug": null - }, - { - "message_id": "msg-U3T1-nXZm8", - "session_id": "asst-kBU5iS0mEt", - "role": "assistant", - "text": "На 31.03.2016 на складе подтверждено 2 позиций с остатком на 812.786,49 ₽.\n\nПозиции:\n1. Шкаф для одежды 824*437*2010 | склад: Основной склад | количество: 11,000 | стоимость: 117.426,49 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2016-03-31T23:59:59Z\n2. Рабочая станция универсального специалиста (индивидуальное изготовление) | склад: Основной склад | количество: 3,000 | стоимость: 695.360,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2016-03-31T23:59:59Z\n\nПодтверждение:\n- Дата среза: 31.03.2016.\n- Контур: остатки по счету 41.01 «Товары на складах».\n- Уникальных товаров: 2.\n- Уникальных складов: 1.\n- Суммарное количество: 14,000.", - "reply_type": "factual", - "created_at": "2026-04-17T07:03:01.200Z", - "trace_id": "address-BWikalW8P7", - "debug": { - "trace_id": "address-BWikalW8P7", - "prompt_version": "address_query_runtime_v1", - "schema_version": "address_query_runtime_v1", - "fallback_type": "none", - "route_summary": null, - "fragments": [], - "requirements_extracted": [], - "coverage_report": { - "requirements_total": 0, - "requirements_covered": 0, - "requirements_uncovered": [], - "requirements_partially_covered": [], - "clarification_needed_for": [], - "out_of_scope_requirements": [] - }, - "routes": [], - "retrieval_status": [], - "retrieval_results": [], - "answer_grounding_check": { - "status": "grounded", - "route_subject_match": true, - "missing_requirements": [], - "reasons": [ - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "why_included_summary": [], - "selection_reason_summary": [] - }, - "dropped_intent_segments": [], - "detected_mode": "address_query", - "detected_mode_confidence": "medium", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "detected_intent": "inventory_on_hand_as_of_date", - "detected_intent_confidence": "low", - "extracted_filters": { - "sort": "period_desc", - "period_from": "2016-03-01", - "period_to": "2016-03-31", - "as_of_date": "2016-03-31", - "organization": "ООО \\Альтернатива Плюс\\" - }, - "missing_required_filters": [], - "selected_recipe": "address_inventory_on_hand_as_of_date_v1", - "mcp_call_status_legacy": "matched_non_empty", - "account_scope_mode": "strict", - "account_scope_fallback_applied": false, - "anchor_type": "organization", - "anchor_value_raw": "ООО \\Альтернатива Плюс\\", - "anchor_value_resolved": "ООО \\Альтернатива Плюс\\", - "resolver_confidence": "medium", - "ambiguity_count": 0, - "match_failure_stage": "none", - "match_failure_reason": null, - "mcp_call_status": "matched_non_empty", - "rows_fetched": 2, - "raw_rows_received": 2, - "rows_after_account_scope": 2, - "rows_after_recipe_filter": 2, - "rows_materialized": 2, - "rows_matched": 2, - "raw_row_keys_sample": [ - "Период", - "Регистратор", - "СчетДт", - "СчетКт", - "Сумма", - "Номенклатура", - "Склад", - "Организация", - "Количество", - "Period", - "Registrator", - "AccountDt", - "Amount" - ], - "materialization_drop_reason": "none", - "account_token_raw": null, - "account_token_normalized": null, - "account_scope_fields_checked": [ - "account_dt", - "account_kt", - "registrator", - "analytics" - ], - "account_scope_match_strategy": "account_code_regex_plus_alias_map_v1", - "account_scope_drop_reason": "not_applicable", - "runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS", - "limited_reason_category": null, - "response_type": "FACTUAL_LIST", - "requested_result_mode": "confirmed_balance", - "result_mode": "confirmed_balance", - "evidence_strength": "strong", - "balance_confirmed": true, - "as_of_date_basis": "period_range", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_layer": "compute", - "capability_route_mode": "exact", - "capability_route_enabled": true, - "capability_route_reason": "inventory_on_hand_route_enabled", - "shadow_route_status": "skipped", - "route_expectation_status": "matched", - "route_expectation_reason": "route_expectation_matched", - "route_expectation_expected_selected_recipes": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "route_expectation_expected_requested_result_modes": [ - "confirmed_balance" - ], - "route_expectation_expected_result_modes": [ - "confirmed_balance" - ], - "execution_lane": "address_query", - "llm_decomposition_applied": true, - "llm_decomposition_attempted": true, - "llm_provider_used": "local", - "llm_decomposition_trace_id": "pa9OQsVipEgvnZ", - "llm_decomposition_effective_message": "получить остатки по складу за март 2016 года", - "llm_decomposition_reason": "normalized_fragment_applied", - "llm_canonical_candidate_detected": true, - "llm_predecompose_contract": { - "schema_version": "address_llm_predecompose_contract_v1", - "source_message": "какие остатки на складе на март 2016", - "canonical_message": "получить остатки по складу за март 2016 года", - "mode": "address_query", - "mode_confidence": "medium", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "intent": "inventory_on_hand_as_of_date", - "intent_confidence": "high", - "entities": { - "account": null, - "counterparty": null, - "contract": null, - "document_type": null, - "document_ref": null, - "organization": null - }, - "period": { - "scope": "as_of", - "period_from": "2016-03-01", - "period_to": "2016-03-31", - "as_of_date": "2016-03-31", - "has_explicit_period": true - }, - "semantics": { - "scope_kind": "implicit_self_scope", - "anchor_kind": "self_scope", - "anchor_value": null, - "date_scope_kind": "explicit", - "date_basis_hint": "period_range", - "self_scope_detected": true, - "selected_object_scope_detected": false - }, - "aggregation_profile": "unknown" - }, - "fallback_rule_hit": null, - "sanitized_user_message": "какие остатки на складе на март 2016", - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "orchestration_contract_v1": { - "schema_version": "assistant_orchestration_contract_v1", - "hard_meta_mode": null, - "address_mode": "address_query", - "address_mode_confidence": "medium", - "address_intent": "inventory_on_hand_as_of_date", - "address_intent_confidence": "high", - "strong_data_signal_detected": true, - "data_retrieval_signal_detected": true, - "semantic_contract_valid": true, - "semantic_apply_canonical_recommended": true, - "semantic_reason_codes": [], - "semantic_route_arbitration": { - "supported_address_intent_detected": true, - "strict_deep_investigation_bypass_allowed": false, - "semantic_deep_investigation_hint_detected": false, - "semantic_aggregate_shape_detected": false, - "followup_semantic_override_to_deep_allowed": false - }, - "followup_context_detected": true, - "unsupported_address_intent_fallback_to_deep": false, - "deep_analysis_signal_fallback_to_deep": false, - "aggregate_analytics_signal_fallback_to_deep": false, - "deep_session_continuation_fallback_to_deep": false, - "final_decision": { - "run_address_lane": true, - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "living_mode": "address_data", - "living_reason": "address_lane_triggered" - } - }, - "dialog_continuation_contract_v2": { - "schema_version": "address_dialog_continuation_contract_v2", - "source_message": "какие остатки на складе на март 2016", - "effective_message": "получить остатки по складу за март 2016 года", - "decision": "continue_previous", - "decision_reasons": [ - "followup_context_detected", - "effective_message_rewritten_by_predecompose", - "llm_contract_intent_available", - "root_context_only_carryover" - ], - "followup_context_applied": true, - "previous_intent": "inventory_on_hand_as_of_date", - "target_intent": "inventory_on_hand_as_of_date", - "intent_selection_mode": "carry_root_context", - "anchor_type": null, - "anchor_value": null, - "implicit_continuation_signal": false - }, - "address_retry_audit": { - "attempted": false, - "reason": null, - "initial_limited_category": null, - "retry_message": null, - "retry_used_followup_context": false, - "retry_result_category": null - }, - "answer_structure_v11": null, - "investigation_state_snapshot": null, - "normalized": null, - "normalizer_output": { - "trace_id": "pa9OQsVipEgvnZ", - "prompt_version": "normalizer_v2_0_2", - "applied": true, - "effective_message": "получить остатки по складу за март 2016 года" - }, - "assistant_known_organizations": [ - "ООО \\Альтернатива Плюс\\" - ], - "assistant_active_organization": "ООО \\Альтернатива Плюс\\", - "address_root_frame_context": { - "root_intent": "inventory_on_hand_as_of_date", - "current_frame_kind": "inventory_root", - "organization": "ООО \\Альтернатива Плюс\\", - "as_of_date": "2021-03-31", - "period_from": "2021-03-01", - "period_to": "2021-03-31" - }, - "assistant_runtime_contract_v1": { - "schema_version": "assistant_runtime_contracts_v1", - "transition_contract_id": "T2", - "transition_contract_title": "Root Follow-Up With Date Or Scope Change", - "transition_contract_reason": [ - "root_followup_continue_previous" - ], - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_reason": [ - "debug_capability_id_matched_contract" - ], - "truth_gate_contract_status": "full_confirmed", - "carryover_eligibility": "root_only" - }, - "transition_contract_id": "T2", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "truth_gate_contract_status": "full_confirmed", - "assistant_truth_answer_policy_v1": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "truth_gate": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T2", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - } - }, - "coverage_gate_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T2", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - }, - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "answer_shape": "confirmed_factual", - "assistant_state_transition_v1": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T2", - "transition_title": "Root Follow-Up With Date Or Scope Change", - "application_status": "applied", - "declared_carryover_depth": "root_only", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "root_only", - "required_prior_state": [ - "root_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "update_root_frame_state", - "run_exact_route", - "refresh_coverage_gate_state" - ], - "forbidden_carryover": [ - "incompatible_selected_object_route" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "update", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_contract": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T2", - "transition_title": "Root Follow-Up With Date Or Scope Change", - "application_status": "applied", - "declared_carryover_depth": "root_only", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "root_only", - "required_prior_state": [ - "root_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "update_root_frame_state", - "run_exact_route", - "refresh_coverage_gate_state" - ], - "forbidden_carryover": [ - "incompatible_selected_object_route" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "update", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_id": "T2", - "state_transition_status": "applied", - "effective_carryover_depth": "root_only", - "assistant_capability_binding_v1": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T2", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "period_from", - "period_to", - "as_of_date", - "organization" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_contract": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T2", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "period_from", - "period_to", - "as_of_date", - "organization" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_status": "bound", - "capability_binding_action": "allow", - "capability_binding_violations": [], - "capability_binding_response_guard": { - "schema_version": "assistant_capability_binding_response_guard_v1", - "guard_owner": "assistantCapabilityBindingResponseGuard", - "applied": false, - "action": "allow", - "original_reply_type": "factual", - "guarded_reply_type": "factual", - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "inventory_on_hand_signal_detected", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - } - } - }, - { - "message_id": "msg-YoVErCg5BW", - "session_id": "asst-kBU5iS0mEt", - "role": "user", - "text": "на июль 2019", - "reply_type": null, - "created_at": "2026-04-17T07:03:04.550Z", - "trace_id": null, - "debug": null - }, - { - "message_id": "msg-WTR742ctqv", - "session_id": "asst-kBU5iS0mEt", - "role": "assistant", - "text": "На 31.07.2019 на складе подтверждено 18 позиций с остатком на 3.521.729,24 ₽.\n\nПозиции:\n1. Подсветка | склад: Основной склад | количество: 90,000 | стоимость: 243.381,35 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n2. Секция мобильная. Тип 1. | склад: Основной склад | количество: 67,000 | стоимость: 1.016.166,67 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n3. Секция монолитная. Тип 1 | склад: Основной склад | количество: 57,000 | стоимость: 819.375,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n4. Модуль прямоугольый 1400*110*750 | склад: Основной склад | количество: 22,000 | стоимость: 148.261,67 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n5. Моноблок леново | склад: Основной склад | количество: 13,000 | стоимость: 614.098,33 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n6. Принтер НР М203 | склад: Основной склад | количество: 13,000 | стоимость: 138.255,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n7. Источник бесперебойного питания | склад: Основной склад | количество: 13,000 | стоимость: 107.347,50 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n8. Шкаф для одежды 824*437*2010 | склад: Основной склад | количество: 9,000 | стоимость: 96.076,22 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n9. Модульная система хранения гардеробная. Тип 1 | склад: Основной склад | количество: 2,000 | стоимость: 110.916,67 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n10. Конструкция трансформер рабочей станции. Тип 2 | склад: Основной склад | количество: 1,000 | стоимость: 165.416,67 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n11. Диван трехместный | склад: Основной склад | количество: 1,000 | стоимость: 34.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n12. Кресло орион | склад: Основной склад | количество: 1,000 | стоимость: 13.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n13. Пуф арий | склад: Основной склад | количество: 1,000 | стоимость: 6.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n14. Столешница 600*3050*26 дуб ниагара | склад: Основной склад | количество: 1,000 | стоимость: 3.724,17 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n15. Столешница 600*3050*26 альмандин | склад: Основной склад | количество: 1,000 | стоимость: 3.075,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n16. Четки Пост (84*117) | склад: Основной склад | количество: 1,000 | стоимость: 833,33 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n17. Кромка с клеем 33 альмандин 137 м | склад: Основной склад | количество: 1,000 | стоимость: 165,83 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n18. Кромка с клеем 33 дуб ниагара 137 м | склад: Основной склад | количество: 1,000 | стоимость: 165,83 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-07-31T23:59:59Z\n\nПодтверждение:\n- Дата среза: 31.07.2019.\n- Контур: остатки по счету 41.01 «Товары на складах».\n- Уникальных товаров: 18.\n- Уникальных складов: 1.\n- Суммарное количество: 295,000.", - "reply_type": "factual", - "created_at": "2026-04-17T07:03:15.384Z", - "trace_id": "address-rtREGdk79X", - "debug": { - "trace_id": "address-rtREGdk79X", - "prompt_version": "address_query_runtime_v1", - "schema_version": "address_query_runtime_v1", - "fallback_type": "none", - "route_summary": null, - "fragments": [], - "requirements_extracted": [], - "coverage_report": { - "requirements_total": 0, - "requirements_covered": 0, - "requirements_uncovered": [], - "requirements_partially_covered": [], - "clarification_needed_for": [], - "out_of_scope_requirements": [] - }, - "routes": [], - "retrieval_status": [], - "retrieval_results": [], - "answer_grounding_check": { - "status": "grounded", - "route_subject_match": true, - "missing_requirements": [], - "reasons": [ - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "why_included_summary": [], - "selection_reason_summary": [] - }, - "dropped_intent_segments": [], - "detected_mode": "address_query", - "detected_mode_confidence": "medium", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "detected_intent": "inventory_on_hand_as_of_date", - "detected_intent_confidence": "low", - "extracted_filters": { - "sort": "period_desc", - "period_from": "2019-07-01", - "period_to": "2019-07-31", - "as_of_date": "2019-07-31", - "organization": "ООО \\Альтернатива Плюс\\" - }, - "missing_required_filters": [], - "selected_recipe": "address_inventory_on_hand_as_of_date_v1", - "mcp_call_status_legacy": "matched_non_empty", - "account_scope_mode": "strict", - "account_scope_fallback_applied": false, - "anchor_type": "organization", - "anchor_value_raw": "ООО \\Альтернатива Плюс\\", - "anchor_value_resolved": "ООО \\Альтернатива Плюс\\", - "resolver_confidence": "medium", - "ambiguity_count": 0, - "match_failure_stage": "none", - "match_failure_reason": null, - "mcp_call_status": "matched_non_empty", - "rows_fetched": 18, - "raw_rows_received": 18, - "rows_after_account_scope": 18, - "rows_after_recipe_filter": 18, - "rows_materialized": 18, - "rows_matched": 18, - "raw_row_keys_sample": [ - "Период", - "Регистратор", - "СчетДт", - "СчетКт", - "Сумма", - "Номенклатура", - "Склад", - "Организация", - "Количество", - "Period", - "Registrator", - "AccountDt", - "Amount" - ], - "materialization_drop_reason": "none", - "account_token_raw": null, - "account_token_normalized": null, - "account_scope_fields_checked": [ - "account_dt", - "account_kt", - "registrator", - "analytics" - ], - "account_scope_match_strategy": "account_code_regex_plus_alias_map_v1", - "account_scope_drop_reason": "not_applicable", - "runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS", - "limited_reason_category": null, - "response_type": "FACTUAL_LIST", - "requested_result_mode": "confirmed_balance", - "result_mode": "confirmed_balance", - "evidence_strength": "strong", - "balance_confirmed": true, - "as_of_date_basis": "period_range", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_layer": "compute", - "capability_route_mode": "exact", - "capability_route_enabled": true, - "capability_route_reason": "inventory_on_hand_route_enabled", - "shadow_route_status": "skipped", - "route_expectation_status": "matched", - "route_expectation_reason": "route_expectation_matched", - "route_expectation_expected_selected_recipes": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "route_expectation_expected_requested_result_modes": [ - "confirmed_balance" - ], - "route_expectation_expected_result_modes": [ - "confirmed_balance" - ], - "execution_lane": "address_query", - "llm_decomposition_applied": false, - "llm_decomposition_attempted": true, - "llm_provider_used": "local", - "llm_decomposition_trace_id": "kHpRaijpcfbNyG", - "llm_decomposition_effective_message": "на июль 2019", - "llm_decomposition_reason": "followup_raw_message_preferred_over_llm_rewrite", - "llm_canonical_candidate_detected": true, - "llm_predecompose_contract": { - "schema_version": "address_llm_predecompose_contract_v1", - "source_message": "на июль 2019", - "canonical_message": "на июль 2019", - "mode": "unsupported", - "mode_confidence": "low", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "intent": "unknown", - "intent_confidence": "low", - "entities": { - "account": null, - "counterparty": null, - "contract": null, - "document_type": null, - "document_ref": null, - "organization": null - }, - "period": { - "scope": "range", - "period_from": "2019-07-01", - "period_to": "2019-07-31", - "as_of_date": null, - "has_explicit_period": true - }, - "semantics": { - "scope_kind": "none", - "anchor_kind": "none", - "anchor_value": null, - "date_scope_kind": "explicit", - "date_basis_hint": "period_range", - "self_scope_detected": false, - "selected_object_scope_detected": false - }, - "aggregation_profile": "unknown" - }, - "fallback_rule_hit": null, - "sanitized_user_message": "на июль 2019", - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "followup_context_detected", - "orchestration_contract_v1": { - "schema_version": "assistant_orchestration_contract_v1", - "hard_meta_mode": null, - "address_mode": "unsupported", - "address_mode_confidence": "low", - "address_intent": "unknown", - "address_intent_confidence": "low", - "strong_data_signal_detected": false, - "data_retrieval_signal_detected": false, - "semantic_contract_valid": true, - "semantic_apply_canonical_recommended": true, - "semantic_reason_codes": [ - "unsupported_low_confidence_contract", - "rewrite_without_structured_gain" - ], - "semantic_route_arbitration": { - "supported_address_intent_detected": false, - "strict_deep_investigation_bypass_allowed": false, - "semantic_deep_investigation_hint_detected": false, - "semantic_aggregate_shape_detected": false, - "followup_semantic_override_to_deep_allowed": true - }, - "followup_context_detected": true, - "unsupported_address_intent_fallback_to_deep": false, - "deep_analysis_signal_fallback_to_deep": false, - "aggregate_analytics_signal_fallback_to_deep": false, - "deep_session_continuation_fallback_to_deep": false, - "final_decision": { - "run_address_lane": true, - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "followup_context_detected", - "living_mode": "address_data", - "living_reason": "address_lane_triggered" - } - }, - "dialog_continuation_contract_v2": { - "schema_version": "address_dialog_continuation_contract_v2", - "source_message": "на июль 2019", - "effective_message": "на июль 2019", - "decision": "continue_previous", - "decision_reasons": [ - "followup_context_detected", - "root_context_only_carryover" - ], - "followup_context_applied": true, - "previous_intent": "inventory_on_hand_as_of_date", - "target_intent": "inventory_on_hand_as_of_date", - "intent_selection_mode": "carry_root_context", - "anchor_type": null, - "anchor_value": null, - "implicit_continuation_signal": false - }, - "address_retry_audit": { - "attempted": false, - "reason": null, - "initial_limited_category": null, - "retry_message": null, - "retry_used_followup_context": false, - "retry_result_category": null - }, - "answer_structure_v11": null, - "investigation_state_snapshot": null, - "normalized": null, - "normalizer_output": { - "trace_id": "kHpRaijpcfbNyG", - "prompt_version": "normalizer_v2_0_2", - "applied": false, - "effective_message": "на июль 2019" - }, - "assistant_known_organizations": [ - "ООО \\Альтернатива Плюс\\" - ], - "assistant_active_organization": "ООО \\Альтернатива Плюс\\", - "address_root_frame_context": { - "root_intent": "inventory_on_hand_as_of_date", - "current_frame_kind": "inventory_root", - "organization": "ООО \\Альтернатива Плюс\\", - "as_of_date": "2016-03-31", - "period_from": "2016-03-01", - "period_to": "2016-03-31" - }, - "assistant_runtime_contract_v1": { - "schema_version": "assistant_runtime_contracts_v1", - "transition_contract_id": "T2", - "transition_contract_title": "Root Follow-Up With Date Or Scope Change", - "transition_contract_reason": [ - "root_followup_continue_previous" - ], - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_reason": [ - "debug_capability_id_matched_contract" - ], - "truth_gate_contract_status": "full_confirmed", - "carryover_eligibility": "root_only" - }, - "transition_contract_id": "T2", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "truth_gate_contract_status": "full_confirmed", - "assistant_truth_answer_policy_v1": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "truth_gate": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T2", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - } - }, - "coverage_gate_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T2", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - }, - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "answer_shape": "confirmed_factual", - "assistant_state_transition_v1": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T2", - "transition_title": "Root Follow-Up With Date Or Scope Change", - "application_status": "applied", - "declared_carryover_depth": "root_only", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "root_only", - "required_prior_state": [ - "root_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "update_root_frame_state", - "run_exact_route", - "refresh_coverage_gate_state" - ], - "forbidden_carryover": [ - "incompatible_selected_object_route" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "update", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_contract": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T2", - "transition_title": "Root Follow-Up With Date Or Scope Change", - "application_status": "applied", - "declared_carryover_depth": "root_only", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "root_only", - "required_prior_state": [ - "root_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "update_root_frame_state", - "run_exact_route", - "refresh_coverage_gate_state" - ], - "forbidden_carryover": [ - "incompatible_selected_object_route" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "update", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_id": "T2", - "state_transition_status": "applied", - "effective_carryover_depth": "root_only", - "assistant_capability_binding_v1": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T2", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "period_from", - "period_to", - "as_of_date", - "organization" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_contract": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T2", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "period_from", - "period_to", - "as_of_date", - "organization" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_status": "bound", - "capability_binding_action": "allow", - "capability_binding_violations": [], - "capability_binding_response_guard": { - "schema_version": "assistant_capability_binding_response_guard_v1", - "guard_owner": "assistantCapabilityBindingResponseGuard", - "applied": false, - "action": "allow", - "original_reply_type": "factual", - "guarded_reply_type": "factual", - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - } - } - }, - { - "message_id": "msg-O6Iu81GiUk", - "session_id": "asst-kBU5iS0mEt", - "role": "user", - "text": "на сентябрь", - "reply_type": null, - "created_at": "2026-04-17T07:03:28.874Z", - "trace_id": null, - "debug": null - }, - { - "message_id": "msg-fYRfbQICPz", - "session_id": "asst-kBU5iS0mEt", - "role": "assistant", - "text": "На 30.09.2019 на складе подтверждено 11 позиций с остатком на 550.153,40 ₽.\n\nПозиции:\n1. Подсветка | склад: Основной склад | количество: 90,000 | стоимость: 243.381,35 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-09-30T23:59:59Z\n2. Модуль прямоугольый 1400*110*750 | склад: Основной склад | количество: 22,000 | стоимость: 148.261,67 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-09-30T23:59:59Z\n3. Шкаф для одежды 824*437*2010 | склад: Основной склад | количество: 9,000 | стоимость: 96.076,22 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-09-30T23:59:59Z\n4. Диван трехместный | склад: Основной склад | количество: 1,000 | стоимость: 34.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-09-30T23:59:59Z\n5. Кресло орион | склад: Основной склад | количество: 1,000 | стоимость: 13.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-09-30T23:59:59Z\n6. Пуф арий | склад: Основной склад | количество: 1,000 | стоимость: 6.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-09-30T23:59:59Z\n7. Столешница 600*3050*26 дуб ниагара | склад: Основной склад | количество: 1,000 | стоимость: 3.724,17 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-09-30T23:59:59Z\n8. Столешница 600*3050*26 альмандин | склад: Основной склад | количество: 1,000 | стоимость: 3.075,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-09-30T23:59:59Z\n9. Четки Пост (84*117) | склад: Основной склад | количество: 1,000 | стоимость: 833,33 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-09-30T23:59:59Z\n10. Кромка с клеем 33 альмандин 137 м | склад: Основной склад | количество: 1,000 | стоимость: 165,83 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-09-30T23:59:59Z\n11. Кромка с клеем 33 дуб ниагара 137 м | склад: Основной склад | количество: 1,000 | стоимость: 165,83 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-09-30T23:59:59Z\n\nПодтверждение:\n- Дата среза: 30.09.2019.\n- Контур: остатки по счету 41.01 «Товары на складах».\n- Уникальных товаров: 11.\n- Уникальных складов: 1.\n- Суммарное количество: 129,000.", - "reply_type": "factual", - "created_at": "2026-04-17T07:03:39.788Z", - "trace_id": "address-TI3CCh0UJC", - "debug": { - "trace_id": "address-TI3CCh0UJC", - "prompt_version": "address_query_runtime_v1", - "schema_version": "address_query_runtime_v1", - "fallback_type": "none", - "route_summary": null, - "fragments": [], - "requirements_extracted": [], - "coverage_report": { - "requirements_total": 0, - "requirements_covered": 0, - "requirements_uncovered": [], - "requirements_partially_covered": [], - "clarification_needed_for": [], - "out_of_scope_requirements": [] - }, - "routes": [], - "retrieval_status": [], - "retrieval_results": [], - "answer_grounding_check": { - "status": "grounded", - "route_subject_match": true, - "missing_requirements": [], - "reasons": [ - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "why_included_summary": [], - "selection_reason_summary": [] - }, - "dropped_intent_segments": [], - "detected_mode": "address_query", - "detected_mode_confidence": "medium", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "detected_intent": "inventory_on_hand_as_of_date", - "detected_intent_confidence": "low", - "extracted_filters": { - "sort": "period_desc", - "as_of_date": "2019-09-30", - "organization": "ООО \\Альтернатива Плюс\\", - "period_from": "2019-09-01", - "period_to": "2019-09-30" - }, - "missing_required_filters": [], - "selected_recipe": "address_inventory_on_hand_as_of_date_v1", - "mcp_call_status_legacy": "matched_non_empty", - "account_scope_mode": "strict", - "account_scope_fallback_applied": false, - "anchor_type": "organization", - "anchor_value_raw": "ООО \\Альтернатива Плюс\\", - "anchor_value_resolved": "ООО \\Альтернатива Плюс\\", - "resolver_confidence": "medium", - "ambiguity_count": 0, - "match_failure_stage": "none", - "match_failure_reason": null, - "mcp_call_status": "matched_non_empty", - "rows_fetched": 11, - "raw_rows_received": 11, - "rows_after_account_scope": 11, - "rows_after_recipe_filter": 11, - "rows_materialized": 11, - "rows_matched": 11, - "raw_row_keys_sample": [ - "Период", - "Регистратор", - "СчетДт", - "СчетКт", - "Сумма", - "Номенклатура", - "Склад", - "Организация", - "Количество", - "Period", - "Registrator", - "AccountDt", - "Amount" - ], - "materialization_drop_reason": "none", - "account_token_raw": null, - "account_token_normalized": null, - "account_scope_fields_checked": [ - "account_dt", - "account_kt", - "registrator", - "analytics" - ], - "account_scope_match_strategy": "account_code_regex_plus_alias_map_v1", - "account_scope_drop_reason": "not_applicable", - "runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS", - "limited_reason_category": null, - "response_type": "FACTUAL_LIST", - "requested_result_mode": "confirmed_balance", - "result_mode": "confirmed_balance", - "evidence_strength": "strong", - "balance_confirmed": true, - "as_of_date_basis": "implicit_current_snapshot", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_layer": "compute", - "capability_route_mode": "exact", - "capability_route_enabled": true, - "capability_route_reason": "inventory_on_hand_route_enabled", - "shadow_route_status": "skipped", - "route_expectation_status": "matched", - "route_expectation_reason": "route_expectation_matched", - "route_expectation_expected_selected_recipes": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "route_expectation_expected_requested_result_modes": [ - "confirmed_balance" - ], - "route_expectation_expected_result_modes": [ - "confirmed_balance" - ], - "execution_lane": "address_query", - "llm_decomposition_applied": false, - "llm_decomposition_attempted": true, - "llm_provider_used": "local", - "llm_decomposition_trace_id": "Fsm5wTbcGCRICj", - "llm_decomposition_effective_message": "на сентябрь", - "llm_decomposition_reason": "followup_raw_message_preferred_over_llm_rewrite", - "llm_canonical_candidate_detected": true, - "llm_predecompose_contract": { - "schema_version": "address_llm_predecompose_contract_v1", - "source_message": "на сентябрь", - "canonical_message": "на сентябрь", - "mode": "unsupported", - "mode_confidence": "low", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "intent": "unknown", - "intent_confidence": "low", - "entities": { - "account": null, - "counterparty": null, - "contract": null, - "document_type": null, - "document_ref": null, - "organization": null - }, - "period": { - "scope": "unspecified", - "period_from": null, - "period_to": null, - "as_of_date": null, - "has_explicit_period": false - }, - "semantics": { - "scope_kind": "none", - "anchor_kind": "none", - "anchor_value": null, - "date_scope_kind": "none", - "date_basis_hint": null, - "self_scope_detected": false, - "selected_object_scope_detected": false - }, - "aggregation_profile": "unknown" - }, - "fallback_rule_hit": null, - "sanitized_user_message": "на сентябрь", - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "followup_context_detected", - "orchestration_contract_v1": { - "schema_version": "assistant_orchestration_contract_v1", - "hard_meta_mode": null, - "address_mode": "unsupported", - "address_mode_confidence": "low", - "address_intent": "unknown", - "address_intent_confidence": "low", - "strong_data_signal_detected": false, - "data_retrieval_signal_detected": false, - "semantic_contract_valid": true, - "semantic_apply_canonical_recommended": true, - "semantic_reason_codes": [ - "unsupported_low_confidence_contract", - "rewrite_without_structured_gain" - ], - "semantic_route_arbitration": { - "supported_address_intent_detected": false, - "strict_deep_investigation_bypass_allowed": false, - "semantic_deep_investigation_hint_detected": false, - "semantic_aggregate_shape_detected": false, - "followup_semantic_override_to_deep_allowed": true - }, - "followup_context_detected": true, - "unsupported_address_intent_fallback_to_deep": false, - "deep_analysis_signal_fallback_to_deep": false, - "aggregate_analytics_signal_fallback_to_deep": false, - "deep_session_continuation_fallback_to_deep": false, - "final_decision": { - "run_address_lane": true, - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "followup_context_detected", - "living_mode": "address_data", - "living_reason": "address_lane_triggered" - } - }, - "dialog_continuation_contract_v2": { - "schema_version": "address_dialog_continuation_contract_v2", - "source_message": "на сентябрь", - "effective_message": "на сентябрь", - "decision": "continue_previous", - "decision_reasons": [ - "followup_context_detected", - "root_context_only_carryover" - ], - "followup_context_applied": true, - "previous_intent": "inventory_on_hand_as_of_date", - "target_intent": "inventory_on_hand_as_of_date", - "intent_selection_mode": "carry_root_context", - "anchor_type": null, - "anchor_value": null, - "implicit_continuation_signal": false - }, - "address_retry_audit": { - "attempted": false, - "reason": null, - "initial_limited_category": null, - "retry_message": null, - "retry_used_followup_context": false, - "retry_result_category": null - }, - "answer_structure_v11": null, - "investigation_state_snapshot": null, - "normalized": null, - "normalizer_output": { - "trace_id": "Fsm5wTbcGCRICj", - "prompt_version": "normalizer_v2_0_2", - "applied": false, - "effective_message": "на сентябрь" - }, - "assistant_known_organizations": [ - "ООО \\Альтернатива Плюс\\" - ], - "assistant_active_organization": "ООО \\Альтернатива Плюс\\", - "address_root_frame_context": { - "root_intent": "inventory_on_hand_as_of_date", - "current_frame_kind": "inventory_root", - "organization": "ООО \\Альтернатива Плюс\\", - "as_of_date": "2019-07-31", - "period_from": "2019-07-01", - "period_to": "2019-07-31" - }, - "assistant_runtime_contract_v1": { - "schema_version": "assistant_runtime_contracts_v1", - "transition_contract_id": "T2", - "transition_contract_title": "Root Follow-Up With Date Or Scope Change", - "transition_contract_reason": [ - "root_followup_continue_previous" - ], - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_reason": [ - "debug_capability_id_matched_contract" - ], - "truth_gate_contract_status": "full_confirmed", - "carryover_eligibility": "root_only" - }, - "transition_contract_id": "T2", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "truth_gate_contract_status": "full_confirmed", - "assistant_truth_answer_policy_v1": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "truth_gate": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T2", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - } - }, - "coverage_gate_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T2", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - }, - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "answer_shape": "confirmed_factual", - "assistant_state_transition_v1": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T2", - "transition_title": "Root Follow-Up With Date Or Scope Change", - "application_status": "applied", - "declared_carryover_depth": "root_only", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "root_only", - "required_prior_state": [ - "root_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "update_root_frame_state", - "run_exact_route", - "refresh_coverage_gate_state" - ], - "forbidden_carryover": [ - "incompatible_selected_object_route" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "update", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_contract": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T2", - "transition_title": "Root Follow-Up With Date Or Scope Change", - "application_status": "applied", - "declared_carryover_depth": "root_only", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "root_only", - "required_prior_state": [ - "root_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "update_root_frame_state", - "run_exact_route", - "refresh_coverage_gate_state" - ], - "forbidden_carryover": [ - "incompatible_selected_object_route" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "update", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_id": "T2", - "state_transition_status": "applied", - "effective_carryover_depth": "root_only", - "assistant_capability_binding_v1": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T2", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "as_of_date", - "organization", - "period_from", - "period_to" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_contract": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T2", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "as_of_date", - "organization", - "period_from", - "period_to" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_status": "bound", - "capability_binding_action": "allow", - "capability_binding_violations": [], - "capability_binding_response_guard": { - "schema_version": "assistant_capability_binding_response_guard_v1", - "guard_owner": "assistantCapabilityBindingResponseGuard", - "applied": false, - "action": "allow", - "original_reply_type": "factual", - "guarded_reply_type": "factual", - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - } - } - }, - { - "message_id": "msg-SFZT_WYkYY", - "session_id": "asst-kBU5iS0mEt", - "role": "user", - "text": "а на март", - "reply_type": null, - "created_at": "2026-04-17T07:03:48.893Z", - "trace_id": null, - "debug": null - }, - { - "message_id": "msg-eV8Drg_UC9", - "session_id": "asst-kBU5iS0mEt", - "role": "assistant", - "text": "На 31.03.2019 на складе подтверждено 16 позиций с остатком на 1.664.391,73 ₽.\n\nПозиции:\n1. Подсветка | склад: Основной склад | количество: 90,000 | стоимость: 243.381,35 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n2. Модуль на монолитном каркасе. Тип 1 | склад: Основной склад | количество: 30,000 | стоимость: 186.325,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n3. Модуль прямоугольый 1400*110*750 | склад: Основной склад | количество: 22,000 | стоимость: 148.261,67 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n4. Модуль на монолитном каркасе передвижной. Тип 1. | склад: Основной склад | количество: 15,000 | стоимость: 68.212,50 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n5. Моноблок леново | склад: Основной склад | количество: 13,000 | стоимость: 614.098,33 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n6. Принтер НР М203 | склад: Основной склад | количество: 13,000 | стоимость: 138.255,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n7. Источник бесперебойного питания | склад: Основной склад | количество: 13,000 | стоимость: 107.347,50 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n8. Шкаф для одежды 824*437*2010 | склад: Основной склад | количество: 9,000 | стоимость: 96.076,22 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n9. Диван трехместный | склад: Основной склад | количество: 1,000 | стоимость: 34.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n10. Кресло орион | склад: Основной склад | количество: 1,000 | стоимость: 13.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n11. Пуф арий | склад: Основной склад | количество: 1,000 | стоимость: 6.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n12. Столешница 600*3050*26 дуб ниагара | склад: Основной склад | количество: 1,000 | стоимость: 3.724,17 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n13. Столешница 600*3050*26 альмандин | склад: Основной склад | количество: 1,000 | стоимость: 3.075,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n14. Четки Пост (84*117) | склад: Основной склад | количество: 1,000 | стоимость: 833,33 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n15. Кромка с клеем 33 альмандин 137 м | склад: Основной склад | количество: 1,000 | стоимость: 165,83 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n16. Кромка с клеем 33 дуб ниагара 137 м | склад: Основной склад | количество: 1,000 | стоимость: 165,83 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n\nПодтверждение:\n- Дата среза: 31.03.2019.\n- Контур: остатки по счету 41.01 «Товары на складах».\n- Уникальных товаров: 16.\n- Уникальных складов: 1.\n- Суммарное количество: 213,000.", - "reply_type": "factual", - "created_at": "2026-04-17T07:04:01.195Z", - "trace_id": "address-A2lTDmKun-", - "debug": { - "trace_id": "address-A2lTDmKun-", - "prompt_version": "address_query_runtime_v1", - "schema_version": "address_query_runtime_v1", - "fallback_type": "none", - "route_summary": null, - "fragments": [], - "requirements_extracted": [], - "coverage_report": { - "requirements_total": 0, - "requirements_covered": 0, - "requirements_uncovered": [], - "requirements_partially_covered": [], - "clarification_needed_for": [], - "out_of_scope_requirements": [] - }, - "routes": [], - "retrieval_status": [], - "retrieval_results": [], - "answer_grounding_check": { - "status": "grounded", - "route_subject_match": true, - "missing_requirements": [], - "reasons": [ - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "why_included_summary": [], - "selection_reason_summary": [] - }, - "dropped_intent_segments": [], - "detected_mode": "address_query", - "detected_mode_confidence": "medium", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "detected_intent": "inventory_on_hand_as_of_date", - "detected_intent_confidence": "low", - "extracted_filters": { - "sort": "period_desc", - "as_of_date": "2019-03-31", - "organization": "ООО \\Альтернатива Плюс\\", - "period_from": "2019-03-01", - "period_to": "2019-03-31" - }, - "missing_required_filters": [], - "selected_recipe": "address_inventory_on_hand_as_of_date_v1", - "mcp_call_status_legacy": "matched_non_empty", - "account_scope_mode": "strict", - "account_scope_fallback_applied": false, - "anchor_type": "organization", - "anchor_value_raw": "ООО \\Альтернатива Плюс\\", - "anchor_value_resolved": "ООО \\Альтернатива Плюс\\", - "resolver_confidence": "medium", - "ambiguity_count": 0, - "match_failure_stage": "none", - "match_failure_reason": null, - "mcp_call_status": "matched_non_empty", - "rows_fetched": 16, - "raw_rows_received": 16, - "rows_after_account_scope": 16, - "rows_after_recipe_filter": 16, - "rows_materialized": 16, - "rows_matched": 16, - "raw_row_keys_sample": [ - "Период", - "Регистратор", - "СчетДт", - "СчетКт", - "Сумма", - "Номенклатура", - "Склад", - "Организация", - "Количество", - "Period", - "Registrator", - "AccountDt", - "Amount" - ], - "materialization_drop_reason": "none", - "account_token_raw": null, - "account_token_normalized": null, - "account_scope_fields_checked": [ - "account_dt", - "account_kt", - "registrator", - "analytics" - ], - "account_scope_match_strategy": "account_code_regex_plus_alias_map_v1", - "account_scope_drop_reason": "not_applicable", - "runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS", - "limited_reason_category": null, - "response_type": "FACTUAL_LIST", - "requested_result_mode": "confirmed_balance", - "result_mode": "confirmed_balance", - "evidence_strength": "strong", - "balance_confirmed": true, - "as_of_date_basis": "implicit_current_snapshot", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_layer": "compute", - "capability_route_mode": "exact", - "capability_route_enabled": true, - "capability_route_reason": "inventory_on_hand_route_enabled", - "shadow_route_status": "skipped", - "route_expectation_status": "matched", - "route_expectation_reason": "route_expectation_matched", - "route_expectation_expected_selected_recipes": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "route_expectation_expected_requested_result_modes": [ - "confirmed_balance" - ], - "route_expectation_expected_result_modes": [ - "confirmed_balance" - ], - "execution_lane": "address_query", - "llm_decomposition_applied": false, - "llm_decomposition_attempted": true, - "llm_provider_used": "local", - "llm_decomposition_trace_id": "V6jhCz4oijXA22", - "llm_decomposition_effective_message": "а на март", - "llm_decomposition_reason": "followup_raw_message_preferred_over_llm_rewrite", - "llm_canonical_candidate_detected": true, - "llm_predecompose_contract": { - "schema_version": "address_llm_predecompose_contract_v1", - "source_message": "а на март", - "canonical_message": "а на март", - "mode": "unsupported", - "mode_confidence": "low", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "intent": "unknown", - "intent_confidence": "low", - "entities": { - "account": null, - "counterparty": null, - "contract": null, - "document_type": null, - "document_ref": null, - "organization": null - }, - "period": { - "scope": "unspecified", - "period_from": null, - "period_to": null, - "as_of_date": null, - "has_explicit_period": false - }, - "semantics": { - "scope_kind": "none", - "anchor_kind": "none", - "anchor_value": null, - "date_scope_kind": "none", - "date_basis_hint": null, - "self_scope_detected": false, - "selected_object_scope_detected": false - }, - "aggregation_profile": "unknown" - }, - "fallback_rule_hit": null, - "sanitized_user_message": "а на март", - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "followup_context_detected", - "orchestration_contract_v1": { - "schema_version": "assistant_orchestration_contract_v1", - "hard_meta_mode": null, - "address_mode": "unsupported", - "address_mode_confidence": "low", - "address_intent": "unknown", - "address_intent_confidence": "low", - "strong_data_signal_detected": false, - "data_retrieval_signal_detected": false, - "semantic_contract_valid": true, - "semantic_apply_canonical_recommended": true, - "semantic_reason_codes": [ - "unsupported_low_confidence_contract", - "rewrite_without_structured_gain" - ], - "semantic_route_arbitration": { - "supported_address_intent_detected": false, - "strict_deep_investigation_bypass_allowed": false, - "semantic_deep_investigation_hint_detected": false, - "semantic_aggregate_shape_detected": false, - "followup_semantic_override_to_deep_allowed": true - }, - "followup_context_detected": true, - "unsupported_address_intent_fallback_to_deep": false, - "deep_analysis_signal_fallback_to_deep": false, - "aggregate_analytics_signal_fallback_to_deep": false, - "deep_session_continuation_fallback_to_deep": false, - "final_decision": { - "run_address_lane": true, - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "followup_context_detected", - "living_mode": "address_data", - "living_reason": "address_lane_triggered" - } - }, - "dialog_continuation_contract_v2": { - "schema_version": "address_dialog_continuation_contract_v2", - "source_message": "а на март", - "effective_message": "а на март", - "decision": "continue_previous", - "decision_reasons": [ - "followup_context_detected", - "root_context_only_carryover" - ], - "followup_context_applied": true, - "previous_intent": "inventory_on_hand_as_of_date", - "target_intent": "inventory_on_hand_as_of_date", - "intent_selection_mode": "carry_root_context", - "anchor_type": null, - "anchor_value": null, - "implicit_continuation_signal": false - }, - "address_retry_audit": { - "attempted": false, - "reason": null, - "initial_limited_category": null, - "retry_message": null, - "retry_used_followup_context": false, - "retry_result_category": null - }, - "answer_structure_v11": null, - "investigation_state_snapshot": null, - "normalized": null, - "normalizer_output": { - "trace_id": "V6jhCz4oijXA22", - "prompt_version": "normalizer_v2_0_2", - "applied": false, - "effective_message": "а на март" - }, - "assistant_known_organizations": [ - "ООО \\Альтернатива Плюс\\" - ], - "assistant_active_organization": "ООО \\Альтернатива Плюс\\", - "address_root_frame_context": { - "root_intent": "inventory_on_hand_as_of_date", - "current_frame_kind": "inventory_root", - "organization": "ООО \\Альтернатива Плюс\\", - "as_of_date": "2019-09-30", - "period_from": "2019-09-01", - "period_to": "2019-09-30" - }, - "assistant_runtime_contract_v1": { - "schema_version": "assistant_runtime_contracts_v1", - "transition_contract_id": "T2", - "transition_contract_title": "Root Follow-Up With Date Or Scope Change", - "transition_contract_reason": [ - "root_followup_continue_previous" - ], - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_reason": [ - "debug_capability_id_matched_contract" - ], - "truth_gate_contract_status": "full_confirmed", - "carryover_eligibility": "root_only" - }, - "transition_contract_id": "T2", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "truth_gate_contract_status": "full_confirmed", - "assistant_truth_answer_policy_v1": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "truth_gate": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T2", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - } - }, - "coverage_gate_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T2", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - }, - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "answer_shape": "confirmed_factual", - "assistant_state_transition_v1": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T2", - "transition_title": "Root Follow-Up With Date Or Scope Change", - "application_status": "applied", - "declared_carryover_depth": "root_only", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "root_only", - "required_prior_state": [ - "root_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "update_root_frame_state", - "run_exact_route", - "refresh_coverage_gate_state" - ], - "forbidden_carryover": [ - "incompatible_selected_object_route" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "update", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_contract": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T2", - "transition_title": "Root Follow-Up With Date Or Scope Change", - "application_status": "applied", - "declared_carryover_depth": "root_only", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "root_only", - "required_prior_state": [ - "root_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "update_root_frame_state", - "run_exact_route", - "refresh_coverage_gate_state" - ], - "forbidden_carryover": [ - "incompatible_selected_object_route" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "update", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_id": "T2", - "state_transition_status": "applied", - "effective_carryover_depth": "root_only", - "assistant_capability_binding_v1": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T2", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "as_of_date", - "organization", - "period_from", - "period_to" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_contract": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T2", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "as_of_date", - "organization", - "period_from", - "period_to" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_status": "bound", - "capability_binding_action": "allow", - "capability_binding_violations": [], - "capability_binding_response_guard": { - "schema_version": "assistant_capability_binding_response_guard_v1", - "guard_owner": "assistantCapabilityBindingResponseGuard", - "applied": false, - "action": "allow", - "original_reply_type": "factual", - "guarded_reply_type": "factual", - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "no_address_or_deep_signal", - "address_mode_from_followup_context", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "intent_restored_to_inventory_root_frame", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_derived_from_inventory_root_frame_year", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - } - } - }, - { - "message_id": "msg-6yHi1t4n78", - "session_id": "asst-kBU5iS0mEt", - "role": "user", - "text": "это по общей базе", - "reply_type": null, - "created_at": "2026-04-17T07:04:08.964Z", - "trace_id": null, - "debug": null - }, - { - "message_id": "msg-GcM8aL1yJc", - "session_id": "asst-kBU5iS0mEt", - "role": "assistant", - "text": "На 31.03.2019 на складе подтверждено 16 позиций с остатком на 1.664.391,73 ₽.\n\nПозиции:\n1. Подсветка | склад: Основной склад | количество: 90,000 | стоимость: 243.381,35 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n2. Модуль на монолитном каркасе. Тип 1 | склад: Основной склад | количество: 30,000 | стоимость: 186.325,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n3. Модуль прямоугольый 1400*110*750 | склад: Основной склад | количество: 22,000 | стоимость: 148.261,67 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n4. Модуль на монолитном каркасе передвижной. Тип 1. | склад: Основной склад | количество: 15,000 | стоимость: 68.212,50 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n5. Моноблок леново | склад: Основной склад | количество: 13,000 | стоимость: 614.098,33 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n6. Принтер НР М203 | склад: Основной склад | количество: 13,000 | стоимость: 138.255,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n7. Источник бесперебойного питания | склад: Основной склад | количество: 13,000 | стоимость: 107.347,50 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n8. Шкаф для одежды 824*437*2010 | склад: Основной склад | количество: 9,000 | стоимость: 96.076,22 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n9. Диван трехместный | склад: Основной склад | количество: 1,000 | стоимость: 34.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n10. Кресло орион | склад: Основной склад | количество: 1,000 | стоимость: 13.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n11. Пуф арий | склад: Основной склад | количество: 1,000 | стоимость: 6.490,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n12. Столешница 600*3050*26 дуб ниагара | склад: Основной склад | количество: 1,000 | стоимость: 3.724,17 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n13. Столешница 600*3050*26 альмандин | склад: Основной склад | количество: 1,000 | стоимость: 3.075,00 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n14. Четки Пост (84*117) | склад: Основной склад | количество: 1,000 | стоимость: 833,33 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n15. Кромка с клеем 33 альмандин 137 м | склад: Основной склад | количество: 1,000 | стоимость: 165,83 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n16. Кромка с клеем 33 дуб ниагара 137 м | склад: Основной склад | количество: 1,000 | стоимость: 165,83 ₽ | организация: ООО \\Альтернатива Плюс\\ | дата строки: 2019-03-31T23:59:59Z\n\nПодтверждение:\n- Дата среза: 31.03.2019.\n- Контур: остатки по счету 41.01 «Товары на складах».\n- Уникальных товаров: 16.\n- Уникальных складов: 1.\n- Суммарное количество: 213,000.", - "reply_type": "factual", - "created_at": "2026-04-17T07:04:19.453Z", - "trace_id": "address-srwtOvv1jk", - "debug": { - "trace_id": "address-srwtOvv1jk", - "prompt_version": "address_query_runtime_v1", - "schema_version": "address_query_runtime_v1", - "fallback_type": "none", - "route_summary": null, - "fragments": [], - "requirements_extracted": [], - "coverage_report": { - "requirements_total": 0, - "requirements_covered": 0, - "requirements_uncovered": [], - "requirements_partially_covered": [], - "clarification_needed_for": [], - "out_of_scope_requirements": [] - }, - "routes": [], - "retrieval_status": [], - "retrieval_results": [], - "answer_grounding_check": { - "status": "grounded", - "route_subject_match": true, - "missing_requirements": [], - "reasons": [ - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "why_included_summary": [], - "selection_reason_summary": [] - }, - "dropped_intent_segments": [], - "detected_mode": "address_query", - "detected_mode_confidence": "medium", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "detected_intent": "inventory_on_hand_as_of_date", - "detected_intent_confidence": "low", - "extracted_filters": { - "sort": "period_desc", - "as_of_date": "2019-03-31", - "organization": "ООО \\Альтернатива Плюс\\", - "period_from": "2019-03-01", - "period_to": "2019-03-31" - }, - "missing_required_filters": [], - "selected_recipe": "address_inventory_on_hand_as_of_date_v1", - "mcp_call_status_legacy": "matched_non_empty", - "account_scope_mode": "strict", - "account_scope_fallback_applied": false, - "anchor_type": "organization", - "anchor_value_raw": "ООО \\Альтернатива Плюс\\", - "anchor_value_resolved": "ООО \\Альтернатива Плюс\\", - "resolver_confidence": "medium", - "ambiguity_count": 0, - "match_failure_stage": "none", - "match_failure_reason": null, - "mcp_call_status": "matched_non_empty", - "rows_fetched": 16, - "raw_rows_received": 16, - "rows_after_account_scope": 16, - "rows_after_recipe_filter": 16, - "rows_materialized": 16, - "rows_matched": 16, - "raw_row_keys_sample": [ - "Период", - "Регистратор", - "СчетДт", - "СчетКт", - "Сумма", - "Номенклатура", - "Склад", - "Организация", - "Количество", - "Period", - "Registrator", - "AccountDt", - "Amount" - ], - "materialization_drop_reason": "none", - "account_token_raw": null, - "account_token_normalized": null, - "account_scope_fields_checked": [ - "account_dt", - "account_kt", - "registrator", - "analytics" - ], - "account_scope_match_strategy": "account_code_regex_plus_alias_map_v1", - "account_scope_drop_reason": "not_applicable", - "runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS", - "limited_reason_category": null, - "response_type": "FACTUAL_LIST", - "requested_result_mode": "confirmed_balance", - "result_mode": "confirmed_balance", - "evidence_strength": "strong", - "balance_confirmed": true, - "as_of_date_basis": "implicit_current_snapshot", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_layer": "compute", - "capability_route_mode": "exact", - "capability_route_enabled": true, - "capability_route_reason": "inventory_on_hand_route_enabled", - "shadow_route_status": "skipped", - "route_expectation_status": "matched", - "route_expectation_reason": "route_expectation_matched", - "route_expectation_expected_selected_recipes": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "route_expectation_expected_requested_result_modes": [ - "confirmed_balance" - ], - "route_expectation_expected_result_modes": [ - "confirmed_balance" - ], - "execution_lane": "address_query", - "llm_decomposition_applied": true, - "llm_decomposition_attempted": true, - "llm_provider_used": "local", - "llm_decomposition_trace_id": "GUwBiOWS9Jln1c", - "llm_decomposition_effective_message": "анализ по общей базе компании", - "llm_decomposition_reason": "normalized_fragment_applied", - "llm_canonical_candidate_detected": true, - "llm_predecompose_contract": { - "schema_version": "address_llm_predecompose_contract_v1", - "source_message": "это по общей базе", - "canonical_message": "анализ по общей базе компании", - "mode": "address_query", - "mode_confidence": "medium", - "query_shape": "UNKNOWN", - "query_shape_confidence": "low", - "intent": "unknown", - "intent_confidence": "low", - "entities": { - "account": null, - "counterparty": null, - "contract": null, - "document_type": null, - "document_ref": null, - "organization": null - }, - "period": { - "scope": "unspecified", - "period_from": null, - "period_to": null, - "as_of_date": null, - "has_explicit_period": false - }, - "semantics": { - "scope_kind": "implicit_self_scope", - "anchor_kind": "self_scope", - "anchor_value": null, - "date_scope_kind": "implicit_current", - "date_basis_hint": "implicit_current_snapshot", - "self_scope_detected": true, - "selected_object_scope_detected": false - }, - "aggregation_profile": "unknown" - }, - "fallback_rule_hit": null, - "sanitized_user_message": "это по общей базе", - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "orchestration_contract_v1": { - "schema_version": "assistant_orchestration_contract_v1", - "hard_meta_mode": null, - "address_mode": "address_query", - "address_mode_confidence": "medium", - "address_intent": "unknown", - "address_intent_confidence": "low", - "strong_data_signal_detected": true, - "data_retrieval_signal_detected": false, - "semantic_contract_valid": true, - "semantic_apply_canonical_recommended": true, - "semantic_reason_codes": [ - "rewrite_without_structured_gain" - ], - "semantic_route_arbitration": { - "supported_address_intent_detected": false, - "strict_deep_investigation_bypass_allowed": false, - "semantic_deep_investigation_hint_detected": false, - "semantic_aggregate_shape_detected": false, - "followup_semantic_override_to_deep_allowed": false - }, - "followup_context_detected": true, - "unsupported_address_intent_fallback_to_deep": false, - "deep_analysis_signal_fallback_to_deep": false, - "aggregate_analytics_signal_fallback_to_deep": false, - "deep_session_continuation_fallback_to_deep": false, - "final_decision": { - "run_address_lane": true, - "tool_gate_decision": "run_address_lane", - "tool_gate_reason": "address_mode_classifier_detected", - "living_mode": "address_data", - "living_reason": "address_lane_triggered" - } - }, - "dialog_continuation_contract_v2": { - "schema_version": "address_dialog_continuation_contract_v2", - "source_message": "это по общей базе", - "effective_message": "анализ по общей базе компании", - "decision": "continue_previous", - "decision_reasons": [ - "followup_context_detected", - "effective_message_rewritten_by_predecompose" - ], - "followup_context_applied": true, - "previous_intent": "inventory_on_hand_as_of_date", - "target_intent": "inventory_on_hand_as_of_date", - "intent_selection_mode": "carry_previous_intent", - "anchor_type": "organization", - "anchor_value": "ООО \\Альтернатива Плюс\\", - "implicit_continuation_signal": false - }, - "address_retry_audit": { - "attempted": false, - "reason": null, - "initial_limited_category": null, - "retry_message": null, - "retry_used_followup_context": false, - "retry_result_category": null - }, - "answer_structure_v11": null, - "investigation_state_snapshot": null, - "normalized": null, - "normalizer_output": { - "trace_id": "GUwBiOWS9Jln1c", - "prompt_version": "normalizer_v2_0_2", - "applied": true, - "effective_message": "анализ по общей базе компании" - }, - "assistant_known_organizations": [ - "ООО \\Альтернатива Плюс\\" - ], - "assistant_active_organization": "ООО \\Альтернатива Плюс\\", - "address_root_frame_context": { - "root_intent": "inventory_on_hand_as_of_date", - "current_frame_kind": "inventory_root", - "organization": "ООО \\Альтернатива Плюс\\", - "as_of_date": "2019-03-31", - "period_from": "2019-03-01", - "period_to": "2019-03-31" - }, - "assistant_runtime_contract_v1": { - "schema_version": "assistant_runtime_contracts_v1", - "transition_contract_id": "T2", - "transition_contract_title": "Root Follow-Up With Date Or Scope Change", - "transition_contract_reason": [ - "root_followup_continue_previous" - ], - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_reason": [ - "debug_capability_id_matched_contract" - ], - "truth_gate_contract_status": "full_confirmed", - "carryover_eligibility": "root_only" - }, - "transition_contract_id": "T2", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "truth_gate_contract_status": "full_confirmed", - "assistant_truth_answer_policy_v1": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "truth_gate": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T2", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - } - }, - "coverage_gate_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ], - "source_truth_gate_status": "full_confirmed", - "blocked_or_limited_explanation": null - }, - "answer_shape_contract": { - "schema_version": "assistant_truth_answer_policy_runtime_v1", - "policy_owner": "assistantTruthAnswerPolicyRuntimeAdapter", - "answer_shape": "confirmed_factual", - "reply_type": "factual", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "transition_contract_id": "T2", - "may_state_confirmed_facts": true, - "must_include_limitation": false, - "may_power_followup": true, - "required_sections": [ - "direct_answer", - "evidence_basis" - ], - "downgrade_only": true - }, - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "answer_shape": "confirmed_factual", - "assistant_state_transition_v1": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T2", - "transition_title": "Root Follow-Up With Date Or Scope Change", - "application_status": "applied", - "declared_carryover_depth": "root_only", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "root_only", - "required_prior_state": [ - "root_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "update_root_frame_state", - "run_exact_route", - "refresh_coverage_gate_state" - ], - "forbidden_carryover": [ - "incompatible_selected_object_route" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "update", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_contract": { - "schema_version": "assistant_state_transition_runtime_v1", - "state_owner": "assistantStateTransitionRuntimeAdapter", - "transition_id": "T2", - "transition_title": "Root Follow-Up With Date Or Scope Change", - "application_status": "applied", - "declared_carryover_depth": "root_only", - "truth_gate_carryover_depth": "root_only", - "effective_carryover_depth": "root_only", - "required_prior_state": [ - "root_frame_state" - ], - "expected_answer_mode": "confirmed", - "state_mutations": [ - "update_root_frame_state", - "run_exact_route", - "refresh_coverage_gate_state" - ], - "forbidden_carryover": [ - "incompatible_selected_object_route" - ], - "state_actions": { - "living_mode_state": "update", - "root_frame_state": "update", - "selected_object_frame_state": "clear", - "meta_frame_state": "clear", - "clarification_state": "clear", - "coverage_gate_state": "create", - "answer_context_state": "create" - }, - "coverage_gate_state": { - "coverage_status": "full", - "evidence_grade": "strong", - "grounding_status": "grounded", - "truth_mode": "confirmed", - "carryover_eligibility": "root_only", - "reason_codes": [ - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "reason_codes": [ - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "state_transition_id": "T2", - "state_transition_status": "applied", - "effective_carryover_depth": "root_only", - "assistant_capability_binding_v1": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T2", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "as_of_date", - "organization", - "period_from", - "period_to" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_contract": { - "schema_version": "assistant_capability_runtime_binding_v1", - "binding_owner": "assistantCapabilityRuntimeBindingAdapter", - "capability_id": "confirmed_inventory_on_hand_as_of_date", - "capability_contract_id": "confirmed_inventory_on_hand_as_of_date", - "binding_status": "bound", - "binding_action": "allow", - "runtime_lane_expected": "address_exact", - "runtime_lane_observed": "address_exact", - "execution_adapter": "AddressQueryService", - "transition_id": "T2", - "transition_allowed": true, - "required_anchors": [], - "provided_anchors": [ - "sort", - "as_of_date", - "organization", - "period_from", - "period_to" - ], - "missing_anchors": [], - "requires_focus_object": false, - "focus_object_binding_status": "not_required", - "result_shape": "item_list_with_quantity_cost_warehouse_organization", - "answer_object_shape": "inventory_stock_snapshot", - "truth_gate_behavior": "partial_or_blocked_if_evidence_insufficient", - "truth_fallback_allowed": true, - "answer_shape_compatible": true, - "violations": [], - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - }, - "capability_binding_status": "bound", - "capability_binding_action": "allow", - "capability_binding_violations": [], - "capability_binding_response_guard": { - "schema_version": "assistant_capability_binding_response_guard_v1", - "guard_owner": "assistantCapabilityBindingResponseGuard", - "applied": false, - "action": "allow", - "original_reply_type": "factual", - "guarded_reply_type": "factual", - "reason_codes": [ - "binding_status_bound", - "binding_action_allow", - "transition_status_applied", - "transition_T2", - "root_followup_continue_previous", - "debug_capability_id_matched_contract", - "truth_gate_full_confirmed", - "truth_mode_confirmed", - "route_expectation_matched", - "loose_by_anchor_detected", - "shape_not_detected", - "intent_not_supported_in_v1", - "intent_from_followup_context", - "organization_from_followup_context", - "as_of_date_from_followup_context", - "period_from_followup_context", - "address_followup_context_applied", - "confirmed_balance_exact_inventory_intent" - ] - } - } - } - ], - "investigation_state": { - "schema_version": "investigation_state_v1", - "session_id": "asst-kBU5iS0mEt", - "status": "idle", - "turn_index": 0, - "updated_at": "2026-04-17T06:59:00.189Z", - "question_id": null, - "question_scope_id": null, - "scope_origin": null, - "focus": { - "domain": null, - "period": null, - "primary_accounts": [], - "active_query_subject": null - }, - "narrowing_status": "unknown", - "evidence_refs": [], - "open_uncertainties": [], - "last_answer_mode": null, - "followup_context": null, - "query_mode_hint": "direct_answer" - }, - "address_navigation_state": { - "schema_version": "address_navigation_state_v1", - "session_id": "asst-kBU5iS0mEt", - "updated_at": "2026-04-17T07:04:19.453Z", - "session_context": { - "active_result_set_id": "rs-msg-GcM8aL1yJc", - "active_focus_object": { - "object_type": "organization", - "object_id": "organization:ооо \\альтернатива плюс\\", - "label": "ООО \\Альтернатива Плюс\\", - "provenance_result_set_id": "rs-msg-GcM8aL1yJc", - "selected_at": "2026-04-17T07:04:19.453Z" - }, - "last_confirmed_route": "address_inventory_on_hand_as_of_date_v1", - "date_scope": { - "as_of_date": "2019-03-31", - "period_from": "2019-03-01", - "period_to": "2019-03-31" - }, - "organization_scope": "ООО \\Альтернатива Плюс\\" - }, - "result_sets": [ - { - "result_set_id": "rs-msg-FbPrdbojCb", - "type": "document_list", - "intent": "list_documents_by_counterparty", - "route_id": "address_documents_by_counterparty_v1", - "filters": { - "sort": "period_desc", - "limit": 20, - "counterparty": "Чепурнов П.Д." - }, - "source_refs": [ - "address_documents_by_counterparty_v1" - ], - "entity_refs": [ - { - "index": 1, - "entity_type": "document_ref", - "value": "2022-01-20T12:00:03Z" - } - ], - "created_from_turn": 1, - "created_at": "2026-04-17T06:59:13.677Z" - }, - { - "result_set_id": "rs-msg-F31DDcZwOL", - "type": "document_list", - "intent": "list_documents_by_counterparty", - "route_id": "address_documents_by_counterparty_v1", - "filters": { - "sort": "period_desc", - "limit": 20, - "counterparty": "Чепурнов П.Д." - }, - "source_refs": [ - "address_documents_by_counterparty_v1" - ], - "entity_refs": [ - { - "index": 1, - "entity_type": "document_ref", - "value": "Поступление на расчетный счет 00000000001 от 20.01.2022 12:00:03" - } - ], - "created_from_turn": 3, - "created_at": "2026-04-17T06:59:28.924Z" - }, - { - "result_set_id": "rs-msg-3BxJ--X0gY", - "type": "inventory_snapshot", - "intent": "inventory_on_hand_as_of_date", - "route_id": "address_inventory_on_hand_as_of_date_v1", - "filters": { - "sort": "period_desc", - "as_of_date": "2026-04-17", - "organization": "ООО \\Альтернатива Плюс\\" - }, - "source_refs": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "entity_refs": [ - { - "index": 1, - "entity_type": "item", - "value": "Модуль прямоугольый 1400*110*750" - }, - { - "index": 2, - "entity_type": "item", - "value": "Конструкция трансформер рабочей станции 1300*900*2000" - }, - { - "index": 3, - "entity_type": "item", - "value": "Диван трехместный" - }, - { - "index": 4, - "entity_type": "item", - "value": "Кресло орион" - }, - { - "index": 5, - "entity_type": "item", - "value": "Зеркало для инвалидов поворотное травмобезопасное" - }, - { - "index": 6, - "entity_type": "item", - "value": "Пуф арий" - }, - { - "index": 7, - "entity_type": "item", - "value": "Столешница 600*3050*26 дуб ниагара" - }, - { - "index": 8, - "entity_type": "item", - "value": "Столешница 600*3050*26 альмандин" - }, - { - "index": 9, - "entity_type": "item", - "value": "Четки Пост (84*117)" - }, - { - "index": 10, - "entity_type": "item", - "value": "Кромка с клеем 33 альмандин 137 м" - }, - { - "index": 11, - "entity_type": "item", - "value": "Кромка с клеем 33 дуб ниагара 137 м" - } - ], - "created_from_turn": 5, - "created_at": "2026-04-17T06:59:50.036Z" - }, - { - "result_set_id": "rs-msg-MXOH4cg-7h", - "type": "open_items_list", - "intent": "open_items_by_counterparty_or_contract", - "route_id": "address_open_items_by_party_or_contract_v1", - "filters": { - "sort": "period_desc", - "limit": 20, - "account": "60", - "period_from": "2022-08-01", - "period_to": "2022-08-31", - "as_of_date": "2022-08-31", - "organization": "ООО \\Альтернатива Плюс\\" - }, - "source_refs": [ - "address_open_items_by_party_or_contract_v1" - ], - "entity_refs": [], - "created_from_turn": 7, - "created_at": "2026-04-17T07:00:16.065Z" - }, - { - "result_set_id": "rs-msg-yllv_YMGcL", - "type": "inventory_snapshot", - "intent": "inventory_on_hand_as_of_date", - "route_id": "address_inventory_on_hand_as_of_date_v1", - "filters": { - "sort": "period_desc", - "period_from": "2021-03-01", - "period_to": "2021-03-31", - "as_of_date": "2021-03-31", - "organization": "ООО \\Альтернатива Плюс\\" - }, - "source_refs": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "entity_refs": [ - { - "index": 1, - "entity_type": "item", - "value": "Модуль прямоугольый 1400*110*750" - }, - { - "index": 2, - "entity_type": "item", - "value": "Конструкция трансформер рабочей станции 1300*900*2000" - }, - { - "index": 3, - "entity_type": "item", - "value": "Диван трехместный" - }, - { - "index": 4, - "entity_type": "item", - "value": "Кресло орион" - }, - { - "index": 5, - "entity_type": "item", - "value": "Зеркало для инвалидов поворотное травмобезопасное" - }, - { - "index": 6, - "entity_type": "item", - "value": "Пуф арий" - }, - { - "index": 7, - "entity_type": "item", - "value": "Столешница 600*3050*26 дуб ниагара" - }, - { - "index": 8, - "entity_type": "item", - "value": "Столешница 600*3050*26 альмандин" - }, - { - "index": 9, - "entity_type": "item", - "value": "Четки Пост (84*117)" - }, - { - "index": 10, - "entity_type": "item", - "value": "Кромка с клеем 33 альмандин 137 м" - }, - { - "index": 11, - "entity_type": "item", - "value": "Кромка с клеем 33 дуб ниагара 137 м" - } - ], - "created_from_turn": 9, - "created_at": "2026-04-17T07:00:49.064Z" - }, - { - "result_set_id": "rs-msg-ursK5G5ZoO", - "type": "inventory_snapshot", - "intent": "inventory_on_hand_as_of_date", - "route_id": "address_inventory_on_hand_as_of_date_v1", - "filters": { - "sort": "period_desc", - "as_of_date": "2021-03-31", - "organization": "ООО \\Альтернатива Плюс\\", - "item": "Столешница 600*3050*26 альмандин", - "period_from": "2021-03-01", - "period_to": "2021-03-31" - }, - "source_refs": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "entity_refs": [ - { - "index": 1, - "entity_type": "item", - "value": "Столешница 600*3050*26 альмандин" - }, - { - "index": 2, - "entity_type": "item", - "value": "Кромка с клеем 33 альмандин 137 м" - } - ], - "created_from_turn": 11, - "created_at": "2026-04-17T07:01:11.435Z" - }, - { - "result_set_id": "rs-msg-3JlrNX8e49", - "type": "inventory_trace", - "intent": "inventory_purchase_documents_for_item", - "route_id": "address_inventory_purchase_documents_for_item_v1", - "filters": { - "sort": "period_desc", - "item": "Столешница 600*3050*26 альмандин", - "organization": "ООО \\Альтернатива Плюс\\" - }, - "source_refs": [ - "address_inventory_purchase_documents_for_item_v1" - ], - "entity_refs": [ - { - "index": 1, - "entity_type": "item", - "value": "Поступление товаров и услуг 00000000003 от 12.02.2019 0:00:00" - } - ], - "created_from_turn": 13, - "created_at": "2026-04-17T07:01:52.029Z" - }, - { - "result_set_id": "rs-msg-G6BtQFSdJv", - "type": "inventory_snapshot", - "intent": "inventory_on_hand_as_of_date", - "route_id": "address_inventory_on_hand_as_of_date_v1", - "filters": { - "sort": "period_desc", - "as_of_date": "2021-03-31", - "organization": "ООО \\Альтернатива Плюс\\", - "period_from": "2021-03-01", - "period_to": "2021-03-31" - }, - "source_refs": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "entity_refs": [], - "created_from_turn": 15, - "created_at": "2026-04-17T07:02:19.571Z" - }, - { - "result_set_id": "rs-msg-U3T1-nXZm8", - "type": "inventory_snapshot", - "intent": "inventory_on_hand_as_of_date", - "route_id": "address_inventory_on_hand_as_of_date_v1", - "filters": { - "sort": "period_desc", - "period_from": "2016-03-01", - "period_to": "2016-03-31", - "as_of_date": "2016-03-31", - "organization": "ООО \\Альтернатива Плюс\\" - }, - "source_refs": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "entity_refs": [ - { - "index": 1, - "entity_type": "item", - "value": "Шкаф для одежды 824*437*2010" - }, - { - "index": 2, - "entity_type": "item", - "value": "Рабочая станция универсального специалиста (индивидуальное изготовление)" - } - ], - "created_from_turn": 17, - "created_at": "2026-04-17T07:03:01.200Z" - }, - { - "result_set_id": "rs-msg-WTR742ctqv", - "type": "inventory_snapshot", - "intent": "inventory_on_hand_as_of_date", - "route_id": "address_inventory_on_hand_as_of_date_v1", - "filters": { - "sort": "period_desc", - "period_from": "2019-07-01", - "period_to": "2019-07-31", - "as_of_date": "2019-07-31", - "organization": "ООО \\Альтернатива Плюс\\" - }, - "source_refs": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "entity_refs": [ - { - "index": 1, - "entity_type": "item", - "value": "Подсветка" - }, - { - "index": 2, - "entity_type": "item", - "value": "Секция мобильная. Тип 1." - }, - { - "index": 3, - "entity_type": "item", - "value": "Секция монолитная. Тип 1" - }, - { - "index": 4, - "entity_type": "item", - "value": "Модуль прямоугольый 1400*110*750" - }, - { - "index": 5, - "entity_type": "item", - "value": "Моноблок леново" - }, - { - "index": 6, - "entity_type": "item", - "value": "Принтер НР М203" - }, - { - "index": 7, - "entity_type": "item", - "value": "Источник бесперебойного питания" - }, - { - "index": 8, - "entity_type": "item", - "value": "Шкаф для одежды 824*437*2010" - }, - { - "index": 9, - "entity_type": "item", - "value": "Модульная система хранения гардеробная. Тип 1" - }, - { - "index": 10, - "entity_type": "item", - "value": "Конструкция трансформер рабочей станции. Тип 2" - }, - { - "index": 11, - "entity_type": "item", - "value": "Диван трехместный" - }, - { - "index": 12, - "entity_type": "item", - "value": "Кресло орион" - }, - { - "index": 13, - "entity_type": "item", - "value": "Пуф арий" - }, - { - "index": 14, - "entity_type": "item", - "value": "Столешница 600*3050*26 дуб ниагара" - }, - { - "index": 15, - "entity_type": "item", - "value": "Столешница 600*3050*26 альмандин" - }, - { - "index": 16, - "entity_type": "item", - "value": "Четки Пост (84*117)" - }, - { - "index": 17, - "entity_type": "item", - "value": "Кромка с клеем 33 альмандин 137 м" - }, - { - "index": 18, - "entity_type": "item", - "value": "Кромка с клеем 33 дуб ниагара 137 м" - } - ], - "created_from_turn": 19, - "created_at": "2026-04-17T07:03:15.384Z" - }, - { - "result_set_id": "rs-msg-fYRfbQICPz", - "type": "inventory_snapshot", - "intent": "inventory_on_hand_as_of_date", - "route_id": "address_inventory_on_hand_as_of_date_v1", - "filters": { - "sort": "period_desc", - "as_of_date": "2019-09-30", - "organization": "ООО \\Альтернатива Плюс\\", - "period_from": "2019-09-01", - "period_to": "2019-09-30" - }, - "source_refs": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "entity_refs": [ - { - "index": 1, - "entity_type": "item", - "value": "Подсветка" - }, - { - "index": 2, - "entity_type": "item", - "value": "Модуль прямоугольый 1400*110*750" - }, - { - "index": 3, - "entity_type": "item", - "value": "Шкаф для одежды 824*437*2010" - }, - { - "index": 4, - "entity_type": "item", - "value": "Диван трехместный" - }, - { - "index": 5, - "entity_type": "item", - "value": "Кресло орион" - }, - { - "index": 6, - "entity_type": "item", - "value": "Пуф арий" - }, - { - "index": 7, - "entity_type": "item", - "value": "Столешница 600*3050*26 дуб ниагара" - }, - { - "index": 8, - "entity_type": "item", - "value": "Столешница 600*3050*26 альмандин" - }, - { - "index": 9, - "entity_type": "item", - "value": "Четки Пост (84*117)" - }, - { - "index": 10, - "entity_type": "item", - "value": "Кромка с клеем 33 альмандин 137 м" - }, - { - "index": 11, - "entity_type": "item", - "value": "Кромка с клеем 33 дуб ниагара 137 м" - } - ], - "created_from_turn": 21, - "created_at": "2026-04-17T07:03:39.788Z" - }, - { - "result_set_id": "rs-msg-eV8Drg_UC9", - "type": "inventory_snapshot", - "intent": "inventory_on_hand_as_of_date", - "route_id": "address_inventory_on_hand_as_of_date_v1", - "filters": { - "sort": "period_desc", - "as_of_date": "2019-03-31", - "organization": "ООО \\Альтернатива Плюс\\", - "period_from": "2019-03-01", - "period_to": "2019-03-31" - }, - "source_refs": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "entity_refs": [ - { - "index": 1, - "entity_type": "item", - "value": "Подсветка" - }, - { - "index": 2, - "entity_type": "item", - "value": "Модуль на монолитном каркасе. Тип 1" - }, - { - "index": 3, - "entity_type": "item", - "value": "Модуль прямоугольый 1400*110*750" - }, - { - "index": 4, - "entity_type": "item", - "value": "Модуль на монолитном каркасе передвижной. Тип 1." - }, - { - "index": 5, - "entity_type": "item", - "value": "Моноблок леново" - }, - { - "index": 6, - "entity_type": "item", - "value": "Принтер НР М203" - }, - { - "index": 7, - "entity_type": "item", - "value": "Источник бесперебойного питания" - }, - { - "index": 8, - "entity_type": "item", - "value": "Шкаф для одежды 824*437*2010" - }, - { - "index": 9, - "entity_type": "item", - "value": "Диван трехместный" - }, - { - "index": 10, - "entity_type": "item", - "value": "Кресло орион" - }, - { - "index": 11, - "entity_type": "item", - "value": "Пуф арий" - }, - { - "index": 12, - "entity_type": "item", - "value": "Столешница 600*3050*26 дуб ниагара" - }, - { - "index": 13, - "entity_type": "item", - "value": "Столешница 600*3050*26 альмандин" - }, - { - "index": 14, - "entity_type": "item", - "value": "Четки Пост (84*117)" - }, - { - "index": 15, - "entity_type": "item", - "value": "Кромка с клеем 33 альмандин 137 м" - }, - { - "index": 16, - "entity_type": "item", - "value": "Кромка с клеем 33 дуб ниагара 137 м" - } - ], - "created_from_turn": 23, - "created_at": "2026-04-17T07:04:01.195Z" - }, - { - "result_set_id": "rs-msg-GcM8aL1yJc", - "type": "inventory_snapshot", - "intent": "inventory_on_hand_as_of_date", - "route_id": "address_inventory_on_hand_as_of_date_v1", - "filters": { - "sort": "period_desc", - "as_of_date": "2019-03-31", - "organization": "ООО \\Альтернатива Плюс\\", - "period_from": "2019-03-01", - "period_to": "2019-03-31" - }, - "source_refs": [ - "address_inventory_on_hand_as_of_date_v1" - ], - "entity_refs": [ - { - "index": 1, - "entity_type": "item", - "value": "Подсветка" - }, - { - "index": 2, - "entity_type": "item", - "value": "Модуль на монолитном каркасе. Тип 1" - }, - { - "index": 3, - "entity_type": "item", - "value": "Модуль прямоугольый 1400*110*750" - }, - { - "index": 4, - "entity_type": "item", - "value": "Модуль на монолитном каркасе передвижной. Тип 1." - }, - { - "index": 5, - "entity_type": "item", - "value": "Моноблок леново" - }, - { - "index": 6, - "entity_type": "item", - "value": "Принтер НР М203" - }, - { - "index": 7, - "entity_type": "item", - "value": "Источник бесперебойного питания" - }, - { - "index": 8, - "entity_type": "item", - "value": "Шкаф для одежды 824*437*2010" - }, - { - "index": 9, - "entity_type": "item", - "value": "Диван трехместный" - }, - { - "index": 10, - "entity_type": "item", - "value": "Кресло орион" - }, - { - "index": 11, - "entity_type": "item", - "value": "Пуф арий" - }, - { - "index": 12, - "entity_type": "item", - "value": "Столешница 600*3050*26 дуб ниагара" - }, - { - "index": 13, - "entity_type": "item", - "value": "Столешница 600*3050*26 альмандин" - }, - { - "index": 14, - "entity_type": "item", - "value": "Четки Пост (84*117)" - }, - { - "index": 15, - "entity_type": "item", - "value": "Кромка с клеем 33 альмандин 137 м" - }, - { - "index": 16, - "entity_type": "item", - "value": "Кромка с клеем 33 дуб ниагара 137 м" - } - ], - "created_from_turn": 25, - "created_at": "2026-04-17T07:04:19.453Z" - } - ], - "navigation_history": [ - { - "event_id": "nav-YmhSdHpzBl", - "action": "open", - "source_result_set_id": null, - "target_object_id": "counterparty:чепурнов п.д.", - "derived_result_set_id": "rs-msg-FbPrdbojCb", - "turn_index": 1, - "created_at": "2026-04-17T06:59:13.677Z" - }, - { - "event_id": "nav-U-0Ob8-Wxb", - "action": "open", - "source_result_set_id": "rs-msg-FbPrdbojCb", - "target_object_id": "counterparty:чепурнов п.д.", - "derived_result_set_id": "rs-msg-F31DDcZwOL", - "turn_index": 3, - "created_at": "2026-04-17T06:59:28.924Z" - }, - { - "event_id": "nav-kXjQouHEvP", - "action": "open", - "source_result_set_id": "rs-msg-F31DDcZwOL", - "target_object_id": null, - "derived_result_set_id": "rs-msg-3BxJ--X0gY", - "turn_index": 5, - "created_at": "2026-04-17T06:59:50.036Z" - }, - { - "event_id": "nav-JDr1Tuby_3", - "action": "open", - "source_result_set_id": "rs-msg-3BxJ--X0gY", - "target_object_id": "organization:ооо \\альтернатива плюс\\", - "derived_result_set_id": "rs-msg-MXOH4cg-7h", - "turn_index": 7, - "created_at": "2026-04-17T07:00:16.065Z" - }, - { - "event_id": "nav-tPireHieCq", - "action": "open", - "source_result_set_id": "rs-msg-MXOH4cg-7h", - "target_object_id": "organization:ооо \\альтернатива плюс\\", - "derived_result_set_id": "rs-msg-yllv_YMGcL", - "turn_index": 9, - "created_at": "2026-04-17T07:00:49.064Z" - }, - { - "event_id": "nav-bp6gS4sq3j", - "action": "drilldown", - "source_result_set_id": "rs-msg-yllv_YMGcL", - "target_object_id": "organization:ооо \\альтернатива плюс\\", - "derived_result_set_id": "rs-msg-ursK5G5ZoO", - "turn_index": 11, - "created_at": "2026-04-17T07:01:11.435Z" - }, - { - "event_id": "nav-evQf0N6Gkk", - "action": "drilldown", - "source_result_set_id": "rs-msg-ursK5G5ZoO", - "target_object_id": "item:столешница 600*3050*26 альмандин", - "derived_result_set_id": "rs-msg-3JlrNX8e49", - "turn_index": 13, - "created_at": "2026-04-17T07:01:52.029Z" - }, - { - "event_id": "nav-DhBjSUIz7H", - "action": "drilldown", - "source_result_set_id": "rs-msg-3JlrNX8e49", - "target_object_id": "organization:ооо \\альтернатива плюс\\", - "derived_result_set_id": "rs-msg-G6BtQFSdJv", - "turn_index": 15, - "created_at": "2026-04-17T07:02:19.571Z" - }, - { - "event_id": "nav-rbeNIjhdc4", - "action": "drilldown", - "source_result_set_id": "rs-msg-G6BtQFSdJv", - "target_object_id": "organization:ооо \\альтернатива плюс\\", - "derived_result_set_id": "rs-msg-U3T1-nXZm8", - "turn_index": 17, - "created_at": "2026-04-17T07:03:01.200Z" - }, - { - "event_id": "nav-qxXvPocs3g", - "action": "drilldown", - "source_result_set_id": "rs-msg-U3T1-nXZm8", - "target_object_id": "organization:ооо \\альтернатива плюс\\", - "derived_result_set_id": "rs-msg-WTR742ctqv", - "turn_index": 19, - "created_at": "2026-04-17T07:03:15.384Z" - }, - { - "event_id": "nav-2pqCjY7jPi", - "action": "drilldown", - "source_result_set_id": "rs-msg-WTR742ctqv", - "target_object_id": "organization:ооо \\альтернатива плюс\\", - "derived_result_set_id": "rs-msg-fYRfbQICPz", - "turn_index": 21, - "created_at": "2026-04-17T07:03:39.788Z" - }, - { - "event_id": "nav-BoSkITaptR", - "action": "drilldown", - "source_result_set_id": "rs-msg-fYRfbQICPz", - "target_object_id": "organization:ооо \\альтернатива плюс\\", - "derived_result_set_id": "rs-msg-eV8Drg_UC9", - "turn_index": 23, - "created_at": "2026-04-17T07:04:01.195Z" - }, - { - "event_id": "nav-65j4e6ilHC", - "action": "drilldown", - "source_result_set_id": "rs-msg-eV8Drg_UC9", - "target_object_id": "organization:ооо \\альтернатива плюс\\", - "derived_result_set_id": "rs-msg-GcM8aL1yJc", - "turn_index": 25, - "created_at": "2026-04-17T07:04:19.453Z" - } - ] - } - } -} \ No newline at end of file diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260424140630_gen-ag04241406-abe4d8.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260424140630_gen-ag04241406-abe4d8.json deleted file mode 100644 index ea511d0..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260424140630_gen-ag04241406-abe4d8.json +++ /dev/null @@ -1,353 +0,0 @@ -{ - "saved_at": "2026-04-24T14:06:30+00:00", - "generation_id": "gen-ag04241406-abe4d8", - "mode": "saved_user_sessions", - "title": "AGENT | Post-F cross-stage semantic integrity canary", - "agent_run": true, - "questions": [ - "Мне нужно понять, где в 1С по НДС вообще лежат данные. Какие объекты стоит смотреть по НДС?", - "Хорошо, тогда покажи движения по ООО Альтернатива Плюс.", - "За 2020 год.", - "А теперь по документам?", - "А теперь за 2021 год?", - "А теперь за все время?", - "С НДС закончили. Новая тема: покажи документы по Жуковке 51.", - "Хорошо, а теперь платежи по нему тоже покажи.", - "А по нему договоры?", - "А по нему документы?", - "А за 2021?", - "С Жуковкой закончили. Теперь другая задача: быстрый денежный срез по одной организации. Если для ответа нужна организация, просто уточни ее. Сколько вообще входящих денег было за 2020 год?", - "По ООО Альтернатива Плюс.", - "Понял, тогда за все время.", - "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?", - "И кто больше всего принес денег этой организации в 2020 году?", - "А в 2021 году?", - "Теперь отдельная тема по конкретному контрагенту. Найди в 1С Группу СВК.", - "Сколько получили по нему за 2020 год?", - "А теперь сколько заплатили?", - "А какое нетто?", - "А по документам?", - "А по движениям?", - "А теперь тот же смысл за 2021 год." - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "cross-stage canary: VAT metadata, numeric counterparty suffix, open organization value-flow, SVK grounded reset", - "architecture_phase": "Post-F Semantic Integrity Hardening", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_post_f_cross_stage_canary_agent_20260424.json", - "scenario_id": "address_truth_harness_post_f_cross_stage_canary_agent_20260424", - "semantic_tags": [ - "account_injection_guard", - "all_time_followup", - "bidirectional_value_flow", - "clarification_resume", - "contracts_followup", - "counterparty_pronoun_resolution", - "cross_stage_canary", - "document_lane_continuity", - "document_pivot_after_movement", - "documents_followup", - "documents_pivot", - "grounded_counterparty", - "incoming_value_flow", - "legacy_phase39", - "legacy_phase64", - "legacy_phase67", - "metadata_surface", - "movement_execution", - "movement_lane_after_metadata", - "movements_pivot", - "net_value_flow", - "numeric_counterparty_suffix", - "open_scope_total", - "organization_clarification", - "organization_scope", - "payments_followup", - "payout_value_flow", - "period_clarification_resume", - "post_f", - "repeated_pivot", - "scope_reuse", - "topic_reset", - "value_flow_ranking", - "vat_orientation", - "year_switch", - "year_switch_after_document_pivot", - "year_switch_after_repeated_pivot" - ] - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "Мне нужно понять, где в 1С по НДС вообще лежат данные. Какие объекты стоит смотреть по НДС?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "Хорошо, тогда покажи движения по ООО Альтернатива Плюс.", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "За 2020 год.", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "А теперь по документам?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-005", - "role": "user", - "text": "А теперь за 2021 год?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-006", - "role": "user", - "text": "А теперь за все время?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-007", - "role": "user", - "text": "С НДС закончили. Новая тема: покажи документы по Жуковке 51.", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-008", - "role": "user", - "text": "Хорошо, а теперь платежи по нему тоже покажи.", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-009", - "role": "user", - "text": "А по нему договоры?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-010", - "role": "user", - "text": "А по нему документы?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-011", - "role": "user", - "text": "А за 2021?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-012", - "role": "user", - "text": "С Жуковкой закончили. Теперь другая задача: быстрый денежный срез по одной организации. Если для ответа нужна организация, просто уточни ее. Сколько вообще входящих денег было за 2020 год?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-013", - "role": "user", - "text": "По ООО Альтернатива Плюс.", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-014", - "role": "user", - "text": "Понял, тогда за все время.", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-015", - "role": "user", - "text": "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-016", - "role": "user", - "text": "И кто больше всего принес денег этой организации в 2020 году?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-017", - "role": "user", - "text": "А в 2021 году?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-018", - "role": "user", - "text": "Теперь отдельная тема по конкретному контрагенту. Найди в 1С Группу СВК.", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-019", - "role": "user", - "text": "Сколько получили по нему за 2020 год?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-020", - "role": "user", - "text": "А теперь сколько заплатили?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-021", - "role": "user", - "text": "А какое нетто?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-022", - "role": "user", - "text": "А по документам?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-023", - "role": "user", - "text": "А по движениям?", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-024", - "role": "user", - "text": "А теперь тот же смысл за 2021 год.", - "created_at": "2026-04-24T14:06:30+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "cross-stage canary: VAT metadata, numeric counterparty suffix, open organization value-flow, SVK grounded reset", - "architecture_phase": "Post-F Semantic Integrity Hardening", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_post_f_cross_stage_canary_agent_20260424.json", - "scenario_id": "address_truth_harness_post_f_cross_stage_canary_agent_20260424", - "semantic_tags": [ - "account_injection_guard", - "all_time_followup", - "bidirectional_value_flow", - "clarification_resume", - "contracts_followup", - "counterparty_pronoun_resolution", - "cross_stage_canary", - "document_lane_continuity", - "document_pivot_after_movement", - "documents_followup", - "documents_pivot", - "grounded_counterparty", - "incoming_value_flow", - "legacy_phase39", - "legacy_phase64", - "legacy_phase67", - "metadata_surface", - "movement_execution", - "movement_lane_after_metadata", - "movements_pivot", - "net_value_flow", - "numeric_counterparty_suffix", - "open_scope_total", - "organization_clarification", - "organization_scope", - "payments_followup", - "payout_value_flow", - "period_clarification_resume", - "post_f", - "repeated_pivot", - "scope_reuse", - "topic_reset", - "value_flow_ranking", - "vat_orientation", - "year_switch", - "year_switch_after_document_pivot", - "year_switch_after_repeated_pivot" - ] - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260424171031_gen-ag04241710-bdb248.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260424171031_gen-ag04241710-bdb248.json deleted file mode 100644 index fa66015..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260424171031_gen-ag04241710-bdb248.json +++ /dev/null @@ -1,177 +0,0 @@ -{ - "saved_at": "2026-04-24T17:10:31+00:00", - "generation_id": "gen-ag04241710-bdb248", - "mode": "saved_user_sessions", - "title": "AGENT | Post-F ручные провалы VAT revenue item-flow live3", - "agent_run": true, - "questions": [ - "кайф - что там на складе по остаткам?", - "АЛЬТЕРНАТИВА", - "март 2016", - "По выбранному объекту \"Рабочая станция универсального специалиста (индивидуальное изготовление)\": где взяли это?", - "ндс можешь прикинуть на дату покупки рабочей станции?", - "прикинь какой ндс нам надо заплатить на февраль 2017", - "кто у нас самый доходный клиент за все время", - "по чепурнову покажи все доки", - "а по свк", - "а сейчас у нас есть что на складе?", - "что нам отгружал чепурнов? какой товар или услугу?" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "manual failures 11/13/14/26 from assistant-stage1-9liEOh-7JP", - "architecture_phase": "Post-F Semantic Integrity Hardening", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_post_f_manual_failures_20260424.json", - "scenario_id": "address_truth_harness_post_f_manual_failures_20260424", - "semantic_tags": [ - "counterparty_grounding", - "counterparty_retarget", - "inventory_context", - "item_flow_failure_26", - "manual_9liEOh", - "materialization_gap", - "organization_scope", - "purchase_date_context", - "revenue_ranking_failure_14", - "selected_object_purchase", - "stale_inventory_scope", - "stale_scope_guard", - "vat_failure_11", - "vat_failure_13" - ] - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "кайф - что там на складе по остаткам?", - "created_at": "2026-04-24T17:10:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "АЛЬТЕРНАТИВА", - "created_at": "2026-04-24T17:10:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "март 2016", - "created_at": "2026-04-24T17:10:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "По выбранному объекту \"Рабочая станция универсального специалиста (индивидуальное изготовление)\": где взяли это?", - "created_at": "2026-04-24T17:10:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-005", - "role": "user", - "text": "ндс можешь прикинуть на дату покупки рабочей станции?", - "created_at": "2026-04-24T17:10:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-006", - "role": "user", - "text": "прикинь какой ндс нам надо заплатить на февраль 2017", - "created_at": "2026-04-24T17:10:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-007", - "role": "user", - "text": "кто у нас самый доходный клиент за все время", - "created_at": "2026-04-24T17:10:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-008", - "role": "user", - "text": "по чепурнову покажи все доки", - "created_at": "2026-04-24T17:10:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-009", - "role": "user", - "text": "а по свк", - "created_at": "2026-04-24T17:10:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-010", - "role": "user", - "text": "а сейчас у нас есть что на складе?", - "created_at": "2026-04-24T17:10:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-011", - "role": "user", - "text": "что нам отгружал чепурнов? какой товар или услугу?", - "created_at": "2026-04-24T17:10:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "manual failures 11/13/14/26 from assistant-stage1-9liEOh-7JP", - "architecture_phase": "Post-F Semantic Integrity Hardening", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_post_f_manual_failures_20260424.json", - "scenario_id": "address_truth_harness_post_f_manual_failures_20260424", - "semantic_tags": [ - "counterparty_grounding", - "counterparty_retarget", - "inventory_context", - "item_flow_failure_26", - "manual_9liEOh", - "materialization_gap", - "organization_scope", - "purchase_date_context", - "revenue_ranking_failure_14", - "selected_object_purchase", - "stale_inventory_scope", - "stale_scope_guard", - "vat_failure_11", - "vat_failure_13" - ] - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260510094921_gen-ag05100949-2a5ed8.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260510094921_gen-ag05100949-2a5ed8.json deleted file mode 100644 index 958b987..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260510094921_gen-ag05100949-2a5ed8.json +++ /dev/null @@ -1,153 +0,0 @@ -{ - "saved_at": "2026-05-10T09:49:21+00:00", - "generation_id": "gen-ag05100949-2a5ed8", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 91 route-candidate-driven enablement loop canary", - "agent_run": true, - "questions": [ - "какой контрагент принес больше всего денег за 2020 год?", - "ООО Альтернатива Плюс", - "а теперь сколько лет мы работаем с Группа СВК?", - "покажи движения по НДС за 2020 по ООО Альтернатива Плюс", - "можно ли по этим данным точно подтвердить резерв под неликвиды на складе?" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "route candidate repair-target grouping + handoff canary", - "architecture_phase": "Route-Candidate-Driven Enablement Loop", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase91_route_candidate_driven_enablement_loop.json", - "scenario_id": "address_truth_harness_phase91_route_candidate_driven_enablement_loop", - "semantic_tags": [ - "clarification_recovery", - "counterparty_lifecycle", - "inventory_reserve_boundary", - "metadata_scope", - "movement_evidence", - "needs_user_scope", - "no_overclaim", - "open_organization_scope", - "ready_for_reviewed_execution", - "route_candidate_handoff", - "stale_scope_guard", - "unreviewed_proof_family", - "value_flow_ranking", - "vat" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\address_truth_harness_phase91_route_candidate_driven_enablement_loop_live1_20260510", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\address_truth_harness_phase91_route_candidate_driven_enablement_loop_live1_20260510", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 5, - "steps_passed": 5, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "какой контрагент принес больше всего денег за 2020 год?", - "created_at": "2026-05-10T09:49:21+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "ООО Альтернатива Плюс", - "created_at": "2026-05-10T09:49:21+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "а теперь сколько лет мы работаем с Группа СВК?", - "created_at": "2026-05-10T09:49:21+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "покажи движения по НДС за 2020 по ООО Альтернатива Плюс", - "created_at": "2026-05-10T09:49:21+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-005", - "role": "user", - "text": "можно ли по этим данным точно подтвердить резерв под неликвиды на складе?", - "created_at": "2026-05-10T09:49:21+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "route candidate repair-target grouping + handoff canary", - "architecture_phase": "Route-Candidate-Driven Enablement Loop", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase91_route_candidate_driven_enablement_loop.json", - "scenario_id": "address_truth_harness_phase91_route_candidate_driven_enablement_loop", - "semantic_tags": [ - "clarification_recovery", - "counterparty_lifecycle", - "inventory_reserve_boundary", - "metadata_scope", - "movement_evidence", - "needs_user_scope", - "no_overclaim", - "open_organization_scope", - "ready_for_reviewed_execution", - "route_candidate_handoff", - "stale_scope_guard", - "unreviewed_proof_family", - "value_flow_ranking", - "vat" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\address_truth_harness_phase91_route_candidate_driven_enablement_loop_live1_20260510", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\address_truth_harness_phase91_route_candidate_driven_enablement_loop_live1_20260510", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 5, - "steps_passed": 5, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260510121326_gen-ag05101213-596d99.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260510121326_gen-ag05101213-596d99.json deleted file mode 100644 index 457ba33..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260510121326_gen-ag05101213-596d99.json +++ /dev/null @@ -1,157 +0,0 @@ -{ - "saved_at": "2026-05-10T12:13:26+00:00", - "generation_id": "gen-ag05101213-596d99", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 93 accounting profit-margin reviewed route", - "agent_run": true, - "questions": [ - "по ООО Альтернатива Плюс за 2020 можно точно сказать чистую прибыль и маржу?", - "а это прибыль или убыток, коротко?", - "по этой же компании на конец 2020 можно точно понять, какая дебиторка просрочена?", - "тогда НДС за 2020 по ООО Альтернатива Плюс какой?", - "а какой контрагент принес больше всего денег за 2020?", - "по ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "accounting profit-margin reviewed route", - "architecture_phase": "Route-Candidate-Driven Enablement Loop", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase93_accounting_profit_margin_reviewed_route.json", - "scenario_id": "address_truth_harness_phase93_accounting_profit_margin_reviewed_route", - "semantic_tags": [ - "accounting_profit_margin", - "business_overview", - "context_carryover", - "debt_due_date_boundary", - "inventory_reserve_boundary", - "missing_proof_families", - "needs_route_enablement", - "profit_margin_boundary", - "ready_for_reviewed_execution", - "value_flow_ranking", - "vat_continuity" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\address_truth_harness_phase93_accounting_profit_margin_reviewed_route_live3_20260510", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\address_truth_harness_phase93_accounting_profit_margin_reviewed_route_live3_20260510", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 6, - "steps_passed": 6, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "по ООО Альтернатива Плюс за 2020 можно точно сказать чистую прибыль и маржу?", - "created_at": "2026-05-10T12:13:26+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "а это прибыль или убыток, коротко?", - "created_at": "2026-05-10T12:13:26+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "по этой же компании на конец 2020 можно точно понять, какая дебиторка просрочена?", - "created_at": "2026-05-10T12:13:26+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "тогда НДС за 2020 по ООО Альтернатива Плюс какой?", - "created_at": "2026-05-10T12:13:26+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-005", - "role": "user", - "text": "а какой контрагент принес больше всего денег за 2020?", - "created_at": "2026-05-10T12:13:26+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-006", - "role": "user", - "text": "по ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?", - "created_at": "2026-05-10T12:13:26+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "accounting profit-margin reviewed route", - "architecture_phase": "Route-Candidate-Driven Enablement Loop", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase93_accounting_profit_margin_reviewed_route.json", - "scenario_id": "address_truth_harness_phase93_accounting_profit_margin_reviewed_route", - "semantic_tags": [ - "accounting_profit_margin", - "business_overview", - "context_carryover", - "debt_due_date_boundary", - "inventory_reserve_boundary", - "missing_proof_families", - "needs_route_enablement", - "profit_margin_boundary", - "ready_for_reviewed_execution", - "value_flow_ranking", - "vat_continuity" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\address_truth_harness_phase93_accounting_profit_margin_reviewed_route_live3_20260510", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\address_truth_harness_phase93_accounting_profit_margin_reviewed_route_live3_20260510", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 6, - "steps_passed": 6, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260510131922_gen-ag05101319-c04f79.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260510131922_gen-ag05101319-c04f79.json deleted file mode 100644 index adef4ef..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260510131922_gen-ag05101319-c04f79.json +++ /dev/null @@ -1,173 +0,0 @@ -{ - "saved_at": "2026-05-10T13:19:22+00:00", - "generation_id": "gen-ag05101319-c04f79", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 94 debt due-date aging reviewed route", - "agent_run": true, - "questions": [ - "по ООО Альтернатива Плюс на конец 2020 можно точно понять, какая дебиторка просрочена?", - "то есть просрочку доказать нельзя, коротко почему?", - "а чистая прибыль и маржа за 2020 по этой же компании какие?", - "НДС за 2020 по ООО Альтернатива Плюс какой?", - "а кто принес больше всего денег за 2020?", - "по ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?", - "а зависимость от одного поставщика за 2020 можно точно оценить?" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Focused semantic replay for promoting debt_due_date_aging_quality from proxy-only enablement to a reviewed payment-term/open-balance route while preserving profit, VAT, inventory, and vendor-risk boundaries.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase94_debt_due_date_aging_reviewed_route.json", - "scenario_id": "address_truth_harness_phase94_debt_due_date_aging_reviewed_route", - "semantic_tags": [ - "accounting_profit_margin", - "business_overview", - "canary", - "checked_negative", - "context_carryover", - "debt_due_date_aging_quality", - "debt_due_date_boundary", - "inventory_reserve_boundary", - "missing_proof_families", - "profit_margin_boundary", - "ready_for_reviewed_execution", - "value_flow_ranking", - "vat_continuity", - "vendor_risk_procurement_boundary" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase94_debt_due_date_aging_reviewed_route_live4", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase94_debt_due_date_aging_reviewed_route_live4", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 7, - "steps_passed": 7, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "по ООО Альтернатива Плюс на конец 2020 можно точно понять, какая дебиторка просрочена?", - "created_at": "2026-05-10T13:19:22+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "то есть просрочку доказать нельзя, коротко почему?", - "created_at": "2026-05-10T13:19:22+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "а чистая прибыль и маржа за 2020 по этой же компании какие?", - "created_at": "2026-05-10T13:19:22+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "НДС за 2020 по ООО Альтернатива Плюс какой?", - "created_at": "2026-05-10T13:19:22+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-005", - "role": "user", - "text": "а кто принес больше всего денег за 2020?", - "created_at": "2026-05-10T13:19:22+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-006", - "role": "user", - "text": "по ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?", - "created_at": "2026-05-10T13:19:22+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-007", - "role": "user", - "text": "а зависимость от одного поставщика за 2020 можно точно оценить?", - "created_at": "2026-05-10T13:19:22+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Focused semantic replay for promoting debt_due_date_aging_quality from proxy-only enablement to a reviewed payment-term/open-balance route while preserving profit, VAT, inventory, and vendor-risk boundaries.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase94_debt_due_date_aging_reviewed_route.json", - "scenario_id": "address_truth_harness_phase94_debt_due_date_aging_reviewed_route", - "semantic_tags": [ - "accounting_profit_margin", - "business_overview", - "canary", - "checked_negative", - "context_carryover", - "debt_due_date_aging_quality", - "debt_due_date_boundary", - "inventory_reserve_boundary", - "missing_proof_families", - "profit_margin_boundary", - "ready_for_reviewed_execution", - "value_flow_ranking", - "vat_continuity", - "vendor_risk_procurement_boundary" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase94_debt_due_date_aging_reviewed_route_live4", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase94_debt_due_date_aging_reviewed_route_live4", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 7, - "steps_passed": 7, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260512135726_gen-ag05121357-9ea5d6.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260512135726_gen-ag05121357-9ea5d6.json deleted file mode 100644 index 6ce23d7..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260512135726_gen-ag05121357-9ea5d6.json +++ /dev/null @@ -1,173 +0,0 @@ -{ - "saved_at": "2026-05-12T13:57:26+00:00", - "generation_id": "gen-ag05121357-9ea5d6", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 95 vendor/procurement quality reviewed route", - "agent_run": true, - "questions": [ - "по ООО Альтернатива Плюс за 2020 есть ли риск, что мы зависим от одного поставщика?", - "а банк из этого ответа считать обычным поставщиком?", - "по этой же компании на конец 2020 можно точно понять, какая дебиторка просрочена?", - "а чистая прибыль и маржа за 2020 какие?", - "НДС за 2020 по ООО Альтернатива Плюс какой?", - "а кто принес больше всего денег за 2020?", - "по ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Focused semantic replay for promoting vendor_risk_procurement_quality from proxy-only enablement to reviewed procurement-concentration evidence while preserving debt, profit, VAT, value-flow, and inventory reserve canaries.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase95_vendor_procurement_quality_reviewed_route.json", - "scenario_id": "address_truth_harness_phase95_vendor_procurement_quality_reviewed_route", - "semantic_tags": [ - "accounting_profit_margin", - "business_overview", - "canary", - "context_carryover", - "debt_due_date_boundary", - "financial_institution_boundary", - "inventory_reserve_boundary", - "missing_proof_families", - "profit_margin_boundary", - "ready_for_reviewed_execution", - "value_flow_ranking", - "vat_continuity", - "vendor_risk_procurement_boundary", - "vendor_risk_procurement_quality" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase95_vendor_procurement_quality_reviewed_route_live2", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase95_vendor_procurement_quality_reviewed_route_live2", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 7, - "steps_passed": 7, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "по ООО Альтернатива Плюс за 2020 есть ли риск, что мы зависим от одного поставщика?", - "created_at": "2026-05-12T13:57:26+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "а банк из этого ответа считать обычным поставщиком?", - "created_at": "2026-05-12T13:57:26+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "по этой же компании на конец 2020 можно точно понять, какая дебиторка просрочена?", - "created_at": "2026-05-12T13:57:26+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "а чистая прибыль и маржа за 2020 какие?", - "created_at": "2026-05-12T13:57:26+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-005", - "role": "user", - "text": "НДС за 2020 по ООО Альтернатива Плюс какой?", - "created_at": "2026-05-12T13:57:26+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-006", - "role": "user", - "text": "а кто принес больше всего денег за 2020?", - "created_at": "2026-05-12T13:57:26+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-007", - "role": "user", - "text": "по ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?", - "created_at": "2026-05-12T13:57:26+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Focused semantic replay for promoting vendor_risk_procurement_quality from proxy-only enablement to reviewed procurement-concentration evidence while preserving debt, profit, VAT, value-flow, and inventory reserve canaries.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase95_vendor_procurement_quality_reviewed_route.json", - "scenario_id": "address_truth_harness_phase95_vendor_procurement_quality_reviewed_route", - "semantic_tags": [ - "accounting_profit_margin", - "business_overview", - "canary", - "context_carryover", - "debt_due_date_boundary", - "financial_institution_boundary", - "inventory_reserve_boundary", - "missing_proof_families", - "profit_margin_boundary", - "ready_for_reviewed_execution", - "value_flow_ranking", - "vat_continuity", - "vendor_risk_procurement_boundary", - "vendor_risk_procurement_quality" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase95_vendor_procurement_quality_reviewed_route_live2", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase95_vendor_procurement_quality_reviewed_route_live2", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 7, - "steps_passed": 7, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260512162841_gen-ag05121628-50ea6c.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260512162841_gen-ag05121628-50ea6c.json deleted file mode 100644 index 474f604..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260512162841_gen-ag05121628-50ea6c.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "saved_at": "2026-05-12T16:28:41+00:00", - "generation_id": "gen-ag05121628-50ea6c", - "mode": "saved_user_sessions", - "title": "AGENT | Phase20 continuity/ranking/self-scope accepted replay 2026-05-12", - "agent_run": true, - "questions": [ - "кто у нас самый доходный клиент за все время?", - "какой у нас самый доходный год?", - "кто нам должен денег на май 2017?", - "а какой ндс мы должны примерно заплатить за этот период?", - "мы должны комуто денег на сегодня?", - "а нам?" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "ranking catalog alignment, self-scope pronoun, compact debt answers", - "architecture_phase": "MCP автономка / semantic integrity", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase20_continuity_stabilization.json", - "scenario_id": "address_truth_harness_phase20_continuity_stabilization", - "semantic_tags": [ - "exact_not_overwritten", - "garbage_anchor_forbidden", - "payables_snapshot", - "period_carryover", - "pronoun_followup", - "receivables_snapshot", - "temporal_tail_not_entity", - "value_flow_ranking", - "vat_followup", - "year_tail_not_entity" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase20_continuity_stabilization_rerun_planner_ranking_fix", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase20_continuity_stabilization_rerun_planner_ranking_fix", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 6, - "steps_passed": 6, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "кто у нас самый доходный клиент за все время?", - "created_at": "2026-05-12T16:28:41+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "какой у нас самый доходный год?", - "created_at": "2026-05-12T16:28:41+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "кто нам должен денег на май 2017?", - "created_at": "2026-05-12T16:28:41+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "а какой ндс мы должны примерно заплатить за этот период?", - "created_at": "2026-05-12T16:28:41+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-005", - "role": "user", - "text": "мы должны комуто денег на сегодня?", - "created_at": "2026-05-12T16:28:41+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-006", - "role": "user", - "text": "а нам?", - "created_at": "2026-05-12T16:28:41+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "ranking catalog alignment, self-scope pronoun, compact debt answers", - "architecture_phase": "MCP автономка / semantic integrity", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase20_continuity_stabilization.json", - "scenario_id": "address_truth_harness_phase20_continuity_stabilization", - "semantic_tags": [ - "exact_not_overwritten", - "garbage_anchor_forbidden", - "payables_snapshot", - "period_carryover", - "pronoun_followup", - "receivables_snapshot", - "temporal_tail_not_entity", - "value_flow_ranking", - "vat_followup", - "year_tail_not_entity" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase20_continuity_stabilization_rerun_planner_ranking_fix", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase20_continuity_stabilization_rerun_planner_ranking_fix", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 6, - "steps_passed": 6, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260512205728_gen-ag05122057-c9786e.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260512205728_gen-ag05122057-c9786e.json deleted file mode 100644 index 7ecfdf4..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260512205728_gen-ag05122057-c9786e.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "saved_at": "2026-05-12T20:57:28+00:00", - "generation_id": "gen-ag05122057-c9786e", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 96 inventory reserve/liquidation quality-events", - "agent_run": true, - "questions": [ - "По ООО Альтернатива Плюс за 2020 год проверь склад: были ли списания товаров, оприходования/корректировки, инвентаризации, переоценки, резервы под неликвиды или ликвидационная стоимость? Скажи коротко и честно, что подтверждено 1С, а что нельзя утверждать.", - "А по этим же данным можно сказать, что склад ликвидный и неликвидов нет?" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "inventory_reserve_liquidation_quality", - "architecture_phase": "Route-Candidate-Driven Enablement Loop", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase96_inventory_reserve_liquidation_quality.json", - "scenario_id": "address_truth_harness_phase96_inventory_reserve_liquidation_quality", - "semantic_tags": [ - "direct_answer_first", - "followup_context_carryover", - "inventory_liquidity_boundary", - "inventory_reserve_liquidation_quality", - "no_inventory_health_overclaim", - "no_market_liquidation_overclaim", - "reviewed_inventory_quality_events" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase96_inventory_reserve_liquidation_quality_rerun", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase96_inventory_reserve_liquidation_quality_rerun", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 2, - "steps_passed": 2, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "По ООО Альтернатива Плюс за 2020 год проверь склад: были ли списания товаров, оприходования/корректировки, инвентаризации, переоценки, резервы под неликвиды или ликвидационная стоимость? Скажи коротко и честно, что подтверждено 1С, а что нельзя утверждать.", - "created_at": "2026-05-12T20:57:28+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "А по этим же данным можно сказать, что склад ликвидный и неликвидов нет?", - "created_at": "2026-05-12T20:57:28+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "inventory_reserve_liquidation_quality", - "architecture_phase": "Route-Candidate-Driven Enablement Loop", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase96_inventory_reserve_liquidation_quality.json", - "scenario_id": "address_truth_harness_phase96_inventory_reserve_liquidation_quality", - "semantic_tags": [ - "direct_answer_first", - "followup_context_carryover", - "inventory_liquidity_boundary", - "inventory_reserve_liquidation_quality", - "no_inventory_health_overclaim", - "no_market_liquidation_overclaim", - "reviewed_inventory_quality_events" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase96_inventory_reserve_liquidation_quality_rerun", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase96_inventory_reserve_liquidation_quality_rerun", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 2, - "steps_passed": 2, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260512225023_gen-ag05122250-4451a8.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260512225023_gen-ag05122250-4451a8.json deleted file mode 100644 index 94a2ec8..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260512225023_gen-ag05122250-4451a8.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "saved_at": "2026-05-12T22:50:23+00:00", - "generation_id": "gen-ag05122250-4451a8", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 97 financial counterparty flow hints replay", - "agent_run": true, - "questions": [ - "По ООО Альтернатива Плюс за 2020 отдельно посмотри платежи в СБЕРБАНК: это обычный поставщик или банковский/финансовый поток? Дай коротко и по проверенным данным 1С.", - "А если по этой же компании СБЕРБАНК встречается во входящих поступлениях, это клиентская выручка или там может быть кредитный/депозитный банковский смысл? Не притягивай, скажи что подтверждено.", - "Теперь дай взрослый краткий обзор ООО Альтернатива Плюс за 2020: входящие, исходящие, нетто и отдельно отметь, если в топах есть банк, почему его нельзя читать как обычного клиента или поставщика.", - "А теперь отдельно по Группа СВК за 2020: сколько денег получили, сколько заплатили и какое нетто?" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Focused semantic replay for the Open-World Schema/Primitive Discovery slice: bank-like counterparties must not be described as ordinary suppliers/customers when operation, payment purpose, contract, or comment fields indicate banking commission, credit, deposit, tax/budget, or payroll-like flows. The replay also keeps a normal counterparty value-flow canary.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase97_financial_counterparty_flow_hints.json", - "scenario_id": "address_truth_harness_phase97_financial_counterparty_flow_hints", - "semantic_tags": [ - "bank_like_customer_boundary", - "bank_like_supplier_boundary", - "business_overview", - "canary", - "counterparty_net_cash_flow", - "customer_revenue_and_payments", - "financial_counterparty_flow_hint", - "profit_margin_boundary", - "stale_scope_guard", - "supplier_payouts_profile" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase97_financial_counterparty_flow_hints_live4", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase97_financial_counterparty_flow_hints_live4", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 4, - "steps_passed": 4, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "По ООО Альтернатива Плюс за 2020 отдельно посмотри платежи в СБЕРБАНК: это обычный поставщик или банковский/финансовый поток? Дай коротко и по проверенным данным 1С.", - "created_at": "2026-05-12T22:50:23+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "А если по этой же компании СБЕРБАНК встречается во входящих поступлениях, это клиентская выручка или там может быть кредитный/депозитный банковский смысл? Не притягивай, скажи что подтверждено.", - "created_at": "2026-05-12T22:50:23+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "Теперь дай взрослый краткий обзор ООО Альтернатива Плюс за 2020: входящие, исходящие, нетто и отдельно отметь, если в топах есть банк, почему его нельзя читать как обычного клиента или поставщика.", - "created_at": "2026-05-12T22:50:23+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "А теперь отдельно по Группа СВК за 2020: сколько денег получили, сколько заплатили и какое нетто?", - "created_at": "2026-05-12T22:50:23+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Focused semantic replay for the Open-World Schema/Primitive Discovery slice: bank-like counterparties must not be described as ordinary suppliers/customers when operation, payment purpose, contract, or comment fields indicate banking commission, credit, deposit, tax/budget, or payroll-like flows. The replay also keeps a normal counterparty value-flow canary.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase97_financial_counterparty_flow_hints.json", - "scenario_id": "address_truth_harness_phase97_financial_counterparty_flow_hints", - "semantic_tags": [ - "bank_like_customer_boundary", - "bank_like_supplier_boundary", - "business_overview", - "canary", - "counterparty_net_cash_flow", - "customer_revenue_and_payments", - "financial_counterparty_flow_hint", - "profit_margin_boundary", - "stale_scope_guard", - "supplier_payouts_profile" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase97_financial_counterparty_flow_hints_live4", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase97_financial_counterparty_flow_hints_live4", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 4, - "steps_passed": 4, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260512231548_gen-ag05122315-f1e27c.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260512231548_gen-ag05122315-f1e27c.json deleted file mode 100644 index 457b2af..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260512231548_gen-ag05122315-f1e27c.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "saved_at": "2026-05-12T23:15:48+00:00", - "generation_id": "gen-ag05122315-f1e27c", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 98 limit honesty and business-language replay", - "agent_run": true, - "questions": [ - "По ООО Альтернатива Плюс на конец 2020 можно точно понять, какая дебиторка просрочена?", - "То есть просрочку доказать нельзя, коротко почему?", - "НДС за 2020 по ООО Альтернатива Плюс какой?", - "А кто принес больше всего денег за 2020?", - "По ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?", - "А зависимость от одного поставщика за 2020 можно точно оценить?" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Focused semantic replay from assistant-stage1-v2qsm_R0fF: answers may be bounded, but they must stay business-readable, direct-first, and must not leak MCP/proxy/route/debug wording when explaining row limits, incomplete coverage, debt due-date proof, inventory reserve proof, supplier dependency, VAT, or bank-like counterparties.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase98_limit_honesty_business_language.json", - "scenario_id": "address_truth_harness_phase98_limit_honesty_business_language", - "semantic_tags": [ - "business_language", - "customer_revenue_and_payments", - "debt_due_date_aging_quality", - "debug_leak_guard", - "financial_counterparty_flow_hint", - "followup_directness", - "inventory_reserve_liquidation_quality", - "limit_honesty", - "vat", - "vendor_risk_procurement_quality" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase98_limit_honesty_business_language_live3", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase98_limit_honesty_business_language_live3", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 6, - "steps_passed": 6, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "По ООО Альтернатива Плюс на конец 2020 можно точно понять, какая дебиторка просрочена?", - "created_at": "2026-05-12T23:15:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "То есть просрочку доказать нельзя, коротко почему?", - "created_at": "2026-05-12T23:15:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "НДС за 2020 по ООО Альтернатива Плюс какой?", - "created_at": "2026-05-12T23:15:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "А кто принес больше всего денег за 2020?", - "created_at": "2026-05-12T23:15:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-005", - "role": "user", - "text": "По ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?", - "created_at": "2026-05-12T23:15:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-006", - "role": "user", - "text": "А зависимость от одного поставщика за 2020 можно точно оценить?", - "created_at": "2026-05-12T23:15:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Focused semantic replay from assistant-stage1-v2qsm_R0fF: answers may be bounded, but they must stay business-readable, direct-first, and must not leak MCP/proxy/route/debug wording when explaining row limits, incomplete coverage, debt due-date proof, inventory reserve proof, supplier dependency, VAT, or bank-like counterparties.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase98_limit_honesty_business_language.json", - "scenario_id": "address_truth_harness_phase98_limit_honesty_business_language", - "semantic_tags": [ - "business_language", - "customer_revenue_and_payments", - "debt_due_date_aging_quality", - "debug_leak_guard", - "financial_counterparty_flow_hint", - "followup_directness", - "inventory_reserve_liquidation_quality", - "limit_honesty", - "vat", - "vendor_risk_procurement_quality" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase98_limit_honesty_business_language_live3", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase98_limit_honesty_business_language_live3", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 6, - "steps_passed": 6, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513100901_gen-ag05131009-f08174.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513100901_gen-ag05131009-f08174.json deleted file mode 100644 index edab59e..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513100901_gen-ag05131009-f08174.json +++ /dev/null @@ -1,133 +0,0 @@ -{ - "saved_at": "2026-05-13T10:09:01+00:00", - "generation_id": "gen-ag05131009-f08174", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 99 large-query budget and continuation policy replay", - "agent_run": true, - "questions": [ - "Дай взрослый бизнес-обзор ООО Альтернатива Плюс за 2020: входящие, исходящие, нетто, кто основные источники денег и где важные ограничения.", - "То есть это можно считать прибылью за 2020 или нет? Коротко.", - "А кто за 2020 принес больше всего денег, и если там банк, не называй его обычным клиентом.", - "По исходящим за 2020 есть зависимость от одного поставщика или это только денежная концентрация?" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Focused semantic replay for explicit-year large business questions: the assistant should use chunked 1C evidence where available, answer direct-first, avoid fake profit claims, keep bank/counterparty boundaries, and not collapse into row-limit refusal wording when yearly money coverage can be recovered.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase99_large_query_budget_continuation.json", - "scenario_id": "address_truth_harness_phase99_large_query_budget_continuation", - "semantic_tags": [ - "business_language", - "business_overview", - "context_continuity", - "direct_answer_first", - "financial_counterparty_flow_hint", - "followup_directness", - "large_query_budget", - "profit_boundary", - "vendor_risk_procurement_quality" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase99_large_query_budget_continuation_live2", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase99_large_query_budget_continuation_live2", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 4, - "steps_passed": 4, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "Дай взрослый бизнес-обзор ООО Альтернатива Плюс за 2020: входящие, исходящие, нетто, кто основные источники денег и где важные ограничения.", - "created_at": "2026-05-13T10:09:01+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "То есть это можно считать прибылью за 2020 или нет? Коротко.", - "created_at": "2026-05-13T10:09:01+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "А кто за 2020 принес больше всего денег, и если там банк, не называй его обычным клиентом.", - "created_at": "2026-05-13T10:09:01+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "По исходящим за 2020 есть зависимость от одного поставщика или это только денежная концентрация?", - "created_at": "2026-05-13T10:09:01+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Focused semantic replay for explicit-year large business questions: the assistant should use chunked 1C evidence where available, answer direct-first, avoid fake profit claims, keep bank/counterparty boundaries, and not collapse into row-limit refusal wording when yearly money coverage can be recovered.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase99_large_query_budget_continuation.json", - "scenario_id": "address_truth_harness_phase99_large_query_budget_continuation", - "semantic_tags": [ - "business_language", - "business_overview", - "context_continuity", - "direct_answer_first", - "financial_counterparty_flow_hint", - "followup_directness", - "large_query_budget", - "profit_boundary", - "vendor_risk_procurement_quality" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase99_large_query_budget_continuation_live2", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase99_large_query_budget_continuation_live2", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 4, - "steps_passed": 4, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513102845_gen-ag05131028-234e5e.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513102845_gen-ag05131028-234e5e.json deleted file mode 100644 index 4f0e601..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513102845_gen-ag05131028-234e5e.json +++ /dev/null @@ -1,121 +0,0 @@ -{ - "saved_at": "2026-05-13T10:28:45+00:00", - "generation_id": "gen-ag05131028-234e5e", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 100 large-query continuation UX replay", - "agent_run": true, - "questions": [ - "Дай общий бизнес-обзор ООО Альтернатива Плюс за весь доступный период: входящие, исходящие, нетто, лучший год. Если срез слишком широкий, не выдумывай полный итог, а скажи как безопасно дособрать.", - "Ок, тогда дособери конкретно 2020: входящие, исходящие и расчетное денежное нетто.", - "Это можно считать прибылью за 2020 или нет? Ответь коротко и по делу." - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Focused semantic replay for all-time or very broad business overview questions: the assistant should answer from checked evidence, disclose row-limit coverage honestly, offer a safe period-narrowing continuation path, and then recover the explicit-year follow-up through chunked evidence without leaking technical mechanics.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase100_large_query_continuation_ux.json", - "scenario_id": "address_truth_harness_phase100_large_query_continuation_ux", - "semantic_tags": [ - "business_language", - "business_overview", - "followup_continuation", - "followup_directness", - "large_query_budget", - "large_query_continuation", - "limit_honesty", - "profit_boundary" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase100_large_query_continuation_ux_live2", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase100_large_query_continuation_ux_live2", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 3, - "steps_passed": 3, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "Дай общий бизнес-обзор ООО Альтернатива Плюс за весь доступный период: входящие, исходящие, нетто, лучший год. Если срез слишком широкий, не выдумывай полный итог, а скажи как безопасно дособрать.", - "created_at": "2026-05-13T10:28:45+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "Ок, тогда дособери конкретно 2020: входящие, исходящие и расчетное денежное нетто.", - "created_at": "2026-05-13T10:28:45+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "Это можно считать прибылью за 2020 или нет? Ответь коротко и по делу.", - "created_at": "2026-05-13T10:28:45+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Focused semantic replay for all-time or very broad business overview questions: the assistant should answer from checked evidence, disclose row-limit coverage honestly, offer a safe period-narrowing continuation path, and then recover the explicit-year follow-up through chunked evidence without leaking technical mechanics.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase100_large_query_continuation_ux.json", - "scenario_id": "address_truth_harness_phase100_large_query_continuation_ux", - "semantic_tags": [ - "business_language", - "business_overview", - "followup_continuation", - "followup_directness", - "large_query_budget", - "large_query_continuation", - "limit_honesty", - "profit_boundary" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase100_large_query_continuation_ux_live2", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase100_large_query_continuation_ux_live2", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 3, - "steps_passed": 3, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513104438_gen-ag05131044-cbe2ff.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513104438_gen-ag05131044-cbe2ff.json deleted file mode 100644 index d50b9ef..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513104438_gen-ag05131044-cbe2ff.json +++ /dev/null @@ -1,165 +0,0 @@ -{ - "saved_at": "2026-05-13T10:44:38+00:00", - "generation_id": "gen-ag05131044-cbe2ff", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 101 inventory root scope without warehouse clarification replay", - "agent_run": true, - "questions": [ - "приветик - че как там дела", - "расскажи что можешь интересного", - "кайф - что там на складе по остаткам?", - "АЛЬТЕРНАТИВА", - "а исторические остатки на другие даты умеешь?", - "давай на июнь 2017", - "март 2016" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Focused semantic replay for the manual assistant-stage1-hyh1A1WR3j signal: after a broad stock-on-hand question and organization clarification, the assistant must resume the root inventory snapshot for the selected company across available warehouses instead of asking the user to name a warehouse, item, category, or material.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase101_inventory_root_scope_no_warehouse_clarification.json", - "scenario_id": "address_truth_harness_phase101_inventory_root_scope_no_warehouse_clarification", - "semantic_tags": [ - "capability_meta", - "clarification_required", - "clarification_resume", - "date_followup", - "historical_inventory", - "human_answer_quality", - "inventory_capability_meta", - "inventory_root", - "smalltalk_entry", - "warehouse_not_required" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase101_inventory_root_scope_no_warehouse_clarification_live1", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase101_inventory_root_scope_no_warehouse_clarification_live1", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 7, - "steps_passed": 7, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "приветик - че как там дела", - "created_at": "2026-05-13T10:44:38+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "расскажи что можешь интересного", - "created_at": "2026-05-13T10:44:38+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "кайф - что там на складе по остаткам?", - "created_at": "2026-05-13T10:44:38+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "АЛЬТЕРНАТИВА", - "created_at": "2026-05-13T10:44:38+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-005", - "role": "user", - "text": "а исторические остатки на другие даты умеешь?", - "created_at": "2026-05-13T10:44:38+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-006", - "role": "user", - "text": "давай на июнь 2017", - "created_at": "2026-05-13T10:44:38+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-007", - "role": "user", - "text": "март 2016", - "created_at": "2026-05-13T10:44:38+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Focused semantic replay for the manual assistant-stage1-hyh1A1WR3j signal: after a broad stock-on-hand question and organization clarification, the assistant must resume the root inventory snapshot for the selected company across available warehouses instead of asking the user to name a warehouse, item, category, or material.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase101_inventory_root_scope_no_warehouse_clarification.json", - "scenario_id": "address_truth_harness_phase101_inventory_root_scope_no_warehouse_clarification", - "semantic_tags": [ - "capability_meta", - "clarification_required", - "clarification_resume", - "date_followup", - "historical_inventory", - "human_answer_quality", - "inventory_capability_meta", - "inventory_root", - "smalltalk_entry", - "warehouse_not_required" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase101_inventory_root_scope_no_warehouse_clarification_live1", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase101_inventory_root_scope_no_warehouse_clarification_live1", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 7, - "steps_passed": 7, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513112152_gen-ag05131121-8c41ab.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513112152_gen-ag05131121-8c41ab.json deleted file mode 100644 index c073f17..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513112152_gen-ag05131121-8c41ab.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "saved_at": "2026-05-13T11:21:52+00:00", - "generation_id": "gen-ag05131121-8c41ab", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 102 debt mirror clean-scope polarity replay", - "agent_run": true, - "questions": [ - "Альтернатива Плюс", - "мы кому реально должны денег на сегодня? коротко, чистый долг к оплате, без встречных обеспечений как основного долга", - "а Комитету государственных услуг мы реально должны эти 3,6 млн или это встречное обеспечение/зачет? объясни именно по смыслу долга", - "а нам Комитет государственных услуг тоже должен 3,6 млн? это же та же сумма — скажи честно, это дебиторка или встречная часть?", - "тогда кто нам реально должен денег на сегодня? именно чистая дебиторка", - "а мы кому?" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "phase102 debt mirror clean-scope polarity", - "architecture_phase": "Open-World Schema/Primitive Discovery", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase102_debt_mirror_clean_scope_polarity.json", - "scenario_id": "address_truth_harness_phase102_debt_mirror_clean_scope_polarity", - "semantic_tags": [ - "company_selected", - "debt_mirror_clean_scope", - "direct_answer_first", - "organization_scope", - "payables_counterparty_check", - "payables_snapshot", - "polarity_honesty", - "receivables_counterparty_check", - "receivables_snapshot", - "settlements_mirror_followup" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase102_debt_mirror_clean_scope_polarity_live3", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase102_debt_mirror_clean_scope_polarity_live3", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 6, - "steps_passed": 6, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "Альтернатива Плюс", - "created_at": "2026-05-13T11:21:52+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "мы кому реально должны денег на сегодня? коротко, чистый долг к оплате, без встречных обеспечений как основного долга", - "created_at": "2026-05-13T11:21:52+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "а Комитету государственных услуг мы реально должны эти 3,6 млн или это встречное обеспечение/зачет? объясни именно по смыслу долга", - "created_at": "2026-05-13T11:21:52+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "а нам Комитет государственных услуг тоже должен 3,6 млн? это же та же сумма — скажи честно, это дебиторка или встречная часть?", - "created_at": "2026-05-13T11:21:52+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-005", - "role": "user", - "text": "тогда кто нам реально должен денег на сегодня? именно чистая дебиторка", - "created_at": "2026-05-13T11:21:52+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-006", - "role": "user", - "text": "а мы кому?", - "created_at": "2026-05-13T11:21:52+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "phase102 debt mirror clean-scope polarity", - "architecture_phase": "Open-World Schema/Primitive Discovery", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase102_debt_mirror_clean_scope_polarity.json", - "scenario_id": "address_truth_harness_phase102_debt_mirror_clean_scope_polarity", - "semantic_tags": [ - "company_selected", - "debt_mirror_clean_scope", - "direct_answer_first", - "organization_scope", - "payables_counterparty_check", - "payables_snapshot", - "polarity_honesty", - "receivables_counterparty_check", - "receivables_snapshot", - "settlements_mirror_followup" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase102_debt_mirror_clean_scope_polarity_live3", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase102_debt_mirror_clean_scope_polarity_live3", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 6, - "steps_passed": 6, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513120047_gen-ag05131200-0ed59a.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513120047_gen-ag05131200-0ed59a.json deleted file mode 100644 index 3f2b77a..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513120047_gen-ag05131200-0ed59a.json +++ /dev/null @@ -1,161 +0,0 @@ -{ - "saved_at": "2026-05-13T12:00:47+00:00", - "generation_id": "gen-ag05131200-0ed59a", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 103 financial role and purpose arbitration replay", - "agent_run": true, - "questions": [ - "Альтернатива Плюс", - "По СБЕРБАНКУ за 2020 покажи коротко: сколько денег входило и уходило, и что это по смыслу в 1С — клиентская выручка, поставщик, комиссия, кредит или другой финансовый поток?", - "Если СБЕРБАНК есть во входящих поступлениях, можно ли считать его нашим клиентом и выручкой? Скажи по подтвержденным строкам, без притягивания.", - "А если деньги уходили в СБЕРБАНК, это наш поставщик или финансовые списания? Раздели по смыслу и покажи основание.", - "Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток, если по назначению он не обычный клиент или поставщик.", - "А теперь отдельно по Группа СВК за 2020: сколько денег получили, сколько заплатили и какое нетто?" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "phase103 financial role and purpose arbitration", - "architecture_phase": "Open-World Schema/Primitive Discovery", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase103_financial_role_purpose_arbitration.json", - "scenario_id": "address_truth_harness_phase103_financial_role_purpose_arbitration", - "semantic_tags": [ - "bank_like_counterparty", - "bank_like_customer_boundary", - "bank_like_supplier_boundary", - "bank_operations_by_counterparty", - "bare_org_scope", - "business_overview", - "canary", - "counterparty_net_cash_flow", - "customer_revenue_and_payments", - "financial_role_purpose", - "phase102_canary", - "stale_scope_guard", - "supplier_payouts_profile" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase103_financial_role_purpose_arbitration_live3", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase103_financial_role_purpose_arbitration_live3", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 6, - "steps_passed": 6, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "Альтернатива Плюс", - "created_at": "2026-05-13T12:00:47+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "По СБЕРБАНКУ за 2020 покажи коротко: сколько денег входило и уходило, и что это по смыслу в 1С — клиентская выручка, поставщик, комиссия, кредит или другой финансовый поток?", - "created_at": "2026-05-13T12:00:47+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "Если СБЕРБАНК есть во входящих поступлениях, можно ли считать его нашим клиентом и выручкой? Скажи по подтвержденным строкам, без притягивания.", - "created_at": "2026-05-13T12:00:47+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "А если деньги уходили в СБЕРБАНК, это наш поставщик или финансовые списания? Раздели по смыслу и покажи основание.", - "created_at": "2026-05-13T12:00:47+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-005", - "role": "user", - "text": "Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток, если по назначению он не обычный клиент или поставщик.", - "created_at": "2026-05-13T12:00:47+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-006", - "role": "user", - "text": "А теперь отдельно по Группа СВК за 2020: сколько денег получили, сколько заплатили и какое нетто?", - "created_at": "2026-05-13T12:00:47+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "phase103 financial role and purpose arbitration", - "architecture_phase": "Open-World Schema/Primitive Discovery", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase103_financial_role_purpose_arbitration.json", - "scenario_id": "address_truth_harness_phase103_financial_role_purpose_arbitration", - "semantic_tags": [ - "bank_like_counterparty", - "bank_like_customer_boundary", - "bank_like_supplier_boundary", - "bank_operations_by_counterparty", - "bare_org_scope", - "business_overview", - "canary", - "counterparty_net_cash_flow", - "customer_revenue_and_payments", - "financial_role_purpose", - "phase102_canary", - "stale_scope_guard", - "supplier_payouts_profile" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase103_financial_role_purpose_arbitration_live3", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase103_financial_role_purpose_arbitration_live3", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 6, - "steps_passed": 6, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513122618_gen-ag05131226-630ddf.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513122618_gen-ag05131226-630ddf.json deleted file mode 100644 index 7145e12..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260513122618_gen-ag05131226-630ddf.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "saved_at": "2026-05-13T12:26:18+00:00", - "generation_id": "gen-ag05131226-630ddf", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 104 generic role-tail anchor hygiene replay", - "agent_run": true, - "questions": [ - "Альтернатива Плюс", - "Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток, если по назначению он не обычный клиент или поставщик.", - "А отдельно по СБЕРБАНКУ: он для нас клиент, поставщик или финансовый поток? Дай коротко по подтвержденным строкам.", - "А теперь по поставщику Группа СВК за 2020: сколько мы ему заплатили и какой общий денежный смысл?" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "phase104 generic role-tail anchor hygiene", - "architecture_phase": "Open-World Schema/Primitive Discovery", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase104_generic_role_tail_anchor_hygiene.json", - "scenario_id": "address_truth_harness_phase104_generic_role_tail_anchor_hygiene", - "semantic_tags": [ - "bank_like_counterparty", - "bare_org_scope", - "business_overview", - "counterparty_net_cash_flow", - "financial_role_purpose", - "generic_role_tail_anchor_hygiene", - "phase102_canary", - "post_overview_anchor_integrity", - "stale_scope_guard", - "supplier_prefix_canary" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase104_generic_role_tail_anchor_hygiene_live2", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase104_generic_role_tail_anchor_hygiene_live2", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 4, - "steps_passed": 4, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "Альтернатива Плюс", - "created_at": "2026-05-13T12:26:18+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток, если по назначению он не обычный клиент или поставщик.", - "created_at": "2026-05-13T12:26:18+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "А отдельно по СБЕРБАНКУ: он для нас клиент, поставщик или финансовый поток? Дай коротко по подтвержденным строкам.", - "created_at": "2026-05-13T12:26:18+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "А теперь по поставщику Группа СВК за 2020: сколько мы ему заплатили и какой общий денежный смысл?", - "created_at": "2026-05-13T12:26:18+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "phase104 generic role-tail anchor hygiene", - "architecture_phase": "Open-World Schema/Primitive Discovery", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase104_generic_role_tail_anchor_hygiene.json", - "scenario_id": "address_truth_harness_phase104_generic_role_tail_anchor_hygiene", - "semantic_tags": [ - "bank_like_counterparty", - "bare_org_scope", - "business_overview", - "counterparty_net_cash_flow", - "financial_role_purpose", - "generic_role_tail_anchor_hygiene", - "phase102_canary", - "post_overview_anchor_integrity", - "stale_scope_guard", - "supplier_prefix_canary" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase104_generic_role_tail_anchor_hygiene_live2", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\phase104_generic_role_tail_anchor_hygiene_live2", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 4, - "steps_passed": 4, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260522131931_gen-ag05221319-4035f5.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260522131931_gen-ag05221319-4035f5.json deleted file mode 100644 index f70b1ba..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260522131931_gen-ag05221319-4035f5.json +++ /dev/null @@ -1,123 +0,0 @@ -{ - "saved_at": "2026-05-22T13:19:31+00:00", - "generation_id": "gen-ag05221319-4035f5", - "mode": "saved_user_sessions", - "title": "AGENT | Inventory margin-ranking accepted replay 2026-05-22", - "agent_run": true, - "questions": [ - "Какая номеклатура товара реализована с высокой прибылью какая с низкой", - "сентябрь 2017", - "покажи найденные строки себестоимостной базы", - "расширь до 2017 года", - "анализ по 41 счету а не 01" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "inventory_margin_ranking_followup_and_business_modes", - "architecture_phase": "Business Answer Contract / margin-ranking safety gate", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\inventory_margin_ranking_agent_loop_20260522.json", - "scenario_id": "inventory_margin_ranking_agent_loop_20260522", - "semantic_tags": [], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\inventory_margin_ranking_agent_loop_live7", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\inventory_margin_ranking_agent_loop_live7", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 5, - "steps_passed": 5, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "Какая номеклатура товара реализована с высокой прибылью какая с низкой", - "created_at": "2026-05-22T13:19:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "сентябрь 2017", - "created_at": "2026-05-22T13:19:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "покажи найденные строки себестоимостной базы", - "created_at": "2026-05-22T13:19:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "расширь до 2017 года", - "created_at": "2026-05-22T13:19:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-005", - "role": "user", - "text": "анализ по 41 счету а не 01", - "created_at": "2026-05-22T13:19:31+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "inventory_margin_ranking_followup_and_business_modes", - "architecture_phase": "Business Answer Contract / margin-ranking safety gate", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\inventory_margin_ranking_agent_loop_20260522.json", - "scenario_id": "inventory_margin_ranking_agent_loop_20260522", - "semantic_tags": [], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\inventory_margin_ranking_agent_loop_live7", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\inventory_margin_ranking_agent_loop_live7", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 5, - "steps_passed": 5, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260522195737_gen-ag05221957-713bbd.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260522195737_gen-ag05221957-713bbd.json deleted file mode 100644 index d09d310..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260522195737_gen-ag05221957-713bbd.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "saved_at": "2026-05-22T19:57:37+00:00", - "generation_id": "gen-ag05221957-713bbd", - "mode": "saved_user_sessions", - "title": "AGENT | Hot value-flow discovery handoff", - "agent_run": true, - "questions": [ - "Сколько входящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?", - "Сколько исходящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?", - "А всего сколько денег пришло в ООО Альтернатива Плюс за 2020, без топов и без контрагентов?" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Targeted AGENT replay for the current Autonomy Core slice: organization-scoped value-flow questions must be answered through guarded MCP discovery response with hot handoff, not through stale exact fallback or a counterparty-only route.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\agent_hot_value_flow_handoff_20260522.json", - "scenario_id": "agent_hot_value_flow_handoff_20260522", - "semantic_tags": [ - "autonomy_core", - "colloquial_total", - "guarded_response", - "hot_handoff", - "incoming_total", - "outgoing_total", - "value_flow" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_hot_value_flow_handoff_live5", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_hot_value_flow_handoff_live5", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 3, - "steps_passed": 3, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "Сколько входящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?", - "created_at": "2026-05-22T19:57:37+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "Сколько исходящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?", - "created_at": "2026-05-22T19:57:37+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "А всего сколько денег пришло в ООО Альтернатива Плюс за 2020, без топов и без контрагентов?", - "created_at": "2026-05-22T19:57:37+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Targeted AGENT replay for the current Autonomy Core slice: organization-scoped value-flow questions must be answered through guarded MCP discovery response with hot handoff, not through stale exact fallback or a counterparty-only route.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\agent_hot_value_flow_handoff_20260522.json", - "scenario_id": "agent_hot_value_flow_handoff_20260522", - "semantic_tags": [ - "autonomy_core", - "colloquial_total", - "guarded_response", - "hot_handoff", - "incoming_total", - "outgoing_total", - "value_flow" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_hot_value_flow_handoff_live5", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_hot_value_flow_handoff_live5", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 3, - "steps_passed": 3, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260523185848_gen-ag05231858-323f86.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260523185848_gen-ag05231858-323f86.json deleted file mode 100644 index 7892a0e..0000000 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260523185848_gen-ag05231858-323f86.json +++ /dev/null @@ -1,287 +0,0 @@ -{ - "saved_at": "2026-05-23T18:58:48+00:00", - "generation_id": "gen-ag05231858-323f86", - "mode": "saved_user_sessions", - "title": "AGENT | Autonomy business quality pack", - "agent_run": true, - "questions": [ - "Сколько входящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?", - "Сколько исходящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?", - "А всего сколько денег пришло в ООО Альтернатива Плюс за 2020, без топов и без контрагентов?", - "Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток.", - "скока денег альтернатива заработала за 20 год?", - "а это чистая прибыль?", - "Какая чистая прибыль по ООО Альтернатива Плюс за 2020?", - "А отдельно по СБЕРБАНКУ: он для нас клиент, поставщик или финансовый поток? Дай коротко по подтвержденным строкам.", - "какое нетто по деньгам с Группа СВК за 2020 год: сколько получили и сколько заплатили?", - "кому мы должны на конец 2020?", - "а нам кто должен на конец 2020?", - "сколько НДС надо заплатить в налоговую за декабрь 2019?", - "Как ты оценишь деятельность компании?", - "Какая номенклатура товара реализована с высокой прибылью какая с низкой?", - "май 2020" - ], - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Expanded targeted AGENT replay for the autonomy milestone: value-flow, business overview, debts, VAT, profit/cashflow distinction, nomenclature margin boundary, and final answer quality must survive realistic business questions.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\agent_autonomy_business_quality_20260523.json", - "scenario_id": "agent_autonomy_business_quality_20260523", - "semantic_tags": [ - "autonomy_core", - "bank_boundary", - "bank_classification", - "business_answer_quality", - "business_evaluation", - "business_overview", - "cashflow_overview", - "cashflow_vs_profit", - "clarification", - "colloquial_money", - "colloquial_total", - "counterparty_value_flow", - "debt_answer_quality", - "direct_profit", - "domain_purity", - "followup_context", - "incoming_total", - "limit_honesty", - "limited_answer", - "net_flow", - "next_action", - "no_profit_substitution", - "no_top_guard", - "nomenclature_margin", - "outgoing_total", - "payables", - "profit_vs_cashflow", - "receivables", - "technical_garbage_guard", - "value_flow", - "vat" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_autonomy_business_quality_live_semantic_gate_accepted_20260523", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_autonomy_business_quality_live_semantic_gate_accepted_20260523", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 15, - "steps_passed": 15, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - }, - "source_session_id": null, - "session": { - "session_id": null, - "mode": "agent_semantic_run", - "items": [ - { - "message_id": "agent-user-001", - "role": "user", - "text": "Сколько входящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?", - "created_at": "2026-05-23T18:58:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-002", - "role": "user", - "text": "Сколько исходящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?", - "created_at": "2026-05-23T18:58:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-003", - "role": "user", - "text": "А всего сколько денег пришло в ООО Альтернатива Плюс за 2020, без топов и без контрагентов?", - "created_at": "2026-05-23T18:58:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-004", - "role": "user", - "text": "Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток.", - "created_at": "2026-05-23T18:58:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-005", - "role": "user", - "text": "скока денег альтернатива заработала за 20 год?", - "created_at": "2026-05-23T18:58:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-006", - "role": "user", - "text": "а это чистая прибыль?", - "created_at": "2026-05-23T18:58:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-007", - "role": "user", - "text": "Какая чистая прибыль по ООО Альтернатива Плюс за 2020?", - "created_at": "2026-05-23T18:58:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-008", - "role": "user", - "text": "А отдельно по СБЕРБАНКУ: он для нас клиент, поставщик или финансовый поток? Дай коротко по подтвержденным строкам.", - "created_at": "2026-05-23T18:58:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-009", - "role": "user", - "text": "какое нетто по деньгам с Группа СВК за 2020 год: сколько получили и сколько заплатили?", - "created_at": "2026-05-23T18:58:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-010", - "role": "user", - "text": "кому мы должны на конец 2020?", - "created_at": "2026-05-23T18:58:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-011", - "role": "user", - "text": "а нам кто должен на конец 2020?", - "created_at": "2026-05-23T18:58:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-012", - "role": "user", - "text": "сколько НДС надо заплатить в налоговую за декабрь 2019?", - "created_at": "2026-05-23T18:58:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-013", - "role": "user", - "text": "Как ты оценишь деятельность компании?", - "created_at": "2026-05-23T18:58:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-014", - "role": "user", - "text": "Какая номенклатура товара реализована с высокой прибылью какая с низкой?", - "created_at": "2026-05-23T18:58:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - }, - { - "message_id": "agent-user-015", - "role": "user", - "text": "май 2020", - "created_at": "2026-05-23T18:58:48+00:00", - "reply_type": null, - "trace_id": null, - "debug": null - } - ], - "agent_run": true, - "metadata": { - "assistant_prompt_version": null, - "decomposition_prompt_version": null, - "prompt_fingerprint": null, - "agent_focus": "Expanded targeted AGENT replay for the autonomy milestone: value-flow, business overview, debts, VAT, profit/cashflow distinction, nomenclature margin boundary, and final answer quality must survive realistic business questions.", - "architecture_phase": "turnaround_11", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\agent_autonomy_business_quality_20260523.json", - "scenario_id": "agent_autonomy_business_quality_20260523", - "semantic_tags": [ - "autonomy_core", - "bank_boundary", - "bank_classification", - "business_answer_quality", - "business_evaluation", - "business_overview", - "cashflow_overview", - "cashflow_vs_profit", - "clarification", - "colloquial_money", - "colloquial_total", - "counterparty_value_flow", - "debt_answer_quality", - "direct_profit", - "domain_purity", - "followup_context", - "incoming_total", - "limit_honesty", - "limited_answer", - "net_flow", - "next_action", - "no_profit_substitution", - "no_top_guard", - "nomenclature_margin", - "outgoing_total", - "payables", - "profit_vs_cashflow", - "receivables", - "technical_garbage_guard", - "value_flow", - "vat" - ], - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_autonomy_business_quality_live_semantic_gate_accepted_20260523", - "saved_after_validated_replay": true, - "save_gate": { - "schema_version": "agent_semantic_save_gate_v1", - "validation_status": "accepted_live_replay", - "validated_run_dir": "artifacts\\domain_runs\\agent_autonomy_business_quality_live_semantic_gate_accepted_20260523", - "final_status": "accepted", - "review_overall_status": "pass", - "business_overall_status": "pass", - "steps_total": 15, - "steps_passed": 15, - "steps_failed": 0, - "steps_with_business_failures": 0, - "steps_with_business_warnings": 0, - "acceptance_gate_passed": true, - "saved_after_validated_replay": true - } - } - } -} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260509183050_gen-ag05091830-062fc9.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260524230641_gen-ag05242306-7b49ab.json similarity index 53% rename from llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260509183050_gen-ag05091830-062fc9.json rename to llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260524230641_gen-ag05242306-7b49ab.json index 481fc00..f329276 100644 --- a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260509183050_gen-ag05091830-062fc9.json +++ b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260524230641_gen-ag05242306-7b49ab.json @@ -1,54 +1,58 @@ { - "saved_at": "2026-05-09T18:30:50+00:00", - "generation_id": "gen-ag05091830-062fc9", + "saved_at": "2026-05-24T23:06:41+00:00", + "generation_id": "gen-ag05242306-7b49ab", "mode": "saved_user_sessions", - "title": "AGENT | Agentic semantic development loop dogfood gate", + "title": "AGENT | Бизнес-обзор компании и СВК accepted replay 2026-05-24", "agent_run": true, "questions": [ "Дай взрослый бизнес-обзор ООО Альтернатива Плюс за 2020 год по данным 1С: обороты, входящие и исходящие деньги, нетто, НДС, долги, склад, клиенты, поставщики и что пока нельзя утверждать.", "Раскрой деньги подробнее: сколько получили, сколько заплатили, какой чистый денежный поток, кто главный клиент и главный поставщик в 2020.", - "А если смотреть за все доступное время, какой самый доходный год по подтвержденным оборотам и почему? Не называй это бухгалтерской прибылью, если чистой прибыли нет.", "Что с НДС за 2020 год по ООО Альтернатива Плюс: какая позиция видна, на чем она основана и чего не хватает для налогового вывода?", "Теперь за все доступное время дай обзор компании в целом, но не тащи НДС за 2020 как подтвержденную общую налоговую позицию.", "Отдельно по контрагенту Группа СВК, без опоры на прошлый диалог: сколько денег прошло, что входящее, что исходящее и есть ли документы или движения, на которых это основано?", "Покажи документы по этой цепочке и не смешивай Группа СВК с организацией ООО Альтернатива Плюс.", "Собери короткий итог: что мы подтвердили по компании, что отдельно по Группа СВК, какие выводы можно делать и какие нельзя.", - "Сделай короткий стартовый чек контекста: есть ли уже выбранная компания или контрагент в текущем диалоге; если нет, скажи честно и не выдумывай память про Группа СВК.", - "Покажи хвосты по счету 60 на август 2020 по ООО Альтернатива Плюс; если точных данных нет, скажи это прямо и не подменяй ответ общим обзором.", - "Что было на складе на март 2021 по доступным данным? Дай прямой ответ и не уводи его в контрагента Группа СВК.", - "Вернись к ООО Альтернатива Плюс: сколько всего денег получили и заплатили по всем подтвержденным данным, но не смешивай это с отдельной цепочкой Группа СВК и не называй оборот чистой прибылью." + "По-человечески посмотри ООО Альтернатива Плюс за 2020: что по бизнесу видно в 1С по деньгам, НДС, долгам, складу, клиентам/поставщикам и где пока нельзя делать вывод?", + "А по деньгам в этом же году кто больше всего занес и кому больше всего ушло? Банк не называй обычным клиентом без оговорки.", + "Возьми как выбранного контрагента Группа СВК: сколько по нему входящих денег, исходящих денег и расчетное нетто, на чем это основано?", + "Теперь по нему покажи документы и не переключайся на организацию.", + "И коротко сравни: что у нас подтверждено по компании, что отдельно по выбранному контрагенту, и какие выводы нельзя делать?", + "ООО Альтернатива Плюс" ], "metadata": { "assistant_prompt_version": null, "decomposition_prompt_version": null, "prompt_fingerprint": null, - "agent_focus": "Automate stage question review, live semantic replay, strong business audit, Lead Codex repair handoff, rerun validation, and final human confirmation.", - "architecture_phase": "turnaround_11_agentic_semantic_development_loop", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\agentic_semantic_development_loop_stage_pack.json", + "agent_focus": "Accepted proof pack for company business overview, SVK counterparty money/documents, selected-object carryover, org clarification, and all-time scope reset", + "architecture_phase": "agent_reliability_uplift_business_overview_counterparty", + "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\agent_business_overview_counterparty_reliability_20260524.json", "scenario_id": null, "semantic_tags": [ "business_overview", + "colloquial", "counterparty", "debt", "documents", "inventory", - "memory", "money", + "organization_clarification", + "pronoun_followup", "scope_guard", + "selected_object", "vat" ], "validation_status": "accepted_domain_pack_loop", - "validated_run_dir": "artifacts\\domain_runs\\stage_agent_loops\\agentic_semantic_development_loop\\domain_loops\\asl", + "validated_run_dir": "artifacts\\domain_runs\\agent_business_overview_counterparty_proof_20260524_39", "saved_after_validated_replay": true, "save_gate": { "schema_version": "agent_semantic_save_gate_v1", "validation_status": "accepted_domain_pack_loop", - "validated_run_dir": "artifacts\\domain_runs\\stage_agent_loops\\agentic_semantic_development_loop\\domain_loops\\asl", + "validated_run_dir": "artifacts\\domain_runs\\agent_business_overview_counterparty_proof_20260524_39", "final_status": "accepted", - "loop_id": "asl", - "target_score": 88, + "loop_id": "agent_business_overview_counterparty_proof_20260524_39", + "target_score": 90, "iterations_ran": 1, - "quality_score": 91, + "quality_score": 92, "repair_target_count": 0, "repair_target_severity_counts": { "P0": 0, @@ -56,6 +60,21 @@ "P2": 0 }, "accepted_gate": true, + "effective_runtime": { + "manifest_path": "artifacts\\domain_runs\\agent_business_overview_counterparty_proof_20260524_39\\effective_runtime.json", + "runner": "domain_case_loop.run-pack-loop", + "git_sha": "7cc65e808eb2430e7d27f2ac786c340aecc7fc50", + "backend_url": "http://127.0.0.1:8787", + "mcp_proxy_url": "http://127.0.0.1:6003", + "llm_provider": "local", + "llm_model": "unsloth/qwen3-30b-a3b-instruct-2507", + "temperature": 0.8, + "max_output_tokens": 900, + "prompt_version": "normalizer_v2_0_2", + "prompt_source": "file", + "prompt_hash": "f36e36a5e491cd24511b380e0c0059cb01aea5e2af738fb9f01671cd291735c1", + "prompt_registry_status": "pass" + }, "saved_after_validated_replay": true } }, @@ -68,7 +87,7 @@ "message_id": "agent-user-001", "role": "user", "text": "Дай взрослый бизнес-обзор ООО Альтернатива Плюс за 2020 год по данным 1С: обороты, входящие и исходящие деньги, нетто, НДС, долги, склад, клиенты, поставщики и что пока нельзя утверждать.", - "created_at": "2026-05-09T18:30:50+00:00", + "created_at": "2026-05-24T23:06:41+00:00", "reply_type": null, "trace_id": null, "debug": null @@ -77,7 +96,7 @@ "message_id": "agent-user-002", "role": "user", "text": "Раскрой деньги подробнее: сколько получили, сколько заплатили, какой чистый денежный поток, кто главный клиент и главный поставщик в 2020.", - "created_at": "2026-05-09T18:30:50+00:00", + "created_at": "2026-05-24T23:06:41+00:00", "reply_type": null, "trace_id": null, "debug": null @@ -85,8 +104,8 @@ { "message_id": "agent-user-003", "role": "user", - "text": "А если смотреть за все доступное время, какой самый доходный год по подтвержденным оборотам и почему? Не называй это бухгалтерской прибылью, если чистой прибыли нет.", - "created_at": "2026-05-09T18:30:50+00:00", + "text": "Что с НДС за 2020 год по ООО Альтернатива Плюс: какая позиция видна, на чем она основана и чего не хватает для налогового вывода?", + "created_at": "2026-05-24T23:06:41+00:00", "reply_type": null, "trace_id": null, "debug": null @@ -94,8 +113,8 @@ { "message_id": "agent-user-004", "role": "user", - "text": "Что с НДС за 2020 год по ООО Альтернатива Плюс: какая позиция видна, на чем она основана и чего не хватает для налогового вывода?", - "created_at": "2026-05-09T18:30:50+00:00", + "text": "Теперь за все доступное время дай обзор компании в целом, но не тащи НДС за 2020 как подтвержденную общую налоговую позицию.", + "created_at": "2026-05-24T23:06:41+00:00", "reply_type": null, "trace_id": null, "debug": null @@ -103,8 +122,8 @@ { "message_id": "agent-user-005", "role": "user", - "text": "Теперь за все доступное время дай обзор компании в целом, но не тащи НДС за 2020 как подтвержденную общую налоговую позицию.", - "created_at": "2026-05-09T18:30:50+00:00", + "text": "Отдельно по контрагенту Группа СВК, без опоры на прошлый диалог: сколько денег прошло, что входящее, что исходящее и есть ли документы или движения, на которых это основано?", + "created_at": "2026-05-24T23:06:41+00:00", "reply_type": null, "trace_id": null, "debug": null @@ -112,8 +131,8 @@ { "message_id": "agent-user-006", "role": "user", - "text": "Отдельно по контрагенту Группа СВК, без опоры на прошлый диалог: сколько денег прошло, что входящее, что исходящее и есть ли документы или движения, на которых это основано?", - "created_at": "2026-05-09T18:30:50+00:00", + "text": "Покажи документы по этой цепочке и не смешивай Группа СВК с организацией ООО Альтернатива Плюс.", + "created_at": "2026-05-24T23:06:41+00:00", "reply_type": null, "trace_id": null, "debug": null @@ -121,8 +140,8 @@ { "message_id": "agent-user-007", "role": "user", - "text": "Покажи документы по этой цепочке и не смешивай Группа СВК с организацией ООО Альтернатива Плюс.", - "created_at": "2026-05-09T18:30:50+00:00", + "text": "Собери короткий итог: что мы подтвердили по компании, что отдельно по Группа СВК, какие выводы можно делать и какие нельзя.", + "created_at": "2026-05-24T23:06:41+00:00", "reply_type": null, "trace_id": null, "debug": null @@ -130,8 +149,8 @@ { "message_id": "agent-user-008", "role": "user", - "text": "Собери короткий итог: что мы подтвердили по компании, что отдельно по Группа СВК, какие выводы можно делать и какие нельзя.", - "created_at": "2026-05-09T18:30:50+00:00", + "text": "По-человечески посмотри ООО Альтернатива Плюс за 2020: что по бизнесу видно в 1С по деньгам, НДС, долгам, складу, клиентам/поставщикам и где пока нельзя делать вывод?", + "created_at": "2026-05-24T23:06:41+00:00", "reply_type": null, "trace_id": null, "debug": null @@ -139,8 +158,8 @@ { "message_id": "agent-user-009", "role": "user", - "text": "Сделай короткий стартовый чек контекста: есть ли уже выбранная компания или контрагент в текущем диалоге; если нет, скажи честно и не выдумывай память про Группа СВК.", - "created_at": "2026-05-09T18:30:50+00:00", + "text": "А по деньгам в этом же году кто больше всего занес и кому больше всего ушло? Банк не называй обычным клиентом без оговорки.", + "created_at": "2026-05-24T23:06:41+00:00", "reply_type": null, "trace_id": null, "debug": null @@ -148,8 +167,8 @@ { "message_id": "agent-user-010", "role": "user", - "text": "Покажи хвосты по счету 60 на август 2020 по ООО Альтернатива Плюс; если точных данных нет, скажи это прямо и не подменяй ответ общим обзором.", - "created_at": "2026-05-09T18:30:50+00:00", + "text": "Возьми как выбранного контрагента Группа СВК: сколько по нему входящих денег, исходящих денег и расчетное нетто, на чем это основано?", + "created_at": "2026-05-24T23:06:41+00:00", "reply_type": null, "trace_id": null, "debug": null @@ -157,8 +176,8 @@ { "message_id": "agent-user-011", "role": "user", - "text": "Что было на складе на март 2021 по доступным данным? Дай прямой ответ и не уводи его в контрагента Группа СВК.", - "created_at": "2026-05-09T18:30:50+00:00", + "text": "Теперь по нему покажи документы и не переключайся на организацию.", + "created_at": "2026-05-24T23:06:41+00:00", "reply_type": null, "trace_id": null, "debug": null @@ -166,8 +185,17 @@ { "message_id": "agent-user-012", "role": "user", - "text": "Вернись к ООО Альтернатива Плюс: сколько всего денег получили и заплатили по всем подтвержденным данным, но не смешивай это с отдельной цепочкой Группа СВК и не называй оборот чистой прибылью.", - "created_at": "2026-05-09T18:30:50+00:00", + "text": "И коротко сравни: что у нас подтверждено по компании, что отдельно по выбранному контрагенту, и какие выводы нельзя делать?", + "created_at": "2026-05-24T23:06:41+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-013", + "role": "user", + "text": "ООО Альтернатива Плюс", + "created_at": "2026-05-24T23:06:41+00:00", "reply_type": null, "trace_id": null, "debug": null @@ -178,33 +206,36 @@ "assistant_prompt_version": null, "decomposition_prompt_version": null, "prompt_fingerprint": null, - "agent_focus": "Automate stage question review, live semantic replay, strong business audit, Lead Codex repair handoff, rerun validation, and final human confirmation.", - "architecture_phase": "turnaround_11_agentic_semantic_development_loop", - "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\agentic_semantic_development_loop_stage_pack.json", + "agent_focus": "Accepted proof pack for company business overview, SVK counterparty money/documents, selected-object carryover, org clarification, and all-time scope reset", + "architecture_phase": "agent_reliability_uplift_business_overview_counterparty", + "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\agent_business_overview_counterparty_reliability_20260524.json", "scenario_id": null, "semantic_tags": [ "business_overview", + "colloquial", "counterparty", "debt", "documents", "inventory", - "memory", "money", + "organization_clarification", + "pronoun_followup", "scope_guard", + "selected_object", "vat" ], "validation_status": "accepted_domain_pack_loop", - "validated_run_dir": "artifacts\\domain_runs\\stage_agent_loops\\agentic_semantic_development_loop\\domain_loops\\asl", + "validated_run_dir": "artifacts\\domain_runs\\agent_business_overview_counterparty_proof_20260524_39", "saved_after_validated_replay": true, "save_gate": { "schema_version": "agent_semantic_save_gate_v1", "validation_status": "accepted_domain_pack_loop", - "validated_run_dir": "artifacts\\domain_runs\\stage_agent_loops\\agentic_semantic_development_loop\\domain_loops\\asl", + "validated_run_dir": "artifacts\\domain_runs\\agent_business_overview_counterparty_proof_20260524_39", "final_status": "accepted", - "loop_id": "asl", - "target_score": 88, + "loop_id": "agent_business_overview_counterparty_proof_20260524_39", + "target_score": 90, "iterations_ran": 1, - "quality_score": 91, + "quality_score": 92, "repair_target_count": 0, "repair_target_severity_counts": { "P0": 0, @@ -212,6 +243,21 @@ "P2": 0 }, "accepted_gate": true, + "effective_runtime": { + "manifest_path": "artifacts\\domain_runs\\agent_business_overview_counterparty_proof_20260524_39\\effective_runtime.json", + "runner": "domain_case_loop.run-pack-loop", + "git_sha": "7cc65e808eb2430e7d27f2ac786c340aecc7fc50", + "backend_url": "http://127.0.0.1:8787", + "mcp_proxy_url": "http://127.0.0.1:6003", + "llm_provider": "local", + "llm_model": "unsloth/qwen3-30b-a3b-instruct-2507", + "temperature": 0.8, + "max_output_tokens": 900, + "prompt_version": "normalizer_v2_0_2", + "prompt_source": "file", + "prompt_hash": "f36e36a5e491cd24511b380e0c0059cb01aea5e2af738fb9f01671cd291735c1", + "prompt_registry_status": "pass" + }, "saved_after_validated_replay": true } } diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260417070448_gen-mo2kcds2-tlqmvng.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260417070448_gen-mo2kcds2-tlqmvng.json deleted file mode 100644 index 6910724..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260417070448_gen-mo2kcds2-tlqmvng.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-mo2kcds2-tlqmvng", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-04-17T07:04:48.578Z", - "generation_id": "gen-mo2kcds2-tlqmvng", - "mode": "saved_user_sessions", - "title": "Ручная сессия 17.04.2026, 10:04:19 ТЕМП", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "saved_user_sessions", - "title": "Ручная сессия 17.04.2026, 10:04:19 ТЕМП", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "покажи все документы по чепурнову" - }, - { - "user_message": "что нам отгружал чепурнов, какой товар или услугу?" - }, - { - "user_message": "какие остатки на складе на сегодня?" - }, - { - "user_message": "хвосты по счету 60 на август 2022" - }, - { - "user_message": "какие остатки на складе на март 2021" - }, - { - "user_message": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": кто нам это поставил?" - }, - { - "user_message": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": покажи документы по этой позиции" - }, - { - "user_message": "покажи еще раз остатки на эту же дату" - }, - { - "user_message": "какие остатки на складе на март 2016" - }, - { - "user_message": "на июль 2019" - }, - { - "user_message": "на сентябрь" - }, - { - "user_message": "а на март" - }, - { - "user_message": "это по общей базе" - } - ] - } - ] -} \ No newline at end of file diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260424140630_gen-ag04241406-abe4d8.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260424140630_gen-ag04241406-abe4d8.json deleted file mode 100644 index 49fa7b3..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260424140630_gen-ag04241406-abe4d8.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag04241406-abe4d8", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-04-24T14:06:30+00:00", - "generation_id": "gen-ag04241406-abe4d8", - "mode": "saved_user_sessions", - "title": "AGENT | Post-F cross-stage semantic integrity canary", - "domain": "address_post_f_cross_stage_canary_agent", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Post-F cross-stage semantic integrity canary", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "Мне нужно понять, где в 1С по НДС вообще лежат данные. Какие объекты стоит смотреть по НДС?" - }, - { - "user_message": "Хорошо, тогда покажи движения по ООО Альтернатива Плюс." - }, - { - "user_message": "За 2020 год." - }, - { - "user_message": "А теперь по документам?" - }, - { - "user_message": "А теперь за 2021 год?" - }, - { - "user_message": "А теперь за все время?" - }, - { - "user_message": "С НДС закончили. Новая тема: покажи документы по Жуковке 51." - }, - { - "user_message": "Хорошо, а теперь платежи по нему тоже покажи." - }, - { - "user_message": "А по нему договоры?" - }, - { - "user_message": "А по нему документы?" - }, - { - "user_message": "А за 2021?" - }, - { - "user_message": "С Жуковкой закончили. Теперь другая задача: быстрый денежный срез по одной организации. Если для ответа нужна организация, просто уточни ее. Сколько вообще входящих денег было за 2020 год?" - }, - { - "user_message": "По ООО Альтернатива Плюс." - }, - { - "user_message": "Понял, тогда за все время." - }, - { - "user_message": "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?" - }, - { - "user_message": "И кто больше всего принес денег этой организации в 2020 году?" - }, - { - "user_message": "А в 2021 году?" - }, - { - "user_message": "Теперь отдельная тема по конкретному контрагенту. Найди в 1С Группу СВК." - }, - { - "user_message": "Сколько получили по нему за 2020 год?" - }, - { - "user_message": "А теперь сколько заплатили?" - }, - { - "user_message": "А какое нетто?" - }, - { - "user_message": "А по документам?" - }, - { - "user_message": "А по движениям?" - }, - { - "user_message": "А теперь тот же смысл за 2021 год." - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260424171031_gen-ag04241710-bdb248.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260424171031_gen-ag04241710-bdb248.json deleted file mode 100644 index ed96e6e..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260424171031_gen-ag04241710-bdb248.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag04241710-bdb248", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-04-24T17:10:31+00:00", - "generation_id": "gen-ag04241710-bdb248", - "mode": "saved_user_sessions", - "title": "AGENT | Post-F ручные провалы VAT revenue item-flow live3", - "domain": "address_post_f_manual_failures", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Post-F ручные провалы VAT revenue item-flow live3", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "кайф - что там на складе по остаткам?" - }, - { - "user_message": "АЛЬТЕРНАТИВА" - }, - { - "user_message": "март 2016" - }, - { - "user_message": "По выбранному объекту \"Рабочая станция универсального специалиста (индивидуальное изготовление)\": где взяли это?" - }, - { - "user_message": "ндс можешь прикинуть на дату покупки рабочей станции?" - }, - { - "user_message": "прикинь какой ндс нам надо заплатить на февраль 2017" - }, - { - "user_message": "кто у нас самый доходный клиент за все время" - }, - { - "user_message": "по чепурнову покажи все доки" - }, - { - "user_message": "а по свк" - }, - { - "user_message": "а сейчас у нас есть что на складе?" - }, - { - "user_message": "что нам отгружал чепурнов? какой товар или услугу?" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260510094921_gen-ag05100949-2a5ed8.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260510094921_gen-ag05100949-2a5ed8.json deleted file mode 100644 index f4cec04..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260510094921_gen-ag05100949-2a5ed8.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05100949-2a5ed8", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-10T09:49:21+00:00", - "generation_id": "gen-ag05100949-2a5ed8", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 91 route-candidate-driven enablement loop canary", - "domain": "address_phase91_route_candidate_driven_enablement_loop", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Phase 91 route-candidate-driven enablement loop canary", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "какой контрагент принес больше всего денег за 2020 год?" - }, - { - "user_message": "ООО Альтернатива Плюс" - }, - { - "user_message": "а теперь сколько лет мы работаем с Группа СВК?" - }, - { - "user_message": "покажи движения по НДС за 2020 по ООО Альтернатива Плюс" - }, - { - "user_message": "можно ли по этим данным точно подтвердить резерв под неликвиды на складе?" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260510121326_gen-ag05101213-596d99.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260510121326_gen-ag05101213-596d99.json deleted file mode 100644 index 1c00126..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260510121326_gen-ag05101213-596d99.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05101213-596d99", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-10T12:13:26+00:00", - "generation_id": "gen-ag05101213-596d99", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 93 accounting profit-margin reviewed route", - "domain": "address_phase93_accounting_profit_margin_reviewed_route", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Phase 93 accounting profit-margin reviewed route", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "по ООО Альтернатива Плюс за 2020 можно точно сказать чистую прибыль и маржу?" - }, - { - "user_message": "а это прибыль или убыток, коротко?" - }, - { - "user_message": "по этой же компании на конец 2020 можно точно понять, какая дебиторка просрочена?" - }, - { - "user_message": "тогда НДС за 2020 по ООО Альтернатива Плюс какой?" - }, - { - "user_message": "а какой контрагент принес больше всего денег за 2020?" - }, - { - "user_message": "по ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260510131922_gen-ag05101319-c04f79.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260510131922_gen-ag05101319-c04f79.json deleted file mode 100644 index 3b7bb2d..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260510131922_gen-ag05101319-c04f79.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05101319-c04f79", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-10T13:19:22+00:00", - "generation_id": "gen-ag05101319-c04f79", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 94 debt due-date aging reviewed route", - "domain": "address_phase94_debt_due_date_aging_reviewed_route", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Phase 94 debt due-date aging reviewed route", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "по ООО Альтернатива Плюс на конец 2020 можно точно понять, какая дебиторка просрочена?" - }, - { - "user_message": "то есть просрочку доказать нельзя, коротко почему?" - }, - { - "user_message": "а чистая прибыль и маржа за 2020 по этой же компании какие?" - }, - { - "user_message": "НДС за 2020 по ООО Альтернатива Плюс какой?" - }, - { - "user_message": "а кто принес больше всего денег за 2020?" - }, - { - "user_message": "по ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?" - }, - { - "user_message": "а зависимость от одного поставщика за 2020 можно точно оценить?" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260512135726_gen-ag05121357-9ea5d6.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260512135726_gen-ag05121357-9ea5d6.json deleted file mode 100644 index 2797a3d..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260512135726_gen-ag05121357-9ea5d6.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05121357-9ea5d6", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-12T13:57:26+00:00", - "generation_id": "gen-ag05121357-9ea5d6", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 95 vendor/procurement quality reviewed route", - "domain": "address_phase95_vendor_procurement_quality_reviewed_route", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Phase 95 vendor/procurement quality reviewed route", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "по ООО Альтернатива Плюс за 2020 есть ли риск, что мы зависим от одного поставщика?" - }, - { - "user_message": "а банк из этого ответа считать обычным поставщиком?" - }, - { - "user_message": "по этой же компании на конец 2020 можно точно понять, какая дебиторка просрочена?" - }, - { - "user_message": "а чистая прибыль и маржа за 2020 какие?" - }, - { - "user_message": "НДС за 2020 по ООО Альтернатива Плюс какой?" - }, - { - "user_message": "а кто принес больше всего денег за 2020?" - }, - { - "user_message": "по ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260512162841_gen-ag05121628-50ea6c.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260512162841_gen-ag05121628-50ea6c.json deleted file mode 100644 index 1be5d5f..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260512162841_gen-ag05121628-50ea6c.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05121628-50ea6c", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-12T16:28:41+00:00", - "generation_id": "gen-ag05121628-50ea6c", - "mode": "saved_user_sessions", - "title": "AGENT | Phase20 continuity/ranking/self-scope accepted replay 2026-05-12", - "domain": "address_phase20_continuity_stabilization", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Phase20 continuity/ranking/self-scope accepted replay 2026-05-12", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "кто у нас самый доходный клиент за все время?" - }, - { - "user_message": "какой у нас самый доходный год?" - }, - { - "user_message": "кто нам должен денег на май 2017?" - }, - { - "user_message": "а какой ндс мы должны примерно заплатить за этот период?" - }, - { - "user_message": "мы должны комуто денег на сегодня?" - }, - { - "user_message": "а нам?" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260512205728_gen-ag05122057-c9786e.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260512205728_gen-ag05122057-c9786e.json deleted file mode 100644 index 2d9b5d9..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260512205728_gen-ag05122057-c9786e.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05122057-c9786e", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-12T20:57:28+00:00", - "generation_id": "gen-ag05122057-c9786e", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 96 inventory reserve/liquidation quality-events", - "domain": "address_phase96_inventory_reserve_liquidation_quality", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Phase 96 inventory reserve/liquidation quality-events", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "По ООО Альтернатива Плюс за 2020 год проверь склад: были ли списания товаров, оприходования/корректировки, инвентаризации, переоценки, резервы под неликвиды или ликвидационная стоимость? Скажи коротко и честно, что подтверждено 1С, а что нельзя утверждать." - }, - { - "user_message": "А по этим же данным можно сказать, что склад ликвидный и неликвидов нет?" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260512225023_gen-ag05122250-4451a8.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260512225023_gen-ag05122250-4451a8.json deleted file mode 100644 index 27bf4cc..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260512225023_gen-ag05122250-4451a8.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05122250-4451a8", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-12T22:50:23+00:00", - "generation_id": "gen-ag05122250-4451a8", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 97 financial counterparty flow hints replay", - "domain": "address_phase97_financial_counterparty_flow_hints", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Phase 97 financial counterparty flow hints replay", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "По ООО Альтернатива Плюс за 2020 отдельно посмотри платежи в СБЕРБАНК: это обычный поставщик или банковский/финансовый поток? Дай коротко и по проверенным данным 1С." - }, - { - "user_message": "А если по этой же компании СБЕРБАНК встречается во входящих поступлениях, это клиентская выручка или там может быть кредитный/депозитный банковский смысл? Не притягивай, скажи что подтверждено." - }, - { - "user_message": "Теперь дай взрослый краткий обзор ООО Альтернатива Плюс за 2020: входящие, исходящие, нетто и отдельно отметь, если в топах есть банк, почему его нельзя читать как обычного клиента или поставщика." - }, - { - "user_message": "А теперь отдельно по Группа СВК за 2020: сколько денег получили, сколько заплатили и какое нетто?" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260512231548_gen-ag05122315-f1e27c.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260512231548_gen-ag05122315-f1e27c.json deleted file mode 100644 index adbc100..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260512231548_gen-ag05122315-f1e27c.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05122315-f1e27c", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-12T23:15:48+00:00", - "generation_id": "gen-ag05122315-f1e27c", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 98 limit honesty and business-language replay", - "domain": "address_phase98_limit_honesty_business_language", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Phase 98 limit honesty and business-language replay", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "По ООО Альтернатива Плюс на конец 2020 можно точно понять, какая дебиторка просрочена?" - }, - { - "user_message": "То есть просрочку доказать нельзя, коротко почему?" - }, - { - "user_message": "НДС за 2020 по ООО Альтернатива Плюс какой?" - }, - { - "user_message": "А кто принес больше всего денег за 2020?" - }, - { - "user_message": "По ООО Альтернатива Плюс на конец 2020 можно точно подтвердить резерв под неликвиды на складе?" - }, - { - "user_message": "А зависимость от одного поставщика за 2020 можно точно оценить?" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513100901_gen-ag05131009-f08174.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513100901_gen-ag05131009-f08174.json deleted file mode 100644 index 712af6b..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513100901_gen-ag05131009-f08174.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05131009-f08174", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-13T10:09:01+00:00", - "generation_id": "gen-ag05131009-f08174", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 99 large-query budget and continuation policy replay", - "domain": "address_phase99_large_query_budget_continuation", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Phase 99 large-query budget and continuation policy replay", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "Дай взрослый бизнес-обзор ООО Альтернатива Плюс за 2020: входящие, исходящие, нетто, кто основные источники денег и где важные ограничения." - }, - { - "user_message": "То есть это можно считать прибылью за 2020 или нет? Коротко." - }, - { - "user_message": "А кто за 2020 принес больше всего денег, и если там банк, не называй его обычным клиентом." - }, - { - "user_message": "По исходящим за 2020 есть зависимость от одного поставщика или это только денежная концентрация?" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513102845_gen-ag05131028-234e5e.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513102845_gen-ag05131028-234e5e.json deleted file mode 100644 index 2e720a9..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513102845_gen-ag05131028-234e5e.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05131028-234e5e", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-13T10:28:45+00:00", - "generation_id": "gen-ag05131028-234e5e", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 100 large-query continuation UX replay", - "domain": "address_phase100_large_query_continuation_ux", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Phase 100 large-query continuation UX replay", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "Дай общий бизнес-обзор ООО Альтернатива Плюс за весь доступный период: входящие, исходящие, нетто, лучший год. Если срез слишком широкий, не выдумывай полный итог, а скажи как безопасно дособрать." - }, - { - "user_message": "Ок, тогда дособери конкретно 2020: входящие, исходящие и расчетное денежное нетто." - }, - { - "user_message": "Это можно считать прибылью за 2020 или нет? Ответь коротко и по делу." - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513104438_gen-ag05131044-cbe2ff.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513104438_gen-ag05131044-cbe2ff.json deleted file mode 100644 index cae0d9b..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513104438_gen-ag05131044-cbe2ff.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05131044-cbe2ff", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-13T10:44:38+00:00", - "generation_id": "gen-ag05131044-cbe2ff", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 101 inventory root scope without warehouse clarification replay", - "domain": "address_phase101_inventory_root_scope_no_warehouse_clarification", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Phase 101 inventory root scope without warehouse clarification replay", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "приветик - че как там дела" - }, - { - "user_message": "расскажи что можешь интересного" - }, - { - "user_message": "кайф - что там на складе по остаткам?" - }, - { - "user_message": "АЛЬТЕРНАТИВА" - }, - { - "user_message": "а исторические остатки на другие даты умеешь?" - }, - { - "user_message": "давай на июнь 2017" - }, - { - "user_message": "март 2016" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513112152_gen-ag05131121-8c41ab.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513112152_gen-ag05131121-8c41ab.json deleted file mode 100644 index 0524bf8..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513112152_gen-ag05131121-8c41ab.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05131121-8c41ab", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-13T11:21:52+00:00", - "generation_id": "gen-ag05131121-8c41ab", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 102 debt mirror clean-scope polarity replay", - "domain": "address_phase102_debt_mirror_clean_scope_polarity", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Phase 102 debt mirror clean-scope polarity replay", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "Альтернатива Плюс" - }, - { - "user_message": "мы кому реально должны денег на сегодня? коротко, чистый долг к оплате, без встречных обеспечений как основного долга" - }, - { - "user_message": "а Комитету государственных услуг мы реально должны эти 3,6 млн или это встречное обеспечение/зачет? объясни именно по смыслу долга" - }, - { - "user_message": "а нам Комитет государственных услуг тоже должен 3,6 млн? это же та же сумма — скажи честно, это дебиторка или встречная часть?" - }, - { - "user_message": "тогда кто нам реально должен денег на сегодня? именно чистая дебиторка" - }, - { - "user_message": "а мы кому?" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513120047_gen-ag05131200-0ed59a.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513120047_gen-ag05131200-0ed59a.json deleted file mode 100644 index 8628bb9..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513120047_gen-ag05131200-0ed59a.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05131200-0ed59a", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-13T12:00:47+00:00", - "generation_id": "gen-ag05131200-0ed59a", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 103 financial role and purpose arbitration replay", - "domain": "address_phase103_financial_role_purpose_arbitration", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Phase 103 financial role and purpose arbitration replay", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "Альтернатива Плюс" - }, - { - "user_message": "По СБЕРБАНКУ за 2020 покажи коротко: сколько денег входило и уходило, и что это по смыслу в 1С — клиентская выручка, поставщик, комиссия, кредит или другой финансовый поток?" - }, - { - "user_message": "Если СБЕРБАНК есть во входящих поступлениях, можно ли считать его нашим клиентом и выручкой? Скажи по подтвержденным строкам, без притягивания." - }, - { - "user_message": "А если деньги уходили в СБЕРБАНК, это наш поставщик или финансовые списания? Раздели по смыслу и покажи основание." - }, - { - "user_message": "Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток, если по назначению он не обычный клиент или поставщик." - }, - { - "user_message": "А теперь отдельно по Группа СВК за 2020: сколько денег получили, сколько заплатили и какое нетто?" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513122618_gen-ag05131226-630ddf.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513122618_gen-ag05131226-630ddf.json deleted file mode 100644 index 4a760d2..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260513122618_gen-ag05131226-630ddf.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05131226-630ddf", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-13T12:26:18+00:00", - "generation_id": "gen-ag05131226-630ddf", - "mode": "saved_user_sessions", - "title": "AGENT | Phase 104 generic role-tail anchor hygiene replay", - "domain": "address_phase104_generic_role_tail_anchor_hygiene", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Phase 104 generic role-tail anchor hygiene replay", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "Альтернатива Плюс" - }, - { - "user_message": "Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток, если по назначению он не обычный клиент или поставщик." - }, - { - "user_message": "А отдельно по СБЕРБАНКУ: он для нас клиент, поставщик или финансовый поток? Дай коротко по подтвержденным строкам." - }, - { - "user_message": "А теперь по поставщику Группа СВК за 2020: сколько мы ему заплатили и какой общий денежный смысл?" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260522131931_gen-ag05221319-4035f5.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260522131931_gen-ag05221319-4035f5.json deleted file mode 100644 index 2d6f751..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260522131931_gen-ag05221319-4035f5.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05221319-4035f5", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-22T13:19:31+00:00", - "generation_id": "gen-ag05221319-4035f5", - "mode": "saved_user_sessions", - "title": "AGENT | Inventory margin-ranking accepted replay 2026-05-22", - "domain": "inventory_margin_ranking", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Inventory margin-ranking accepted replay 2026-05-22", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "Какая номеклатура товара реализована с высокой прибылью какая с низкой" - }, - { - "user_message": "сентябрь 2017" - }, - { - "user_message": "покажи найденные строки себестоимостной базы" - }, - { - "user_message": "расширь до 2017 года" - }, - { - "user_message": "анализ по 41 счету а не 01" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260522195737_gen-ag05221957-713bbd.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260522195737_gen-ag05221957-713bbd.json deleted file mode 100644 index 10d317b..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260522195737_gen-ag05221957-713bbd.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05221957-713bbd", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-22T19:57:37+00:00", - "generation_id": "gen-ag05221957-713bbd", - "mode": "saved_user_sessions", - "title": "AGENT | Hot value-flow discovery handoff", - "domain": "autonomy_hot_value_flow_handoff", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Hot value-flow discovery handoff", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "Сколько входящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?" - }, - { - "user_message": "Сколько исходящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?" - }, - { - "user_message": "А всего сколько денег пришло в ООО Альтернатива Плюс за 2020, без топов и без контрагентов?" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260523185848_gen-ag05231858-323f86.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260523185848_gen-ag05231858-323f86.json deleted file mode 100644 index 0c7b288..0000000 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260523185848_gen-ag05231858-323f86.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "suite_id": "assistant_saved_session_gen-ag05231858-323f86", - "suite_version": "0.1.0", - "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-23T18:58:48+00:00", - "generation_id": "gen-ag05231858-323f86", - "mode": "saved_user_sessions", - "title": "AGENT | Autonomy business quality pack", - "domain": "autonomy_business_quality", - "scenario_count": 1, - "case_ids": [ - "SAVED-001" - ], - "cases": [ - { - "case_id": "SAVED-001", - "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Autonomy business quality pack", - "question_type": "followup", - "broadness_level": "medium", - "turns": [ - { - "user_message": "Сколько входящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?" - }, - { - "user_message": "Сколько исходящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?" - }, - { - "user_message": "А всего сколько денег пришло в ООО Альтернатива Плюс за 2020, без топов и без контрагентов?" - }, - { - "user_message": "Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток." - }, - { - "user_message": "скока денег альтернатива заработала за 20 год?" - }, - { - "user_message": "а это чистая прибыль?" - }, - { - "user_message": "Какая чистая прибыль по ООО Альтернатива Плюс за 2020?" - }, - { - "user_message": "А отдельно по СБЕРБАНКУ: он для нас клиент, поставщик или финансовый поток? Дай коротко по подтвержденным строкам." - }, - { - "user_message": "какое нетто по деньгам с Группа СВК за 2020 год: сколько получили и сколько заплатили?" - }, - { - "user_message": "кому мы должны на конец 2020?" - }, - { - "user_message": "а нам кто должен на конец 2020?" - }, - { - "user_message": "сколько НДС надо заплатить в налоговую за декабрь 2019?" - }, - { - "user_message": "Как ты оценишь деятельность компании?" - }, - { - "user_message": "Какая номенклатура товара реализована с высокой прибылью какая с низкой?" - }, - { - "user_message": "май 2020" - } - ] - } - ] -} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260509183050_gen-ag05091830-062fc9.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260524230641_gen-ag05242306-7b49ab.json similarity index 57% rename from llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260509183050_gen-ag05091830-062fc9.json rename to llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260524230641_gen-ag05242306-7b49ab.json index 71c9552..ac18760 100644 --- a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260509183050_gen-ag05091830-062fc9.json +++ b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260524230641_gen-ag05242306-7b49ab.json @@ -1,12 +1,12 @@ { - "suite_id": "assistant_saved_session_gen-ag05091830-062fc9", + "suite_id": "assistant_saved_session_gen-ag05242306-7b49ab", "suite_version": "0.1.0", "schema_version": "assistant_saved_session_suite_v0_1", - "generated_at": "2026-05-09T18:30:50+00:00", - "generation_id": "gen-ag05091830-062fc9", + "generated_at": "2026-05-24T23:06:41+00:00", + "generation_id": "gen-ag05242306-7b49ab", "mode": "saved_user_sessions", - "title": "AGENT | Agentic semantic development loop dogfood gate", - "domain": "agentic_semantic_development_loop_control", + "title": "AGENT | Бизнес-обзор компании и СВК accepted replay 2026-05-24", + "domain": "agent_business_overview_counterparty_reliability", "scenario_count": 1, "case_ids": [ "SAVED-001" @@ -15,7 +15,7 @@ { "case_id": "SAVED-001", "scenario_tag": "agent_saved_user_sessions", - "title": "AGENT | Agentic semantic development loop dogfood gate", + "title": "AGENT | Бизнес-обзор компании и СВК accepted replay 2026-05-24", "question_type": "followup", "broadness_level": "medium", "turns": [ @@ -25,9 +25,6 @@ { "user_message": "Раскрой деньги подробнее: сколько получили, сколько заплатили, какой чистый денежный поток, кто главный клиент и главный поставщик в 2020." }, - { - "user_message": "А если смотреть за все доступное время, какой самый доходный год по подтвержденным оборотам и почему? Не называй это бухгалтерской прибылью, если чистой прибыли нет." - }, { "user_message": "Что с НДС за 2020 год по ООО Альтернатива Плюс: какая позиция видна, на чем она основана и чего не хватает для налогового вывода?" }, @@ -44,16 +41,22 @@ "user_message": "Собери короткий итог: что мы подтвердили по компании, что отдельно по Группа СВК, какие выводы можно делать и какие нельзя." }, { - "user_message": "Сделай короткий стартовый чек контекста: есть ли уже выбранная компания или контрагент в текущем диалоге; если нет, скажи честно и не выдумывай память про Группа СВК." + "user_message": "По-человечески посмотри ООО Альтернатива Плюс за 2020: что по бизнесу видно в 1С по деньгам, НДС, долгам, складу, клиентам/поставщикам и где пока нельзя делать вывод?" }, { - "user_message": "Покажи хвосты по счету 60 на август 2020 по ООО Альтернатива Плюс; если точных данных нет, скажи это прямо и не подменяй ответ общим обзором." + "user_message": "А по деньгам в этом же году кто больше всего занес и кому больше всего ушло? Банк не называй обычным клиентом без оговорки." }, { - "user_message": "Что было на складе на март 2021 по доступным данным? Дай прямой ответ и не уводи его в контрагента Группа СВК." + "user_message": "Возьми как выбранного контрагента Группа СВК: сколько по нему входящих денег, исходящих денег и расчетное нетто, на чем это основано?" }, { - "user_message": "Вернись к ООО Альтернатива Плюс: сколько всего денег получили и заплатили по всем подтвержденным данным, но не смешивай это с отдельной цепочкой Группа СВК и не называй оборот чистой прибылью." + "user_message": "Теперь по нему покажи документы и не переключайся на организацию." + }, + { + "user_message": "И коротко сравни: что у нас подтверждено по компании, что отдельно по выбранному контрагенту, и какие выводы нельзя делать?" + }, + { + "user_message": "ООО Альтернатива Плюс" } ] } diff --git a/scripts/domain_case_loop.py b/scripts/domain_case_loop.py index 183841a..870326a 100644 --- a/scripts/domain_case_loop.py +++ b/scripts/domain_case_loop.py @@ -1972,6 +1972,11 @@ def derive_step_execution_status(reply_type: str | None, debug_payload: dict[str and mcp_discovery_candidate_status == "ready_for_guarded_use" and reply_type in {"factual", "factual_with_explanation", "partial_coverage"} ): + if ( + mcp_discovery_candidate.get("hot_runtime_wired") is True + and debug_payload.get("mcp_discovery_execution_handoff_can_use_guarded_response") is True + ): + return "exact" return "partial" capability_route_mode = str(debug_payload.get("capability_route_mode") or "").strip() fallback_type = str(debug_payload.get("fallback_type") or "").strip() @@ -2360,6 +2365,8 @@ def is_validated_memory_checkpoint_answer( business_review: dict[str, Any], violations: list[str], ) -> bool: + if is_validated_comparison_boundary_memory_checkpoint(state, business_review, violations): + return True tags = set(normalize_string_list(state.get("semantic_tags"))) if "memory" not in tags: return False @@ -2375,6 +2382,46 @@ def is_validated_memory_checkpoint_answer( ) +def is_validated_comparison_boundary_memory_checkpoint( + state: dict[str, Any], + business_review: dict[str, Any], + violations: list[str], +) -> bool: + if violations: + return False + tags = set(normalize_string_list(state.get("semantic_tags"))) + if not {"business_overview", "selected_object", "organization_clarification"} <= tags: + return False + comparison_scope = state.get("comparison_scope") if isinstance(state.get("comparison_scope"), dict) else {} + organization = comparison_scope.get("organization") if isinstance(comparison_scope.get("organization"), dict) else {} + counterparty = comparison_scope.get("counterparty") if isinstance(comparison_scope.get("counterparty"), dict) else {} + proof_bundles = comparison_scope.get("proof_bundles") if isinstance(comparison_scope.get("proof_bundles"), dict) else {} + value_flow_bundle = ( + proof_bundles.get("counterparty_value_flow_bundle") + if isinstance(proof_bundles.get("counterparty_value_flow_bundle"), dict) + else None + ) + document_bundle = ( + proof_bundles.get("counterparty_document_bundle") + if isinstance(proof_bundles.get("counterparty_document_bundle"), dict) + else None + ) + organization_label = str(organization.get("label") or "").strip() + counterparty_label = str(counterparty.get("label") or "").strip() + focus_object = state.get("focus_object") if isinstance(state.get("focus_object"), dict) else {} + focus_label = str(focus_object.get("label") or "").strip() + if not organization_label or not counterparty_label or not (value_flow_bundle or document_bundle): + return False + if focus_label and focus_label.casefold() != counterparty_label.casefold(): + return False + return ( + business_review.get("direct_answer_first_ok") is True + and business_review.get("answer_layering_ok") is True + and business_review.get("technical_garbage_present") is False + and business_review.get("business_usefulness_ok") is True + ) + + def is_validated_confirmed_runtime_answer( state: dict[str, Any], execution_status: str, @@ -2386,7 +2433,17 @@ def is_validated_confirmed_runtime_answer( if violations: return False if state.get("mcp_discovery_response_applied") is True: - return False + return ( + str(state.get("mcp_discovery_response_candidate_status") or "").strip() == "ready_for_guarded_use" + and state.get("mcp_discovery_response_candidate_hot_runtime_wired") is True + and state.get("mcp_discovery_execution_handoff_can_use_guarded_response") is True + and str(state.get("reply_type") or "").strip() + in {"factual", "factual_with_explanation", "partial_coverage"} + and business_review.get("business_usefulness_ok") is True + and business_review.get("direct_answer_first_ok") is True + and business_review.get("answer_layering_ok") is True + and business_review.get("technical_garbage_present") is False + ) if str(state.get("reply_type") or "").strip() not in {"factual", "factual_with_explanation", "empty_but_valid"}: return False if str(state.get("fallback_type") or "").strip() not in {"", "none"}: @@ -2489,6 +2546,33 @@ def is_validated_clarification_answer( ) +def is_validated_missing_axis_clarification_answer( + state: dict[str, Any], + execution_status: str, + business_review: dict[str, Any], + violations: list[str], +) -> bool: + if execution_status != "partial": + return False + if violations: + return False + if str(state.get("mcp_discovery_response_candidate_status") or "").strip() != "clarification_candidate": + return False + if str(state.get("mcp_discovery_route_candidate_status") or "").strip() != "needs_user_scope": + return False + if str(state.get("mcp_discovery_response_reply_type") or "").strip() != "clarification_required": + return False + if not normalize_string_list(state.get("mcp_discovery_route_candidate_missing_axes")): + return False + return ( + business_review.get("business_usefulness_ok") is True + and business_review.get("direct_answer_first_ok") is True + and business_review.get("answer_layering_ok") is True + and business_review.get("technical_garbage_present") is False + and business_review.get("next_action_present") is True + ) + + def _business_review_is_clean(step_state: dict[str, Any]) -> bool: business_review = step_state.get("business_first_review") if not isinstance(business_review, dict): @@ -2736,6 +2820,12 @@ def validate_step_contract(step_state: dict[str, Any]) -> dict[str, Any]: business_review, unique_violations, ) + missing_axis_clarification_validated = is_validated_missing_axis_clarification_answer( + state, + execution_status, + business_review, + unique_violations, + ) state["violated_invariants"] = unique_violations state["warnings"] = list(dict.fromkeys(warnings)) state["hard_fail"] = hard_fail @@ -2744,6 +2834,7 @@ def validate_step_contract(step_state: dict[str, Any]) -> dict[str, Any]: state["runtime_factual_answer_validated"] = runtime_factual_validated state["guarded_insufficiency_validated"] = guarded_insufficiency_validated state["clarification_answer_validated"] = clarification_validated + state["missing_axis_clarification_validated"] = missing_axis_clarification_validated state["acceptance_status"] = acceptance_status_from_execution( execution_status, hard_fail, @@ -2753,6 +2844,7 @@ def validate_step_contract(step_state: dict[str, Any]) -> dict[str, Any]: or runtime_factual_validated or guarded_insufficiency_validated or clarification_validated + or missing_axis_clarification_validated ), ) state["status"] = state["acceptance_status"] @@ -2913,6 +3005,7 @@ def build_scenario_step_state( "actual_direct_answer": top_non_empty[0] if top_non_empty else None, "extracted_filters": debug.get("extracted_filters") if isinstance(debug.get("extracted_filters"), dict) else {}, "focus_object": context.get("active_focus_object") if isinstance(context.get("active_focus_object"), dict) else None, + "comparison_scope": context.get("comparison_scope") if isinstance(context.get("comparison_scope"), dict) else None, "fallback_type": debug.get("fallback_type"), "mcp_call_status": debug.get("mcp_call_status"), "balance_confirmed": debug.get("balance_confirmed"), @@ -2947,6 +3040,20 @@ def save_scenario_step_bundle( write_text(step_dir / "resolved_question.txt", f"{step_state['question_resolved']}\n") +def is_effectively_complete_partial_step(step_output: dict[str, Any]) -> bool: + execution_status = str(step_output.get("execution_status") or step_output.get("status") or "").strip() + if execution_status == "exact": + return True + if execution_status != "partial": + return False + if str(step_output.get("acceptance_status") or "").strip() != "validated": + return False + return ( + step_output.get("missing_axis_clarification_validated") is True + or step_output.get("clarification_answer_validated") is True + ) + + def derive_scenario_execution_status(step_outputs: dict[str, dict[str, Any]]) -> str: statuses = [str(item.get("execution_status") or item.get("status") or "") for item in step_outputs.values()] if not statuses: @@ -2955,7 +3062,7 @@ def derive_scenario_execution_status(step_outputs: dict[str, dict[str, Any]]) -> return "blocked" if any(status == "needs_exact_capability" for status in statuses): return "needs_exact_capability" - if any(status == "partial" for status in statuses): + if any(not is_effectively_complete_partial_step(item) for item in step_outputs.values()): return "partial" return "exact" @@ -3419,6 +3526,7 @@ def build_pack_summary( scenario_results: list[dict[str, Any]], final_status: str, execution_status: str, + acceptance_status: str, ) -> str: lines = [ "# Pack summary", @@ -3427,6 +3535,7 @@ def build_pack_summary( f"- domain: `{pack['domain']}`", f"- title: {pack['title']}", f"- execution_status: `{execution_status}`", + f"- acceptance_status: `{acceptance_status}`", f"- final_status: `{final_status}`", "", "## Scenarios", @@ -3450,6 +3559,7 @@ def build_pack_final_status( scenario_results: list[dict[str, Any]], final_status: str, execution_status: str, + acceptance_status: str, ) -> str: expected_scenarios = len(pack.get("scenarios") or []) executed_scenarios = len(scenario_results) @@ -3471,6 +3581,7 @@ def build_pack_final_status( - status: `{final_status}` - execution_status: `{execution_status}` + - acceptance_status: `{acceptance_status}` - pack_id: `{pack['pack_id']}` - domain: `{pack['domain']}` - reason: {reason} @@ -3522,6 +3633,18 @@ def derive_pack_final_status(pack: dict[str, Any], scenario_results: list[dict[s return "accepted" if len(scenario_results) == len(pack.get("scenarios") or []) else "partial" +def derive_pack_effective_final_status(acceptance_status: str, execution_status: str) -> str: + normalized_acceptance = str(acceptance_status or "").strip() or "partial" + normalized_execution = str(execution_status or "").strip() or "partial" + if normalized_acceptance in {"blocked", "needs_exact_capability"}: + return normalized_acceptance + if normalized_execution in {"blocked", "needs_exact_capability"}: + return normalized_execution + if normalized_acceptance == "accepted" and normalized_execution == "exact": + return "accepted" + return "partial" + + def build_scenario_acceptance_matrix(pack: dict[str, Any], scenario_results: list[dict[str, Any]]) -> str: scenario_status_map = { str(item.get("scenario_id") or ""): str(item.get("final_status") or "unknown") @@ -3906,6 +4029,7 @@ def compact_step_output_for_review(step_output: Any) -> dict[str, Any]: "required_carryover_invariants": step_output.get("required_carryover_invariants"), "extracted_filters": step_output.get("extracted_filters"), "focus_object": step_output.get("focus_object"), + "comparison_scope": step_output.get("comparison_scope"), "date_scope": step_output.get("date_scope"), "result_mode": step_output.get("result_mode"), "truth_mode": step_output.get("truth_mode"), @@ -4436,6 +4560,8 @@ def build_deterministic_repair_targets( "schema_version": "domain_pack_repair_targets_v1", "pack_id": pack_state.get("pack_id"), "domain": pack_state.get("domain"), + "execution_status": pack_state.get("execution_status"), + "acceptance_status": pack_state.get("acceptance_status"), "final_status": pack_state.get("final_status"), "target_count": len(targets), "severity_counts": severity_counts, @@ -4588,6 +4714,18 @@ def analyst_target_contradicts_validated_step(target: dict[str, Any], step_snaps ): return True + if step_snapshot.get("memory_checkpoint_validated") is True and evidence_problem: + memory_checkpoint_markers = ( + "machine-readable", + "comparison boundary", + "carryover", + "comparison bundle", + "reusable comparison", + "selected counterparty", + ) + if any(marker in target_text for marker in memory_checkpoint_markers): + return True + followup_problem = problem_type in { "followup_action_resolution_gap", "object_memory_gap", @@ -4980,8 +5118,9 @@ def evaluate_deterministic_loop_gate( repair_targets: dict[str, Any], ) -> tuple[bool, str]: pack_final_status = str(pack_state.get("final_status") or "").strip() or "partial" - if pack_final_status != "accepted": - return False, f"pack_final_status={pack_final_status}" + pack_acceptance_status = str(pack_state.get("acceptance_status") or pack_final_status).strip() or "partial" + if pack_acceptance_status != "accepted": + return False, f"pack_acceptance_status={pack_acceptance_status};pack_final_status={pack_final_status}" severity_counts = repair_targets.get("severity_counts") if isinstance(repair_targets, dict) else {} if isinstance(severity_counts, dict): p0_count = int(severity_counts.get("P0") or 0) @@ -5120,7 +5259,8 @@ def build_analyst_loop_prompt( Rules: - `accepted` is allowed only if quality_score >= {target_score}, unresolved_p0_count = 0, and regression_detected = false; - - `accepted` is forbidden if the evidence bundle shows `pack_state.final_status != accepted` or the deterministic repair targets still contain any `P0` or `P1` items; + - `accepted` is forbidden if the evidence bundle shows `pack_state.acceptance_status != accepted` (or, for old artifacts without `acceptance_status`, `pack_state.final_status != accepted`) or the deterministic repair targets still contain any `P0` or `P1` items; + - `pack_state.final_status=partial` with `acceptance_status=accepted` means the run still had partial execution evidence; treat it as a proof-strength signal, not as a presentation bug by itself; - `accepted` also requires `direct_answer_ok = true`, `business_usefulness_ok = true`, `temporal_honesty_ok = true`, and `field_truth_ok = true`; - Treat validated bounded MCP discovery as the semantic route when `bounded_mcp_answer_validated = true`, `mcp_discovery_response_applied = true`, `mcp_discovery_response_candidate_status = ready_for_guarded_use`, and `mcp_discovery_effective_intents` matches the business question. The legacy address route may be only a seed lane; do not call that silent heuristic masking unless the selected discovery chain is wrong, not ready, not applied, or the user-facing answer/state is semantically wrong. - Use `mcp_discovery_route_candidate_status`, `mcp_discovery_route_candidate_missing_axes`, and `mcp_discovery_route_candidate_enablement_reason` to distinguish a valid user-scope clarification from a real missing reviewed route. Do not ask the coder to overfit the visible answer when the correct next action is route enablement or missing-axis clarification. @@ -5998,7 +6138,8 @@ def handle_run_pack(args: argparse.Namespace) -> int: ) execution_status = derive_pack_execution_status(scenario_results) - final_status = derive_pack_final_status(pack, scenario_results) + acceptance_status = derive_pack_final_status(pack, scenario_results) + final_status = derive_pack_effective_final_status(acceptance_status, execution_status) pack_state = { "schema_version": SCENARIO_PACK_SCHEMA_VERSION, @@ -6009,6 +6150,7 @@ def handle_run_pack(args: argparse.Namespace) -> int: "bindings": pack.get("bindings") or {}, "scenario_results": scenario_results, "execution_status": execution_status, + "acceptance_status": acceptance_status, "final_status": final_status, "updated_at": datetime.now(timezone.utc).replace(microsecond=0).isoformat(), } @@ -6018,8 +6160,8 @@ def handle_run_pack(args: argparse.Namespace) -> int: write_json(pack_dir / "pack_state.json", pack_state) write_json(pack_dir / "repair_targets.json", repair_targets) write_text(pack_dir / "repair_targets.md", build_repair_targets_summary(repair_targets)) - write_text(pack_dir / "pack_summary.md", build_pack_summary(pack, scenario_results, final_status, execution_status)) - write_text(pack_dir / "final_status.md", build_pack_final_status(pack, scenario_results, final_status, execution_status)) + write_text(pack_dir / "pack_summary.md", build_pack_summary(pack, scenario_results, final_status, execution_status, acceptance_status)) + write_text(pack_dir / "final_status.md", build_pack_final_status(pack, scenario_results, final_status, execution_status, acceptance_status)) print(f"[domain-case-loop] saved pack artifacts to {pack_dir}") print(f"[domain-case-loop] execution_status={execution_status} final_status={final_status}") return 0 diff --git a/scripts/review_assistant_stage1_run.py b/scripts/review_assistant_stage1_run.py index 3aa1d4b..653b170 100644 --- a/scripts/review_assistant_stage1_run.py +++ b/scripts/review_assistant_stage1_run.py @@ -135,6 +135,45 @@ COMPANY_PROFIT_ANSWER_RE = re.compile( "(?:\u0447\u0438\u0441\u0442\u0430\u044f\\s+\u043f\u0440\u0438\u0431\u044b\u043b\u044c|\u043f\u0440\u0438\u0431\u044b\u043b\u044c\u044e|90/91/99|\u0444\u0438\u043d\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442|\u0443\u0431\u044b\u0442\u043e\u043a)", re.IGNORECASE, ) +BACKEND_ERROR_ANSWER_RE = re.compile( + "(?:backend_error|internal\\s+error|" + "\u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\\w*\\s+\u043e\u0448\u0438\u0431\u043a|" + "\u043d\u0435\\s+\u0443\u0434\u0430\u043b\u043e\u0441\u044c\\s+\u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c\\s+\u0440\u0430\u0437\u0431\u043e\u0440)", + re.IGNORECASE, +) +TOP_YEAR_QUESTION_RE = re.compile( + "(?:\u0441\u0430\u043c\\w*\\s+\u0434\u043e\u0445\u043e\u0434\u043d\\w*\\s+\u0433\u043e\u0434|" + "\u0434\u043e\u0445\u043e\u0434\u043d\\w*\\s+\u0433\u043e\u0434|" + "\u043b\u0443\u0447\u0448\\w*\\s+\u0433\u043e\u0434|top[-\\s]*year|best\\s+year)", + re.IGNORECASE, +) +DIRECT_TOP_YEAR_ANSWER_RE = re.compile( + "(?:(?:\u0441\u0430\u043c\\w*\\s+\u0434\u043e\u0445\u043e\u0434\u043d\\w*\\s+\u0433\u043e\u0434|" + "\u043b\u0443\u0447\u0448\\w*\\s+\u0433\u043e\u0434|\u043b\u0438\u0434\u0438\u0440\\w*|" + "\u0442\u043e\u043f[-\\s]*1|top[-\\s]*year|best\\s+year)[^\\n]{0,160}(?:19|20)\\d{2}|" + "(?:19|20)\\d{2}[^\\n]{0,120}(?:\u043b\u0438\u0434\u0438\u0440\\w*|" + "\u0441\u0430\u043c\\w*\\s+\u0434\u043e\u0445\u043e\u0434\u043d\\w*|" + "\u043b\u0443\u0447\u0448\\w*\\s+\u0433\u043e\u0434))", + re.IGNORECASE, +) +GENERIC_BUSINESS_OVERVIEW_ANSWER_RE = re.compile( + "(?:\u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442\\s+\u043a\u0430\u043a\\s+\u0431\u0438\u0437\u043d\u0435\u0441|" + "\u043a\u0440\u0443\u043f\u043d\\w*\\s+\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\\w*\\s+\u0434\u0435\u043d\u0435\u0436\u043d\\w*\\s+\u043f\u043e\u0442\u043e\u043a|" + "\u0431\u0438\u0437\u043d\u0435\u0441-\u043e\u0431\u0437\u043e\u0440|\u043e\u0431\u0449\\w*\\s+\u0431\u0438\u0437\u043d\u0435\u0441\\w*\\s+\u043e\u0431\u0437\u043e\u0440)", + re.IGNORECASE, +) +VAT_PURCHASE_DATE_QUESTION_RE = re.compile( + "(?:\u043d\u0434\u0441[^\\n]{0,80}\u0434\u0430\u0442[ау]\\s+\u043f\u043e\u043a\u0443\u043f\u043a|" + "\u0434\u0430\u0442[ау]\\s+\u043f\u043e\u043a\u0443\u043f\u043a[^\\n]{0,80}\u043d\u0434\u0441)", + re.IGNORECASE, +) +VAT_PURCHASE_DATE_BASIS_RE = re.compile( + "(?:\u0434\u0430\u0442[ауы]\\s+\u043f\u043e\u043a\u0443\u043f\u043a|\u043f\u043e\u043a\u0443\u043f\u043a[аи]\\s+\u043e\u0442|" + "\u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438[ея]\\s+\u043e\u0442|\u043e\u043f\u043e\u0440\u043d\\w*\\s+\u0434\u0430\u0442|" + "\u043f\u0435\u0440\u0432\\w*\\s+(?:\u043d\u0430\u0439\u0434\u0435\u043d\u043d\\w*\\s+)?(?:\u043f\u043e\u043a\u0443\u043f\u043a|\u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d)|" + "\u0434\u0430\u0442\\w*\\s+\u0437\u0430\u043a\u0443\u043f)", + re.IGNORECASE, +) def now_iso() -> str: @@ -360,6 +399,9 @@ def build_step_for_pair(pair: dict[str, Any]) -> dict[str, Any]: "business_answer_too_verbose": "P1", "bank_counterparty_misclassified_as_business_partner": "P1", "counterparty_value_flow_misrouted_to_company_profit": "P0", + "backend_error_response": "P0", + "year_ranking_direct_answer_missing": "P0", + "purchase_date_vat_anchor_ambiguous": "P1", }, } @@ -374,6 +416,20 @@ def marker_hits(text: str, markers: tuple[str, ...]) -> list[str]: return [marker for marker in markers if marker and marker.casefold() in lowered] +def add_review_issue( + *, + issue_codes: list[str], + root_layers: list[str], + issue_code: str, + layers: tuple[str, ...], +) -> None: + if issue_code not in issue_codes: + issue_codes.append(issue_code) + for layer in layers: + if layer and layer not in root_layers: + root_layers.append(layer) + + def detect_counterparty_value_flow_profit_mismatch(question: str, assistant_text: str) -> dict[str, Any] | None: question_text = str(question or "") answer_text = str(assistant_text or "") @@ -412,6 +468,51 @@ def augment_gui_business_review(step_state: dict[str, Any]) -> dict[str, Any]: assistant_text = str(step_state.get("assistant_text") or "") issue_codes = [str(item) for item in review.get("issue_codes", []) if str(item).strip()] root_layers = [str(item) for item in review.get("suggested_root_cause_layers", []) if str(item).strip()] + semantic_details = ( + dict(review.get("semantic_mismatch_details")) + if isinstance(review.get("semantic_mismatch_details"), dict) + else {} + ) + first_answer_line = next((line.strip() for line in assistant_text.splitlines() if line.strip()), "") + + if str(step_state.get("reply_type") or "").strip() == "backend_error" or BACKEND_ERROR_ANSWER_RE.search(assistant_text): + add_review_issue( + issue_codes=issue_codes, + root_layers=root_layers, + issue_code="backend_error_response", + layers=("runtime_error", "business_utility_gap"), + ) + semantic_details["backend_error_response"] = { + "reply_type": step_state.get("reply_type"), + "first_answer_line": first_answer_line, + } + + if TOP_YEAR_QUESTION_RE.search(question): + has_direct_top_year = bool(DIRECT_TOP_YEAR_ANSWER_RE.search(assistant_text)) + generic_overview_first = bool(GENERIC_BUSINESS_OVERVIEW_ANSWER_RE.search(first_answer_line)) + if not has_direct_top_year or generic_overview_first: + add_review_issue( + issue_codes=issue_codes, + root_layers=root_layers, + issue_code="year_ranking_direct_answer_missing", + layers=("answer_shape_mismatch", "business_utility_gap"), + ) + semantic_details["year_ranking_direct_answer_missing"] = { + "has_direct_top_year": has_direct_top_year, + "generic_overview_first": generic_overview_first, + "first_answer_line": first_answer_line, + } + + if VAT_PURCHASE_DATE_QUESTION_RE.search(question) and not VAT_PURCHASE_DATE_BASIS_RE.search(assistant_text): + add_review_issue( + issue_codes=issue_codes, + root_layers=root_layers, + issue_code="purchase_date_vat_anchor_ambiguous", + layers=("domain_anchor_gap", "field_mapping_gap"), + ) + semantic_details["purchase_date_vat_anchor_ambiguous"] = { + "first_answer_line": first_answer_line, + } technical_hits = [str(item) for item in review.get("technical_garbage_hits", []) if str(item).strip()] for hit in marker_hits(assistant_text, GUI_TECHNICAL_LEAK_MARKERS): @@ -434,17 +535,18 @@ def augment_gui_business_review(step_state: dict[str, Any]) -> dict[str, Any]: mismatch_details = detect_counterparty_value_flow_profit_mismatch(question, assistant_text) if mismatch_details: - issue_code = "counterparty_value_flow_misrouted_to_company_profit" - if issue_code not in issue_codes: - issue_codes.append(issue_code) - if "followup_action_resolution_gap" not in root_layers: - root_layers.append("followup_action_resolution_gap") - if "answer_shape_mismatch" not in root_layers: - root_layers.append("answer_shape_mismatch") - review["semantic_mismatch_details"] = mismatch_details + add_review_issue( + issue_codes=issue_codes, + root_layers=root_layers, + issue_code="counterparty_value_flow_misrouted_to_company_profit", + layers=("followup_action_resolution_gap", "answer_shape_mismatch"), + ) + semantic_details["counterparty_value_flow_misrouted_to_company_profit"] = mismatch_details review["technical_garbage_present"] = bool(technical_hits) review["technical_garbage_hits"] = technical_hits + if semantic_details: + review["semantic_mismatch_details"] = semantic_details review["issue_codes"] = issue_codes review["suggested_root_cause_layers"] = list(dict.fromkeys(root_layers)) review["business_usefulness_ok"] = not issue_codes diff --git a/scripts/test_review_assistant_stage1_run.py b/scripts/test_review_assistant_stage1_run.py index cea5345..fca7c5d 100644 --- a/scripts/test_review_assistant_stage1_run.py +++ b/scripts/test_review_assistant_stage1_run.py @@ -104,6 +104,117 @@ class AssistantStage1RunReviewTests(unittest.TestCase): self.assertEqual(review["question_quality_review"]["turns_total"], 2) self.assertIn("contextual_followup", review["question_quality_review"]["tag_counts"]) + def test_review_flags_backend_error_as_business_blocker(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + sessions_dir = root / "sessions" + reports_dir = root / "reports" + run_id = "assistant-stage1-backend-error" + session_file = sessions_dir / f"{run_id}-SAVED-001.json" + report_file = reports_dir / f"{run_id}.md" + write_json( + session_file, + session_payload( + [ + {"role": "user", "text": "приветик - че как там дела"}, + { + "role": "assistant", + "text": "Сейчас не удалось завершить разбор из-за внутренней ошибки контуров LLM.", + "reply_type": "backend_error", + "message_id": "a-backend-error", + "trace_id": "trace-backend-error", + "debug": {}, + }, + ] + ), + ) + report_file.parent.mkdir(parents=True, exist_ok=True) + report_file.write_text(f"# Assistant Stage 1 Eval Run\n\n- run_id: {run_id}\n", encoding="utf-8") + + review = reviewer.build_run_review( + run_id=run_id, + session_files=[session_file], + report_path=report_file, + ) + + self.assertEqual(review["summary"]["overall_business_status"], "fail") + self.assertIn("backend_error_response", review["summary"]["issue_counts"]) + target_by_issue = {item["issue_code"]: item for item in review["repair_targets"]} + self.assertEqual(target_by_issue["backend_error_response"]["severity"], "P0") + + def test_review_flags_top_year_generic_overview_without_direct_year(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + sessions_dir = root / "sessions" + reports_dir = root / "reports" + run_id = "assistant-stage1-top-year-generic" + session_file = sessions_dir / f"{run_id}-SAVED-001.json" + report_file = reports_dir / f"{run_id}.md" + write_json( + session_file, + session_payload( + [ + {"role": "user", "text": "какой у нас самый доходный год"}, + { + "role": "assistant", + "text": "Коротко: по доступным данным компания выглядит как бизнес с крупными контрактными денежными потоками. Входящие деньги за доступное время: 10 000 руб.", + "reply_type": "partial_coverage", + "message_id": "a-top-year-generic", + "trace_id": "trace-top-year-generic", + "debug": {"capability_id": "address_customer_revenue_and_payments"}, + }, + ] + ), + ) + report_file.parent.mkdir(parents=True, exist_ok=True) + report_file.write_text(f"# Assistant Stage 1 Eval Run\n\n- run_id: {run_id}\n", encoding="utf-8") + + review = reviewer.build_run_review( + run_id=run_id, + session_files=[session_file], + report_path=report_file, + ) + + self.assertEqual(review["summary"]["overall_business_status"], "fail") + self.assertIn("year_ranking_direct_answer_missing", review["summary"]["issue_counts"]) + target_by_issue = {item["issue_code"]: item for item in review["repair_targets"]} + self.assertEqual(target_by_issue["year_ranking_direct_answer_missing"]["severity"], "P0") + + def test_review_accepts_direct_top_year_answer(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + sessions_dir = root / "sessions" + reports_dir = root / "reports" + run_id = "assistant-stage1-top-year-clean" + session_file = sessions_dir / f"{run_id}-SAVED-001.json" + report_file = reports_dir / f"{run_id}.md" + write_json( + session_file, + session_payload( + [ + {"role": "user", "text": "какой у нас самый доходный год"}, + { + "role": "assistant", + "text": "Самый доходный год по подтвержденным поступлениям: 2021 (320 000 руб. по 1 операции). Это денежный поток, а не чистая прибыль.", + "reply_type": "factual", + "message_id": "a-top-year-clean", + "trace_id": "trace-top-year-clean", + "debug": {"capability_id": "address_customer_revenue_and_payments"}, + }, + ] + ), + ) + report_file.parent.mkdir(parents=True, exist_ok=True) + report_file.write_text(f"# Assistant Stage 1 Eval Run\n\n- run_id: {run_id}\n", encoding="utf-8") + + review = reviewer.build_run_review( + run_id=run_id, + session_files=[session_file], + report_path=report_file, + ) + + self.assertNotIn("year_ranking_direct_answer_missing", review["summary"]["issue_counts"]) + def test_save_run_review_materializes_machine_and_markdown_artifacts(self) -> None: with tempfile.TemporaryDirectory() as tmp: output_dir = Path(tmp) / "review"