АДРЕСНЫЙ РЕЖИМ - 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,701 @@
TZ_address_query_runtime_V1_MCP.md
## Project Sync Override (2026-03-29)
Этот документ используется в связке с:
- `docs/ADDRESS/tz/TZ_address_query_runtime_V1_MCP_SYNC_2026-03-29.md`
Критичная фиксация для текущего проекта:
- мобильный интерфейс **не входит** в scope реализации;
- диалог ведется через существующую оболочку ассистента;
- поддерживаются короткие разговорные формулировки, но без отдельной mobile UI ветки.
## Контекст
По проекту уже подготовлен bootstrap-пакет в `docs/ADDRESS`:
* карта сущностей по snapshot 2020;
* матрица address-сценариев;
* каталог фильтров и recipe draft;
* план интеграции `question_mode=address_query`;
* сводный bootstrap report.
Этот пакет считается baseline и **не переписывается с нуля**.
Новая задача — перейти от проектного пакета к **реальному внедрению runtime-слоя**.
---
## Ключевая архитектурная идея
Нужно реализовать **не изолированный address-остров**, а **общий semantic/query foundation layer**, который включает:
1. каталог сущностей;
2. каталог фильтров;
3. нормализацию пользовательских названий;
4. resolver’ы name -> id / alias -> canonical entity;
5. whitelist query recipes;
6. общий result contract.
На первом этапе этот foundation layer используется для `question_mode=address_query`.
В будущем этот же слой должен быть пригоден для:
* deep-analysis маршрутов,
* controlled drilldown,
* guided factual reasoning поверх live/MCP.
---
## Главная цель этапа
Реализовать V1 отдельного runtime-контура для быстрых адресных вопросов к 1С через MCP, при этом:
* **не ломать** существующий deep-analysis pipeline;
* **не дублировать** сущностную модель в двух местах;
* **не открывать** свободный natural-language query builder;
* дать пользователю в текущей оболочке ассистента возможность задавать короткие поисковые вопросы типа:
* “кто должен нам на сегодня”
* “покажи хвосты по альфе”
* “найди платежи по договору такому-то”
* “проверь, какие документы формируют остаток”
* “по 60 счету что висит на текущую дату”
---
## Что уже считать входными материалами
Перед началом реализации использовать как source of truth следующие документы из `docs/ADDRESS/address_query/`:
* `entity_map_1c_2020.md`
* `address_scenario_matrix.md`
* `query_recipes_v1.md`
* `runtime_integration_plan.md`
* `address_query_bootstrap_report_2026-03-29.md`
Нужно опираться на них, а не проектировать заново поверх пустого места.
---
# 1. Что нужно реализовать
## 1.1. Общий semantic/query foundation layer
Нужно ввести общий слой, который станет основой для address-runtime.
### В состав foundation layer должны войти:
#### A. Entity Registry
Единый реестр сущностей, доступных для запроса.
Для каждой сущности:
* `entity_family`
* `entity_name`
* `business_label`
* `description`
* `priority`
* `query_suitability`
* `key_fields`
* `filterable_fields`
* `relations`
* `readiness`
* `source_origin`
#### B. Alias / Label Normalization Layer
Нужно предусмотреть слой нормализации пользовательских названий.
Например:
* “контрагент”
* “договор”
* “60 счет”
* “реализация”
* “платежка”
* “банковская выписка”
* “хвосты”
* “долг”
* “дебиторка”
* “кредиторка”
Должны приводиться к каноническим сущностям / filter tokens / intents.
Отдельно учесть:
* декодирование mojibake-labels из snapshot mapping;
* синонимы;
* бухгалтерские разговорные формулировки;
* краткие разговорные запросы без строгой терминологии.
#### C. Resolver Layer
Нужны resolver’ы, которые переводят слова пользователя в реальные объекты.
Минимально:
* `counterpartyResolver`
* `contractResolver`
* `organizationResolver`
* `accountResolver`
* `documentTypeResolver`
* `bankAccountResolver`
Выход:
* `resolved_value`
* `resolved_id/ref`
* `confidence`
* `ambiguous_candidates[]`
#### D. Filter Catalog
Единый каталог поддерживаемых фильтров.
Минимум:
* `as_of_date`
* `period_from`
* `period_to`
* `organization`
* `counterparty`
* `contract`
* `account`
* `document_type`
* `document_ref`
* `bank_account`
* `posted`
* `status`
* `limit`
* `sort`
#### E. Recipe Catalog
Только whitelist recipes.
Для каждого recipe:
* `recipe_id`
* `intent`
* `purpose`
* `required_filters`
* `optional_filters`
* `resolver_dependencies`
* `result_schema`
* `sort_rules`
* `limit_rules`
* `drilldown_targets`
* `mcp_template_id`
#### F. Unified Result Contract
Единый контракт ответа:
* `FACTUAL_LIST`
* `FACTUAL_SUMMARY`
* `LIMITED_WITH_REASON`
---
# 2. Что нужно реализовать в runtime
## 2.1. Отдельный `question_mode=address_query`
В текущий assistant pipeline добавить ранний mode-routing:
* `address_query`
* `deep_analysis`
* `unsupported`
### Правило
Если вопрос относится к поисковому factual lookup, он должен идти в `address_query`.
Если вопрос требует объяснения причин, доказательства, анализа ошибок учета или длинного reasoning — он должен уходить в deep-path.
---
## 2.2. Address intent resolver
Нужно реализовать определение address-intent.
### P0 intents
* `list_open_contracts`
* `list_payables_counterparties`
* `list_receivables_counterparties`
* `account_balance_snapshot`
* `open_items_by_counterparty_or_contract`
### P1 intents
* `list_documents_by_counterparty`
* `list_documents_by_contract`
* `documents_forming_balance`
* `bank_operations_by_counterparty`
* `bank_operations_by_contract`
* `documents_by_period`
* `account_turnover_snapshot`
* `document_lookup_by_number_or_date`
---
## 2.3. Multi-query decomposition
Нужно учитывать, что пользователь может писать составные запросы в свободной разговорной форме.
Примеры:
* “покажи хвосты по альфе и отдельно по бете”
* “найди долг по договору 15 и покажи документы”
* “что по 60 счету и какие контрагенты там висят”
* “проверь оплаты за март и какие из них без договора”
* “по поставщикам кто должен и что формирует остаток”
Нужен `addressQueryDecomposer`, который умеет:
1. определить, что вопрос составной;
2. разбить его на подзапросы;
3. проверить, что все части остаются в factual-search зоне;
4. выполнить их последовательно;
5. склеить ответ в один компактный output.
Для V1 достаточно baseline-режима:
* максимум 2 подзапроса;
* без сложной межподзапросной оркестрации;
* без скрытого перехода в reasoning-chain.
Расширенная decomposition-логика фиксируется как V1.1.
### Важно
Если составной вопрос требует уже reasoning-связки, а не просто нескольких factual lookup, нужно:
* либо честно ограничить ответ;
* либо переводить его в deep-path с явной пометкой.
---
## 2.4. Filter extraction + validation
Нужно выделять:
* явные фильтры;
* подразумеваемые фильтры;
* отсутствующие обязательные фильтры.
Например:
* “кто должен нам” -> нужен `as_of_date`, можно подставить `today` по умолчанию;
* “остаток по 60 за март” -> `account=60`, `period_from`, `period_to`;
* “документы по альфе” -> нужен resolver контрагента;
* “покажи хвосты” -> недостаточно фильтров, нужен scope.
---
## 2.5. MCP execution layer
Нужен выделенный `addressMcpExecutor`.
### Правила:
* только whitelist recipes;
* read-only;
* fixed sorting profiles;
* limit controlled by recipe, а не свободным текстом;
* live-first;
* snapshot fallback только как explicit controlled mode, не silent.
---
## 2.6. Answer composer под короткий factual-формат оболочки
Нужно сделать composer, ориентированный на компактный factual-ответ в текущей оболочке ассистента.
### Формат ответа должен уметь:
#### A. Короткий итог
Например:
* “На сегодня найдено 12 контрагентов с дебиторкой, общий объем 1.54 млн ₽.”
* “По договору найдено 7 открытых позиций на 430 тыс. ₽.”
#### B. Список top-строк
Например:
* контрагент
* сумма
* число документов
#### C. Что можно уточнить дальше
Например:
* “Можно показать документы по каждому контрагенту.”
* “Можно раскрыть остаток по документам.”
* “Можно отфильтровать по организации или периоду.”
#### D. Honest limitation
Если фильтров не хватает:
* “Недостаточно данных для точного поиска: не указан контрагент / договор / счет.”
* “Найдено несколько договоров с похожим названием, нужно уточнение.”
---
# 3. Важное архитектурное требование
## Не делать “отдельные сущности” только под address-runtime
Вместо этого нужно:
* создать **единый semantic layer**;
* использовать его первым потребителем в `address_query`;
* оставить возможность потом подключить deep-path к тем же registry/resolver/filter primitives.
Иными словами:
**address-query — это первый runtime-потребитель общего semantic/query слоя, а не отдельная параллельная модель мира.**
---
# 4. Список пользовательских вопросов, который нужно заложить в проект
Нужно не просто реализовать intents, а подготовить **question bank**.
Создать отдельный файл, например:
* `docs/ADDRESS/address_query/question_bank_v1.md`
В нем нужно разложить реальные пользовательские формулировки.
---
## 4.1. Группа A — задолженность и хвосты
Примеры:
* кто должен нам на сегодня
* кому должны мы на сегодня
* какие хвосты висят
* покажи хвосты по контрагентам
* покажи хвосты по договору
* какие незакрытые позиции по альфе
* где висит дебиторка
* где висит кредиторка
* по каким контрагентам есть долг
* по каким договорам есть незакрытые расчеты
* какие открытые взаиморасчеты на текущую дату
* у кого самый большой долг перед нами
* кому больше всего должны мы
---
## 4.2. Группа B — счета и остатки
Примеры:
* какой остаток по 60 счету
* какой остаток по 62 на дату
* покажи остаток по счету 76
* что висит на 60 счете
* что висит на 62 счете
* какие контрагенты формируют остаток по 60
* какие документы формируют остаток по 62
* оборот по 60 за март
* оборот по 62 за период
* по какому договору висит остаток на счете 60
---
## 4.3. Группа C — договоры
Примеры:
* какие договоры не закрыты
* покажи незакрытые договоры
* что по договору 15/24
* какие хвосты по договору номер 15
* есть ли долг по договору с альфой
* покажи открытые позиции по договору
* какие документы связаны с этим договором
* какие платежи были по договору
* что осталось незакрытым по договору
---
## 4.4. Группа D — документы
Примеры:
* найди документы по контрагенту альфа
* покажи документы по договору
* покажи платежки по альфе
* найди реализации за март
* найди поступления за февраль
* покажи списания с расчетного счета по контрагенту
* покажи поступления на расчетный счет по договору
* найди документ по номеру
* какие документы были 15 марта
* покажи последние документы по поставщику
* покажи неоплаченные документы
* покажи проведенные документы по организации
---
## 4.5. Группа E — bank / payment lookup
Примеры:
* какие платежи были по альфе
* какие списания были по договору
* были ли поступления от беты
* покажи банковские операции за неделю
* какие платежи ушли без договора
* какие поступления пришли по этому контрагенту
* найди оплату на сумму 150 тысяч
* покажи платежи по статье ддс
---
## 4.6. Группа F — drilldown от агрегата к деталям
Примеры:
* кто должен нам и какие документы это формируют
* что висит по альфе и покажи документы
* по 60 счету что висит и раскрой по документам
* покажи остаток по договору и документы под ним
* найди дебиторку и раскрой по договорам
* покажи кредиторку и раскрой по контрагентам
---
## 4.7. Группа G — составные поисковые вопросы
Примеры:
* покажи хвосты по альфе и бете
* найди долг по договору и покажи документы
* кто должен нам и отдельно кому должны мы
* покажи остаток по 60 и кто его формирует
* найди платежи по альфе за март и отдельно поступления от нее
* покажи незакрытые договоры и по каждому сумму хвоста
* по контрагенту альфа покажи долг, договоры и последние документы
---
## 4.8. Группа H — check / verify формулировки, но still factual
Нужно предусмотреть вопросы вида “проверь”, если они остаются в lookup-логике.
Примеры:
* проверь, есть ли долг по альфе
* проверь, есть ли незакрытые документы
* проверь, были ли платежи в марте
* проверь, что висит на 60 счете
* проверь, есть ли оплаты по договору
* проверь, какие документы формируют остаток
### Важно
Если “проверь” означает именно factual lookup — это address.
Если “проверь, правильно ли…” — это уже не address, а deeper reasoning.
---
# 5. Что нужно реализовать в коде
## 5.1. Новые/обновляемые модули
Ожидаемый набор:
* `addressQueryService.ts`
* `addressModeClassifier.ts`
* `addressIntentResolver.ts`
* `addressQueryDecomposer.ts`
* `addressFilterExtractor.ts`
* `addressFilterValidator.ts`
* `addressRecipeCatalog.ts`
* `addressRecipeSelector.ts`
* `addressMcpExecutor.ts`
* `addressResultMaterializer.ts`
* `addressAnswerComposer.ts`
### Shared foundation
* `semanticEntityRegistry.ts`
* `semanticAliasMap.ts`
* `semanticResolvers/`
* `semanticFilterCatalog.ts`
---
## 5.2. Нормализованный debug contract
Минимальный debug payload:
* `question_mode`
* `address_intent`
* `is_compound_query`
* `subqueries_count`
* `resolved_entities`
* `resolved_filters`
* `missing_filters`
* `selected_recipe_ids`
* `mcp_call_status`
* `rows_fetched`
* `response_type`
* `fallback_reason`
---
## 5.3. Тесты
Нужны тесты не только на intent, но и на разбор живых пользовательских формулировок.
### Минимум:
* 20 single-query tests
* 15 filter extraction tests
* 10 resolver ambiguity tests
* 10 compound-query decomposition tests
* 10 composer response tests
* 5 negative tests на unsafe/free-form query behavior
---
# 6. Что нужно создать в docs
Нужно дополнить пакет следующими файлами:
* `question_bank_v1.md`
* `semantic_layer_design.md`
* `address_runtime_contracts.md`
* `address_v1_acceptance_pack.md`
---
# 7. Очередность выполнения
## M0 — Contracts and Foundation Skeleton
На базе уже собранных docs оформить и завести в коде минимальные контракты:
* `question_mode` / `address_intent`;
* filter schema;
* recipe schema;
* debug contract;
* P0 foundation skeleton (без поведенческих переключений).
## M1 — Classifier + Intent + Filter Pipeline
Реализовать:
* mode classifier;
* intent resolver для P0;
* filter extraction + validation;
* baseline compound decomposition (как указано в 2.3).
## M2 — Recipe Selection + MCP Executor
Реализовать **recipe selection + MCP executor** для P0 с live-first политикой.
## M3 — Factual Composer + Debug
Реализовать **answer composer** под factual/shell-friendly output и стабилизировать debug payload.
## M4 — Live Acceptance Pack
Сделать **acceptance pack**:
* реальные тестовые вопросы;
* debug traces;
* примерные ответы;
* список ограничений.
---
# 8. Что не входит в V1
Не делать на этом этапе:
* свободный query builder от LLM;
* доказательный бухгалтерский reasoning;
* объяснение причин расхождений;
* поиск ошибок учета;
* автоматическую интерпретацию НДС-логики;
* “универсальный доступ ко всем сущностям” без recipe/guardrails;
* silent fallback между snapshot/live.
---
# 9. Критерии приемки
Задача считается выполненной, если:
### Архитектурно
* `address_query` внедрен как отдельный runtime lane;
* deep-analysis path не деградировал;
* сущностная модель не продублирована в отдельный address-only мир;
* общий semantic/query foundation layer создан.
### Функционально
* P0 intents работают через MCP/live-first;
* resolver’ы умеют базово разруливать контрагентов/договоры/счета;
* составные factual-запросы поддержаны хотя бы в базовом виде;
* ответы укладываются в единый factual contract.
### UX
* короткие разговорные запросы разбираются стабильно;
* при нехватке фильтров система не фантазирует, а честно просит уточнение или возвращает `LIMITED_WITH_REASON`;
* ответ читабелен в текущей оболочке ассистента.
### Безопасность
* только whitelist recipes;
* read-only MCP;
* никакой генерации свободного запроса LLM’ом.
---
# 10. Что должно быть в финальном отчете по задаче
В конце работы нужно явно показать:
1. какие модули добавлены;
2. какие контракты введены;
3. какие P0 и P1 intents реально поддержаны;
4. какие resolver’ы готовы;
5. как обрабатываются составные вопросы;
6. какие ограничения остались;
7. какие следующие шаги нужны для V1.1.
---
# 11. Дополнительное указание
При проектировании ориентироваться не только на “идеальные бухгалтерские формулировки”, но и на реальную разговорную подачу пользователя:
* коротко;
* обрывочно;
* без строгих терминов;
* с бытовыми словами;
* с запросами в стиле “найди”, “проверь”, “что висит”, “что по договору”, “покажи остаток”.
Нужно проектировать слой так, чтобы он был полезен в простом повседневном интерфейсе, а не только в аналитическом desktop-flow.
---
Если нужно, следующим сообщением я могу сразу собрать это в ещё более прикладной вид: **короткий production-prompt для Codex** без объяснений, чтобы его можно было просто вставить в задачу.
@@ -0,0 +1,91 @@
# TZ Sync Note — Address Query Runtime V1 MCP (Project-Aligned)
Дата: 2026-03-29
Источник: `docs/ADDRESS/tz/TZ_address_query_runtime_V1_MCP.md`
Статус: `SYNCED_WITH_PROJECT_ARCHITECTURE`
## 1) Что синхронизировано без изменений
Эти части полностью совпадают с нашим курсом и сохраняются:
- отдельный runtime-режим `question_mode=address_query`;
- MCP/live-first для address lane;
- whitelist recipe-модель (`intent -> filters -> recipe -> MCP -> factual result`);
- запрет free-form query generation от LLM;
- явный fallback и честный `LIMITED_WITH_REASON`;
- сохранение existing deep-analysis path без ломки.
## 2) Что скорректировано под реальный проект
### 2.1 Mobile interface — исключен из scope
В исходном ТЗ есть акцент на “телефонный интерфейс/мобильный UX”.
В проекте фиксируем:
- **мобильный интерфейс не реализуем**;
- **единый канал взаимодействия — текущая оболочка ассистента** (наш existing dialogue shell);
- поддерживаем короткие, разговорные и обрывочные формулировки как NL-вход, но без отдельной mobile UI ветки.
### 2.2 Compound decomposition — не blocker для V1 core
`addressQueryDecomposer` оставляем как важную capability, но:
- для V1 core делаем базовую поддержку составных factual-запросов;
- advanced decomposition (многосвязная склейка и сложный orchestration) переносим в V1.1.
### 2.3 Foundation layer — вводим поэтапно, без big-bang
Семантический слой (registry/aliases/resolvers/filter catalog) внедряем итеративно:
- сначала минимальный P0 registry + resolver subset;
- затем расширение на P1 intents.
Никакого “одним большим неразмеченным рефактором”.
### 2.4 Acceptance — staged
Стадии приемки:
- `M0` contracts ready;
- `M1` classifier+intent+filters;
- `M2` MCP executor + P0 recipes;
- `M3` factual composer + debug;
- `M4` live acceptance run.
## 3) Синхронизированный scope V1
### In scope (V1)
- mode-classifier (`address_query` / `deep_analysis` / `unsupported`);
- P0 intents;
- filter extraction + validation;
- resolver subset: counterparty/contract/account/document_type/organization;
- recipe whitelist;
- MCP live-first execution;
- factual answer contract;
- debug contract for address lane;
- acceptance pack в `docs/ADDRESS/runs/...`.
### Out of scope (V1)
- mobile UI/mobile-specific rendering;
- full proof reasoning;
- universal free-form access ко всем сущностям;
- deep-path redesign;
- advanced compound orchestration beyond baseline.
## 4) Runtime compatibility points (код-база)
Синк с текущей архитектурой:
- early mode branching в `assistantService.ts`;
- classifier/routing integration рядом с `routeHintAdapter.ts`;
- отдельный `addressQueryService.ts` и специализированные address-модули;
- текущий deep chain (claim-bound/evidence/admissibility/eligibility) не трогаем как default path.
## 5) Вердикт синка
`TZ_V1_MCP_IS_VALID_AFTER_PROJECT_SYNC`
Главная поправка: **убрать мобильный интерфейс из требований реализации и оставить только поддержку коротких разговорных формулировок в существующей оболочке.**
@@ -0,0 +1,397 @@
рекомендации после первых двух этапов.md
## Что видно по текущему состоянию
Не похоже, что у вас основная проблема в том, что “ассистент не понимает вопрос”.
По текущим run-артефактам картина такая:
* `address lane` **включается корректно**;
* ранняя ветка в `AssistantService` **срабатывает правильно**;
* `intent resolver` после перевода на token-based стал **стабильнее**;
* `false factual rate = 0` — это хорошо.
Но дальше почти все упирается в другое:
* `mcp_call_status=empty`, либо
* `no_contract_anchors_in_live_rows`, либо
* controlled `LIMITED_WITH_REASON`.
То есть **верхний слой уже более-менее жив**, а основной потолок сейчас — это **небогатый live-result на уровне рецептов и materialization**.
---
## Глобальный вывод
Сейчас у вас смешались **два разных понятия готовности**:
### 1. “Сущность видна в snapshot”
Это значит:
* она существует в 2020 corpus;
* у нее есть поля;
* есть связи;
* она красиво выглядит в entity map.
### 2. “По этой сущности можно стабильно отвечать в runtime через текущий live recipe”
Это уже совсем другое:
* есть нужные якоря в live-строках;
* эти якоря доезжают до MCP-ответа;
* по ним можно собрать уверенный factual answer.
И вот по артефактам видно, что у вас **эти две вещи пока переоценены как будто они одинаковые**.
А они не одинаковые.
---
## Самый важный сигнал из ваших документов
В inventory у вас формально много P0-сущностей, но по факту:
* для `account_balances` опора есть;
* для `counterparties/contracts` картина значительно слабее;
* `open_contracts` и часть `open_items` уже сейчас честно уходят в limited, потому что **в live rows не хватает договорных якорей**.
Это очень хороший симптом с точки зрения честности системы.
Но одновременно это показывает, что:
**entity map сейчас структурно сильнее, чем runtime-ready model.**
---
# Что я бы улучшал уже сейчас
## 1. Развести два уровня readiness
Сейчас у вас полезно ввести не один `priority/readiness`, а два.
### A. Structural readiness
Сущность:
* есть в snapshot;
* понятны поля;
* понятны связи;
* можно проектировать recipes.
### B. Runtime readiness
Сущность:
* реально доступна через текущий MCP/live маршрут;
* по ней есть достаточные якоря;
* можно собрать factual answer без натяжки.
### Практически
Добавьте для каждой сущности и/или сценария отдельный статус:
* `STRUCTURALLY_VISIBLE`
* `LIVE_QUERYABLE`
* `LIVE_QUERYABLE_WITH_LIMITS`
* `REQUIRES_SPECIALIZED_RECIPE`
* `DEEP_ONLY`
Это сразу уберет ложное ощущение, что “раз сущность в P0, значит можно уже уверенно спрашивать”.
---
## 2. Перестать пытаться вытащить `open_contracts` из одного movement-среза
Вот это сейчас, по-моему, ключевой архитектурный затык.
Для:
* `list_open_contracts`
* `open_items_by_contract`
* часть `open_items_by_counterparty_or_contract`
движений из `Хозрасчетный` **недостаточно**, если в live строках не приезжает нормальный contract anchor.
### Что делать
Для этих сценариев нужны **специализированные recipes**, а не просто еще одна вариация movement-query.
Минимум отдельные live-рецепты на базе:
* документов поставщиков,
* документов покупателей,
* банковских выписок,
* договорных реквизитов документных линий,
* актов сверки,
* возможно, отдельных регистров взаиморасчетов, если через MCP они доступны лучше, чем бухрегистр.
То есть:
**для balances movement-рецепт ок,
для contracts/open items нужен object-aware recipe.**
---
## 3. Ввести двухшаговый execution вместо одного прямого
Сейчас у вас, судя по артефактам, часто логика такая:
`intent -> recipe -> empty -> LIMITED`
Это честно, но слишком грубо.
Я бы сделал для части сценариев **controlled two-step plan**.
### Пример
Для вопроса:
“какие хвосты по договору X”
не сразу идти в movement summary, а:
#### Шаг 1. Anchor resolution
* найти договор;
* понять контрагента;
* понять связанные документы/тип маршрута.
#### Шаг 2. Focused recipe
* уже по найденному anchor выполнять узкий live query.
Это особенно важно для:
* `by_contract`
* `documents_forming_balance`
* `bank_operations_by_contract`
* `open_items_by_counterparty_or_contract`
---
## 4. Разделить `empty`, `blind`, `missing_anchor`
Сейчас у вас многие ответы схлопываются в один limited-мод.
А на деле это три разных случая:
### A. `EMPTY`
Данные действительно не найдены по фильтру.
### B. `BLIND_RECIPE`
Данные, возможно, есть, но текущий recipe их не видит.
### C. `MISSING_ANCHOR`
Нет достаточного ключа для точного запроса.
Это суперважно, потому что сейчас пользователь может видеть одинаковый ограниченный ответ, но причины там разные.
### Что это даст
Тогда limited-ответ станет полезнее:
* “По указанному фильтру данные не найдены.”
* “Текущий live-рецепт не возвращает договорную аналитику для этого сценария.”
* “Нужно уточнить договор или контрагента.”
Это уже не просто safety, а нормальный рабочий UX.
---
## 5. Усилить слой anchor-first resolution раньше intent
Сейчас вы уже улучшили token-based intent resolver — это хорошо.
Но на раннем этапе я бы вообще сделал акцент не на intent-first, а на:
**anchor-first + intent-second**
То есть сначала пытаться вытащить:
* счет,
* контрагента,
* договор,
* тип документа,
* период,
* дату среза,
а уже потом выбирать intent.
Потому что в реальной короткой подаче пользователь часто говорит не “тип запроса”, а якорь:
* “по альфе что висит”
* “по договору 15 покажи хвост”
* “60 счет на сегодня”
* “платежки по бете за март”
Именно anchor здесь важнее красивой intent-классификации.
---
## 6. Добавить `query shape classification`
Нужно разделить не только по intent, но и по форме вопроса.
Например:
* `AGGREGATE_LOOKUP`
* `OBJECT_LOOKUP`
* `DOCUMENT_LIST`
* `DRILLDOWN_REQUEST`
* `COMPOUND_FACTUAL_QUERY`
* `VERIFY_FACTUAL`
* `EXPLAIN_OR_REASON`
Это сильно поможет на раннем этапе, потому что многие “многочастные” вопросы на самом деле нормально раскладываются не через “один сложный intent”, а через форму запроса.
---
## 7. Для composer: limited-ответы сделать намного полезнее
Сейчас safety у вас честная, но UX можно усилить.
Когда система не может дать factual result, она уже сейчас должна возвращать не просто ограничение, а **полезный следующий шаг**.
### Например:
вместо
* “не найдено”
лучше:
* “Текущий маршрут не видит договорную аналитику в live-строках. Можно продолжить по одному из вариантов: по контрагенту, по счету 60/62/76 или по документам за период.”
или
* “Для точного поиска не хватает якоря. Можно уточнить контрагента, договор или дату.”
То есть limited-mode должен стать **операционным**, а не просто защитным.
---
# Что, скорее всего, “глобально происходит” на текущих двух этапах
Если упрощенно, то так:
## Верхний этап
Работает уже лучше, чем кажется:
* классификация,
* заход в address lane,
* базовый intent/filter layer.
## Нижний этап
Не дотягивает по фактической выразительности live-data:
* текущие рецепты слишком общие,
* movement layer беден для contract-aware сценариев,
* многие кейсы рано упираются в `empty/limited`.
То есть у вас сейчас проблема не “LLM тупой”, а **семантический слой уже обогнал реальную мощность live recipe layer**.
Это нормальная ранняя стадия.
Просто теперь нужно не бесконечно шлифовать классификатор, а **сильно усилить слой address recipes и anchor resolution**.
---
# Что бы я делал следующим коротким шагом
## Sprint A — не расширение фич, а прояснение runtime-реальности
### 1. Ввести отдельную матрицу:
`scenario -> structural readiness -> runtime readiness -> blocker`
Для каждого P0/P1 сценария явно указать:
* видна ли сущность в snapshot;
* видна ли она через текущий live recipe;
* чего не хватает;
* нужен ли новый recipe.
### 2. Добавить 3 статуса failure mode:
* `empty_match`
* `missing_anchor`
* `recipe_visibility_gap`
### 3. Для 5–10 ключевых сценариев собрать live evidence pack
Не просто “PASS/limited”, а:
* какой recipe вызывался,
* какие поля реально вернулись,
* каких anchors не хватило,
* на каком шаге потерялась сущность.
Это сразу покажет, что именно ломается.
---
## Sprint B — минимальное усиление без раздувания системы
### Приоритетно добавить:
1. `documents_by_counterparty`
2. `documents_by_contract`
3. `bank_operations_by_counterparty`
4. `bank_operations_by_contract`
5. `documents_forming_balance`
Потому что эти маршруты обычно лучше дают якоря, чем голый movement slice.
---
## Sprint C — небольшой апгрейд NLU, но без фанатизма
### Что стоит сделать
* account token extractor (`60`, `62`, `76`, `60.01`, `62.02`);
* contract number recognizer;
* counterparty fuzzy resolver;
* short mobile phrase normalization:
* “что висит”
* “хвосты”
* “по альфе”
* “на сегодня”
* “за март”
* “проверь оплаты”
### Что пока не надо делать
* тяжелую многошаговую reasoning-логику;
* сложный free-form planner;
* глубокий unified-intelligence слой.
Рано.
---
# Мой короткий вывод
Сейчас у вас ситуация на самом деле хорошая.
Потому что:
* lane уже заведен;
* deep-path не сломан;
* false factual не генерируется;
* система честно ограничивается там, где live-слой не тянет.
Главное, что я бы зафиксировал:
**узкое место сейчас не в понимании вопроса, а в несоответствии между “сущность есть в inventory” и “по ней можно стабильно ответить текущим live recipe”.**
То есть следующий шаг — это не столько “еще умнее классификатор”, сколько:
* отдельный runtime-readiness слой,
* richer anchor resolution,
* specialized recipes вместо общих movement-срезов,
* и более полезный limited-mode.
Если хочешь, следующим сообщением я могу собрать тебе уже **конкретное ТЗ для Codex на M2.1/M2.2**, именно на усиление runtime-ready слоя и evidence pack по live-рецептам.