АДРЕСНЫЙ РЕЖИМ - M2.3b тюнинг account-scope и диагностика стадий адресного рантайма

This commit is contained in:
2026-03-29 20:57:55 +03:00
parent c82ebd70b7
commit 2bf16de4ea
498 changed files with 2619075 additions and 3 deletions
@@ -0,0 +1,20 @@
# Known Positive Live Suite Template
Date: 2026-03-29
Purpose: run pack template for positive-evidence acceptance.
## Required artifacts
- README.md
- run_summary.json
- known_positive_case_matrix.md
- chat_export_known_positive_live.md
- debug_payloads/
- live_call_inventory_address.json
## Core rule
Each case must be pre-anchored (account/counterparty/contract + period), and expected to produce non-empty data.
If result is limited, reason must be explicit (`missing_anchor`, `recipe_visibility_gap`, etc).
@@ -0,0 +1,11 @@
{
"run_id": "2026-03-29_Address_Query_Known_Positive_Live_Suite_Template",
"suite_type": "positive_evidence",
"status": "TEMPLATE",
"metrics": {
"known_positive_case_count": 0,
"known_positive_non_empty_rate": 0,
"known_positive_factual_rate": 0,
"known_positive_false_factual_rate": 0
}
}
@@ -0,0 +1,43 @@
# Address Query Runtime V1 — M0/M1/M2 Baseline Start
Дата: 2026-03-29
Статус: IMPLEMENTED_BASELINE
## Что сделано
- Добавлен отдельный address-query контур в backend (`question_mode` detection на runtime-ветке ассистента).
- Добавлены контракты `addressQuery` и debug-поля address lane.
- Добавлены сервисы:
- classifier
- intent resolver
- filter extractor
- recipe catalog
- MCP client
- address query orchestrator
- В `assistantService` добавлена ранняя развилка:
- если вопрос адресный и поддержан -> address lane;
- иначе -> без изменений в существующий deep-analysis path.
## Что покрыто сейчас
- Базовые P0 intents с recipe:
- `list_payables_counterparties`
- `list_receivables_counterparties`
- `account_balance_snapshot`
- Неподдержанные intent'ы в V1 возвращают `LIMITED_WITH_REASON`.
- Live-first execution через MCP `/api/execute_query`.
## Важные ограничения baseline
- Текущие recipe используют movement snapshot query из `РегистрБухгалтерии.Хозрасчетный`.
- Для `list_open_contracts` и `open_items_by_counterparty_or_contract` пока только controlled limited mode.
- Factual-ответы пока строятся по движениям и account-scope, без полноценного object-level contract closure.
## Проверка
- `npm run build` (backend) — PASSED.
## Следующий шаг
- Расширить recipe whitelist под object-level адресные сценарии (contracts/open items/documents by counterparty/contract).
- Добавить acceptance live-run pack по 5 P0 вопросам address lane.
@@ -0,0 +1,11 @@
llm_normalizer/backend/src/types/addressQuery.ts
llm_normalizer/backend/src/services/addressQueryClassifier.ts
llm_normalizer/backend/src/services/addressIntentResolver.ts
llm_normalizer/backend/src/services/addressFilterExtractor.ts
llm_normalizer/backend/src/services/addressRecipeCatalog.ts
llm_normalizer/backend/src/services/addressMcpClient.ts
llm_normalizer/backend/src/services/addressQueryService.ts
llm_normalizer/backend/src/services/assistantService.ts
llm_normalizer/backend/src/types/assistant.ts
llm_normalizer/backend/src/config.ts
llm_normalizer/.env.example
@@ -0,0 +1,18 @@
{
"run_id": "2026-03-29_Address_Query_Runtime_V1_M0_M1_M2_Baseline_Start",
"date": "2026-03-29",
"scope": "address_query_runtime_bootstrap_to_code",
"status": "IMPLEMENTED_BASELINE",
"build_status": "PASSED",
"deep_path_regression_expected": "none (no deep-path contract change)",
"implemented": {
"address_mode_runtime_branch": true,
"intent_filter_recipe_pipeline": true,
"mcp_live_query_executor": true,
"address_debug_contract": true
},
"limitations": [
"open_contracts and open_items intents still limited",
"movement-based recipes only in baseline"
]
}
@@ -0,0 +1,22 @@
# Verification
Дата: 2026-03-29
## 1) TypeScript build
Команда: `npm run build` (backend)
Результат: PASS
## 2) Address lane smoke checks
Команды проверок (node scripts against `dist/`):
- `detectAddressQuestionMode('who owes us today')` -> `address_query`
- `AddressQueryService.tryHandle('who owes us today')` -> handled=true
- `AssistantService.handleMessage('who owes us today')` with normalizer stub -> ранний `assistant_message_address` path (normalizer не требуется)
Результат: PASS
## Примечание
Live MCP вернул `rows_fetched>0`, но `rows_matched=0` для receivables scope в тестовом запросе, поэтому ответ в `LIMITED_WITH_REASON` — это ожидаемое честное поведение на текущем baseline.
@@ -0,0 +1,29 @@
# Run README — Address Query Runtime V1 M2.1
Дата: 2026-03-29
Run ID: `2026-03-29_Address_Query_Runtime_V1_M2_1_QueryShape_LimitedTaxonomy`
## Цель инкремента
Зафиксировать следующий шаг по согласованному плану:
- добавить `query_shape` в address-runtime debug;
- зафиксировать, что `COMPOUND_FACTUAL_QUERY` в M2.1 пока only-detection (без decomposition execution);
- развести limited-mode по категориям причин:
- `empty_match`
- `missing_anchor`
- `recipe_visibility_gap`
- `execution_error`
- `unsupported`
- добавить runtime-readiness статус в ответ address lane;
- не ломать deep-path и не допускать false-factual.
## Что проверено
- `npm run build` — PASS.
- `vitest` таргет на новый слой (`tests/addressQueryRuntimeM21.test.ts`) — PASS.
- dry-run через `/api/assistant/message` на 7 вопросах — сохранен в `assistant_window_dry_run_results.json`.
## Основной вывод
Address lane продолжает стабильно маршрутизироваться и теперь дает структурированную операционную диагностику причины ограничения. Основной блокер остался прежним: недостаточная видимость данных в текущих movement-based recipes для contract/document-heavy сценариев.
@@ -0,0 +1,138 @@
{
"generated_at": "2026-03-29T16:04:06.939Z",
"questions": [
{
"id": "Q1",
"question": "who owes us today",
"expected_intent": "list_receivables_counterparties",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "AGGREGATE_LOOKUP",
"detected_intent": "list_receivables_counterparties",
"selected_recipe": "address_movements_receivables_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
},
{
"id": "Q2",
"question": "who we owe today",
"expected_intent": "list_payables_counterparties",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "AGGREGATE_LOOKUP",
"detected_intent": "list_payables_counterparties",
"selected_recipe": "address_movements_payables_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
},
{
"id": "Q3",
"question": "show account balance 60 today",
"expected_intent": "account_balance_snapshot",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "AGGREGATE_LOOKUP",
"detected_intent": "account_balance_snapshot",
"selected_recipe": "address_movements_account_snapshot_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
},
{
"id": "Q4",
"question": "show open items by contract",
"expected_intent": "open_items_by_counterparty_or_contract",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "OBJECT_LOOKUP",
"detected_intent": "open_items_by_counterparty_or_contract",
"selected_recipe": null,
"mcp_call_status": "skipped",
"rows_fetched": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "missing_anchor",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "Для точного адресного поиска не хватает обязательного якоря.\nПричина: для open_items нужен якорь контрагента или договора.\nЧто нужно уточнить: укажите контрагента или номер/название договора."
},
{
"id": "Q5",
"question": "list open contracts as of today",
"expected_intent": "list_open_contracts",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "OBJECT_LOOKUP",
"detected_intent": "list_open_contracts",
"selected_recipe": "address_open_contracts_candidates_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"rows_matched": 0,
"runtime_readiness": "REQUIRES_SPECIALIZED_RECIPE",
"limited_reason_category": "recipe_visibility_gap",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "Текущий live recipe не дает нужную видимость данных для этого сценария.\nПричина: в live строках нет договорных якорей для уверенного списка незакрытых договоров.\nЧто нужно уточнить: сузьте запрос по контрагенту или добав"
},
{
"id": "Q6",
"question": "show bank operations by counterparty Alfa",
"expected_intent": "unknown",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "unknown",
"selected_recipe": null,
"mcp_call_status": "skipped",
"rows_fetched": 0,
"rows_matched": 0,
"runtime_readiness": "DEEP_ONLY",
"limited_reason_category": "unsupported",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "Этот запрос не подходит под address_query V1.\nПричина: intent пока не поддержан в address V1.\nЧто нужно уточнить: переформулируйте вопрос как адресный lookup по счету/контрагенту/договору."
},
{
"id": "Q7",
"question": "who owes us and who we owe today",
"expected_intent": "list_receivables_counterparties",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "COMPOUND_FACTUAL_QUERY",
"detected_intent": "list_receivables_counterparties",
"selected_recipe": "address_movements_receivables_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
}
]
}
@@ -0,0 +1,26 @@
{
"baseline_run": "2026-03-29_Address_Query_Runtime_V1_M2_Plus_OpenContracts_OpenItems",
"current_run": "2026-03-29_Address_Query_Runtime_V1_M2_1_QueryShape_LimitedTaxonomy",
"changes": {
"debug_query_shape": {
"before": false,
"after": true
},
"debug_runtime_readiness": {
"before": false,
"after": true
},
"debug_limited_reason_category": {
"before": false,
"after": true
},
"limited_reason_taxonomy_depth": {
"before": 1,
"after": 4
},
"false_factual_rate": {
"before": 0.0,
"after": 0.0
}
}
}
@@ -0,0 +1,14 @@
llm_normalizer/backend/src/types/addressQuery.ts
llm_normalizer/backend/src/services/addressQueryShapeClassifier.ts
llm_normalizer/backend/src/services/addressQueryService.ts
llm_normalizer/backend/src/services/assistantService.ts
llm_normalizer/backend/src/types/assistant.ts
llm_normalizer/backend/tests/addressQueryRuntimeM21.test.ts
docs/ADDRESS/address_query/address_runtime_contracts.md
docs/ADDRESS/address_query/runtime_readiness_matrix_v1.md
docs/ADDRESS/address_query/README.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_1_QueryShape_LimitedTaxonomy/README.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_1_QueryShape_LimitedTaxonomy/run_summary.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_1_QueryShape_LimitedTaxonomy/smoke_checks.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_1_QueryShape_LimitedTaxonomy/before_after_metrics.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_1_QueryShape_LimitedTaxonomy/assistant_window_dry_run_results.json
@@ -0,0 +1,34 @@
{
"run_id": "2026-03-29_Address_Query_Runtime_V1_M2_1_QueryShape_LimitedTaxonomy",
"date": "2026-03-29",
"stage": "address_query_runtime_v1",
"scope": "m2_1_query_shape_plus_limited_taxonomy",
"build_status": "PASSED",
"tests_status": "PASSED",
"dry_run_status": "PASSED_WITH_LIMITED_RESULTS",
"implemented": {
"query_shape_classification": true,
"compound_query_execution_status": "detection_only",
"limited_reason_taxonomy": true,
"runtime_readiness_status": true,
"operational_limited_reply_text": true
},
"dry_run_metrics": {
"questions_total": 7,
"address_mode_hit_rate": 1.0,
"query_shape_detected_rate": 1.0,
"intent_alignment_rate": 1.0,
"supported_recipe_selection_rate": 0.7143,
"factual_positive_rate": 0.0,
"limited_mode_rate": 1.0,
"false_factual_rate": 0.0
},
"limited_reason_distribution": {
"empty_match": 4,
"missing_anchor": 1,
"recipe_visibility_gap": 1,
"unsupported": 1,
"execution_error": 0
},
"next_priority": "Sprint B specialized recipes for contract/document visibility"
}
@@ -0,0 +1,35 @@
# Smoke Checks
Дата: 2026-03-29
## Build
- `npm run build` -> PASS
## Tests
- `npx vitest run tests/addressQueryRuntimeM21.test.ts` -> PASS (5/5)
## Dry-run (assistant window equivalent)
Источник: `assistant_window_dry_run_results.json`
- total questions: 7
- `detected_mode=address_query`: 7/7
- `query_shape` detected: 7/7
- expected intent alignment: 7/7
- `selected_recipe` present: 5/7
- `response_type=LIMITED_WITH_REASON`: 7/7
- `false_factual_rate`: 0
### New diagnostics observed
- `query_shape` surfaced in debug payload.
- `runtime_readiness` surfaced in debug payload.
- `limited_reason_category` surfaced in debug payload.
### Limited taxonomy distribution
- `empty_match`: 4
- `missing_anchor`: 1
- `recipe_visibility_gap`: 1
- `unsupported`: 1
- `execution_error`: 0
@@ -0,0 +1,29 @@
# Run README — Address Query Runtime V1 M2.2
Дата: 2026-03-29
Run ID: `2026-03-29_Address_Query_Runtime_V1_M2_2_Documents_BankOps_By_Counterparty`
## Цель инкремента
Сделать следующий практический шаг Sprint B:
- добавить intent `list_documents_by_counterparty`;
- добавить intent `bank_operations_by_counterparty`;
- добавить live recipes для этих intent;
- усилить extraction фильтров периода (`from/to`, `between/and`) и default period для by-counterparty сценариев;
- сохранить safety-контракт (`false_factual_rate = 0`) и честный limited mode.
## Что проверено
- `npm.cmd run build` — PASS.
- `npx.cmd vitest run tests/addressQueryRuntimeM22.test.ts` — PASS (7/7).
- dry-run через `/api/assistant/message` на 6 вопросах — сохранен в `assistant_window_dry_run_results.json`.
## Основной вывод
Address lane расширен на два новых P0-сценария и стабильно маршрутизирует их в правильные intent/recipe. При этом positive factual output пока не достигнут: текущий блокер — live visibility (преобладает `empty_match`), а не routing/intent detection.
## Важное ограничение M2.2
`COMPOUND_FACTUAL_QUERY` по-прежнему только detection-only.
M2.2 не включает multi-intent decomposition execution.
@@ -0,0 +1,162 @@
{
"generated_at": "2026-03-29T16:28:22.969Z",
"questions": [
{
"id": "Q1",
"question": "show documents by counterparty Alfa from 2020-07-01 to 2020-07-31",
"expected_intent": "list_documents_by_counterparty",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "list_documents_by_counterparty",
"selected_recipe": "address_documents_by_counterparty_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"counterparty": "Alfa",
"period_from": "2020-07-01",
"period_to": "2020-07-31"
},
"missing_required_filters": [],
"mcp_call_status": "empty",
"rows_fetched": 20,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
},
{
"id": "Q2",
"question": "show bank operations by counterparty Alfa from 2020-07-01 to 2020-07-31",
"expected_intent": "bank_operations_by_counterparty",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "bank_operations_by_counterparty",
"selected_recipe": "address_bank_operations_by_counterparty_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"counterparty": "Alfa",
"period_from": "2020-07-01",
"period_to": "2020-07-31"
},
"missing_required_filters": [],
"mcp_call_status": "empty",
"rows_fetched": 20,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
},
{
"id": "Q3",
"question": "show bank operations by counterparty Alfa",
"expected_intent": "bank_operations_by_counterparty",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "bank_operations_by_counterparty",
"selected_recipe": "address_bank_operations_by_counterparty_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"counterparty": "Alfa",
"period_to": "2026-03-29",
"period_from": "2025-12-29"
},
"missing_required_filters": [],
"mcp_call_status": "empty",
"rows_fetched": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
},
{
"id": "Q4",
"question": "show documents by contract 15/24",
"expected_intent": "unknown",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "unknown",
"selected_recipe": null,
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"contract": "15/24"
},
"missing_required_filters": [],
"mcp_call_status": "skipped",
"rows_fetched": 0,
"rows_matched": 0,
"runtime_readiness": "DEEP_ONLY",
"limited_reason_category": "unsupported",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "Этот запрос не подходит под address_query V1.\nПричина: intent пока не поддержан в address V1.\nЧто нужно уточнить: переформулируйте вопрос как адресный lookup по счету/контрагенту/договору."
},
{
"id": "Q5",
"question": "show open items by contract",
"expected_intent": "open_items_by_counterparty_or_contract",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "OBJECT_LOOKUP",
"detected_intent": "open_items_by_counterparty_or_contract",
"selected_recipe": null,
"extracted_filters": {
"sort": "period_desc",
"limit": 20
},
"missing_required_filters": [
"counterparty_or_contract"
],
"mcp_call_status": "skipped",
"rows_fetched": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "missing_anchor",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "Для точного адресного поиска не хватает обязательного якоря.\nПричина: для open_items нужен якорь контрагента или договора.\nЧто нужно уточнить: укажите контрагента или номер/название договора."
},
{
"id": "Q6",
"question": "who owes us today",
"expected_intent": "list_receivables_counterparties",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "AGGREGATE_LOOKUP",
"detected_intent": "list_receivables_counterparties",
"selected_recipe": "address_movements_receivables_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"as_of_date": "2026-03-29"
},
"missing_required_filters": [],
"mcp_call_status": "empty",
"rows_fetched": 20,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
}
]
}
@@ -0,0 +1,34 @@
{
"baseline_run": "2026-03-29_Address_Query_Runtime_V1_M2_1_QueryShape_LimitedTaxonomy",
"current_run": "2026-03-29_Address_Query_Runtime_V1_M2_2_Documents_BankOps_By_Counterparty",
"changes": {
"intent_documents_by_counterparty": {
"before": false,
"after": true
},
"intent_bank_operations_by_counterparty": {
"before": false,
"after": true
},
"recipe_documents_by_counterparty_v1": {
"before": false,
"after": true
},
"recipe_bank_operations_by_counterparty_v1": {
"before": false,
"after": true
},
"period_range_extraction": {
"before": false,
"after": true
},
"default_period_for_by_counterparty": {
"before": false,
"after": true
},
"false_factual_rate": {
"before": 0.0,
"after": 0.0
}
}
}
@@ -0,0 +1,15 @@
llm_normalizer/backend/src/types/addressQuery.ts
llm_normalizer/backend/src/services/addressIntentResolver.ts
llm_normalizer/backend/src/services/addressFilterExtractor.ts
llm_normalizer/backend/src/services/addressRecipeCatalog.ts
llm_normalizer/backend/src/services/addressQueryService.ts
llm_normalizer/backend/tests/addressQueryRuntimeM22.test.ts
docs/ADDRESS/address_query/address_scenario_matrix.md
docs/ADDRESS/address_query/query_recipes_v1.md
docs/ADDRESS/address_query/runtime_readiness_matrix_v1.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_2_Documents_BankOps_By_Counterparty/README.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_2_Documents_BankOps_By_Counterparty/run_summary.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_2_Documents_BankOps_By_Counterparty/before_after_metrics.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_2_Documents_BankOps_By_Counterparty/smoke_checks.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_2_Documents_BankOps_By_Counterparty/assistant_window_dry_run_results.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_2_Documents_BankOps_By_Counterparty/changed_files.txt
@@ -0,0 +1,35 @@
{
"run_id": "2026-03-29_Address_Query_Runtime_V1_M2_2_Documents_BankOps_By_Counterparty",
"date": "2026-03-29",
"stage": "address_query_runtime_v1",
"scope": "m2_2_documents_and_bank_ops_by_counterparty",
"build_status": "PASSED",
"tests_status": "PASSED",
"dry_run_status": "PASSED_WITH_LIMITED_RESULTS",
"implemented": {
"intent_documents_by_counterparty": true,
"intent_bank_operations_by_counterparty": true,
"recipe_documents_by_counterparty_v1": true,
"recipe_bank_operations_by_counterparty_v1": true,
"period_range_extraction": true,
"default_period_last_90_days_for_by_counterparty": true
},
"dry_run_metrics": {
"questions_total": 6,
"address_mode_hit_rate": 1.0,
"query_shape_detected_rate": 1.0,
"intent_alignment_rate": 1.0,
"supported_recipe_selection_rate": 0.6667,
"factual_positive_rate": 0.0,
"limited_mode_rate": 1.0,
"false_factual_rate": 0.0
},
"limited_reason_distribution": {
"empty_match": 4,
"missing_anchor": 1,
"recipe_visibility_gap": 0,
"unsupported": 1,
"execution_error": 0
},
"next_priority": "Sprint B Priority 3: documents_forming_balance + known-positive live suite execution"
}
@@ -0,0 +1,34 @@
# Smoke Checks
Дата: 2026-03-29
## Build
- `npm.cmd run build` -> PASS
## Tests
- `npx.cmd vitest run tests/addressQueryRuntimeM22.test.ts` -> PASS (7/7)
## Dry-run (assistant window equivalent)
Источник: `assistant_window_dry_run_results.json`
- total questions: 6
- `detected_mode=address_query`: 6/6
- `query_shape` detected: 6/6
- expected intent alignment: 6/6
- `selected_recipe` present: 4/6
- `response_type=LIMITED_WITH_REASON`: 6/6
- `false_factual_rate`: 0
### Limited taxonomy distribution
- `empty_match`: 4
- `missing_anchor`: 1
- `recipe_visibility_gap`: 0
- `unsupported`: 1
- `execution_error`: 0
### Operational note
`documents_by_counterparty` and `bank_operations_by_counterparty` are now implemented and routed correctly.
Current blocker remains live data visibility on selected anchors/periods (non-empty positive evidence suite still required).
@@ -0,0 +1,35 @@
# Run README — Address Query Runtime V1 M2.3a
Дата: 2026-03-29
Run ID: `2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization`
## Цель инкремента
Сделать узкий диагностический шаг после M2.3:
- развести `mcp_call_status` по стадиям;
- зафиксировать, где именно теряются строки (`raw -> account_scope -> materialization -> recipe_filter -> matched`);
- убрать неинформативный общий `empty` статус;
- подготовить техническую базу для следующего exploratory live pass.
## Что проверено
- `npm.cmd run build` — PASS.
- `npx.cmd vitest run tests/addressQueryRuntimeM23.test.ts` — PASS (10/10).
- stage-diagnostic dry-run через `/api/assistant/message` на 5 core cases — сохранен в `assistant_window_stage_diagnostic_results.json`.
## Ключевой вывод
Диагностический паттерн стабилен:
- `raw_rows_received > 0`;
- `rows_after_account_scope = 0`;
- `rows_materialized = 0`;
- `rows_after_recipe_filter = 0`;
- `rows_matched = 0`.
То есть текущий primary bottleneck находится на account-scope filtration до materialization.
## Что это значит для next step
Следующий шаг нужно делать как targeted tuning account-scope per recipe, а уже затем запускать curated non-empty data-aware positive acceptance.
@@ -0,0 +1,242 @@
{
"generated_at": "2026-03-29T17:33:28.054Z",
"cases": [
{
"id": "D1",
"question": "show account balance 60 today",
"expected_intent": "account_balance_snapshot",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "AGGREGATE_LOOKUP",
"detected_intent": "account_balance_snapshot",
"intent_aligned": true,
"selected_recipe": "address_movements_account_snapshot_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "60",
"as_of_date": "2026-03-29"
},
"anchor_type": "account",
"anchor_value_raw": "60",
"resolver_confidence": "high",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"stage_interpretation": "Rows came from MCP but were lost before/at materialization.",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"Сумма",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview_escaped": "\\u0412 live-\\u0434\\u0430\\u043d\\u043d\\u044b\\u0445 \\u043f\\u043e \\u0442\\u0435\\u043a\\u0443\\u0449\\u0435\\u043c\\u0443 \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0443 \\u0437\\u0430\\u043f\\u0438\\u0441\\u0438 \\u043d\\u0435 \\u043d\\u0430\\u0439\\u0434\\u0435\\u043d\\u044b.\n\\u041f\\u0440\\u0438\\u0447\\u0438\\u043d\\u0430: \\u043f\\u043e \\u0432\\u044b\\u0431\\u0440\\u0430\\u043d\\u043d\\u044b\\u043c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0430\\u043c \\u0432 live-\\u0432\\u044b\\u0431\\u043e\\u0440\\u043a\\u0435 \\u043d\\u0435\\u0442 \\u0441\\u0442\\u0440\\u043e\\u043a.\n\\u0427\\u0442\\u043e \\u043d\\u0443\\u0436\\u043d\\u043e \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u044c: \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u0435 \\u043f\\u0435\\u0440\\u0438\\u043e\\u0434, \\u043a\\u043e\\u043d\\u0442\\u0440\\u0430\\u0433\\u0435\\u043d\\u0442\\u0430, \\u0434\\u043e\\u0433\\u043e\\u0432\\u043e\\u0440 \\u0438\\u043b\\u0438 \\u0441\\u043d\\u0438\\u043c\\u0438\\u0442\\u0435 \\u0447\\u0430\\u0441\\u0442\\u044c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u043e\\u0432."
},
{
"id": "D2",
"question": "which documents form balance for account 62 as of 2020-07-31",
"expected_intent": "documents_forming_balance",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "documents_forming_balance",
"intent_aligned": true,
"selected_recipe": "address_documents_forming_balance_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "62",
"as_of_date": "2020-07-31"
},
"anchor_type": "account",
"anchor_value_raw": "62",
"resolver_confidence": "high",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"stage_interpretation": "Rows came from MCP but were lost before/at materialization.",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"Сумма",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview_escaped": "\\u0412 live-\\u0434\\u0430\\u043d\\u043d\\u044b\\u0445 \\u043f\\u043e \\u0442\\u0435\\u043a\\u0443\\u0449\\u0435\\u043c\\u0443 \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0443 \\u0437\\u0430\\u043f\\u0438\\u0441\\u0438 \\u043d\\u0435 \\u043d\\u0430\\u0439\\u0434\\u0435\\u043d\\u044b.\n\\u041f\\u0440\\u0438\\u0447\\u0438\\u043d\\u0430: \\u043f\\u043e \\u0432\\u044b\\u0431\\u0440\\u0430\\u043d\\u043d\\u044b\\u043c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0430\\u043c \\u0432 live-\\u0432\\u044b\\u0431\\u043e\\u0440\\u043a\\u0435 \\u043d\\u0435\\u0442 \\u0441\\u0442\\u0440\\u043e\\u043a.\n\\u0427\\u0442\\u043e \\u043d\\u0443\\u0436\\u043d\\u043e \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u044c: \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u0435 \\u043f\\u0435\\u0440\\u0438\\u043e\\u0434, \\u043a\\u043e\\u043d\\u0442\\u0440\\u0430\\u0433\\u0435\\u043d\\u0442\\u0430, \\u0434\\u043e\\u0433\\u043e\\u0432\\u043e\\u0440 \\u0438\\u043b\\u0438 \\u0441\\u043d\\u0438\\u043c\\u0438\\u0442\\u0435 \\u0447\\u0430\\u0441\\u0442\\u044c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u043e\\u0432."
},
{
"id": "D3",
"question": "reveal balance documents for account 60",
"expected_intent": "documents_forming_balance",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "documents_forming_balance",
"intent_aligned": true,
"selected_recipe": "address_documents_forming_balance_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "60",
"as_of_date": "2026-03-29"
},
"anchor_type": "account",
"anchor_value_raw": "60",
"resolver_confidence": "high",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"stage_interpretation": "Rows came from MCP but were lost before/at materialization.",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"Сумма",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview_escaped": "\\u0412 live-\\u0434\\u0430\\u043d\\u043d\\u044b\\u0445 \\u043f\\u043e \\u0442\\u0435\\u043a\\u0443\\u0449\\u0435\\u043c\\u0443 \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0443 \\u0437\\u0430\\u043f\\u0438\\u0441\\u0438 \\u043d\\u0435 \\u043d\\u0430\\u0439\\u0434\\u0435\\u043d\\u044b.\n\\u041f\\u0440\\u0438\\u0447\\u0438\\u043d\\u0430: \\u043f\\u043e \\u0432\\u044b\\u0431\\u0440\\u0430\\u043d\\u043d\\u044b\\u043c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0430\\u043c \\u0432 live-\\u0432\\u044b\\u0431\\u043e\\u0440\\u043a\\u0435 \\u043d\\u0435\\u0442 \\u0441\\u0442\\u0440\\u043e\\u043a.\n\\u0427\\u0442\\u043e \\u043d\\u0443\\u0436\\u043d\\u043e \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u044c: \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u0435 \\u043f\\u0435\\u0440\\u0438\\u043e\\u0434, \\u043a\\u043e\\u043d\\u0442\\u0440\\u0430\\u0433\\u0435\\u043d\\u0442\\u0430, \\u0434\\u043e\\u0433\\u043e\\u0432\\u043e\\u0440 \\u0438\\u043b\\u0438 \\u0441\\u043d\\u0438\\u043c\\u0438\\u0442\\u0435 \\u0447\\u0430\\u0441\\u0442\\u044c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u043e\\u0432."
},
{
"id": "D4",
"question": "show documents by counterparty Alfa from 2020-07-01 to 2020-07-31",
"expected_intent": "list_documents_by_counterparty",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "list_documents_by_counterparty",
"intent_aligned": true,
"selected_recipe": "address_documents_by_counterparty_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"counterparty": "Alfa",
"period_from": "2020-07-01",
"period_to": "2020-07-31"
},
"anchor_type": "counterparty",
"anchor_value_raw": "Alfa",
"resolver_confidence": "medium",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"stage_interpretation": "Rows came from MCP but were lost before/at materialization.",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"Сумма",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview_escaped": "\\u0412 live-\\u0434\\u0430\\u043d\\u043d\\u044b\\u0445 \\u043f\\u043e \\u0442\\u0435\\u043a\\u0443\\u0449\\u0435\\u043c\\u0443 \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0443 \\u0437\\u0430\\u043f\\u0438\\u0441\\u0438 \\u043d\\u0435 \\u043d\\u0430\\u0439\\u0434\\u0435\\u043d\\u044b.\n\\u041f\\u0440\\u0438\\u0447\\u0438\\u043d\\u0430: \\u043f\\u043e \\u0432\\u044b\\u0431\\u0440\\u0430\\u043d\\u043d\\u044b\\u043c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0430\\u043c \\u0432 live-\\u0432\\u044b\\u0431\\u043e\\u0440\\u043a\\u0435 \\u043d\\u0435\\u0442 \\u0441\\u0442\\u0440\\u043e\\u043a.\n\\u0427\\u0442\\u043e \\u043d\\u0443\\u0436\\u043d\\u043e \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u044c: \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u0435 \\u043f\\u0435\\u0440\\u0438\\u043e\\u0434, \\u043a\\u043e\\u043d\\u0442\\u0440\\u0430\\u0433\\u0435\\u043d\\u0442\\u0430, \\u0434\\u043e\\u0433\\u043e\\u0432\\u043e\\u0440 \\u0438\\u043b\\u0438 \\u0441\\u043d\\u0438\\u043c\\u0438\\u0442\\u0435 \\u0447\\u0430\\u0441\\u0442\\u044c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u043e\\u0432."
},
{
"id": "D5",
"question": "show bank operations by counterparty Alfa from 2020-07-01 to 2020-07-31",
"expected_intent": "bank_operations_by_counterparty",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "bank_operations_by_counterparty",
"intent_aligned": true,
"selected_recipe": "address_bank_operations_by_counterparty_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"counterparty": "Alfa",
"period_from": "2020-07-01",
"period_to": "2020-07-31"
},
"anchor_type": "counterparty",
"anchor_value_raw": "Alfa",
"resolver_confidence": "medium",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"stage_interpretation": "Rows came from MCP but were lost before/at materialization.",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"Сумма",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview_escaped": "\\u0412 live-\\u0434\\u0430\\u043d\\u043d\\u044b\\u0445 \\u043f\\u043e \\u0442\\u0435\\u043a\\u0443\\u0449\\u0435\\u043c\\u0443 \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0443 \\u0437\\u0430\\u043f\\u0438\\u0441\\u0438 \\u043d\\u0435 \\u043d\\u0430\\u0439\\u0434\\u0435\\u043d\\u044b.\n\\u041f\\u0440\\u0438\\u0447\\u0438\\u043d\\u0430: \\u043f\\u043e \\u0432\\u044b\\u0431\\u0440\\u0430\\u043d\\u043d\\u044b\\u043c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0430\\u043c \\u0432 live-\\u0432\\u044b\\u0431\\u043e\\u0440\\u043a\\u0435 \\u043d\\u0435\\u0442 \\u0441\\u0442\\u0440\\u043e\\u043a.\n\\u0427\\u0442\\u043e \\u043d\\u0443\\u0436\\u043d\\u043e \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u044c: \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u0435 \\u043f\\u0435\\u0440\\u0438\\u043e\\u0434, \\u043a\\u043e\\u043d\\u0442\\u0440\\u0430\\u0433\\u0435\\u043d\\u0442\\u0430, \\u0434\\u043e\\u0433\\u043e\\u0432\\u043e\\u0440 \\u0438\\u043b\\u0438 \\u0441\\u043d\\u0438\\u043c\\u0438\\u0442\\u0435 \\u0447\\u0430\\u0441\\u0442\\u044c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u043e\\u0432."
}
]
}
@@ -0,0 +1,26 @@
{
"baseline_run": "2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance",
"current_run": "2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization",
"changes": {
"mcp_call_status_granularity": {
"before": "ok|empty|error|skipped",
"after": "no_raw_rows|raw_rows_received_but_not_materialized|materialized_but_not_matched|matched_non_empty|error|skipped"
},
"debug_rows_after_account_scope": {
"before": false,
"after": true
},
"debug_materialization_drop_reason": {
"before": false,
"after": true
},
"test_suite_file": {
"before": "addressQueryRuntimeM22.test.ts",
"after": "addressQueryRuntimeM23.test.ts"
},
"factual_positive_rate": {
"before": 0,
"after": 0
}
}
}
@@ -0,0 +1,28 @@
llm_normalizer/backend/src/types/addressQuery.ts
llm_normalizer/backend/src/types/assistant.ts
llm_normalizer/backend/src/services/addressMcpClient.ts
llm_normalizer/backend/src/services/addressIntentResolver.ts
llm_normalizer/backend/src/services/addressQueryService.ts
llm_normalizer/backend/src/services/assistantService.ts
llm_normalizer/backend/tests/addressQueryRuntimeM23.test.ts
llm_normalizer/backend/tests/addressQueryRuntimeM22.test.ts (deleted)
docs/ADDRESS/address_query/address_runtime_contracts.md
docs/ADDRESS/address_query/runtime_readiness_matrix_v1.md
docs/ADDRESS/address_query/address_scenario_matrix.md
docs/ADDRESS/address_query/data_aware_positive_acceptance_suite_v1.md
docs/ADDRESS/address_query/README.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization/README.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization/run_summary.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization/before_after_metrics.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization/smoke_checks.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization/stage_diagnostic_report.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization/stage_diagnostic_matrix.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization/assistant_window_stage_diagnostic_results.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization/chat_export_stage_diagnostic.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization/live_call_inventory_address.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization/debug_payloads/D1.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization/debug_payloads/D2.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization/debug_payloads/D3.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization/debug_payloads/D4.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization/debug_payloads/D5.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization/changed_files.txt
@@ -0,0 +1,44 @@
# Chat Export — Stage Diagnostic Pass (M2.3a)
Date: 2026-03-29
## D1
Question: show account balance 60 today
Detected intent: account_balance_snapshot
MCP stage status: raw_rows_received_but_not_materialized
Preview (escaped): \u0412 live-\u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 \u0444\u0438\u043b\u044c\u0442\u0440\u0443 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b.
\u041f\u0440\u0438\u0447\u0438\u043d\u0430: \u043f\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u043c \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c \u0432 live-\u0432\u044b\u0431\u043e\u0440\u043a\u0435 \u043d\u0435\u0442 \u0441\u0442\u0440\u043e\u043a.
\u0427\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u044c: \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u0435 \u043f\u0435\u0440\u0438\u043e\u0434, \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430, \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0438\u043b\u0438 \u0441\u043d\u0438\u043c\u0438\u0442\u0435 \u0447\u0430\u0441\u0442\u044c \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432.
## D2
Question: which documents form balance for account 62 as of 2020-07-31
Detected intent: documents_forming_balance
MCP stage status: raw_rows_received_but_not_materialized
Preview (escaped): \u0412 live-\u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 \u0444\u0438\u043b\u044c\u0442\u0440\u0443 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b.
\u041f\u0440\u0438\u0447\u0438\u043d\u0430: \u043f\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u043c \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c \u0432 live-\u0432\u044b\u0431\u043e\u0440\u043a\u0435 \u043d\u0435\u0442 \u0441\u0442\u0440\u043e\u043a.
\u0427\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u044c: \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u0435 \u043f\u0435\u0440\u0438\u043e\u0434, \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430, \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0438\u043b\u0438 \u0441\u043d\u0438\u043c\u0438\u0442\u0435 \u0447\u0430\u0441\u0442\u044c \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432.
## D3
Question: reveal balance documents for account 60
Detected intent: documents_forming_balance
MCP stage status: raw_rows_received_but_not_materialized
Preview (escaped): \u0412 live-\u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 \u0444\u0438\u043b\u044c\u0442\u0440\u0443 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b.
\u041f\u0440\u0438\u0447\u0438\u043d\u0430: \u043f\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u043c \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c \u0432 live-\u0432\u044b\u0431\u043e\u0440\u043a\u0435 \u043d\u0435\u0442 \u0441\u0442\u0440\u043e\u043a.
\u0427\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u044c: \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u0435 \u043f\u0435\u0440\u0438\u043e\u0434, \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430, \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0438\u043b\u0438 \u0441\u043d\u0438\u043c\u0438\u0442\u0435 \u0447\u0430\u0441\u0442\u044c \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432.
## D4
Question: show documents by counterparty Alfa from 2020-07-01 to 2020-07-31
Detected intent: list_documents_by_counterparty
MCP stage status: raw_rows_received_but_not_materialized
Preview (escaped): \u0412 live-\u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 \u0444\u0438\u043b\u044c\u0442\u0440\u0443 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b.
\u041f\u0440\u0438\u0447\u0438\u043d\u0430: \u043f\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u043c \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c \u0432 live-\u0432\u044b\u0431\u043e\u0440\u043a\u0435 \u043d\u0435\u0442 \u0441\u0442\u0440\u043e\u043a.
\u0427\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u044c: \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u0435 \u043f\u0435\u0440\u0438\u043e\u0434, \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430, \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0438\u043b\u0438 \u0441\u043d\u0438\u043c\u0438\u0442\u0435 \u0447\u0430\u0441\u0442\u044c \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432.
## D5
Question: show bank operations by counterparty Alfa from 2020-07-01 to 2020-07-31
Detected intent: bank_operations_by_counterparty
MCP stage status: raw_rows_received_but_not_materialized
Preview (escaped): \u0412 live-\u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 \u0444\u0438\u043b\u044c\u0442\u0440\u0443 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b.
\u041f\u0440\u0438\u0447\u0438\u043d\u0430: \u043f\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u043c \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c \u0432 live-\u0432\u044b\u0431\u043e\u0440\u043a\u0435 \u043d\u0435\u0442 \u0441\u0442\u0440\u043e\u043a.
\u0427\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u044c: \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u0435 \u043f\u0435\u0440\u0438\u043e\u0434, \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430, \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0438\u043b\u0438 \u0441\u043d\u0438\u043c\u0438\u0442\u0435 \u0447\u0430\u0441\u0442\u044c \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432.
@@ -0,0 +1,47 @@
{
"id": "D1",
"question": "show account balance 60 today",
"expected_intent": "account_balance_snapshot",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "AGGREGATE_LOOKUP",
"detected_intent": "account_balance_snapshot",
"intent_aligned": true,
"selected_recipe": "address_movements_account_snapshot_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "60",
"as_of_date": "2026-03-29"
},
"anchor_type": "account",
"anchor_value_raw": "60",
"resolver_confidence": "high",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"stage_interpretation": "Rows came from MCP but were lost before/at materialization.",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"РЎСѓРјРјР°",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview_escaped": "\\u0412 live-\\u0434\\u0430\\u043d\\u043d\\u044b\\u0445 \\u043f\\u043e \\u0442\\u0435\\u043a\\u0443\\u0449\\u0435\\u043c\\u0443 \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0443 \\u0437\\u0430\\u043f\\u0438\\u0441\\u0438 \\u043d\\u0435 \\u043d\\u0430\\u0439\\u0434\\u0435\\u043d\\u044b.\n\\u041f\\u0440\\u0438\\u0447\\u0438\\u043d\\u0430: \\u043f\\u043e \\u0432\\u044b\\u0431\\u0440\\u0430\\u043d\\u043d\\u044b\\u043c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0430\\u043c \\u0432 live-\\u0432\\u044b\\u0431\\u043e\\u0440\\u043a\\u0435 \\u043d\\u0435\\u0442 \\u0441\\u0442\\u0440\\u043e\\u043a.\n\\u0427\\u0442\\u043e \\u043d\\u0443\\u0436\\u043d\\u043e \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u044c: \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u0435 \\u043f\\u0435\\u0440\\u0438\\u043e\\u0434, \\u043a\\u043e\\u043d\\u0442\\u0440\\u0430\\u0433\\u0435\\u043d\\u0442\\u0430, \\u0434\\u043e\\u0433\\u043e\\u0432\\u043e\\u0440 \\u0438\\u043b\\u0438 \\u0441\\u043d\\u0438\\u043c\\u0438\\u0442\\u0435 \\u0447\\u0430\\u0441\\u0442\\u044c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u043e\\u0432."
}
@@ -0,0 +1,47 @@
{
"id": "D2",
"question": "which documents form balance for account 62 as of 2020-07-31",
"expected_intent": "documents_forming_balance",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "documents_forming_balance",
"intent_aligned": true,
"selected_recipe": "address_documents_forming_balance_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "62",
"as_of_date": "2020-07-31"
},
"anchor_type": "account",
"anchor_value_raw": "62",
"resolver_confidence": "high",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"stage_interpretation": "Rows came from MCP but were lost before/at materialization.",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"РЎСѓРјРјР°",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview_escaped": "\\u0412 live-\\u0434\\u0430\\u043d\\u043d\\u044b\\u0445 \\u043f\\u043e \\u0442\\u0435\\u043a\\u0443\\u0449\\u0435\\u043c\\u0443 \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0443 \\u0437\\u0430\\u043f\\u0438\\u0441\\u0438 \\u043d\\u0435 \\u043d\\u0430\\u0439\\u0434\\u0435\\u043d\\u044b.\n\\u041f\\u0440\\u0438\\u0447\\u0438\\u043d\\u0430: \\u043f\\u043e \\u0432\\u044b\\u0431\\u0440\\u0430\\u043d\\u043d\\u044b\\u043c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0430\\u043c \\u0432 live-\\u0432\\u044b\\u0431\\u043e\\u0440\\u043a\\u0435 \\u043d\\u0435\\u0442 \\u0441\\u0442\\u0440\\u043e\\u043a.\n\\u0427\\u0442\\u043e \\u043d\\u0443\\u0436\\u043d\\u043e \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u044c: \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u0435 \\u043f\\u0435\\u0440\\u0438\\u043e\\u0434, \\u043a\\u043e\\u043d\\u0442\\u0440\\u0430\\u0433\\u0435\\u043d\\u0442\\u0430, \\u0434\\u043e\\u0433\\u043e\\u0432\\u043e\\u0440 \\u0438\\u043b\\u0438 \\u0441\\u043d\\u0438\\u043c\\u0438\\u0442\\u0435 \\u0447\\u0430\\u0441\\u0442\\u044c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u043e\\u0432."
}
@@ -0,0 +1,47 @@
{
"id": "D3",
"question": "reveal balance documents for account 60",
"expected_intent": "documents_forming_balance",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "documents_forming_balance",
"intent_aligned": true,
"selected_recipe": "address_documents_forming_balance_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "60",
"as_of_date": "2026-03-29"
},
"anchor_type": "account",
"anchor_value_raw": "60",
"resolver_confidence": "high",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"stage_interpretation": "Rows came from MCP but were lost before/at materialization.",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"РЎСѓРјРјР°",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview_escaped": "\\u0412 live-\\u0434\\u0430\\u043d\\u043d\\u044b\\u0445 \\u043f\\u043e \\u0442\\u0435\\u043a\\u0443\\u0449\\u0435\\u043c\\u0443 \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0443 \\u0437\\u0430\\u043f\\u0438\\u0441\\u0438 \\u043d\\u0435 \\u043d\\u0430\\u0439\\u0434\\u0435\\u043d\\u044b.\n\\u041f\\u0440\\u0438\\u0447\\u0438\\u043d\\u0430: \\u043f\\u043e \\u0432\\u044b\\u0431\\u0440\\u0430\\u043d\\u043d\\u044b\\u043c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0430\\u043c \\u0432 live-\\u0432\\u044b\\u0431\\u043e\\u0440\\u043a\\u0435 \\u043d\\u0435\\u0442 \\u0441\\u0442\\u0440\\u043e\\u043a.\n\\u0427\\u0442\\u043e \\u043d\\u0443\\u0436\\u043d\\u043e \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u044c: \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u0435 \\u043f\\u0435\\u0440\\u0438\\u043e\\u0434, \\u043a\\u043e\\u043d\\u0442\\u0440\\u0430\\u0433\\u0435\\u043d\\u0442\\u0430, \\u0434\\u043e\\u0433\\u043e\\u0432\\u043e\\u0440 \\u0438\\u043b\\u0438 \\u0441\\u043d\\u0438\\u043c\\u0438\\u0442\\u0435 \\u0447\\u0430\\u0441\\u0442\\u044c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u043e\\u0432."
}
@@ -0,0 +1,48 @@
{
"id": "D4",
"question": "show documents by counterparty Alfa from 2020-07-01 to 2020-07-31",
"expected_intent": "list_documents_by_counterparty",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "list_documents_by_counterparty",
"intent_aligned": true,
"selected_recipe": "address_documents_by_counterparty_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"counterparty": "Alfa",
"period_from": "2020-07-01",
"period_to": "2020-07-31"
},
"anchor_type": "counterparty",
"anchor_value_raw": "Alfa",
"resolver_confidence": "medium",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"stage_interpretation": "Rows came from MCP but were lost before/at materialization.",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"РЎСѓРјРјР°",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview_escaped": "\\u0412 live-\\u0434\\u0430\\u043d\\u043d\\u044b\\u0445 \\u043f\\u043e \\u0442\\u0435\\u043a\\u0443\\u0449\\u0435\\u043c\\u0443 \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0443 \\u0437\\u0430\\u043f\\u0438\\u0441\\u0438 \\u043d\\u0435 \\u043d\\u0430\\u0439\\u0434\\u0435\\u043d\\u044b.\n\\u041f\\u0440\\u0438\\u0447\\u0438\\u043d\\u0430: \\u043f\\u043e \\u0432\\u044b\\u0431\\u0440\\u0430\\u043d\\u043d\\u044b\\u043c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0430\\u043c \\u0432 live-\\u0432\\u044b\\u0431\\u043e\\u0440\\u043a\\u0435 \\u043d\\u0435\\u0442 \\u0441\\u0442\\u0440\\u043e\\u043a.\n\\u0427\\u0442\\u043e \\u043d\\u0443\\u0436\\u043d\\u043e \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u044c: \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u0435 \\u043f\\u0435\\u0440\\u0438\\u043e\\u0434, \\u043a\\u043e\\u043d\\u0442\\u0440\\u0430\\u0433\\u0435\\u043d\\u0442\\u0430, \\u0434\\u043e\\u0433\\u043e\\u0432\\u043e\\u0440 \\u0438\\u043b\\u0438 \\u0441\\u043d\\u0438\\u043c\\u0438\\u0442\\u0435 \\u0447\\u0430\\u0441\\u0442\\u044c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u043e\\u0432."
}
@@ -0,0 +1,48 @@
{
"id": "D5",
"question": "show bank operations by counterparty Alfa from 2020-07-01 to 2020-07-31",
"expected_intent": "bank_operations_by_counterparty",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "bank_operations_by_counterparty",
"intent_aligned": true,
"selected_recipe": "address_bank_operations_by_counterparty_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"counterparty": "Alfa",
"period_from": "2020-07-01",
"period_to": "2020-07-31"
},
"anchor_type": "counterparty",
"anchor_value_raw": "Alfa",
"resolver_confidence": "medium",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"stage_interpretation": "Rows came from MCP but were lost before/at materialization.",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"РЎСѓРјРјР°",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview_escaped": "\\u0412 live-\\u0434\\u0430\\u043d\\u043d\\u044b\\u0445 \\u043f\\u043e \\u0442\\u0435\\u043a\\u0443\\u0449\\u0435\\u043c\\u0443 \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0443 \\u0437\\u0430\\u043f\\u0438\\u0441\\u0438 \\u043d\\u0435 \\u043d\\u0430\\u0439\\u0434\\u0435\\u043d\\u044b.\n\\u041f\\u0440\\u0438\\u0447\\u0438\\u043d\\u0430: \\u043f\\u043e \\u0432\\u044b\\u0431\\u0440\\u0430\\u043d\\u043d\\u044b\\u043c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u0430\\u043c \\u0432 live-\\u0432\\u044b\\u0431\\u043e\\u0440\\u043a\\u0435 \\u043d\\u0435\\u0442 \\u0441\\u0442\\u0440\\u043e\\u043a.\n\\u0427\\u0442\\u043e \\u043d\\u0443\\u0436\\u043d\\u043e \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u044c: \\u0443\\u0442\\u043e\\u0447\\u043d\\u0438\\u0442\\u0435 \\u043f\\u0435\\u0440\\u0438\\u043e\\u0434, \\u043a\\u043e\\u043d\\u0442\\u0440\\u0430\\u0433\\u0435\\u043d\\u0442\\u0430, \\u0434\\u043e\\u0433\\u043e\\u0432\\u043e\\u0440 \\u0438\\u043b\\u0438 \\u0441\\u043d\\u0438\\u043c\\u0438\\u0442\\u0435 \\u0447\\u0430\\u0441\\u0442\\u044c \\u0444\\u0438\\u043b\\u044c\\u0442\\u0440\\u043e\\u0432."
}
@@ -0,0 +1,72 @@
[
{
"case_id": "D1",
"question": "show account balance 60 today",
"detected_intent": "account_balance_snapshot",
"selected_recipe": "address_movements_account_snapshot_v1",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"materialization_drop_reason": "dropped_by_account_scope_filter",
"limited_reason_category": "empty_match"
},
{
"case_id": "D2",
"question": "which documents form balance for account 62 as of 2020-07-31",
"detected_intent": "documents_forming_balance",
"selected_recipe": "address_documents_forming_balance_v1",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"materialization_drop_reason": "dropped_by_account_scope_filter",
"limited_reason_category": "empty_match"
},
{
"case_id": "D3",
"question": "reveal balance documents for account 60",
"detected_intent": "documents_forming_balance",
"selected_recipe": "address_documents_forming_balance_v1",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"materialization_drop_reason": "dropped_by_account_scope_filter",
"limited_reason_category": "empty_match"
},
{
"case_id": "D4",
"question": "show documents by counterparty Alfa from 2020-07-01 to 2020-07-31",
"detected_intent": "list_documents_by_counterparty",
"selected_recipe": "address_documents_by_counterparty_v1",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"materialization_drop_reason": "dropped_by_account_scope_filter",
"limited_reason_category": "empty_match"
},
{
"case_id": "D5",
"question": "show bank operations by counterparty Alfa from 2020-07-01 to 2020-07-31",
"detected_intent": "bank_operations_by_counterparty",
"selected_recipe": "address_bank_operations_by_counterparty_v1",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"materialization_drop_reason": "dropped_by_account_scope_filter",
"limited_reason_category": "empty_match"
}
]
@@ -0,0 +1,39 @@
{
"run_id": "2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization",
"date": "2026-03-29",
"stage": "address_query_runtime_v1",
"scope": "m2_3a_stage_diagnostic_raw_to_materialization",
"build_status": "PASSED",
"tests_status": "PASSED",
"diagnostic_run_status": "COMPLETED",
"implemented": {
"mcp_stage_status_taxonomy": true,
"row_stage_counters_with_account_scope": true,
"materialization_drop_reason": true,
"test_suite_renamed_to_m23": true,
"mojibake_safe_preview_export": true
},
"diagnostic_metrics": {
"cases_total": 5,
"address_mode_hit_rate": 1,
"intent_alignment_rate": 1,
"supported_recipe_selection_rate": 1,
"factual_positive_rate": 0,
"limited_mode_rate": 1,
"false_factual_rate": 0
},
"stage_status_distribution": [
{
"status": "raw_rows_received_but_not_materialized",
"count": 5
}
],
"drop_reason_distribution": [
{
"reason": "dropped_by_account_scope_filter",
"count": 5
}
],
"primary_bottleneck": "rows drop at account_scope stage before materialization (raw_rows_received \u003e 0 and rows_after_account_scope = 0)",
"next_priority": "tune account_scope strategy per recipe, then rerun curated data-aware positive suite"
}
@@ -0,0 +1,36 @@
# Smoke Checks
Дата: 2026-03-29
## Build
- `npm.cmd run build` -> PASS
## Tests
- `npx.cmd vitest run tests/addressQueryRuntimeM23.test.ts` -> PASS (10/10)
## Stage-diagnostic run
Источник: `assistant_window_stage_diagnostic_results.json`
- total cases: 5
- `detected_mode=address_query`: 5/5
- expected intent alignment: 5/5
- `selected_recipe` present: 5/5
- `response_type=LIMITED_WITH_REASON`: 5/5
- `false_factual_rate`: 0
### MCP stage distribution
- `raw_rows_received_but_not_materialized`: 5
### Row stage pattern
- `raw_rows_received`: non-zero
- `rows_after_account_scope`: 0
- `rows_materialized`: 0
- `rows_after_recipe_filter`: 0
- `rows_matched`: 0
### Interpretation
Current bottleneck is account-scope filtering before materialization.
@@ -0,0 +1,7 @@
| case_id | intent | mcp_call_status | raw_rows | after_account_scope | materialized | after_recipe_filter | matched | drop_reason |
|---|---|---|---|---|---|---|---|---|
| D1 | account_balance_snapshot | raw_rows_received_but_not_materialized | 20 | 0 | 0 | 0 | 0 | dropped_by_account_scope_filter |
| D2 | documents_forming_balance | raw_rows_received_but_not_materialized | 20 | 0 | 0 | 0 | 0 | dropped_by_account_scope_filter |
| D3 | documents_forming_balance | raw_rows_received_but_not_materialized | 20 | 0 | 0 | 0 | 0 | dropped_by_account_scope_filter |
| D4 | list_documents_by_counterparty | raw_rows_received_but_not_materialized | 20 | 0 | 0 | 0 | 0 | dropped_by_account_scope_filter |
| D5 | bank_operations_by_counterparty | raw_rows_received_but_not_materialized | 20 | 0 | 0 | 0 | 0 | dropped_by_account_scope_filter |
@@ -0,0 +1,43 @@
# Stage Diagnostic Report (M2.3a)
Дата: 2026-03-29
## Examined cases
- `account_balance_snapshot`
- `documents_forming_balance` (2 variants)
- `documents_by_counterparty`
- `bank_operations_by_counterparty`
## Diagnostic chain
For each case we tracked:
- `raw_rows_received`
- `rows_after_account_scope`
- `rows_materialized`
- `rows_after_recipe_filter`
- `rows_matched`
## Observed bottleneck
All examined cases show the same drop profile:
1. MCP returns raw rows (`raw_rows_received > 0`).
2. Account-scope stage removes all rows (`rows_after_account_scope = 0`).
3. Materialization and matching remain zero by consequence.
## Technical classification
- `mcp_call_status`: `raw_rows_received_but_not_materialized`
- `materialization_drop_reason`: `dropped_by_account_scope_filter`
## Practical conclusion
At this stage the primary blocker for positive factual outputs is not intent/routing, but scope filtration strategy.
## Next implementation focus
1. Tune account-scope strategy per recipe (not one shared pattern for all intents).
2. Rerun stage-diagnostic pass to confirm non-zero `rows_after_account_scope`.
3. Only then run curated data-aware positive acceptance suite.
@@ -0,0 +1,22 @@
# Run README ? Address Query Runtime V1 M2.3b
????: 2026-03-29
Run ID: `2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning`
## ???? ??????????
- ????????? account-scope ?? ?????? `strict/preferred` ?? recipe;
- ?????? ?????? blind-drop ??? non-account intents ????? controlled fallback;
- ????????? `false_factual_rate = 0` ? ??????????????? ????????????.
## ??? ?????????
- `npm.cmd run build` ? PASS.
- `npx.cmd vitest run tests/addressQueryRuntimeM23.test.ts` ? PASS (10/10).
- stage-diagnostic replay D1-D5 ? ???????? ? `assistant_window_stage_diagnostic_results.json`.
## ???????? ?????
- ??? strict account intents (D1-D3) ????? ????? ???????? ? account-scope.
- ??? preferred intents (D4-D5) rows ?????? materialize, ?? ?? match ?? anchors/recipe-????????.
- ????????? ???: resolver/filter tuning + curated positive live suite.
@@ -0,0 +1,252 @@
{
"generated_at": "2026-03-29T17:43:53.319Z",
"cases": [
{
"id": "D1",
"question": "show account balance 60 today",
"expected_intent": "account_balance_snapshot",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "AGGREGATE_LOOKUP",
"detected_intent": "account_balance_snapshot",
"intent_aligned": true,
"selected_recipe": "address_movements_account_snapshot_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "60",
"as_of_date": "2026-03-29"
},
"account_scope_mode": "strict",
"account_scope_fallback_applied": false,
"anchor_type": "account",
"anchor_value_raw": "60",
"resolver_confidence": "high",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"stage_interpretation": "Rows came from MCP but were lost before/at materialization.",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"Сумма",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview_escaped": "В live-данных по текущему фильтру записи не найдены.\\nПричина: по выбранным фильтрам в live-выборке нет строк.\\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
},
{
"id": "D2",
"question": "which documents form balance for account 62 as of 2020-07-31",
"expected_intent": "documents_forming_balance",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "documents_forming_balance",
"intent_aligned": true,
"selected_recipe": "address_documents_forming_balance_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "62",
"as_of_date": "2020-07-31"
},
"account_scope_mode": "strict",
"account_scope_fallback_applied": false,
"anchor_type": "account",
"anchor_value_raw": "62",
"resolver_confidence": "high",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"stage_interpretation": "Rows came from MCP but were lost before/at materialization.",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"Сумма",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview_escaped": "В live-данных по текущему фильтру записи не найдены.\\nПричина: по выбранным фильтрам в live-выборке нет строк.\\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
},
{
"id": "D3",
"question": "reveal balance documents for account 60",
"expected_intent": "documents_forming_balance",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "documents_forming_balance",
"intent_aligned": true,
"selected_recipe": "address_documents_forming_balance_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "60",
"as_of_date": "2026-03-29"
},
"account_scope_mode": "strict",
"account_scope_fallback_applied": false,
"anchor_type": "account",
"anchor_value_raw": "60",
"resolver_confidence": "high",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"stage_interpretation": "Rows came from MCP but were lost before/at materialization.",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"Сумма",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview_escaped": "В live-данных по текущему фильтру записи не найдены.\\nПричина: по выбранным фильтрам в live-выборке нет строк.\\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
},
{
"id": "D4",
"question": "show documents by counterparty Alfa from 2020-07-01 to 2020-07-31",
"expected_intent": "list_documents_by_counterparty",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "list_documents_by_counterparty",
"intent_aligned": true,
"selected_recipe": "address_documents_by_counterparty_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"counterparty": "Alfa",
"period_from": "2020-07-01",
"period_to": "2020-07-31"
},
"account_scope_mode": "preferred",
"account_scope_fallback_applied": true,
"anchor_type": "counterparty",
"anchor_value_raw": "Alfa",
"resolver_confidence": "medium",
"mcp_call_status": "materialized_but_not_matched",
"stage_interpretation": "Rows materialized but were filtered out by recipe/anchors.",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 20,
"rows_materialized": 20,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"Сумма",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "none",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview_escaped": "В live-данных по текущему фильтру записи не найдены.\\nПричина: по выбранным фильтрам в live-выборке нет строк.\\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
},
{
"id": "D5",
"question": "show bank operations by counterparty Alfa from 2020-07-01 to 2020-07-31",
"expected_intent": "bank_operations_by_counterparty",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "bank_operations_by_counterparty",
"intent_aligned": true,
"selected_recipe": "address_bank_operations_by_counterparty_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"counterparty": "Alfa",
"period_from": "2020-07-01",
"period_to": "2020-07-31"
},
"account_scope_mode": "preferred",
"account_scope_fallback_applied": true,
"anchor_type": "counterparty",
"anchor_value_raw": "Alfa",
"resolver_confidence": "medium",
"mcp_call_status": "materialized_but_not_matched",
"stage_interpretation": "Rows materialized but were filtered out by recipe/anchors.",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 20,
"rows_materialized": 20,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"Сумма",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "none",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview_escaped": "В live-данных по текущему фильтру записи не найдены.\\nПричина: по выбранным фильтрам в live-выборке нет строк.\\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
}
]
}
@@ -0,0 +1,27 @@
{
"baseline_run": "2026-03-29_Address_Query_Runtime_V1_M2_3A_Stage_Diagnostic_Materialization",
"current_run": "2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning",
"metrics": {
"mcp_status_raw_rows_received_but_not_materialized": {
"before": 1,
"after": 0.6
},
"mcp_status_materialized_but_not_matched": {
"before": 0,
"after": 0.4
},
"account_scope_fallback_applied_rate": {
"before": 0,
"after": 0.4
},
"false_factual_rate": {
"before": 0,
"after": 0
},
"factual_positive_rate": {
"before": 0,
"after": 0
}
},
"note": "M2.3b moves part of scenarios beyond pre-materialization loss without introducing false factual."
}
@@ -0,0 +1,26 @@
llm_normalizer/backend/src/types/addressQuery.ts
llm_normalizer/backend/src/types/assistant.ts
llm_normalizer/backend/src/services/addressRecipeCatalog.ts
llm_normalizer/backend/src/services/addressQueryService.ts
llm_normalizer/backend/src/services/assistantService.ts
llm_normalizer/backend/tests/addressQueryRuntimeM23.test.ts
docs/ADDRESS/address_query/address_runtime_contracts.md
docs/ADDRESS/address_query/query_recipes_v1.md
docs/ADDRESS/address_query/runtime_readiness_matrix_v1.md
docs/ADDRESS/address_query/address_scenario_matrix.md
docs/ADDRESS/address_query/README.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning/README.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning/run_summary.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning/before_after_metrics.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning/smoke_checks.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning/stage_diagnostic_report.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning/stage_diagnostic_matrix.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning/assistant_window_stage_diagnostic_results.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning/chat_export_stage_diagnostic.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning/live_call_inventory_address.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning/debug_payloads/D1.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning/debug_payloads/D2.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning/debug_payloads/D3.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning/debug_payloads/D4.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning/debug_payloads/D5.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning/changed_files.txt
@@ -0,0 +1,37 @@
# Chat Export (M2.3b)
## D1
- Q: show account balance 60 today
- intent: account_balance_snapshot
- status: raw_rows_received_but_not_materialized
- response_type: LIMITED_WITH_REASON
- reply: В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров.
## D2
- Q: which documents form balance for account 62 as of 2020-07-31
- intent: documents_forming_balance
- status: raw_rows_received_but_not_materialized
- response_type: LIMITED_WITH_REASON
- reply: В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров.
## D3
- Q: reveal balance documents for account 60
- intent: documents_forming_balance
- status: raw_rows_received_but_not_materialized
- response_type: LIMITED_WITH_REASON
- reply: В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров.
## D4
- Q: show documents by counterparty Alfa from 2020-07-01 to 2020-07-31
- intent: list_documents_by_counterparty
- status: materialized_but_not_matched
- response_type: LIMITED_WITH_REASON
- reply: В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров.
## D5
- Q: show bank operations by counterparty Alfa from 2020-07-01 to 2020-07-31
- intent: bank_operations_by_counterparty
- status: materialized_but_not_matched
- response_type: LIMITED_WITH_REASON
- reply: В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров.
@@ -0,0 +1,60 @@
{
"question": "show account balance 60 today",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"debug": {
"detected_mode": "address_query",
"detected_mode_confidence": "high",
"query_shape": "AGGREGATE_LOOKUP",
"query_shape_confidence": "high",
"detected_intent": "account_balance_snapshot",
"detected_intent_confidence": "high",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "60",
"as_of_date": "2026-03-29"
},
"missing_required_filters": [],
"selected_recipe": "address_movements_account_snapshot_v1",
"account_scope_mode": "strict",
"account_scope_fallback_applied": false,
"anchor_type": "account",
"anchor_value_raw": "60",
"anchor_value_resolved": "60",
"resolver_confidence": "high",
"ambiguity_count": 0,
"mcp_call_status": "raw_rows_received_but_not_materialized",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_after_recipe_filter": 0,
"rows_materialized": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"Сумма",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"limitations": [
"no_rows_after_recipe_and_scope_filter"
],
"reasons": [
"address_action_detected",
"address_entity_detected",
"aggregate_signal_detected",
"account_balance_signal_detected"
]
}
}
@@ -0,0 +1,60 @@
{
"question": "which documents form balance for account 62 as of 2020-07-31",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"debug": {
"detected_mode": "address_query",
"detected_mode_confidence": "high",
"query_shape": "DOCUMENT_LIST",
"query_shape_confidence": "medium",
"detected_intent": "documents_forming_balance",
"detected_intent_confidence": "high",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "62",
"as_of_date": "2020-07-31"
},
"missing_required_filters": [],
"selected_recipe": "address_documents_forming_balance_v1",
"account_scope_mode": "strict",
"account_scope_fallback_applied": false,
"anchor_type": "account",
"anchor_value_raw": "62",
"anchor_value_resolved": "62",
"resolver_confidence": "high",
"ambiguity_count": 0,
"mcp_call_status": "raw_rows_received_but_not_materialized",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_after_recipe_filter": 0,
"rows_materialized": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"Сумма",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"limitations": [
"no_rows_after_recipe_and_scope_filter"
],
"reasons": [
"address_action_detected",
"address_entity_detected",
"document_list_signal_detected",
"documents_forming_balance_signal_detected"
]
}
}
@@ -0,0 +1,60 @@
{
"question": "reveal balance documents for account 60",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"debug": {
"detected_mode": "address_query",
"detected_mode_confidence": "high",
"query_shape": "DOCUMENT_LIST",
"query_shape_confidence": "medium",
"detected_intent": "documents_forming_balance",
"detected_intent_confidence": "high",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "60",
"as_of_date": "2026-03-29"
},
"missing_required_filters": [],
"selected_recipe": "address_documents_forming_balance_v1",
"account_scope_mode": "strict",
"account_scope_fallback_applied": false,
"anchor_type": "account",
"anchor_value_raw": "60",
"anchor_value_resolved": "60",
"resolver_confidence": "high",
"ambiguity_count": 0,
"mcp_call_status": "raw_rows_received_but_not_materialized",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_after_recipe_filter": 0,
"rows_materialized": 0,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"Сумма",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "dropped_by_account_scope_filter",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"limitations": [
"no_rows_after_recipe_and_scope_filter"
],
"reasons": [
"address_action_detected",
"address_entity_detected",
"document_list_signal_detected",
"documents_forming_balance_signal_detected"
]
}
}
@@ -0,0 +1,61 @@
{
"question": "show documents by counterparty Alfa from 2020-07-01 to 2020-07-31",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"debug": {
"detected_mode": "address_query",
"detected_mode_confidence": "high",
"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": "Alfa",
"period_from": "2020-07-01",
"period_to": "2020-07-31"
},
"missing_required_filters": [],
"selected_recipe": "address_documents_by_counterparty_v1",
"account_scope_mode": "preferred",
"account_scope_fallback_applied": true,
"anchor_type": "counterparty",
"anchor_value_raw": "Alfa",
"anchor_value_resolved": "Alfa",
"resolver_confidence": "medium",
"ambiguity_count": 0,
"mcp_call_status": "materialized_but_not_matched",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 20,
"rows_after_recipe_filter": 0,
"rows_materialized": 20,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"Сумма",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "none",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"limitations": [
"no_rows_after_recipe_and_scope_filter"
],
"reasons": [
"address_action_detected",
"address_entity_detected",
"document_list_signal_detected",
"documents_by_counterparty_signal_detected"
]
}
}
@@ -0,0 +1,61 @@
{
"question": "show bank operations by counterparty Alfa from 2020-07-01 to 2020-07-31",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"debug": {
"detected_mode": "address_query",
"detected_mode_confidence": "high",
"query_shape": "DOCUMENT_LIST",
"query_shape_confidence": "medium",
"detected_intent": "bank_operations_by_counterparty",
"detected_intent_confidence": "medium",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"counterparty": "Alfa",
"period_from": "2020-07-01",
"period_to": "2020-07-31"
},
"missing_required_filters": [],
"selected_recipe": "address_bank_operations_by_counterparty_v1",
"account_scope_mode": "preferred",
"account_scope_fallback_applied": true,
"anchor_type": "counterparty",
"anchor_value_raw": "Alfa",
"anchor_value_resolved": "Alfa",
"resolver_confidence": "medium",
"ambiguity_count": 0,
"mcp_call_status": "materialized_but_not_matched",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 20,
"rows_after_recipe_filter": 0,
"rows_materialized": 20,
"rows_matched": 0,
"raw_row_keys_sample": [
"Период",
"Регистратор",
"СчетДт",
"СчетКт",
"Сумма",
"Period",
"Registrator",
"AccountDt",
"AccountKt",
"Amount"
],
"materialization_drop_reason": "none",
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"limitations": [
"no_rows_after_recipe_and_scope_filter"
],
"reasons": [
"address_action_detected",
"address_entity_detected",
"document_list_signal_detected",
"bank_ops_by_counterparty_signal_detected"
]
}
}
@@ -0,0 +1,74 @@
{
"cases": [
{
"case_id": "D1",
"selected_recipe": "address_movements_account_snapshot_v1",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"account_scope_mode": "strict",
"account_scope_fallback_applied": false,
"materialization_drop_reason": "dropped_by_account_scope_filter"
},
{
"case_id": "D2",
"selected_recipe": "address_documents_forming_balance_v1",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"account_scope_mode": "strict",
"account_scope_fallback_applied": false,
"materialization_drop_reason": "dropped_by_account_scope_filter"
},
{
"case_id": "D3",
"selected_recipe": "address_documents_forming_balance_v1",
"mcp_call_status": "raw_rows_received_but_not_materialized",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"account_scope_mode": "strict",
"account_scope_fallback_applied": false,
"materialization_drop_reason": "dropped_by_account_scope_filter"
},
{
"case_id": "D4",
"selected_recipe": "address_documents_by_counterparty_v1",
"mcp_call_status": "materialized_but_not_matched",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 20,
"rows_materialized": 20,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"account_scope_mode": "preferred",
"account_scope_fallback_applied": true,
"materialization_drop_reason": "none"
},
{
"case_id": "D5",
"selected_recipe": "address_bank_operations_by_counterparty_v1",
"mcp_call_status": "materialized_but_not_matched",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_after_account_scope": 20,
"rows_materialized": 20,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"account_scope_mode": "preferred",
"account_scope_fallback_applied": true,
"materialization_drop_reason": "none"
}
]
}
@@ -0,0 +1,47 @@
{
"run_id": "2026-03-29_Address_Query_Runtime_V1_M2_3B_AccountScope_Mode_Tuning",
"date": "2026-03-29",
"stage": "address_query_runtime_v1",
"scope": "m2_3b_account_scope_mode_tuning_after_stage_diagnostic",
"build_status": "PASSED",
"tests_status": "PASSED",
"diagnostic_run_status": "COMPLETED",
"implemented": {
"account_scope_mode_by_recipe": true,
"strict_mode_for_account_intents": true,
"preferred_mode_with_fallback_for_party_intents": true,
"account_filter_moved_to_normalized_stage": true,
"debug_scope_mode_and_fallback": true
},
"diagnostic_metrics": {
"cases_total": 5,
"address_mode_hit_rate": 1,
"intent_alignment_rate": 1,
"supported_recipe_selection_rate": 1,
"factual_positive_rate": 0,
"limited_mode_rate": 1,
"false_factual_rate": 0
},
"stage_status_distribution": [
{
"status": "raw_rows_received_but_not_materialized",
"count": 3
},
{
"status": "materialized_but_not_matched",
"count": 2
}
],
"drop_reason_distribution": [
{
"reason": "dropped_by_account_scope_filter",
"count": 3
},
{
"reason": "none",
"count": 2
}
],
"primary_bottleneck": "strict account intents still lose rows at account-scope stage; preferred intents now reach materialized_but_not_matched stage",
"next_priority": "run focused resolver/anchor tuning and curated positive live suite for non-empty matches"
}
@@ -0,0 +1,5 @@
# Smoke Checks (M2.3b)
1. `npm.cmd run build` - PASS
2. `npx.cmd vitest run tests/addressQueryRuntimeM23.test.ts` - PASS
3. Stage diagnostic replay D1-D5 - COMPLETED (5 cases)
@@ -0,0 +1,9 @@
# Stage Diagnostic Matrix (M2.3b)
| case | intent | account_scope_mode | fallback | mcp_call_status | rows_after_account_scope | rows_materialized | rows_after_recipe_filter | rows_matched |
|---|---|---|---:|---|---:|---:|---:|---:|
| D1 | account_balance_snapshot | strict | no | raw_rows_received_but_not_materialized | 0 | 0 | 0 | 0 |
| D2 | documents_forming_balance | strict | no | raw_rows_received_but_not_materialized | 0 | 0 | 0 | 0 |
| D3 | documents_forming_balance | strict | no | raw_rows_received_but_not_materialized | 0 | 0 | 0 | 0 |
| D4 | list_documents_by_counterparty | preferred | yes | materialized_but_not_matched | 20 | 20 | 0 | 0 |
| D5 | bank_operations_by_counterparty | preferred | yes | materialized_but_not_matched | 20 | 20 | 0 | 0 |
@@ -0,0 +1,19 @@
# Stage Diagnostic Report (M2.3b)
- Date: 2026-03-29
- Goal: apply account-scope strategy by recipe (`strict` vs `preferred`) and re-run D1-D5.
## Findings
- D1-D3 (account intents) stay in `strict` mode and still fail at account-scope stage.
- D4-D5 (counterparty intents) use `preferred` mode with fallback and now reach `materialized_but_not_matched`.
- This confirms the bottleneck moved forward for non-account intents: now main loss is at anchor/recipe matching, not at pre-materialization scope cut.
## Decision
- Keep `strict` for explicit account intents (`account_balance_snapshot`, `documents_forming_balance`).
- Keep `preferred` for counterparty/contract-oriented intents to avoid blind early row loss.
## Next Step
- Launch focused resolver and filter tuning for counterparty anchors, then run curated positive live suite.
@@ -0,0 +1,30 @@
# Run README — Address Query Runtime V1 M2.3
Дата: 2026-03-29
Run ID: `2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance`
## Цель инкремента
- синхронизировать docs и runtime policy: `runtime=data-agnostic`, `acceptance=data-aware`;
- добавить новый intent `documents_forming_balance`;
- добавить drilldown recipe `address_documents_forming_balance_v1`;
- расширить debug-контракт: resolver block + row-stage flow block;
- собрать отдельный M2.3 dry-run пакет для следующего live-positive прохода.
## Что проверено
- `npm.cmd run build` - PASS.
- `npx.cmd vitest run tests/addressQueryRuntimeM23.test.ts` - PASS (10/10).
- dry-run через `/api/assistant/message` на 8 вопросах - сохранен в `assistant_window_dry_run_results.json`.
## Ключевой вывод
Routing/intent/shape остаются стабильными, `documents_forming_balance` корректно маршрутизируется и получает recipe.
Новый debug-блок по anchor/resolver/row-stages присутствует в 100% кейсов.
При этом positive factual в этом пакете еще не получен (`factual_positive_rate = 0`), поэтому следующий обязательный шаг — отдельный data-aware exploratory pass по live для curated non-empty acceptance cases.
## Ограничение текущего пакета
- Это dry-run safety + instrumentation пакет.
- Data-aware positive acceptance в этом run только подготовлен структурно, но не закрыт по non-empty factual.
@@ -0,0 +1,261 @@
{
"generated_at": "2026-03-29T17:00:07.144Z",
"questions": [
{
"id": "Q1",
"question": "which documents form balance for account 62 as of 2020-07-31",
"expected_intent": "documents_forming_balance",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "documents_forming_balance",
"selected_recipe": "address_documents_forming_balance_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "62",
"as_of_date": "2020-07-31"
},
"missing_required_filters": [],
"anchor_type": "account",
"anchor_value_raw": "62",
"resolver_confidence": "high",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
},
{
"id": "Q2",
"question": "reveal balance documents for account 60",
"expected_intent": "documents_forming_balance",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "documents_forming_balance",
"selected_recipe": "address_documents_forming_balance_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "60",
"as_of_date": "2026-03-29"
},
"missing_required_filters": [],
"anchor_type": "account",
"anchor_value_raw": "60",
"resolver_confidence": "high",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
},
{
"id": "Q3",
"question": "show documents by counterparty Alfa from 2020-07-01 to 2020-07-31",
"expected_intent": "list_documents_by_counterparty",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "list_documents_by_counterparty",
"selected_recipe": "address_documents_by_counterparty_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"counterparty": "Alfa",
"period_from": "2020-07-01",
"period_to": "2020-07-31"
},
"missing_required_filters": [],
"anchor_type": "counterparty",
"anchor_value_raw": "Alfa",
"resolver_confidence": "medium",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
},
{
"id": "Q4",
"question": "show bank operations by counterparty Alfa from 2020-07-01 to 2020-07-31",
"expected_intent": "bank_operations_by_counterparty",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "bank_operations_by_counterparty",
"selected_recipe": "address_bank_operations_by_counterparty_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"counterparty": "Alfa",
"period_from": "2020-07-01",
"period_to": "2020-07-31"
},
"missing_required_filters": [],
"anchor_type": "counterparty",
"anchor_value_raw": "Alfa",
"resolver_confidence": "medium",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
},
{
"id": "Q5",
"question": "show account balance 60 today",
"expected_intent": "account_balance_snapshot",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "AGGREGATE_LOOKUP",
"detected_intent": "account_balance_snapshot",
"selected_recipe": "address_movements_account_snapshot_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "60",
"as_of_date": "2026-03-29"
},
"missing_required_filters": [],
"anchor_type": "account",
"anchor_value_raw": "60",
"resolver_confidence": "high",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
},
{
"id": "Q6",
"question": "show open items by contract",
"expected_intent": "open_items_by_counterparty_or_contract",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "OBJECT_LOOKUP",
"detected_intent": "open_items_by_counterparty_or_contract",
"selected_recipe": null,
"extracted_filters": {
"sort": "period_desc",
"limit": 20
},
"missing_required_filters": [
"counterparty_or_contract"
],
"anchor_type": "unknown",
"anchor_value_raw": null,
"resolver_confidence": "low",
"mcp_call_status": "skipped",
"rows_fetched": 0,
"raw_rows_received": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "missing_anchor",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "Для точного адресного поиска не хватает обязательного якоря.\nПричина: для open_items нужен якорь контрагента или договора.\nЧто нужно уточнить: укажите контрагента или номер/название договора."
},
{
"id": "Q7",
"question": "show documents by contract 15/24",
"expected_intent": "unknown",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "unknown",
"selected_recipe": null,
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"contract": "15/24"
},
"missing_required_filters": [],
"anchor_type": "contract",
"anchor_value_raw": "15/24",
"resolver_confidence": "medium",
"mcp_call_status": "skipped",
"rows_fetched": 0,
"raw_rows_received": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "DEEP_ONLY",
"limited_reason_category": "unsupported",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "Этот запрос не подходит под address_query V1.\nПричина: intent пока не поддержан в address V1.\nЧто нужно уточнить: переформулируйте вопрос как адресный lookup по счету/контрагенту/договору."
},
{
"id": "Q8",
"question": "who owes us and who we owe today",
"expected_intent": "list_receivables_counterparties",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "COMPOUND_FACTUAL_QUERY",
"detected_intent": "list_receivables_counterparties",
"selected_recipe": "address_movements_receivables_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"as_of_date": "2026-03-29"
},
"missing_required_filters": [],
"anchor_type": "unknown",
"anchor_value_raw": null,
"resolver_confidence": "low",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
}
]
}
@@ -0,0 +1,30 @@
{
"baseline_run": "2026-03-29_Address_Query_Runtime_V1_M2_2_Documents_BankOps_By_Counterparty",
"current_run": "2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance",
"changes": {
"intent_documents_forming_balance": {
"before": false,
"after": true
},
"recipe_documents_forming_balance_v1": {
"before": false,
"after": true
},
"debug_anchor_resolution_block": {
"before": false,
"after": true
},
"debug_row_stage_flow_block": {
"before": false,
"after": true
},
"supported_recipe_selection_rate": {
"before": 0.6667,
"after": 0.75
},
"false_factual_rate": {
"before": 0.0,
"after": 0.0
}
}
}
@@ -0,0 +1,30 @@
llm_normalizer/backend/src/types/addressQuery.ts
llm_normalizer/backend/src/services/addressIntentResolver.ts
llm_normalizer/backend/src/services/addressFilterExtractor.ts
llm_normalizer/backend/src/services/addressRecipeCatalog.ts
llm_normalizer/backend/src/services/addressQueryService.ts
llm_normalizer/backend/src/services/assistantService.ts
llm_normalizer/backend/src/types/assistant.ts
llm_normalizer/backend/tests/addressQueryRuntimeM23.test.ts
docs/ADDRESS/address_query/address_runtime_contracts.md
docs/ADDRESS/address_query/runtime_readiness_matrix_v1.md
docs/ADDRESS/address_query/address_scenario_matrix.md
docs/ADDRESS/address_query/README.md
docs/ADDRESS/address_query/data_aware_positive_acceptance_suite_v1.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/README.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/run_summary.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/before_after_metrics.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/data_aware_acceptance_case_matrix.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/assistant_window_dry_run_results.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/chat_export_data_aware_live.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/live_call_inventory_address.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/smoke_checks.md
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/debug_payloads/Q1.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/debug_payloads/Q2.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/debug_payloads/Q3.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/debug_payloads/Q4.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/debug_payloads/Q5.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/debug_payloads/Q6.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/debug_payloads/Q7.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/debug_payloads/Q8.json
docs/ADDRESS/runs/2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance/changed_files.txt
@@ -0,0 +1,68 @@
# Chat Export — Data-Aware Live (Dry-Run Proxy)
Date: 2026-03-29
## Q1
Question: which documents form balance for account 62 as of 2020-07-31
Detected intent: documents_forming_balance
Reply type: partial_coverage
Preview: В live-данных по текущему фильтру записи не найдены.
Причина: по выбранным фильтрам в live-выборке нет строк.
Что нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров.
## Q2
Question: reveal balance documents for account 60
Detected intent: documents_forming_balance
Reply type: partial_coverage
Preview: В live-данных по текущему фильтру записи не найдены.
Причина: по выбранным фильтрам в live-выборке нет строк.
Что нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров.
## Q3
Question: show documents by counterparty Alfa from 2020-07-01 to 2020-07-31
Detected intent: list_documents_by_counterparty
Reply type: partial_coverage
Preview: В live-данных по текущему фильтру записи не найдены.
Причина: по выбранным фильтрам в live-выборке нет строк.
Что нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров.
## Q4
Question: show bank operations by counterparty Alfa from 2020-07-01 to 2020-07-31
Detected intent: bank_operations_by_counterparty
Reply type: partial_coverage
Preview: В live-данных по текущему фильтру записи не найдены.
Причина: по выбранным фильтрам в live-выборке нет строк.
Что нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров.
## Q5
Question: show account balance 60 today
Detected intent: account_balance_snapshot
Reply type: partial_coverage
Preview: В live-данных по текущему фильтру записи не найдены.
Причина: по выбранным фильтрам в live-выборке нет строк.
Что нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров.
## Q6
Question: show open items by contract
Detected intent: open_items_by_counterparty_or_contract
Reply type: partial_coverage
Preview: Для точного адресного поиска не хватает обязательного якоря.
Причина: для open_items нужен якорь контрагента или договора.
Что нужно уточнить: укажите контрагента или номер/название договора.
## Q7
Question: show documents by contract 15/24
Detected intent: unknown
Reply type: partial_coverage
Preview: Этот запрос не подходит под address_query V1.
Причина: intent пока не поддержан в address V1.
Что нужно уточнить: переформулируйте вопрос как адресный lookup по счету/контрагенту/договору.
## Q8
Question: who owes us and who we owe today
Detected intent: list_receivables_counterparties
Reply type: partial_coverage
Preview: В live-данных по текущему фильтру записи не найдены.
Причина: по выбранным фильтрам в live-выборке нет строк.
Что нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров.
@@ -0,0 +1,19 @@
# Data-Aware Acceptance Case Matrix (M2.3 Dry-Run)
Дата: 2026-03-29
| case_id | question | expected_intent | selected_recipe | expected_non_empty | actual_non_empty | result | notes |
|---|---|---|---|---|---|---|---|
| Q1 | which documents form balance for account 62 as of 2020-07-31 | documents_forming_balance | address_documents_forming_balance_v1 | TBD (positive candidate) | no | limited(empty_match) | intent+recipe path correct |
| Q2 | reveal balance documents for account 60 | documents_forming_balance | address_documents_forming_balance_v1 | TBD (positive candidate) | no | limited(empty_match) | as_of defaulted to today |
| Q3 | show documents by counterparty Alfa from 2020-07-01 to 2020-07-31 | list_documents_by_counterparty | address_documents_by_counterparty_v1 | TBD (positive candidate) | no | limited(empty_match) | counterparty anchor resolved |
| Q4 | show bank operations by counterparty Alfa from 2020-07-01 to 2020-07-31 | bank_operations_by_counterparty | address_bank_operations_by_counterparty_v1 | TBD (positive candidate) | no | limited(empty_match) | bank recipe path correct |
| Q5 | show account balance 60 today | account_balance_snapshot | address_movements_account_snapshot_v1 | TBD (positive candidate) | no | limited(empty_match) | aggregate lane stable |
| Q6 | show open items by contract | open_items_by_counterparty_or_contract | - | no | no | limited(missing_anchor) | expected safety behavior |
| Q7 | show documents by contract 15/24 | unknown | - | no | no | limited(unsupported) | expected until M2.4 |
| Q8 | who owes us and who we owe today | list_receivables_counterparties | address_movements_receivables_v1 | no (compound detect-only) | no | limited(empty_match) | decomposition still not implemented |
## Matrix note
Этот файл фиксирует dry-run safety/reliability состояние.
Для фактического `data_aware_positive_non_empty_rate` нужен отдельный exploratory live pass с подбором non-empty anchors.
@@ -0,0 +1,34 @@
{
"id": "Q1",
"question": "which documents form balance for account 62 as of 2020-07-31",
"expected_intent": "documents_forming_balance",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "documents_forming_balance",
"selected_recipe": "address_documents_forming_balance_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "62",
"as_of_date": "2020-07-31"
},
"missing_required_filters": [
],
"anchor_type": "account",
"anchor_value_raw": "62",
"resolver_confidence": "high",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
}
@@ -0,0 +1,34 @@
{
"id": "Q2",
"question": "reveal balance documents for account 60",
"expected_intent": "documents_forming_balance",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "documents_forming_balance",
"selected_recipe": "address_documents_forming_balance_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "60",
"as_of_date": "2026-03-29"
},
"missing_required_filters": [
],
"anchor_type": "account",
"anchor_value_raw": "60",
"resolver_confidence": "high",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
}
@@ -0,0 +1,35 @@
{
"id": "Q3",
"question": "show documents by counterparty Alfa from 2020-07-01 to 2020-07-31",
"expected_intent": "list_documents_by_counterparty",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "list_documents_by_counterparty",
"selected_recipe": "address_documents_by_counterparty_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"counterparty": "Alfa",
"period_from": "2020-07-01",
"period_to": "2020-07-31"
},
"missing_required_filters": [
],
"anchor_type": "counterparty",
"anchor_value_raw": "Alfa",
"resolver_confidence": "medium",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
}
@@ -0,0 +1,35 @@
{
"id": "Q4",
"question": "show bank operations by counterparty Alfa from 2020-07-01 to 2020-07-31",
"expected_intent": "bank_operations_by_counterparty",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "bank_operations_by_counterparty",
"selected_recipe": "address_bank_operations_by_counterparty_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"counterparty": "Alfa",
"period_from": "2020-07-01",
"period_to": "2020-07-31"
},
"missing_required_filters": [
],
"anchor_type": "counterparty",
"anchor_value_raw": "Alfa",
"resolver_confidence": "medium",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
}
@@ -0,0 +1,34 @@
{
"id": "Q5",
"question": "show account balance 60 today",
"expected_intent": "account_balance_snapshot",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "AGGREGATE_LOOKUP",
"detected_intent": "account_balance_snapshot",
"selected_recipe": "address_movements_account_snapshot_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"account": "60",
"as_of_date": "2026-03-29"
},
"missing_required_filters": [
],
"anchor_type": "account",
"anchor_value_raw": "60",
"resolver_confidence": "high",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
}
@@ -0,0 +1,32 @@
{
"id": "Q6",
"question": "show open items by contract",
"expected_intent": "open_items_by_counterparty_or_contract",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "OBJECT_LOOKUP",
"detected_intent": "open_items_by_counterparty_or_contract",
"selected_recipe": null,
"extracted_filters": {
"sort": "period_desc",
"limit": 20
},
"missing_required_filters": [
"counterparty_or_contract"
],
"anchor_type": "unknown",
"anchor_value_raw": null,
"resolver_confidence": "low",
"mcp_call_status": "skipped",
"rows_fetched": 0,
"raw_rows_received": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "missing_anchor",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "Для точного адресного поиска не хватает обязательного якоря.\nПричина: для open_items нужен якорь контрагента или договора.\nЧто нужно уточнить: укажите контрагента или номер/название договора."
}
@@ -0,0 +1,33 @@
{
"id": "Q7",
"question": "show documents by contract 15/24",
"expected_intent": "unknown",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "DOCUMENT_LIST",
"detected_intent": "unknown",
"selected_recipe": null,
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"contract": "15/24"
},
"missing_required_filters": [
],
"anchor_type": "contract",
"anchor_value_raw": "15/24",
"resolver_confidence": "medium",
"mcp_call_status": "skipped",
"rows_fetched": 0,
"raw_rows_received": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "DEEP_ONLY",
"limited_reason_category": "unsupported",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "Этот запрос не подходит под address_query V1.\nПричина: intent пока не поддержан в address V1.\nЧто нужно уточнить: переформулируйте вопрос как адресный lookup по счету/контрагенту/договору."
}
@@ -0,0 +1,33 @@
{
"id": "Q8",
"question": "who owes us and who we owe today",
"expected_intent": "list_receivables_counterparties",
"http_status": 200,
"ok": true,
"detected_mode": "address_query",
"query_shape": "COMPOUND_FACTUAL_QUERY",
"detected_intent": "list_receivables_counterparties",
"selected_recipe": "address_movements_receivables_v1",
"extracted_filters": {
"sort": "period_desc",
"limit": 20,
"as_of_date": "2026-03-29"
},
"missing_required_filters": [
],
"anchor_type": "unknown",
"anchor_value_raw": null,
"resolver_confidence": "low",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON",
"reply_type": "partial_coverage",
"assistant_reply_preview": "В live-данных по текущему фильтру записи не найдены.\nПричина: по выбранным фильтрам в live-выборке нет строк.\nЧто нужно уточнить: уточните период, контрагента, договор или снимите часть фильтров."
}
@@ -0,0 +1,122 @@
[
{
"case_id": "Q1",
"question": "which documents form balance for account 62 as of 2020-07-31",
"detected_intent": "documents_forming_balance",
"selected_recipe": "address_documents_forming_balance_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON"
},
{
"case_id": "Q2",
"question": "reveal balance documents for account 60",
"detected_intent": "documents_forming_balance",
"selected_recipe": "address_documents_forming_balance_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON"
},
{
"case_id": "Q3",
"question": "show documents by counterparty Alfa from 2020-07-01 to 2020-07-31",
"detected_intent": "list_documents_by_counterparty",
"selected_recipe": "address_documents_by_counterparty_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON"
},
{
"case_id": "Q4",
"question": "show bank operations by counterparty Alfa from 2020-07-01 to 2020-07-31",
"detected_intent": "bank_operations_by_counterparty",
"selected_recipe": "address_bank_operations_by_counterparty_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON"
},
{
"case_id": "Q5",
"question": "show account balance 60 today",
"detected_intent": "account_balance_snapshot",
"selected_recipe": "address_movements_account_snapshot_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON"
},
{
"case_id": "Q6",
"question": "show open items by contract",
"detected_intent": "open_items_by_counterparty_or_contract",
"selected_recipe": null,
"mcp_call_status": "skipped",
"rows_fetched": 0,
"raw_rows_received": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "missing_anchor",
"response_type": "LIMITED_WITH_REASON"
},
{
"case_id": "Q7",
"question": "show documents by contract 15/24",
"detected_intent": "unknown",
"selected_recipe": null,
"mcp_call_status": "skipped",
"rows_fetched": 0,
"raw_rows_received": 0,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "DEEP_ONLY",
"limited_reason_category": "unsupported",
"response_type": "LIMITED_WITH_REASON"
},
{
"case_id": "Q8",
"question": "who owes us and who we owe today",
"detected_intent": "list_receivables_counterparties",
"selected_recipe": "address_movements_receivables_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"raw_rows_received": 20,
"rows_materialized": 0,
"rows_after_recipe_filter": 0,
"rows_matched": 0,
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
"limited_reason_category": "empty_match",
"response_type": "LIMITED_WITH_REASON"
}
]
@@ -0,0 +1,44 @@
{
"run_id": "2026-03-29_Address_Query_Runtime_V1_M2_3_DocumentsFormingBalance_DataAwareAcceptance",
"date": "2026-03-29",
"stage": "address_query_runtime_v1",
"scope": "m2_3_documents_forming_balance_plus_data_aware_acceptance_sync",
"build_status": "PASSED",
"tests_status": "PASSED",
"dry_run_status": "PASSED_WITH_LIMITED_RESULTS",
"implemented": {
"intent_documents_forming_balance": true,
"recipe_documents_forming_balance_v1": true,
"required_filters_account_as_of_for_balance_intents": true,
"as_of_defaulting_for_balance_intents": true,
"resolver_debug_block": true,
"row_stage_debug_block": true,
"docs_sync_data_aware_policy": true
},
"dry_run_metrics": {
"questions_total": 8,
"address_mode_hit_rate": 1.0,
"query_shape_detected_rate": 1.0,
"intent_alignment_rate": 1.0,
"supported_recipe_selection_rate": 0.75,
"factual_positive_rate": 0.0,
"limited_mode_rate": 1.0,
"false_factual_rate": 0.0,
"anchor_debug_coverage_rate": 1.0,
"row_stage_debug_coverage_rate": 1.0
},
"limited_reason_distribution": {
"empty_match": 6,
"missing_anchor": 1,
"unsupported": 1,
"recipe_visibility_gap": 0,
"execution_error": 0
},
"data_aware_acceptance_status": {
"suite_defined": true,
"exploratory_live_pass_completed": false,
"known_positive_non_empty_rate": 0.0,
"status": "prepared_for_next_live_iteration"
},
"next_priority": "Run exploratory live pass and curate non-empty data-aware positive acceptance cases"
}
@@ -0,0 +1,36 @@
# Smoke Checks
Дата: 2026-03-29
## Build
- `npm.cmd run build` -> PASS
## Tests
- `npx.cmd vitest run tests/addressQueryRuntimeM23.test.ts` -> PASS (10/10)
## Dry-run (assistant window equivalent)
Источник: `assistant_window_dry_run_results.json`
- total questions: 8
- `detected_mode=address_query`: 8/8
- `query_shape` detected: 8/8
- expected intent alignment: 8/8
- `selected_recipe` present: 6/8
- `response_type=LIMITED_WITH_REASON`: 8/8
- `false_factual_rate`: 0
- `anchor_debug_coverage_rate`: 1.0
- `row_stage_debug_coverage_rate`: 1.0
### Limited taxonomy distribution
- `empty_match`: 6
- `missing_anchor`: 1
- `unsupported`: 1
- `recipe_visibility_gap`: 0
- `execution_error`: 0
### Operational note
`documents_forming_balance` routing is now implemented and stable by intent/recipe.
The next hard gate remains data-aware positive live pass (non-empty factual evidence).
@@ -0,0 +1,51 @@
# Address Query Runtime V1 — M2+ (Open Contracts / Open Items)
Дата: 2026-03-29
Статус: IMPLEMENTED_WITH_LIMITED_MODE
## Что расширено
1. Расширены P0 intent/recipe маршруты:
- `list_open_contracts`
- `open_items_by_counterparty_or_contract`
2. Расширен recipe-catalog:
- единый movement-query с period filters (`as_of_date`, `period_from`, `period_to`)
- account scopes для family-веток:
- receivables: `62/76`
- payables: `60/76`
- open contracts/open items: `60/62/76`
3. Усилен intent/filter слой:
- intent resolver переписан на token-based (более стабильно для коротких формулировок);
- filter extractor поддерживает `by contract` / `by counterparty` и русские варианты.
4. Усилен answer contract:
- для `open_items` обязателен anchor (`counterparty` или `contract`), иначе controlled limited mode;
- для `open_contracts` при отсутствии явных договорных аналитик в live-строках возвращается честный limited mode;
- false factual не генерируется.
## Что подтверждено smoke-проверкой
- Address lane срабатывает через `AssistantService` ранней веткой (без normalizer вызова).
- Новые intents распознаются и маршрутизируются в recipe path.
- При отсутствии релевантных live-строк система остается в `LIMITED_WITH_REASON` с конкретной причиной.
## Параллельно добавлено для следующего этапа
- Набор вопросов для dry-run через окно ассистента:
- `docs/ADDRESS/address_query/ui_dry_run_question_set_v1.md`
- Чек-лист проверки:
- `docs/ADDRESS/address_query/ui_dry_run_checklist_v1.md`
- Результаты dry-run набора (5 вопросов):
- `assistant_window_dry_run_results.json`
## Ограничения текущего шага
- MCP текущего рецепта не возвращает явные договорные аналитики в достаточном объеме для устойчивого `FACTUAL_LIST` по open contracts.
- Поэтому `list_open_contracts` и часть `open_items` работают в honest-limited режиме, что соответствует safety policy.
## Следующий шаг
- Добавить специализированные live recipes на уровне документов/регистров (контрагент/договор) вместо только movement-среза,
чтобы перевести `open_contracts` и `open_items` из `LIMITED_WITH_REASON` в стабильный factual mode на positive-cases.
@@ -0,0 +1,57 @@
[
{
"query": "кто должен нам на сегодня",
"expected_intent": "list_receivables_counterparties",
"detected_mode": "address_query",
"detected_intent": "list_receivables_counterparties",
"selected_recipe": "address_movements_receivables_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"rows_matched": 0,
"response_type": "LIMITED_WITH_REASON"
},
{
"query": "кому должны мы на сегодня",
"expected_intent": "list_payables_counterparties",
"detected_mode": "address_query",
"detected_intent": "list_payables_counterparties",
"selected_recipe": "address_movements_payables_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"rows_matched": 0,
"response_type": "LIMITED_WITH_REASON"
},
{
"query": "покажи остаток по счету 60 на сегодня",
"expected_intent": "account_balance_snapshot",
"detected_mode": "address_query",
"detected_intent": "account_balance_snapshot",
"selected_recipe": "address_movements_account_snapshot_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"rows_matched": 0,
"response_type": "LIMITED_WITH_REASON"
},
{
"query": "какие договоры не закрыты",
"expected_intent": "list_open_contracts",
"detected_mode": "address_query",
"detected_intent": "list_open_contracts",
"selected_recipe": "address_open_contracts_candidates_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"rows_matched": 0,
"response_type": "LIMITED_WITH_REASON"
},
{
"query": "покажи открытые позиции по договору 01/19-ПТ",
"expected_intent": "open_items_by_counterparty_or_contract",
"detected_mode": "address_query",
"detected_intent": "open_items_by_counterparty_or_contract",
"selected_recipe": "address_open_items_by_party_or_contract_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"rows_matched": 0,
"response_type": "LIMITED_WITH_REASON"
}
]
@@ -0,0 +1,4 @@
llm_normalizer/backend/src/services/addressIntentResolver.ts
llm_normalizer/backend/src/services/addressRecipeCatalog.ts
llm_normalizer/backend/src/services/addressQueryService.ts
llm_normalizer/backend/src/services/addressFilterExtractor.ts
@@ -0,0 +1,28 @@
{
"run_id": "2026-03-29_Address_Query_Runtime_V1_M2_Plus_OpenContracts_OpenItems",
"date": "2026-03-29",
"stage": "address_query_runtime_v1",
"scope": "m2_plus_intent_recipe_expansion",
"build_status": "PASSED",
"smoke_status": "PASSED",
"ui_dry_run_status": "PASSED_INTENT_ROUTING",
"implemented": {
"intent_open_contracts": true,
"intent_open_items_by_counterparty_or_contract": true,
"period_filterable_query_recipe": true,
"token_based_intent_resolution": true
},
"current_answer_mode": {
"receivables_payables_account_snapshot": "operational (may be limited on empty matches)",
"open_contracts": "honest_limited_when_no_contract_anchors",
"open_items": "honest_limited_without_anchor_or_no_rows"
},
"ui_dry_run_5q": {
"mode_routing_pass_rate": 1.0,
"intent_alignment_pass_rate": 1.0,
"selected_recipe_non_empty_rate": 1.0,
"factual_positive_rate": 0.0,
"limited_mode_rate": 1.0
},
"false_factual_rate": 0
}
@@ -0,0 +1,49 @@
# Smoke Checks
Дата: 2026-03-29
## Build
- `npm run build` -> PASS
## Address service checks (dist)
1. `who owes us today`
- detected_intent: `list_receivables_counterparties`
- selected_recipe: `address_movements_receivables_v1`
- result: `LIMITED_WITH_REASON` (mcp_call_status=`empty`)
2. `who we owe today`
- detected_intent: `list_payables_counterparties`
- selected_recipe: `address_movements_payables_v1`
- result: `LIMITED_WITH_REASON` (mcp_call_status=`empty`)
3. `show account balance 60`
- detected_intent: `account_balance_snapshot`
- selected_recipe: `address_movements_account_snapshot_v1`
- result: `LIMITED_WITH_REASON` (mcp_call_status=`empty`)
4. `list open contracts`
- detected_intent: `list_open_contracts`
- selected_recipe: `address_open_contracts_candidates_v1`
- result: `LIMITED_WITH_REASON` (`no_contract_anchors_in_live_rows`)
5. `open items by contract 01/19-PT`
- detected_intent: `open_items_by_counterparty_or_contract`
- selected_recipe: `address_open_items_by_party_or_contract_v1`
- result: `LIMITED_WITH_REASON` (mcp_call_status=`empty`)
## AssistantService early-lane checks
`AssistantService.handleMessage(...)` с normalizer stub:
- для address запросов идет в `assistant_message_address` event;
- deep normalizer path не вызывается.
## UI dry-run через окно ассистента (RU set)
- Прогнан набор из 5 русскоязычных вопросов из `docs/ADDRESS/address_query/ui_dry_run_question_set_v1.md`.
- Результаты сохранены в `assistant_window_dry_run_results.json`.
- Все 5 кейсов:
- `detected_mode=address_query`;
- `detected_intent` совпал с `expected_intent`;
- `selected_recipe` не пустой.
- Текущий answer mode: `LIMITED_WITH_REASON` по причине `mcp_call_status=empty` (matched rows = 0).
@@ -0,0 +1,27 @@
# Address Query UI Dry Run Readiness Check
Дата: 2026-03-29
## Проверка доступности
- Backend health: `http://127.0.0.1:8787/api/health` -> RUNNING
- MCP execute endpoint: `http://127.0.0.1:6003/api/execute_query?channel=default` -> отвечает
## Реальный dry-call через assistant endpoint
Запрос:
- `who owes us today`
Результат:
- `detected_mode=address_query`
- `detected_intent=list_receivables_counterparties`
- `selected_recipe=address_movements_receivables_v1`
- `mcp_call_status=empty`
- `rows_fetched=20`
- `rows_matched=0`
- `response_type=LIMITED_WITH_REASON`
## Вывод
Сухой тест через окно ассистента уже возможен (address lane активен и отвечает через MCP).
Ограничительный ответ на этом кейсе обусловлен отсутствием matched rows, а не отсутствием runtime ветки.
@@ -0,0 +1,17 @@
{
"run_id": "2026-03-29_Address_Query_UI_Dry_Run_Readiness_Check",
"date": "2026-03-29",
"backend_health": "RUNNING",
"mcp_endpoint_reachable": true,
"assistant_dry_call": {
"query": "who owes us today",
"detected_mode": "address_query",
"detected_intent": "list_receivables_counterparties",
"selected_recipe": "address_movements_receivables_v1",
"mcp_call_status": "empty",
"rows_fetched": 20,
"rows_matched": 0,
"response_type": "LIMITED_WITH_REASON"
},
"verdict": "UI_DRY_RUN_READY"
}
@@ -0,0 +1,28 @@
# Run: 2026-03-29 Address Runtime Pivot Baseline
Тип прогона: архитектурный baseline-аудит перед реализацией address-lane.
## Цель
Подтвердить фактическое состояние:
1. текущий assistant runtime = snapshot-primary;
2. live MCP = overlay и не для всех маршрутов;
3. Postgres не является активным runtime-слоем в assistant path;
4. требуется отдельный MCP-first lane для address-вопросов.
## Состав артефактов
- `run_summary.json`
- `postgres_runtime_check.json`
- `source_inventory.json`
- `code_path_inventory.md`
## Краткий результат
Статус: `BASELINE_CONFIRMED`.
Ключевой вывод:
- технически проще и быстрее добавить отдельный `address_query` lane поверх текущего Stage 4, чем пытаться продолжать расширять snapshot-first path под новый класс задач.
@@ -0,0 +1,20 @@
# Architecture Findings
## Confirmed
1. Current assistant execution is snapshot-primary, MCP-secondary.
2. Large full snapshots exist, but assistant reads only narrow export samples.
3. Existing claim-bound live path was designed for deep accounting families (VAT/RBP/FA), not address lookup UX.
4. Canonical store DB layer is present (SQLite now, Postgres optional), but not part of active assistant runtime retrieval path.
## Decision for next implementation wave
1. Keep Stage 4 deep-chain flow unchanged.
2. Add `address_query` lane with MCP-first source policy.
3. Define explicit address intents, recipes, and response contract.
4. Keep snapshot fallback explicit and limited (no silent substitution).
## Baseline verdict
`BASELINE_CONFIRMED_FOR_MCP_FIRST_ADDRESS_PIVOT`
@@ -0,0 +1,54 @@
# Code Path Inventory (Address Pivot Baseline)
## A. Assistant runtime data path
1. `llm_normalizer/backend/src/services/assistantDataLayer.ts:2804`
`AssistantDataLayer` uses `ARCH_EXPORT_2020_DIR` root by default.
2. `llm_normalizer/backend/src/services/assistantDataLayer.ts:3379-3386`
Runtime loads fixed sample files from `docs/ARCH/2020экспорт` (narrow package).
3. `llm_normalizer/backend/src/services/assistantDataLayer.ts:2858-2863`
MCP overlay is runtime-optional and route-limited.
4. `llm_normalizer/backend/src/services/assistantDataLayer.ts:332`
`buildLiveMcpCallPlan(...)` generates live calls.
5. `llm_normalizer/backend/src/services/assistantDataLayer.ts:348,396,460,444`
Claim-specific live plans exist for FA/VAT/RBP; else `claim_type: null`.
## B. Routing discipline
1. `llm_normalizer/backend/src/services/routeHintAdapter.ts:86-87`
`exact_object_trace -> live_mcp_drilldown`.
2. `llm_normalizer/backend/src/services/routeHintAdapter.ts:149-150`
`canonical_fact_lookup -> store_canonical` (snapshot-oriented path).
## C. MCP runtime config
1. `llm_normalizer/backend/src/config.ts:90-100`
MCP feature flag and defaults:
- `FEATURE_ASSISTANT_MCP_RUNTIME_V1` (default false),
- `ASSISTANT_MCP_PROXY_URL=http://127.0.0.1:6003`,
- `ASSISTANT_MCP_CHANNEL=default`.
2. `llm_normalizer/package.json:11`
`dev:all:mcp` enables MCP flags for local dev.
## D. Canonical layer / DB
1. `.env.example:18` and `README.md:89`
Default canonical DB URL is SQLite.
2. `canonical_layer/store.py:55,59`
SQLAlchemy store supports non-SQLite URLs (including Postgres), but SQLite is default branch.
3. `canonical_layer/app.py:61,82,96,128`
Canonical API exposes read and refresh endpoints (`/documents`, `/postings`, `/counterparties/...`, `/refresh/run`).
## E. Architectural implication
Для Address V1 достаточно внедрить новый `address_query` lane в assistant runtime и сделать его MCP-first.
Это не требует немедленной обязательной миграции в Postgres, но требует разведения route/intents и отдельного answer contract.
@@ -0,0 +1,20 @@
{
"dataset": "docs/ARCH/2020_monthly_company_asof_full/_tmp_ndjson",
"total_files": 12,
"total_mb": 6732,
"files": [
{ "name": "snapshot_2020-01.ndjson", "mb": 553.16 },
{ "name": "snapshot_2020-02.ndjson", "mb": 554.27 },
{ "name": "snapshot_2020-03.ndjson", "mb": 556.83 },
{ "name": "snapshot_2020-04.ndjson", "mb": 557.63 },
{ "name": "snapshot_2020-05.ndjson", "mb": 558.38 },
{ "name": "snapshot_2020-06.ndjson", "mb": 561.38 },
{ "name": "snapshot_2020-07.ndjson", "mb": 562.26 },
{ "name": "snapshot_2020-08.ndjson", "mb": 563.23 },
{ "name": "snapshot_2020-09.ndjson", "mb": 564.69 },
{ "name": "snapshot_2020-10.ndjson", "mb": 565.01 },
{ "name": "snapshot_2020-11.ndjson", "mb": 566.03 },
{ "name": "snapshot_2020-12.ndjson", "mb": 569.14 }
]
}
@@ -0,0 +1,16 @@
{
"check_date": "2026-03-29",
"postgres_process_detected": false,
"canonical_db_url_in_env_example": "sqlite:///X:/1C/NDC_1C/data/canonical_store.db",
"canonical_store_sqlite_file": {
"path": "X:/1C/NDC_1C/data/canonical_store.db",
"exists": true,
"size_bytes": 6594560
},
"assistant_runtime_direct_db_dependency_detected": false,
"notes": [
"Postgres is currently optional in canonical layer design, not mandatory in assistant runtime path.",
"Assistant runtime uses snapshot files and optional MCP overlay; it is not wired to canonical store reads."
]
}
@@ -0,0 +1,24 @@
{
"run_id": "2026-03-29_Address_Runtime_Pivot_Baseline",
"date_utc": "2026-03-29",
"scope": "architecture_audit_for_mcp_first_address_queries",
"source_of_truth": [
"llm_normalizer/backend/src/services/assistantDataLayer.ts",
"llm_normalizer/backend/src/services/routeHintAdapter.ts",
"llm_normalizer/backend/src/config.ts",
"canonical_layer/store.py",
"canonical_layer/app.py",
".env.example",
"README.md"
],
"key_findings": [
"assistant runtime currently loads a narrow snapshot package (2020export) as primary source",
"live MCP is optional (feature-flagged) and route-limited overlay",
"current claim-bound live plan is focused on VAT/RBP/FA and does not define address-query intents",
"canonical layer supports SQLAlchemy db_url, but assistant runtime does not directly use canonical store",
"sqlite canonical store file exists, postgres process was not detected"
],
"verdict": "MCP_INFRA_EXISTS_BUT_ADDRESS_RUNTIME_NOT_IMPLEMENTED",
"next_status_target": "ADDRESS_RUNTIME_V1_READY"
}
@@ -0,0 +1,31 @@
{
"snapshot_primary_runtime_package": {
"path": "X:/1C/NDC_1C/docs/ARCH/2020экспорт",
"files_total": 10,
"total_bytes": 1913578,
"total_mb": 1.82,
"files": [
"03_snapshot_fragment_problem_cases.json",
"04_samples_SpisanieSRaschetnogoScheta.json",
"05_samples_RealizaciyaTovarovUslug.json",
"06_samples_PostuplenieTovarovUslug.json",
"07_samples_DocumentJournals.json",
"08_samples_NDS_registers.json",
"09_samples_key_fields_Recorder_Ref_Supplier_Buyer_Responsible.json"
]
},
"full_monthly_snapshot_corpus": {
"path": "X:/1C/NDC_1C/docs/ARCH/2020_monthly_company_asof_full/_tmp_ndjson",
"files_total": 12,
"total_bytes": 7059009054,
"total_mb": 6732,
"average_file_mb": 561
},
"live_mcp_channel_defaults": {
"proxy_url_default": "http://127.0.0.1:6003",
"channel_default": "default",
"feature_flag_default": false
},
"conclusion": "large_gap_between_available_snapshot_volume_and_runtime_loaded_snapshot_volume_confirmed"
}