АДРЕСНЫЙ РЕЖИМ - Batch-2 (Phase A/B): стабилизация LLM-маршрутизации жизненного цикла контрагентов и договоров + актуализация документации
This commit is contained in:
parent
eec5ef4fc0
commit
1f9bb886ee
|
|
@ -21,3 +21,7 @@ llm_normalizer/reports/normalizer_v*_micro_eval.md
|
||||||
llm_normalizer/reports/minimal_package_*
|
llm_normalizer/reports/minimal_package_*
|
||||||
llm_normalizer/docs/runs/*/
|
llm_normalizer/docs/runs/*/
|
||||||
!llm_normalizer/docs/runs/README.md
|
!llm_normalizer/docs/runs/README.md
|
||||||
|
|
||||||
|
# graphify artifacts
|
||||||
|
graphify-out/
|
||||||
|
.graphify_*
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Core VCS and caches
|
||||||
|
.git/
|
||||||
|
.vs/
|
||||||
|
.pytest_cache/
|
||||||
|
__pycache__/
|
||||||
|
.venv/
|
||||||
|
graphify-out/
|
||||||
|
|
||||||
|
# Runtime outputs and local datasets
|
||||||
|
logs/
|
||||||
|
tmp/
|
||||||
|
data/
|
||||||
|
llm_normalizer/data/traces/
|
||||||
|
llm_normalizer/data/assistant_sessions/
|
||||||
|
llm_normalizer/reports/
|
||||||
|
docs/ARCH/9_audit_artifacts/snapshot_samples/
|
||||||
|
|
||||||
|
# Frontend/build artifacts
|
||||||
|
**/node_modules/
|
||||||
|
**/dist/
|
||||||
|
**/.next/
|
||||||
|
**/.turbo/
|
||||||
|
|
||||||
|
# Large binary artifacts
|
||||||
|
*.zip
|
||||||
|
*.7z
|
||||||
|
*.db
|
||||||
|
*.sqlite
|
||||||
|
*.sqlite3
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
## graphify
|
||||||
|
|
||||||
|
This project has a graphify knowledge graph at graphify-out/.
|
||||||
|
|
||||||
|
Rules:
|
||||||
|
- Before answering architecture or codebase questions, read graphify-out/GRAPH_REPORT.md for god nodes and community structure
|
||||||
|
- If graphify-out/wiki/index.md exists, navigate it instead of reading raw files
|
||||||
|
- After modifying code files in this session, run `python -c "from graphify.watch import _rebuild_code; from pathlib import Path; _rebuild_code(Path('.'))"` to keep the graph current
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
# ADDRESS Test Questions (обновлено 2026-04-02)
|
|
||||||
|
|
||||||
Важно:
|
|
||||||
1. Цепочки `FOLLOW-UP` прогоняй в одной сессии подряд.
|
|
||||||
2. Блоки `SINGLE` можно гонять по отдельности.
|
|
||||||
3. Для проверок смотри не только ответ, но и `technical_debug_payload_json`.
|
|
||||||
|
|
||||||
## SINGLE: Документы по контрагенту
|
|
||||||
1. Покажи документы по СВК за 2020 год
|
|
||||||
2. свк доки за 20й
|
|
||||||
3. что по свк за 2020 выведи все доки плиз
|
|
||||||
4. Какие документы по контрагенту СВК за весь период
|
|
||||||
5. какие есть доки по свк с 2000 по 2025 год
|
|
||||||
6. Покажи документы по контрагенту СВК
|
|
||||||
|
|
||||||
## SINGLE: Банковские операции
|
|
||||||
7. Покажи банковские операции по СВК за 2020
|
|
||||||
8. Какие платежи по СВК в 2020
|
|
||||||
9. Покажи банковские операции по контрагенту СВК за весь период
|
|
||||||
|
|
||||||
## SINGLE: Договор
|
|
||||||
10. Покажи документы по договору 19/15 за 2020
|
|
||||||
11. Покажи документы по договору 19/15
|
|
||||||
12. Покажи банковские операции по договору 19/15
|
|
||||||
13. Есть ли долг по договору 19/15 на 2020-07-31
|
|
||||||
14. Покажи операции по договору 19/15 за весь период
|
|
||||||
|
|
||||||
## SINGLE: Сальдо / остаток
|
|
||||||
15. Покажи сальдо по счету 60.01 на дату 2020-07-31
|
|
||||||
16. Какой остаток по счету 60 на 2020.05
|
|
||||||
17. Какой остаток по счету 60 на 2020 май
|
|
||||||
18. Какие документы формируют остаток по счету 60.01 на 2020-07-31
|
|
||||||
19. Какой остаток по счету 62 на сегодня
|
|
||||||
|
|
||||||
## FOLLOW-UP CHAIN A (одна сессия)
|
|
||||||
20. Покажи документы по СВК за 2020
|
|
||||||
21. а теперь только за май 2020
|
|
||||||
22. а за все время?
|
|
||||||
23. а по счету 60.01 на ту же дату
|
|
||||||
|
|
||||||
## FOLLOW-UP CHAIN B (одна сессия)
|
|
||||||
24. Покажи банковские операции по договору 19/15
|
|
||||||
25. а за 2020 год
|
|
||||||
26. а теперь только за май 2020
|
|
||||||
27. а по счету 51 на ту же дату
|
|
||||||
|
|
||||||
## FOLLOW-UP CHAIN C (одна сессия)
|
|
||||||
28. Какой остаток по счету 60 на 2020.05
|
|
||||||
29. а теперь по 60.01
|
|
||||||
30. а на ту же дату по 62
|
|
||||||
|
|
||||||
## NOISY / TYPO
|
|
||||||
31. бля епт покажи доки по свк за 20й
|
|
||||||
32. свк 20 год - покажи доки плс
|
|
||||||
33. покажи банк опер по дог 19/15 пж
|
|
||||||
34. остаток 60 на 2020 май покеж
|
|
||||||
35. по свк за весь период че есть
|
|
||||||
|
|
||||||
## NEGATIVE / LIMIT CASE
|
|
||||||
36. Покажи технические константы конфигурации
|
|
||||||
37. кто президент США
|
|
||||||
## SINGLE: Дебиторка / Кредиторка
|
|
||||||
38. Кто нам должен на 2020-12-31
|
|
||||||
39. Кому мы должны на 2020-12-31
|
|
||||||
40. Покажи дебиторскую задолженность за 2020
|
|
||||||
41. Покажи кредиторскую задолженность за 2020
|
|
||||||
|
|
||||||
## SINGLE: Незакрытые договоры / открытые позиции
|
|
||||||
42. Покажи незакрытые договоры на 2020-12-31
|
|
||||||
43. Какие открытые договоры есть на 2020-12-31
|
|
||||||
44. Покажи хвосты по контрагенту СВК на 2020-12-31
|
|
||||||
45. Есть ли незакрытые позиции по договору 19/15 на 2020-12-31
|
|
||||||
46. Покажи открытые позиции по договору 19/15
|
|
||||||
|
|
||||||
## FOLLOW-UP CHAIN D (одна сессия)
|
|
||||||
47. Покажи документы по контрагенту СВК за 2020
|
|
||||||
48. а только за июль 2020
|
|
||||||
49. а теперь банковские операции
|
|
||||||
50. а за весь период
|
|
||||||
51. а сальдо по счету 51 на ту же дату
|
|
||||||
|
|
||||||
## FOLLOW-UP CHAIN E (одна сессия)
|
|
||||||
52. Покажи незакрытые позиции по контрагенту СВК
|
|
||||||
53. а на 2020-12-31
|
|
||||||
54. а теперь по договору 19/15
|
|
||||||
55. а только банковские операции
|
|
||||||
56. а за май 2020
|
|
||||||
|
|
||||||
## EN / Transliteration Stress
|
|
||||||
57. show documents by counterparty svk for 2020
|
|
||||||
58. show bank operations by contract 19/15
|
|
||||||
59. kakoi ostatok po schetu 60.01 na 2020-07-31
|
|
||||||
60. kto nam dolzhen na 2020-12-31
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,669 @@
|
||||||
|
# Assistant conversation export
|
||||||
|
session_id: asst-qsZmniA1bx
|
||||||
|
export_mode: technical
|
||||||
|
exported_at: 2026-04-08T08:42:43.575Z
|
||||||
|
|
||||||
|
## 1. user
|
||||||
|
message_id: msg-f9gF7eEEGy
|
||||||
|
created_at: 2026-04-08T08:40:56.493Z
|
||||||
|
reply_type: n/a
|
||||||
|
|
||||||
|
Покажи документы по договору 19/15 за 2020
|
||||||
|
|
||||||
|
## 2. assistant
|
||||||
|
message_id: msg-Je6z6-84tL
|
||||||
|
created_at: 2026-04-08T08:41:03.503Z
|
||||||
|
reply_type: factual
|
||||||
|
trace_id: address-bMqqNTkC2y
|
||||||
|
|
||||||
|
Период сохранен. Глубина live-выборки автоматически расширена до 1000 строк.
|
||||||
|
Собран список документов по договору (live address lane).
|
||||||
|
Строк отобрано: 8.
|
||||||
|
1. 2020-08-31T15:00:06Z | Поступление товаров и услуг 00000000024 от 31.08.2020 15:00:06 | 19.04 / 76.05 | 233.33
|
||||||
|
2. 2020-07-15T13:11:19Z | Реализация товаров и услуг 00000000008 от 15.07.2020 13:11:19 | 62.01 / 90.01.1 | 43804.8
|
||||||
|
3. 2020-07-15T13:11:19Z | Реализация товаров и услуг 00000000008 от 15.07.2020 13:11:19 | 62.01 / 90.01.1 | 9776
|
||||||
|
4. 2020-07-15T13:11:19Z | Реализация товаров и услуг 00000000008 от 15.07.2020 13:11:19 | 62.01 / 90.01.1 | 73968
|
||||||
|
5. 2020-07-15T13:11:19Z | Реализация товаров и услуг 00000000008 от 15.07.2020 13:11:19 | 62.01 / 90.01.1 | 94924.8
|
||||||
|
6. 2020-07-15T13:11:19Z | Реализация товаров и услуг 00000000008 от 15.07.2020 13:11:19 | 62.01 / 90.01.1 | 54400
|
||||||
|
7. 2020-07-15T13:11:19Z | Реализация товаров и услуг 00000000008 от 15.07.2020 13:11:19 | 62.02 / 62.01 | 276873.6
|
||||||
|
8. 2020-06-30T12:00:00Z | Поступление товаров и услуг 00000000015 от 30.06.2020 12:00:00 | 19.04 / 76.05 | 233.33
|
||||||
|
|
||||||
|
### technical_debug_payload_json
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"trace_id": "address-bMqqNTkC2y",
|
||||||
|
"prompt_version": "address_query_runtime_v1",
|
||||||
|
"schema_version": "address_query_runtime_v1",
|
||||||
|
"fallback_type": "none",
|
||||||
|
"route_summary": null,
|
||||||
|
"fragments": [],
|
||||||
|
"requirements_extracted": [],
|
||||||
|
"coverage_report": {
|
||||||
|
"requirements_total": 0,
|
||||||
|
"requirements_covered": 0,
|
||||||
|
"requirements_uncovered": [],
|
||||||
|
"requirements_partially_covered": [],
|
||||||
|
"clarification_needed_for": [],
|
||||||
|
"out_of_scope_requirements": []
|
||||||
|
},
|
||||||
|
"routes": [],
|
||||||
|
"retrieval_status": [],
|
||||||
|
"retrieval_results": [],
|
||||||
|
"answer_grounding_check": {
|
||||||
|
"status": "grounded",
|
||||||
|
"route_subject_match": true,
|
||||||
|
"missing_requirements": [],
|
||||||
|
"reasons": [
|
||||||
|
"address_action_detected",
|
||||||
|
"address_entity_detected",
|
||||||
|
"document_list_signal_detected",
|
||||||
|
"documents_by_contract_signal_detected",
|
||||||
|
"query_limit_auto_expanded_for_anchor_recovery"
|
||||||
|
],
|
||||||
|
"why_included_summary": [],
|
||||||
|
"selection_reason_summary": []
|
||||||
|
},
|
||||||
|
"dropped_intent_segments": [],
|
||||||
|
"detected_mode": "address_query",
|
||||||
|
"detected_mode_confidence": "high",
|
||||||
|
"query_shape": "DOCUMENT_LIST",
|
||||||
|
"query_shape_confidence": "medium",
|
||||||
|
"detected_intent": "list_documents_by_contract",
|
||||||
|
"detected_intent_confidence": "medium",
|
||||||
|
"extracted_filters": {
|
||||||
|
"sort": "period_desc",
|
||||||
|
"limit": 20,
|
||||||
|
"contract": "19/15",
|
||||||
|
"period_from": "2020-01-01",
|
||||||
|
"period_to": "2020-12-31"
|
||||||
|
},
|
||||||
|
"missing_required_filters": [],
|
||||||
|
"selected_recipe": "address_documents_by_contract_v1",
|
||||||
|
"mcp_call_status_legacy": "matched_non_empty",
|
||||||
|
"account_scope_mode": "preferred",
|
||||||
|
"account_scope_fallback_applied": false,
|
||||||
|
"anchor_type": "contract",
|
||||||
|
"anchor_value_raw": "19/15",
|
||||||
|
"anchor_value_resolved": "19/15",
|
||||||
|
"resolver_confidence": "medium",
|
||||||
|
"ambiguity_count": 0,
|
||||||
|
"match_failure_stage": "none",
|
||||||
|
"match_failure_reason": null,
|
||||||
|
"mcp_call_status": "matched_non_empty",
|
||||||
|
"rows_fetched": 1000,
|
||||||
|
"raw_rows_received": 1000,
|
||||||
|
"rows_after_account_scope": 438,
|
||||||
|
"rows_after_recipe_filter": 11,
|
||||||
|
"rows_materialized": 438,
|
||||||
|
"rows_matched": 8,
|
||||||
|
"raw_row_keys_sample": [
|
||||||
|
"Период",
|
||||||
|
"Регистратор",
|
||||||
|
"СчетДт",
|
||||||
|
"СчетКт",
|
||||||
|
"Сумма",
|
||||||
|
"Period",
|
||||||
|
"Registrator",
|
||||||
|
"AccountDt",
|
||||||
|
"AccountKt",
|
||||||
|
"Amount"
|
||||||
|
],
|
||||||
|
"materialization_drop_reason": "none",
|
||||||
|
"account_token_raw": null,
|
||||||
|
"account_token_normalized": null,
|
||||||
|
"account_scope_fields_checked": [
|
||||||
|
"account_dt",
|
||||||
|
"account_kt",
|
||||||
|
"registrator",
|
||||||
|
"analytics"
|
||||||
|
],
|
||||||
|
"account_scope_match_strategy": "account_code_regex_plus_alias_map_v1",
|
||||||
|
"account_scope_drop_reason": "not_applicable",
|
||||||
|
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
|
||||||
|
"limited_reason_category": null,
|
||||||
|
"response_type": "FACTUAL_LIST",
|
||||||
|
"execution_lane": "address_query",
|
||||||
|
"llm_decomposition_applied": true,
|
||||||
|
"llm_decomposition_attempted": true,
|
||||||
|
"llm_provider_used": "local",
|
||||||
|
"llm_decomposition_trace_id": "RsRWAyD29sjgY7",
|
||||||
|
"llm_decomposition_effective_message": "Показать документы по договору 19/15 за период 2020 года.",
|
||||||
|
"llm_decomposition_reason": "normalized_fragment_applied",
|
||||||
|
"llm_canonical_candidate_detected": true,
|
||||||
|
"llm_predecompose_contract": {
|
||||||
|
"schema_version": "address_llm_predecompose_contract_v1",
|
||||||
|
"source_message": "Покажи документы по договору 19/15 за 2020",
|
||||||
|
"canonical_message": "Показать документы по договору 19/15 за период 2020 года.",
|
||||||
|
"mode": "address_query",
|
||||||
|
"mode_confidence": "high",
|
||||||
|
"query_shape": "DOCUMENT_LIST",
|
||||||
|
"query_shape_confidence": "medium",
|
||||||
|
"intent": "list_documents_by_contract",
|
||||||
|
"intent_confidence": "medium",
|
||||||
|
"entities": {
|
||||||
|
"account": null,
|
||||||
|
"counterparty": null,
|
||||||
|
"contract": "19/15",
|
||||||
|
"document_type": null,
|
||||||
|
"document_ref": null,
|
||||||
|
"organization": null
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"scope": "year",
|
||||||
|
"period_from": "2020-01-01",
|
||||||
|
"period_to": "2020-12-31",
|
||||||
|
"as_of_date": null,
|
||||||
|
"has_explicit_period": true
|
||||||
|
},
|
||||||
|
"aggregation_profile": "list_lookup"
|
||||||
|
},
|
||||||
|
"fallback_rule_hit": null,
|
||||||
|
"sanitized_user_message": "покажи документы по договору 19/15 за 2020",
|
||||||
|
"tool_gate_decision": "run_address_lane",
|
||||||
|
"tool_gate_reason": "address_mode_classifier_detected",
|
||||||
|
"answer_structure_v11": null,
|
||||||
|
"investigation_state_snapshot": null,
|
||||||
|
"normalized": null,
|
||||||
|
"normalizer_output": {
|
||||||
|
"trace_id": "RsRWAyD29sjgY7",
|
||||||
|
"prompt_version": "normalizer_v2_0_2",
|
||||||
|
"applied": true,
|
||||||
|
"effective_message": "Показать документы по договору 19/15 за период 2020 года."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. user
|
||||||
|
message_id: msg-1w0963YnGN
|
||||||
|
created_at: 2026-04-08T08:41:09.598Z
|
||||||
|
reply_type: n/a
|
||||||
|
|
||||||
|
а теперь банковские операции
|
||||||
|
|
||||||
|
## 4. assistant
|
||||||
|
message_id: msg-76jKqn5b1O
|
||||||
|
created_at: 2026-04-08T08:41:17.668Z
|
||||||
|
reply_type: factual
|
||||||
|
trace_id: address-mB-Zxj7T3o
|
||||||
|
|
||||||
|
Период сохранен. Глубина live-выборки автоматически расширена до 1000 строк.
|
||||||
|
Собран список банковских операций по договору (live address lane).
|
||||||
|
Строк отобрано: 3.
|
||||||
|
1. 2020-10-15T13:34:19Z | Списание с расчетного счета 00000000245 от 15.10.2020 13:34:19 | 66.01 / 51 | 134206.53
|
||||||
|
2. 2020-07-15T13:11:23Z | Списание с расчетного счета 00000000191 от 15.07.2020 13:11:23 | 66.02 / 51 | 54125.93
|
||||||
|
3. 2020-07-15T13:11:22Z | Списание с расчетного счета 00000000190 от 15.07.2020 13:11:22 | 66.01 / 51 | 122035.07
|
||||||
|
|
||||||
|
### technical_debug_payload_json
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"trace_id": "address-mB-Zxj7T3o",
|
||||||
|
"prompt_version": "address_query_runtime_v1",
|
||||||
|
"schema_version": "address_query_runtime_v1",
|
||||||
|
"fallback_type": "none",
|
||||||
|
"route_summary": null,
|
||||||
|
"fragments": [],
|
||||||
|
"requirements_extracted": [],
|
||||||
|
"coverage_report": {
|
||||||
|
"requirements_total": 0,
|
||||||
|
"requirements_covered": 0,
|
||||||
|
"requirements_uncovered": [],
|
||||||
|
"requirements_partially_covered": [],
|
||||||
|
"clarification_needed_for": [],
|
||||||
|
"out_of_scope_requirements": []
|
||||||
|
},
|
||||||
|
"routes": [],
|
||||||
|
"retrieval_status": [],
|
||||||
|
"retrieval_results": [],
|
||||||
|
"answer_grounding_check": {
|
||||||
|
"status": "grounded",
|
||||||
|
"route_subject_match": true,
|
||||||
|
"missing_requirements": [],
|
||||||
|
"reasons": [
|
||||||
|
"address_entity_detected",
|
||||||
|
"shape_not_detected",
|
||||||
|
"bank_ops_by_counterparty_signal_detected",
|
||||||
|
"intent_adjusted_to_contract_followup_context",
|
||||||
|
"contract_from_followup_context",
|
||||||
|
"period_from_followup_context",
|
||||||
|
"address_followup_context_applied",
|
||||||
|
"query_limit_auto_expanded_for_anchor_recovery"
|
||||||
|
],
|
||||||
|
"why_included_summary": [],
|
||||||
|
"selection_reason_summary": []
|
||||||
|
},
|
||||||
|
"dropped_intent_segments": [],
|
||||||
|
"detected_mode": "address_query",
|
||||||
|
"detected_mode_confidence": "medium",
|
||||||
|
"query_shape": "UNKNOWN",
|
||||||
|
"query_shape_confidence": "low",
|
||||||
|
"detected_intent": "bank_operations_by_contract",
|
||||||
|
"detected_intent_confidence": "low",
|
||||||
|
"extracted_filters": {
|
||||||
|
"sort": "period_desc",
|
||||||
|
"limit": 20,
|
||||||
|
"contract": "19/15",
|
||||||
|
"period_from": "2020-01-01",
|
||||||
|
"period_to": "2020-12-31"
|
||||||
|
},
|
||||||
|
"missing_required_filters": [],
|
||||||
|
"selected_recipe": "address_bank_operations_by_contract_v1",
|
||||||
|
"mcp_call_status_legacy": "matched_non_empty",
|
||||||
|
"account_scope_mode": "preferred",
|
||||||
|
"account_scope_fallback_applied": false,
|
||||||
|
"anchor_type": "contract",
|
||||||
|
"anchor_value_raw": "19/15",
|
||||||
|
"anchor_value_resolved": "19/15",
|
||||||
|
"resolver_confidence": "medium",
|
||||||
|
"ambiguity_count": 0,
|
||||||
|
"match_failure_stage": "none",
|
||||||
|
"match_failure_reason": null,
|
||||||
|
"mcp_call_status": "matched_non_empty",
|
||||||
|
"rows_fetched": 1000,
|
||||||
|
"raw_rows_received": 1000,
|
||||||
|
"rows_after_account_scope": 234,
|
||||||
|
"rows_after_recipe_filter": 3,
|
||||||
|
"rows_materialized": 234,
|
||||||
|
"rows_matched": 3,
|
||||||
|
"raw_row_keys_sample": [
|
||||||
|
"Период",
|
||||||
|
"Регистратор",
|
||||||
|
"СчетДт",
|
||||||
|
"СчетКт",
|
||||||
|
"Сумма",
|
||||||
|
"Period",
|
||||||
|
"Registrator",
|
||||||
|
"AccountDt",
|
||||||
|
"AccountKt",
|
||||||
|
"Amount"
|
||||||
|
],
|
||||||
|
"materialization_drop_reason": "none",
|
||||||
|
"account_token_raw": null,
|
||||||
|
"account_token_normalized": null,
|
||||||
|
"account_scope_fields_checked": [
|
||||||
|
"account_dt",
|
||||||
|
"account_kt",
|
||||||
|
"registrator",
|
||||||
|
"analytics"
|
||||||
|
],
|
||||||
|
"account_scope_match_strategy": "account_code_regex_plus_alias_map_v1",
|
||||||
|
"account_scope_drop_reason": "not_applicable",
|
||||||
|
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
|
||||||
|
"limited_reason_category": null,
|
||||||
|
"response_type": "FACTUAL_LIST",
|
||||||
|
"execution_lane": "address_query",
|
||||||
|
"llm_decomposition_applied": false,
|
||||||
|
"llm_decomposition_attempted": true,
|
||||||
|
"llm_provider_used": "local",
|
||||||
|
"llm_decomposition_trace_id": "fQPoAyba2nzNW_",
|
||||||
|
"llm_decomposition_effective_message": "а теперь банковские операции",
|
||||||
|
"llm_decomposition_reason": "normalized_fragment_same",
|
||||||
|
"llm_canonical_candidate_detected": true,
|
||||||
|
"llm_predecompose_contract": {
|
||||||
|
"schema_version": "address_llm_predecompose_contract_v1",
|
||||||
|
"source_message": "а теперь банковские операции",
|
||||||
|
"canonical_message": "а теперь банковские операции",
|
||||||
|
"mode": "address_query",
|
||||||
|
"mode_confidence": "medium",
|
||||||
|
"query_shape": "UNKNOWN",
|
||||||
|
"query_shape_confidence": "low",
|
||||||
|
"intent": "bank_operations_by_counterparty",
|
||||||
|
"intent_confidence": "medium",
|
||||||
|
"entities": {
|
||||||
|
"account": null,
|
||||||
|
"counterparty": null,
|
||||||
|
"contract": null,
|
||||||
|
"document_type": null,
|
||||||
|
"document_ref": null,
|
||||||
|
"organization": null
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"scope": "unspecified",
|
||||||
|
"period_from": null,
|
||||||
|
"period_to": null,
|
||||||
|
"as_of_date": null,
|
||||||
|
"has_explicit_period": false
|
||||||
|
},
|
||||||
|
"aggregation_profile": "list_lookup"
|
||||||
|
},
|
||||||
|
"fallback_rule_hit": null,
|
||||||
|
"sanitized_user_message": "а теперь банковские операции",
|
||||||
|
"tool_gate_decision": "run_address_lane",
|
||||||
|
"tool_gate_reason": "address_mode_classifier_detected",
|
||||||
|
"answer_structure_v11": null,
|
||||||
|
"investigation_state_snapshot": null,
|
||||||
|
"normalized": null,
|
||||||
|
"normalizer_output": {
|
||||||
|
"trace_id": "fQPoAyba2nzNW_",
|
||||||
|
"prompt_version": "normalizer_v2_0_2",
|
||||||
|
"applied": false,
|
||||||
|
"effective_message": "а теперь банковские операции"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. user
|
||||||
|
message_id: msg-FfUbRQG205
|
||||||
|
created_at: 2026-04-08T08:41:40.344Z
|
||||||
|
reply_type: n/a
|
||||||
|
|
||||||
|
есть ли открытые позиции по договору 19/15 на 2020-12-31
|
||||||
|
|
||||||
|
## 6. assistant
|
||||||
|
message_id: msg-kML8gXvOyB
|
||||||
|
created_at: 2026-04-08T08:41:48.227Z
|
||||||
|
reply_type: factual
|
||||||
|
trace_id: address-oAwR0ldclP
|
||||||
|
|
||||||
|
Период сохранен. Глубина live-выборки автоматически расширена до 1000 строк.
|
||||||
|
Собраны открытые позиции по указанному фильтру (контрагент/договор).
|
||||||
|
Строк отобрано: 8.
|
||||||
|
1. 2020-08-31T15:00:06Z | Поступление товаров и услуг 00000000024 от 31.08.2020 15:00:06 | 19.04 / 76.05 | 233.33
|
||||||
|
2. 2020-07-15T13:11:19Z | Реализация товаров и услуг 00000000008 от 15.07.2020 13:11:19 | 62.01 / 90.01.1 | 43804.8
|
||||||
|
3. 2020-07-15T13:11:19Z | Реализация товаров и услуг 00000000008 от 15.07.2020 13:11:19 | 62.01 / 90.01.1 | 9776
|
||||||
|
4. 2020-07-15T13:11:19Z | Реализация товаров и услуг 00000000008 от 15.07.2020 13:11:19 | 62.01 / 90.01.1 | 73968
|
||||||
|
5. 2020-07-15T13:11:19Z | Реализация товаров и услуг 00000000008 от 15.07.2020 13:11:19 | 62.01 / 90.01.1 | 94924.8
|
||||||
|
6. 2020-07-15T13:11:19Z | Реализация товаров и услуг 00000000008 от 15.07.2020 13:11:19 | 62.01 / 90.01.1 | 54400
|
||||||
|
|
||||||
|
### technical_debug_payload_json
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"trace_id": "address-oAwR0ldclP",
|
||||||
|
"prompt_version": "address_query_runtime_v1",
|
||||||
|
"schema_version": "address_query_runtime_v1",
|
||||||
|
"fallback_type": "none",
|
||||||
|
"route_summary": null,
|
||||||
|
"fragments": [],
|
||||||
|
"requirements_extracted": [],
|
||||||
|
"coverage_report": {
|
||||||
|
"requirements_total": 0,
|
||||||
|
"requirements_covered": 0,
|
||||||
|
"requirements_uncovered": [],
|
||||||
|
"requirements_partially_covered": [],
|
||||||
|
"clarification_needed_for": [],
|
||||||
|
"out_of_scope_requirements": []
|
||||||
|
},
|
||||||
|
"routes": [],
|
||||||
|
"retrieval_status": [],
|
||||||
|
"retrieval_results": [],
|
||||||
|
"answer_grounding_check": {
|
||||||
|
"status": "grounded",
|
||||||
|
"route_subject_match": true,
|
||||||
|
"missing_requirements": [],
|
||||||
|
"reasons": [
|
||||||
|
"address_entity_detected",
|
||||||
|
"verify_signal_detected",
|
||||||
|
"open_items_signal_detected",
|
||||||
|
"query_limit_auto_expanded_for_anchor_recovery"
|
||||||
|
],
|
||||||
|
"why_included_summary": [],
|
||||||
|
"selection_reason_summary": []
|
||||||
|
},
|
||||||
|
"dropped_intent_segments": [],
|
||||||
|
"detected_mode": "address_query",
|
||||||
|
"detected_mode_confidence": "medium",
|
||||||
|
"query_shape": "VERIFY_FACTUAL",
|
||||||
|
"query_shape_confidence": "medium",
|
||||||
|
"detected_intent": "open_items_by_counterparty_or_contract",
|
||||||
|
"detected_intent_confidence": "medium",
|
||||||
|
"extracted_filters": {
|
||||||
|
"sort": "period_desc",
|
||||||
|
"limit": 20,
|
||||||
|
"contract": "19/15",
|
||||||
|
"as_of_date": "2020-12-31"
|
||||||
|
},
|
||||||
|
"missing_required_filters": [],
|
||||||
|
"selected_recipe": "address_open_items_by_party_or_contract_v1",
|
||||||
|
"mcp_call_status_legacy": "matched_non_empty",
|
||||||
|
"account_scope_mode": "preferred",
|
||||||
|
"account_scope_fallback_applied": false,
|
||||||
|
"anchor_type": "contract",
|
||||||
|
"anchor_value_raw": "19/15",
|
||||||
|
"anchor_value_resolved": "19/15",
|
||||||
|
"resolver_confidence": "medium",
|
||||||
|
"ambiguity_count": 0,
|
||||||
|
"match_failure_stage": "none",
|
||||||
|
"match_failure_reason": null,
|
||||||
|
"mcp_call_status": "matched_non_empty",
|
||||||
|
"rows_fetched": 1000,
|
||||||
|
"raw_rows_received": 1000,
|
||||||
|
"rows_after_account_scope": 285,
|
||||||
|
"rows_after_recipe_filter": 8,
|
||||||
|
"rows_materialized": 285,
|
||||||
|
"rows_matched": 8,
|
||||||
|
"raw_row_keys_sample": [
|
||||||
|
"Период",
|
||||||
|
"Регистратор",
|
||||||
|
"СчетДт",
|
||||||
|
"СчетКт",
|
||||||
|
"Сумма",
|
||||||
|
"Period",
|
||||||
|
"Registrator",
|
||||||
|
"AccountDt",
|
||||||
|
"AccountKt",
|
||||||
|
"Amount"
|
||||||
|
],
|
||||||
|
"materialization_drop_reason": "none",
|
||||||
|
"account_token_raw": null,
|
||||||
|
"account_token_normalized": null,
|
||||||
|
"account_scope_fields_checked": [
|
||||||
|
"account_dt",
|
||||||
|
"account_kt",
|
||||||
|
"registrator",
|
||||||
|
"analytics"
|
||||||
|
],
|
||||||
|
"account_scope_match_strategy": "account_code_regex_plus_alias_map_v1",
|
||||||
|
"account_scope_drop_reason": "not_applicable",
|
||||||
|
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
|
||||||
|
"limited_reason_category": null,
|
||||||
|
"response_type": "FACTUAL_LIST",
|
||||||
|
"execution_lane": "address_query",
|
||||||
|
"llm_decomposition_applied": true,
|
||||||
|
"llm_decomposition_attempted": true,
|
||||||
|
"llm_provider_used": "local",
|
||||||
|
"llm_decomposition_trace_id": "v905zWHzp1kuHh",
|
||||||
|
"llm_decomposition_effective_message": "Проверить наличие открытых позиций по договору 19/15 на конец периода 2020-12-31.",
|
||||||
|
"llm_decomposition_reason": "normalized_fragment_applied",
|
||||||
|
"llm_canonical_candidate_detected": true,
|
||||||
|
"llm_predecompose_contract": {
|
||||||
|
"schema_version": "address_llm_predecompose_contract_v1",
|
||||||
|
"source_message": "есть ли открытые позиции по договору 19/15 на 2020-12-31",
|
||||||
|
"canonical_message": "Проверить наличие открытых позиций по договору 19/15 на конец периода 2020-12-31.",
|
||||||
|
"mode": "address_query",
|
||||||
|
"mode_confidence": "medium",
|
||||||
|
"query_shape": "VERIFY_FACTUAL",
|
||||||
|
"query_shape_confidence": "medium",
|
||||||
|
"intent": "open_items_by_counterparty_or_contract",
|
||||||
|
"intent_confidence": "medium",
|
||||||
|
"entities": {
|
||||||
|
"account": null,
|
||||||
|
"counterparty": null,
|
||||||
|
"contract": "19/15",
|
||||||
|
"document_type": null,
|
||||||
|
"document_ref": null,
|
||||||
|
"organization": null
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"scope": "as_of",
|
||||||
|
"period_from": null,
|
||||||
|
"period_to": null,
|
||||||
|
"as_of_date": "2020-12-31",
|
||||||
|
"has_explicit_period": true
|
||||||
|
},
|
||||||
|
"aggregation_profile": "open_items"
|
||||||
|
},
|
||||||
|
"fallback_rule_hit": null,
|
||||||
|
"sanitized_user_message": "есть ли открытые позиции по договору 19/15 на 2020-12-31",
|
||||||
|
"tool_gate_decision": "run_address_lane",
|
||||||
|
"tool_gate_reason": "address_mode_classifier_detected",
|
||||||
|
"answer_structure_v11": null,
|
||||||
|
"investigation_state_snapshot": null,
|
||||||
|
"normalized": null,
|
||||||
|
"normalizer_output": {
|
||||||
|
"trace_id": "v905zWHzp1kuHh",
|
||||||
|
"prompt_version": "normalizer_v2_0_2",
|
||||||
|
"applied": true,
|
||||||
|
"effective_message": "Проверить наличие открытых позиций по договору 19/15 на конец периода 2020-12-31."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. user
|
||||||
|
message_id: msg-VtC7fvCUIt
|
||||||
|
created_at: 2026-04-08T08:42:06.001Z
|
||||||
|
reply_type: n/a
|
||||||
|
|
||||||
|
покажи документы по этому же договору
|
||||||
|
|
||||||
|
## 8. assistant
|
||||||
|
message_id: msg-VswRgnV4fb
|
||||||
|
created_at: 2026-04-08T08:42:11.635Z
|
||||||
|
reply_type: factual
|
||||||
|
trace_id: address-zoj3HXDSnN
|
||||||
|
|
||||||
|
Собран список документов по договору (live address lane).
|
||||||
|
Строк отобрано: 1.
|
||||||
|
1. 2021-12-31T12:00:00Z | Поступление товаров и услуг 00000000015 от 31.12.2021 12:00:00 | 19.04 / 76.05 | 233.33
|
||||||
|
|
||||||
|
### technical_debug_payload_json
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"trace_id": "address-zoj3HXDSnN",
|
||||||
|
"prompt_version": "address_query_runtime_v1",
|
||||||
|
"schema_version": "address_query_runtime_v1",
|
||||||
|
"fallback_type": "none",
|
||||||
|
"route_summary": null,
|
||||||
|
"fragments": [],
|
||||||
|
"requirements_extracted": [],
|
||||||
|
"coverage_report": {
|
||||||
|
"requirements_total": 0,
|
||||||
|
"requirements_covered": 0,
|
||||||
|
"requirements_uncovered": [],
|
||||||
|
"requirements_partially_covered": [],
|
||||||
|
"clarification_needed_for": [],
|
||||||
|
"out_of_scope_requirements": []
|
||||||
|
},
|
||||||
|
"routes": [],
|
||||||
|
"retrieval_status": [],
|
||||||
|
"retrieval_results": [],
|
||||||
|
"answer_grounding_check": {
|
||||||
|
"status": "grounded",
|
||||||
|
"route_subject_match": true,
|
||||||
|
"missing_requirements": [],
|
||||||
|
"reasons": [
|
||||||
|
"address_action_detected",
|
||||||
|
"address_entity_detected",
|
||||||
|
"document_list_signal_detected",
|
||||||
|
"documents_by_contract_signal_detected",
|
||||||
|
"contract_from_followup_context",
|
||||||
|
"address_followup_context_applied"
|
||||||
|
],
|
||||||
|
"why_included_summary": [],
|
||||||
|
"selection_reason_summary": []
|
||||||
|
},
|
||||||
|
"dropped_intent_segments": [],
|
||||||
|
"detected_mode": "address_query",
|
||||||
|
"detected_mode_confidence": "high",
|
||||||
|
"query_shape": "DOCUMENT_LIST",
|
||||||
|
"query_shape_confidence": "medium",
|
||||||
|
"detected_intent": "list_documents_by_contract",
|
||||||
|
"detected_intent_confidence": "medium",
|
||||||
|
"extracted_filters": {
|
||||||
|
"sort": "period_desc",
|
||||||
|
"limit": 20,
|
||||||
|
"contract": "19/15"
|
||||||
|
},
|
||||||
|
"missing_required_filters": [],
|
||||||
|
"selected_recipe": "address_documents_by_contract_v1",
|
||||||
|
"mcp_call_status_legacy": "matched_non_empty",
|
||||||
|
"account_scope_mode": "preferred",
|
||||||
|
"account_scope_fallback_applied": false,
|
||||||
|
"anchor_type": "contract",
|
||||||
|
"anchor_value_raw": "19/15",
|
||||||
|
"anchor_value_resolved": "19/15",
|
||||||
|
"resolver_confidence": "medium",
|
||||||
|
"ambiguity_count": 0,
|
||||||
|
"match_failure_stage": "none",
|
||||||
|
"match_failure_reason": null,
|
||||||
|
"mcp_call_status": "matched_non_empty",
|
||||||
|
"rows_fetched": 1000,
|
||||||
|
"raw_rows_received": 1000,
|
||||||
|
"rows_after_account_scope": 416,
|
||||||
|
"rows_after_recipe_filter": 2,
|
||||||
|
"rows_materialized": 416,
|
||||||
|
"rows_matched": 1,
|
||||||
|
"raw_row_keys_sample": [
|
||||||
|
"Период",
|
||||||
|
"Регистратор",
|
||||||
|
"СчетДт",
|
||||||
|
"СчетКт",
|
||||||
|
"Сумма",
|
||||||
|
"Period",
|
||||||
|
"Registrator",
|
||||||
|
"AccountDt",
|
||||||
|
"AccountKt",
|
||||||
|
"Amount"
|
||||||
|
],
|
||||||
|
"materialization_drop_reason": "none",
|
||||||
|
"account_token_raw": null,
|
||||||
|
"account_token_normalized": null,
|
||||||
|
"account_scope_fields_checked": [
|
||||||
|
"account_dt",
|
||||||
|
"account_kt",
|
||||||
|
"registrator",
|
||||||
|
"analytics"
|
||||||
|
],
|
||||||
|
"account_scope_match_strategy": "account_code_regex_plus_alias_map_v1",
|
||||||
|
"account_scope_drop_reason": "not_applicable",
|
||||||
|
"runtime_readiness": "LIVE_QUERYABLE_WITH_LIMITS",
|
||||||
|
"limited_reason_category": null,
|
||||||
|
"response_type": "FACTUAL_LIST",
|
||||||
|
"execution_lane": "address_query",
|
||||||
|
"llm_decomposition_applied": true,
|
||||||
|
"llm_decomposition_attempted": true,
|
||||||
|
"llm_provider_used": "local",
|
||||||
|
"llm_decomposition_trace_id": "2owWUuckOkI3Tu",
|
||||||
|
"llm_decomposition_effective_message": "Показать документы по указанному договору.",
|
||||||
|
"llm_decomposition_reason": "normalized_fragment_applied",
|
||||||
|
"llm_canonical_candidate_detected": true,
|
||||||
|
"llm_predecompose_contract": {
|
||||||
|
"schema_version": "address_llm_predecompose_contract_v1",
|
||||||
|
"source_message": "покажи документы по этому же договору",
|
||||||
|
"canonical_message": "Показать документы по указанному договору.",
|
||||||
|
"mode": "address_query",
|
||||||
|
"mode_confidence": "high",
|
||||||
|
"query_shape": "DOCUMENT_LIST",
|
||||||
|
"query_shape_confidence": "medium",
|
||||||
|
"intent": "list_documents_by_contract",
|
||||||
|
"intent_confidence": "medium",
|
||||||
|
"entities": {
|
||||||
|
"account": null,
|
||||||
|
"counterparty": null,
|
||||||
|
"contract": null,
|
||||||
|
"document_type": null,
|
||||||
|
"document_ref": null,
|
||||||
|
"organization": null
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"scope": "unspecified",
|
||||||
|
"period_from": null,
|
||||||
|
"period_to": null,
|
||||||
|
"as_of_date": null,
|
||||||
|
"has_explicit_period": false
|
||||||
|
},
|
||||||
|
"aggregation_profile": "list_lookup"
|
||||||
|
},
|
||||||
|
"fallback_rule_hit": null,
|
||||||
|
"sanitized_user_message": "покажи документы по этому же договору",
|
||||||
|
"tool_gate_decision": "run_address_lane",
|
||||||
|
"tool_gate_reason": "address_mode_classifier_detected",
|
||||||
|
"answer_structure_v11": null,
|
||||||
|
"investigation_state_snapshot": null,
|
||||||
|
"normalized": null,
|
||||||
|
"normalizer_output": {
|
||||||
|
"trace_id": "2owWUuckOkI3Tu",
|
||||||
|
"prompt_version": "normalizer_v2_0_2",
|
||||||
|
"applied": true,
|
||||||
|
"effective_message": "Показать документы по указанному договору."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# ADDRESS Query Docs
|
# ADDRESS Query Docs
|
||||||
|
|
||||||
Дата: 2026-04-03
|
Дата: 2026-04-08
|
||||||
Статус синхронизации: актуализировано по текущему коду в `llm_normalizer/backend/src/services/*`.
|
Статус синхронизации: актуализировано по текущему коду в `llm_normalizer/backend/src/services/*`.
|
||||||
|
|
||||||
## Актуальный статус (2026-04-08)
|
## Актуальный статус (2026-04-08)
|
||||||
|
|
@ -23,6 +23,15 @@
|
||||||
- `followup_25`: `25/25`
|
- `followup_25`: `25/25`
|
||||||
- comparator: `PASS`
|
- comparator: `PASS`
|
||||||
- run: `docs/ADDRESS/runs/2026-04-08_Address_Nightly_Regression_2026-04-08_10-51-20/nightly_summary.json`
|
- run: `docs/ADDRESS/runs/2026-04-08_Address_Nightly_Regression_2026-04-08_10-51-20/nightly_summary.json`
|
||||||
|
- Batch-2 lifecycle официально переведен в `Phase A active`:
|
||||||
|
- domain card: `domain_general_batch2_lifecycle_card_v1.md`
|
||||||
|
- acceptance set: `docs/ADDRESS/question_sets/domain_general_batch2_lifecycle_acceptance_2026-04-08_phaseA.json`
|
||||||
|
- probe report: `wave1_batch2_phaseA_probe_report_2026-04-08.md`
|
||||||
|
- backlog: `step4_wave1_batch2_phaseA_backlog_v1.md`
|
||||||
|
- Batch-2 Phase-B progress:
|
||||||
|
- resolver hardening по `Q12/Q13/Q26/Q27/Q31/Q32` выполнен
|
||||||
|
- targeted test gate: `addressQueryRuntimeM23.test.ts = 210/210`, `build=PASS`
|
||||||
|
- live hotpass: `wave1_batch2_phaseB_resolver_hotpass_2026-04-08.md` (`route match 6/6`)
|
||||||
- Финальный stress-pack: `102/102`
|
- Финальный stress-pack: `102/102`
|
||||||
`docs/ADDRESS/runs/2026-04-02_Address_Slang_Live_Stress_2026-04-02_12-57-27/run_summary.json`
|
`docs/ADDRESS/runs/2026-04-02_Address_Slang_Live_Stress_2026-04-02_12-57-27/run_summary.json`
|
||||||
- Финальный follow-up pack: `25/25`
|
- Финальный follow-up pack: `25/25`
|
||||||
|
|
@ -37,14 +46,14 @@
|
||||||
|
|
||||||
Поддерживаемые intents в runtime:
|
Поддерживаемые intents в runtime:
|
||||||
|
|
||||||
- `period_coverage_profile` (Wave-1 B1, pre-gate)
|
- `period_coverage_profile` (Wave-1 B1, gate-closed)
|
||||||
- `document_type_and_account_section_profile` (Wave-1 B1, pre-gate)
|
- `document_type_and_account_section_profile` (Wave-1 B1, pre-gate)
|
||||||
- `counterparty_population_and_roles` (Wave-1 B1, pre-gate)
|
- `counterparty_population_and_roles` (Wave-1 B1, pre-gate)
|
||||||
- `counterparty_activity_lifecycle` (Wave-1/B2, pre-gate)
|
- `counterparty_activity_lifecycle` (Wave-1/B2, Phase-A active)
|
||||||
- `contract_usage_overview` (Wave-1 B1, pre-gate)
|
- `contract_usage_overview` (Wave-1 B1, gate-closed)
|
||||||
- `customer_revenue_and_payments` (Wave-1 B3 value, pre-gate)
|
- `customer_revenue_and_payments` (Wave-1 B3 value, gate-closed)
|
||||||
- `supplier_payouts_profile` (Wave-1 B3 value, pre-gate)
|
- `supplier_payouts_profile` (Wave-1 B3 value, gate-closed)
|
||||||
- `contract_usage_and_value` (Wave-1 B3 value, pre-gate)
|
- `contract_usage_and_value` (Wave-1 B3 value, gate-closed)
|
||||||
- `list_open_contracts`
|
- `list_open_contracts`
|
||||||
- `list_payables_counterparties`
|
- `list_payables_counterparties`
|
||||||
- `list_receivables_counterparties`
|
- `list_receivables_counterparties`
|
||||||
|
|
@ -84,6 +93,11 @@
|
||||||
- `wave1_batch1_readiness_report_2026-04-02.md` - авто-отчет готовности к старту Batch-1.
|
- `wave1_batch1_readiness_report_2026-04-02.md` - авто-отчет готовности к старту Batch-1.
|
||||||
- `stage3_value_universalization_closeout_2026-04-03.md` - закрытие этапа 3 по value-вопросам общего домена (профит, тестовый gate, остаточные риски).
|
- `stage3_value_universalization_closeout_2026-04-03.md` - закрытие этапа 3 по value-вопросам общего домена (профит, тестовый gate, остаточные риски).
|
||||||
- `wave1_batch1_batch3_live_gate_report_2026-04-03.md` - фактический отчет по live-gate Batch-1/Batch-3 и статусу глобального regression/comparator (PASS в R6).
|
- `wave1_batch1_batch3_live_gate_report_2026-04-03.md` - фактический отчет по live-gate Batch-1/Batch-3 и статусу глобального regression/comparator (PASS в R6).
|
||||||
|
- `project_status_rails_graph_2026-04-08.md` - визуальный граф текущего статуса рельсов (закрытые гейты, operational-контур, точка входа в Batch-2).
|
||||||
|
- `domain_general_batch2_lifecycle_card_v1.md` - domain card для Batch-2 lifecycle (`Q8..Q13 + Q26 + Q27 + Q31 + Q32`).
|
||||||
|
- `wave1_batch2_phaseA_probe_report_2026-04-08.md` - baseline probe Batch-2 с фактическими gap-ами перед Phase B.
|
||||||
|
- `step4_wave1_batch2_phaseA_backlog_v1.md` - рабочий backlog Batch-2 (Phase A/B/C).
|
||||||
|
- `wave1_batch2_phaseB_resolver_hotpass_2026-04-08.md` - фиксация закрытия resolver drift на критичных Batch-2 формулировках (`6/6`).
|
||||||
- `domain_general_batch1_foundation_card_v1.md` - domain card первой волны (Phase A).
|
- `domain_general_batch1_foundation_card_v1.md` - domain card первой волны (Phase A).
|
||||||
- `step4_wave1_batch1_phaseA_backlog_v1.md` - рабочий backlog по подготовке кода и gate-этапам Batch-1.
|
- `step4_wave1_batch1_phaseA_backlog_v1.md` - рабочий backlog по подготовке кода и gate-этапам Batch-1.
|
||||||
- `domain_card_template_v1.md` - шаблон описания домена для repeatable delivery.
|
- `domain_card_template_v1.md` - шаблон описания домена для repeatable delivery.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
Дата: `2026-04-02`
|
Дата: `2026-04-02`
|
||||||
Домен: `general_batch1_foundation`
|
Домен: `general_batch1_foundation`
|
||||||
Статус: `active` (Phase A prepared, Phase B runtime intents implemented, Phase C pending)
|
Статус: `closed` (Phase A/B/C закрыты, domain gate PASS)
|
||||||
Владелец: `Address Runtime Team`
|
Владелец: `Address Runtime Team`
|
||||||
|
|
||||||
## 1. Scope
|
## 1. Scope
|
||||||
|
|
@ -152,3 +152,4 @@ Global gate:
|
||||||
- `2026-04-02` — реализованы `counterparty_population_and_roles` и `contract_usage_overview`; targeted live-pack `Q6/Q7/Q28` прошел `strict factual 9/9` (`2026-04-02_Address_Batch1_NextPack_Q6_Q7_Q28`).
|
- `2026-04-02` — реализованы `counterparty_population_and_roles` и `contract_usage_overview`; targeted live-pack `Q6/Q7/Q28` прошел `strict factual 9/9` (`2026-04-02_Address_Batch1_NextPack_Q6_Q7_Q28`).
|
||||||
- 2026-04-02 - hotfix slang count routing: скока/скок поставщиков|заказчиков стабильно маршрутизируются в counterparty_population_and_roles; targeted live-pack 2026-04-02_Address_SupplierCount_Targeted_AfterFix прошел strict factual 4/4.
|
- 2026-04-02 - hotfix slang count routing: скока/скок поставщиков|заказчиков стабильно маршрутизируются в counterparty_population_and_roles; targeted live-pack 2026-04-02_Address_SupplierCount_Targeted_AfterFix прошел strict factual 4/4.
|
||||||
- 2026-04-02 - hotfix follow-up slang variant: скок клиентов now maps to counterparty_population_and_roles; targeted live-pack 2026-04-02_Address_SupplierClient_Followup_AfterFix passed strict factual 3/3.
|
- 2026-04-02 - hotfix follow-up slang variant: скок клиентов now maps to counterparty_population_and_roles; targeted live-pack 2026-04-02_Address_SupplierClient_Followup_AfterFix passed strict factual 3/3.
|
||||||
|
- 2026-04-08 - статус карточки обновлен на `closed` после live-gate (`strict 28/28`) и global comparator PASS; следующий шаг вынесен в Batch-2 lifecycle.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
# Domain Card — general_batch2_lifecycle V1
|
||||||
|
|
||||||
|
Дата: `2026-04-08`
|
||||||
|
Домен: `general_batch2_lifecycle`
|
||||||
|
Статус: `active` (Phase A стартован)
|
||||||
|
Владелец: `Address Runtime Team`
|
||||||
|
|
||||||
|
## 1. Scope
|
||||||
|
|
||||||
|
Кратко: домен закрывает lifecycle-вопросы общего домена (`Q8..Q13 + Q26 + Q27 + Q31 + Q32`) и готовит единый рельсовый контракт перед Phase B.
|
||||||
|
|
||||||
|
In-scope intents:
|
||||||
|
|
||||||
|
1. `counterparty_activity_lifecycle`
|
||||||
|
2. `contract_usage_overview` (для stale contract слоя)
|
||||||
|
3. `contract_usage_and_value` (для multi-contract структуры)
|
||||||
|
|
||||||
|
Out-of-scope:
|
||||||
|
|
||||||
|
1. value-ranking блок (`Q14..Q25 + Q29 + Q30`) — закрыт отдельным Batch-3.
|
||||||
|
2. debt/aging/risk блок (`Q33+`) — отдельные Batch-4/Batch-5.
|
||||||
|
3. `COMPOUND_FACTUAL_QUERY` multi-step execution вне явного lifecycle контракта.
|
||||||
|
|
||||||
|
## 2. Intent Contract
|
||||||
|
|
||||||
|
### 2.1 `counterparty_activity_lifecycle`
|
||||||
|
|
||||||
|
- `query_shape`: `FACTUAL_LIST`
|
||||||
|
- `required_filters`: `[]`
|
||||||
|
- `optional_filters`: `[period_from, period_to, as_of_date, organization, limit, sort]`
|
||||||
|
- `resolver_signals`: `активны`, `новые`, `исчезли`, `только один раз`, `дольше всех`, `регулярные`, `эпизодические`, `давно не использовались`
|
||||||
|
- `ambiguity_rules`: если есть сигналы lifecycle + role split, приоритет у lifecycle (не у `counterparty_population_and_roles`)
|
||||||
|
- `fallback_policy`: при отсутствии явного периода используется all-time окно; factual без якорей разрешен
|
||||||
|
|
||||||
|
### 2.2 `contract_usage_overview`
|
||||||
|
|
||||||
|
- `query_shape`: `FACTUAL_SUMMARY`
|
||||||
|
- `required_filters`: `[]`
|
||||||
|
- `optional_filters`: `[period_from, period_to, as_of_date, organization, limit]`
|
||||||
|
- `resolver_signals`: `договоры не использовались`, `stale contracts`, `мертвые договоры`
|
||||||
|
- `ambiguity_rules`: если вопрос про общий статус использования договоров без топ-ранжирования, приоритет у `contract_usage_overview`
|
||||||
|
- `fallback_policy`: если stale-метрика не подтверждается, допустим `LIMITED_WITH_REASON` без ложного factual
|
||||||
|
|
||||||
|
### 2.3 `contract_usage_and_value`
|
||||||
|
|
||||||
|
- `query_shape`: `FACTUAL_LIST`
|
||||||
|
- `required_filters`: `[]`
|
||||||
|
- `optional_filters`: `[period_from, period_to, as_of_date, organization, limit, sort]`
|
||||||
|
- `resolver_signals`: `несколько договоров у контрагента`, `мультидоговорные`, `какие договоры активны`
|
||||||
|
- `ambiguity_rules`: multi-contract структура имеет приоритет над anchor-required lookup intent-ами
|
||||||
|
- `fallback_policy`: при невозможности построить структуру выдаем `LIMITED_WITH_REASON`, без перехода в broad document list
|
||||||
|
|
||||||
|
## 3. Recipe Mapping
|
||||||
|
|
||||||
|
Связка `intent -> recipe_id` должна совпадать с runtime catalog (`addressRecipeCatalog.ts`).
|
||||||
|
|
||||||
|
| intent | recipe_id | mcp_method | expected_statuses |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `counterparty_activity_lifecycle` | `address_counterparty_activity_lifecycle_v1` | `POST /api/execute_query` | `matched_non_empty`, `no_raw_rows`, `materialized_but_not_matched` |
|
||||||
|
| `contract_usage_overview` | `address_contract_usage_overview_v1` | `POST /api/execute_query` | `matched_non_empty`, `no_raw_rows`, `materialized_but_not_matched` |
|
||||||
|
| `contract_usage_and_value` | `address_contract_usage_and_value_v1` | `POST /api/execute_query` | `matched_non_empty`, `no_raw_rows`, `materialized_but_not_matched` |
|
||||||
|
|
||||||
|
## 4. Anchor and Resolver Rules
|
||||||
|
|
||||||
|
- `anchor_type`: `period`, `organization`, optional `counterparty` for follow-up context
|
||||||
|
- `anchor_resolution_order`: explicit period -> follow-up period -> all-time default
|
||||||
|
- `min_confidence`: `medium`
|
||||||
|
- `unresolved_behavior`: при unresolved lifecycle сегменте отдавать `LIMITED_WITH_REASON` (`unsupported`/`empty_match`) без псевдо-factual
|
||||||
|
|
||||||
|
## 5. Limited Reasons (taxonomy)
|
||||||
|
|
||||||
|
Разрешенные категории для домена:
|
||||||
|
|
||||||
|
1. `empty_match`
|
||||||
|
2. `unsupported`
|
||||||
|
3. `execution_error`
|
||||||
|
4. `missing_anchor` (только для реального anchor-required маршрута)
|
||||||
|
|
||||||
|
Запрещено:
|
||||||
|
|
||||||
|
- подменять lifecycle intent на lookup intent с обязательным якорем без явного сигнала пользователя;
|
||||||
|
- выдавать broad fallback list в вопросах про lifecycle сегментацию.
|
||||||
|
|
||||||
|
## 6. Test Coverage
|
||||||
|
|
||||||
|
Unit:
|
||||||
|
|
||||||
|
1. resolver positives/negatives для `Q8..Q13`, `Q26`, `Q27`, `Q31`, `Q32`
|
||||||
|
2. приоритет lifecycle над population-role split
|
||||||
|
3. follow-up period switch (`2020 -> 2021`) для lifecycle цепочек
|
||||||
|
4. contract lifecycle phrase routing без обязательного якоря
|
||||||
|
|
||||||
|
Integration:
|
||||||
|
|
||||||
|
1. recipe selection на lifecycle/contract-lifecycle фразах
|
||||||
|
2. execution status mapping (`matched_non_empty`, `unsupported`, `empty_match`)
|
||||||
|
3. debug payload completeness
|
||||||
|
|
||||||
|
Live acceptance:
|
||||||
|
|
||||||
|
1. canonical вопросы
|
||||||
|
2. noisy/slang вопросы
|
||||||
|
3. follow-up chains
|
||||||
|
|
||||||
|
## 7. Gate Criteria
|
||||||
|
|
||||||
|
Domain gate:
|
||||||
|
|
||||||
|
- `strict_pass(route)=100%`
|
||||||
|
- `false_factual_rate=0`
|
||||||
|
- `execution_error_rate=0`
|
||||||
|
|
||||||
|
Global gate:
|
||||||
|
|
||||||
|
- baseline stress не ниже эталона `102/102`
|
||||||
|
- baseline follow-up не ниже эталона `25/25`
|
||||||
|
|
||||||
|
## 8. Rollout Plan
|
||||||
|
|
||||||
|
1. `phase_a` — contract freeze + acceptance set + probe baseline.
|
||||||
|
2. `phase_b` — resolver/compose hardening по lifecycle gap-ам.
|
||||||
|
3. `phase_c` — domain live gate + global comparator PASS.
|
||||||
|
|
||||||
|
## 9. Artifacts
|
||||||
|
|
||||||
|
Обязательные артефакты:
|
||||||
|
|
||||||
|
1. `domain_general_batch2_lifecycle_card_v1.md`
|
||||||
|
2. `question_sets/domain_general_batch2_lifecycle_acceptance_2026-04-08_phaseA.json`
|
||||||
|
3. `wave1_batch2_phaseA_probe_report_2026-04-08.md`
|
||||||
|
4. `step4_wave1_batch2_phaseA_backlog_v1.md`
|
||||||
|
5. `runs/<run_id>/run_summary.json`
|
||||||
|
6. `runs/<run_id>/full_live_results.json`
|
||||||
|
|
||||||
|
## 10. Change Log
|
||||||
|
|
||||||
|
- `2026-04-08` — создана карточка домена Batch-2 lifecycle и зафиксирован contract scope.
|
||||||
|
- `2026-04-08` — добавлен Phase-A acceptance набор `Q8..Q13 + Q26 + Q27 + Q31 + Q32`.
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# Global Execution Checklist V1
|
# Global Execution Checklist V1
|
||||||
|
|
||||||
Дата старта: 2026-04-02
|
Дата старта: 2026-04-02
|
||||||
Последнее обновление: 2026-04-02
|
Последнее обновление: 2026-04-08
|
||||||
Цель: последовательное закрытие Address Query V1 без архитектурного дрейфа и без company-specific хардкода.
|
Цель: последовательное закрытие Address Query V1 без архитектурного дрейфа и без company-specific хардкода.
|
||||||
|
|
||||||
## Правило выполнения
|
## Правило выполнения
|
||||||
|
|
@ -89,12 +89,27 @@
|
||||||
- `domain_general_batch1_foundation_card_v1.md`
|
- `domain_general_batch1_foundation_card_v1.md`
|
||||||
- `domain_general_batch1_acceptance_2026-04-02_phaseA.json`
|
- `domain_general_batch1_acceptance_2026-04-02_phaseA.json`
|
||||||
- `step4_wave1_batch1_phaseA_backlog_v1.md`
|
- `step4_wave1_batch1_phaseA_backlog_v1.md`
|
||||||
- [ ] Phase A закрыт (intent naming freeze + negative cases).
|
- [x] Phase A закрыт (intent naming freeze + acceptance set + domain card).
|
||||||
- [ ] Phase B закрыт (resolver/types/recipes/compose для Batch-1).
|
- [x] Phase B закрыт (resolver/types/recipes/compose для Batch-1).
|
||||||
- [ ] Phase C закрыт (domain gate + global non-regression gate).
|
- [x] Phase C закрыт (domain gate + global non-regression gate).
|
||||||
- [x] Phase B.1 начат: реализован первый Batch-1 intent `period_coverage_profile` (resolver + types + recipe + compose), unit/build green.
|
- [x] Phase B.1 начат: реализован первый Batch-1 intent `period_coverage_profile` (resolver + types + recipe + compose), unit/build green.
|
||||||
- [x] Phase B.1 progress: реализован второй Batch-1 intent `document_type_and_account_section_profile` (resolver + classifier + recipe + compose), unit/build green (`107 passed`).
|
- [x] Phase B.1 progress: реализован второй Batch-1 intent `document_type_and_account_section_profile` (resolver + classifier + recipe + compose), unit/build green (`107 passed`).
|
||||||
|
|
||||||
|
#### Step-4 Wave-1 (general domain, Batch-2 lifecycle: Q8..Q13 + Q26 + Q27 + Q31 + Q32)
|
||||||
|
|
||||||
|
- [x] Phase A стартован:
|
||||||
|
- `domain_general_batch2_lifecycle_card_v1.md`
|
||||||
|
- `domain_general_batch2_lifecycle_acceptance_2026-04-08_phaseA.json`
|
||||||
|
- `wave1_batch2_phaseA_probe_report_2026-04-08.md`
|
||||||
|
- `step4_wave1_batch2_phaseA_backlog_v1.md`
|
||||||
|
- [ ] Phase A закрыт (negative-пары + final contract freeze).
|
||||||
|
- [ ] Phase B закрыт (resolver/decompose/compose hardening для lifecycle gap-ов).
|
||||||
|
- [x] Phase B progress:
|
||||||
|
- resolver hardening по `Q12/Q13/Q26/Q27/Q31/Q32`
|
||||||
|
- test gate: `addressQueryRuntimeM23.test.ts = 210/210`, `build=PASS`
|
||||||
|
- live hotpass: `wave1_batch2_phaseB_resolver_hotpass_2026-04-08.md` (`route match 6/6`)
|
||||||
|
- [ ] Phase C закрыт (Batch-2 domain gate + global comparator PASS).
|
||||||
|
|
||||||
## Документация (code-sync)
|
## Документация (code-sync)
|
||||||
|
|
||||||
- [x] Базовые docs синхронизированы с текущим runtime-кодом (`README`, `address_scenario_matrix`, `query_recipes`, `runtime_readiness_matrix`, `address_runtime_contracts`, `runtime_integration_plan`).
|
- [x] Базовые docs синхронизированы с текущим runtime-кодом (`README`, `address_scenario_matrix`, `query_recipes`, `runtime_readiness_matrix`, `address_runtime_contracts`, `runtime_integration_plan`).
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
# ADDRESS Project Status Rails Graph (2026-04-08)
|
||||||
|
|
||||||
|
Дата среза: 2026-04-08
|
||||||
|
Контур: `question_mode=address_query`
|
||||||
|
|
||||||
|
## Граф статуса
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
A["Step-0 Pre-Prod Rails<br/>CLOSED"]
|
||||||
|
B["Wave-1 Runtime Prep (B1+B3)<br/>intents + tests"]
|
||||||
|
C["Domain Live Gates<br/>B1: 28/28 PASS<br/>B3: 33/33 PASS"]
|
||||||
|
D["Global Nightly Comparator (R6)<br/>102/102 + 25/25 PASS"]
|
||||||
|
E["Auto-nightly Incident<br/>2026-04-08 09:52<br/>MCP fetch failed"]
|
||||||
|
F["Targeted Fix<br/>S019 predecompose anchor drift"]
|
||||||
|
G["Manual Control Nightly Recheck<br/>2026-04-08 10:51<br/>102/102 + 25/25 PASS"]
|
||||||
|
H["CURRENT STATE<br/>BATCH2_PHASE_B_ACTIVE"]
|
||||||
|
I["NEXT STEP<br/>Batch-2 Phase B closeout<br/>Follow-up carryover + compose hardening"]
|
||||||
|
K["Batch-2 Gate<br/>Phase C -> Global Regression"]
|
||||||
|
J["Operational Rail<br/>Scheduler: Disabled<br/>Manual nightly only"]
|
||||||
|
|
||||||
|
A --> B --> C --> D --> H --> I --> K
|
||||||
|
D --> E --> F --> G --> H
|
||||||
|
E --> J
|
||||||
|
H --> J
|
||||||
|
```
|
||||||
|
|
||||||
|
## Контрольные артефакты
|
||||||
|
|
||||||
|
- Global comparator PASS (reference):
|
||||||
|
`docs/ADDRESS/runs/2026-04-03_Address_Nightly_Regression_Post_AnchorHardening_R6/nightly_summary.json`
|
||||||
|
- Incident run (auto-nightly):
|
||||||
|
`docs/ADDRESS/runs/2026-04-08_Address_Nightly_Regression_2026-04-08_09-52-39/nightly_summary.json`
|
||||||
|
- Control recheck PASS (manual):
|
||||||
|
`docs/ADDRESS/runs/2026-04-08_Address_Nightly_Regression_2026-04-08_10-51-20/nightly_summary.json`
|
||||||
|
- Master checker (entry to Batch-2):
|
||||||
|
`docs/ADDRESS/address_query/step4_wave1_batch1_master_checker_v1.md`
|
||||||
|
- Batch-2 Phase-A artifacts:
|
||||||
|
- `docs/ADDRESS/address_query/domain_general_batch2_lifecycle_card_v1.md`
|
||||||
|
- `docs/ADDRESS/question_sets/domain_general_batch2_lifecycle_acceptance_2026-04-08_phaseA.json`
|
||||||
|
- `docs/ADDRESS/address_query/wave1_batch2_phaseA_probe_report_2026-04-08.md`
|
||||||
|
- `docs/ADDRESS/address_query/step4_wave1_batch2_phaseA_backlog_v1.md`
|
||||||
|
- Batch-2 Phase-B hotpass (resolver drift fix):
|
||||||
|
- `docs/ADDRESS/address_query/wave1_batch2_phaseB_resolver_hotpass_2026-04-08.md`
|
||||||
|
|
||||||
|
## Коротко по статусу
|
||||||
|
|
||||||
|
- Функциональные гейты закрыты.
|
||||||
|
- Точечный flake `S019` закрыт.
|
||||||
|
- Batch-2 переведен в `Phase B active`; resolver drift по `Q12/Q13/Q26/Q27/Q31/Q32` закрыт (`hotpass 6/6`).
|
||||||
|
- Следующий практический шаг: Phase-B closeout (follow-up carryover + compose), затем Batch-2 domain gate.
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Runtime Readiness Matrix V1 (Code Sync)
|
# Runtime Readiness Matrix V1 (Code Sync)
|
||||||
|
|
||||||
Дата: 2026-04-03
|
Дата: 2026-04-08
|
||||||
|
|
||||||
Формат: `scenario -> structural_readiness -> runtime_readiness -> blocker`
|
Формат: `scenario -> structural_readiness -> runtime_readiness -> blocker`
|
||||||
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
| AQ-B1-10 | period_coverage_profile | STRUCTURALLY_VISIBLE | LIVE_QUERYABLE_WITH_LIMITS | functional gates закрыты; остаточный риск в operational стабильности auto-nightly/MCP канала | держать comparator PASS (R6) и переходить к Batch-2 lifecycle |
|
| AQ-B1-10 | period_coverage_profile | STRUCTURALLY_VISIBLE | LIVE_QUERYABLE_WITH_LIMITS | functional gates закрыты; остаточный риск в operational стабильности auto-nightly/MCP канала | держать comparator PASS (R6) и переходить к Batch-2 lifecycle |
|
||||||
| AQ-B1-11 | document_type_and_account_section_profile | STRUCTURALLY_VISIBLE | LIVE_QUERYABLE_WITH_LIMITS | functional gates закрыты; остаточный риск в operational стабильности auto-nightly/MCP канала | держать comparator PASS (R6) и переходить к Batch-2 lifecycle |
|
| AQ-B1-11 | document_type_and_account_section_profile | STRUCTURALLY_VISIBLE | LIVE_QUERYABLE_WITH_LIMITS | functional gates закрыты; остаточный риск в operational стабильности auto-nightly/MCP канала | держать comparator PASS (R6) и переходить к Batch-2 lifecycle |
|
||||||
| AQ-B1-12 | counterparty_population_and_roles | STRUCTURALLY_VISIBLE | LIVE_QUERYABLE_WITH_LIMITS | functional gates закрыты; остаточный риск в operational стабильности auto-nightly/MCP канала | держать comparator PASS (R6) и переходить к Batch-2 lifecycle |
|
| AQ-B1-12 | counterparty_population_and_roles | STRUCTURALLY_VISIBLE | LIVE_QUERYABLE_WITH_LIMITS | functional gates закрыты; остаточный риск в operational стабильности auto-nightly/MCP канала | держать comparator PASS (R6) и переходить к Batch-2 lifecycle |
|
||||||
| AQ-B2-13 | counterparty_activity_lifecycle | STRUCTURALLY_VISIBLE | LIVE_QUERYABLE_WITH_LIMITS | lifecycle-сценарии требуют отдельного доменного live-pack (Batch-2) | собрать Batch-2 acceptance и закрыть route gate |
|
| AQ-B2-13 | counterparty_activity_lifecycle | STRUCTURALLY_VISIBLE | LIVE_QUERYABLE_WITH_LIMITS | resolver drift hotfix закрыт, но Batch-2 domain gate еще не прогнан | закрыть Phase-B (follow-up/compose) и выполнить Batch-2 domain gate |
|
||||||
| AQ-B1-14 | contract_usage_overview | STRUCTURALLY_VISIBLE | LIVE_QUERYABLE_WITH_LIMITS | functional gates закрыты; остаточный риск в operational стабильности auto-nightly/MCP канала | держать comparator PASS (R6) и переходить к Batch-2 lifecycle |
|
| AQ-B1-14 | contract_usage_overview | STRUCTURALLY_VISIBLE | LIVE_QUERYABLE_WITH_LIMITS | functional gates закрыты; остаточный риск в operational стабильности auto-nightly/MCP канала | держать comparator PASS (R6) и переходить к Batch-2 lifecycle |
|
||||||
| AQ-B3-15 | customer_revenue_and_payments | STRUCTURALLY_VISIBLE | LIVE_QUERYABLE_WITH_LIMITS | functional gates закрыты; остаточный риск в operational стабильности auto-nightly/MCP канала | держать comparator PASS (R6) и переходить к Batch-2 lifecycle |
|
| AQ-B3-15 | customer_revenue_and_payments | STRUCTURALLY_VISIBLE | LIVE_QUERYABLE_WITH_LIMITS | functional gates закрыты; остаточный риск в operational стабильности auto-nightly/MCP канала | держать comparator PASS (R6) и переходить к Batch-2 lifecycle |
|
||||||
| AQ-B3-16 | supplier_payouts_profile | STRUCTURALLY_VISIBLE | LIVE_QUERYABLE_WITH_LIMITS | functional gates закрыты; остаточный риск в operational стабильности auto-nightly/MCP канала | держать comparator PASS (R6) и переходить к Batch-2 lifecycle |
|
| AQ-B3-16 | supplier_payouts_profile | STRUCTURALLY_VISIBLE | LIVE_QUERYABLE_WITH_LIMITS | functional gates закрыты; остаточный риск в operational стабильности auto-nightly/MCP канала | держать comparator PASS (R6) и переходить к Batch-2 lifecycle |
|
||||||
|
|
@ -67,6 +67,14 @@
|
||||||
- авто-запуск nightly из Task Scheduler дал `overall_ok=false` из-за инфраструктурного `MCP fetch failed: fetch failed` в части вызовов, не как функциональный откат доменных intent-ов.
|
- авто-запуск nightly из Task Scheduler дал `overall_ok=false` из-за инфраструктурного `MCP fetch failed: fetch failed` в части вызовов, не как функциональный откат доменных intent-ов.
|
||||||
- ручной контрольный nightly (`2026-04-08 10:29`) показал точечный flake в `AQ-P0-07` семействе (`S019`: `materialized_but_not_anchor_matched`), при этом `followup_25` остался `25/25`.
|
- ручной контрольный nightly (`2026-04-08 10:29`) показал точечный flake в `AQ-P0-07` семействе (`S019`: `materialized_but_not_anchor_matched`), при этом `followup_25` остался `25/25`.
|
||||||
- повторный контрольный nightly (`2026-04-08 10:51`) закрыт в `PASS`: `stress_102=102/102`, `followup_25=25/25`, comparator `PASS` (`docs/ADDRESS/runs/2026-04-08_Address_Nightly_Regression_2026-04-08_10-51-20/nightly_summary.json`).
|
- повторный контрольный nightly (`2026-04-08 10:51`) закрыт в `PASS`: `stress_102=102/102`, `followup_25=25/25`, comparator `PASS` (`docs/ADDRESS/runs/2026-04-08_Address_Nightly_Regression_2026-04-08_10-51-20/nightly_summary.json`).
|
||||||
|
- Batch-2 lifecycle Phase-A probe (2026-04-08):
|
||||||
|
- report: `docs/ADDRESS/address_query/wave1_batch2_phaseA_probe_report_2026-04-08.md`
|
||||||
|
- baseline coverage: `semantic_match 4/10`
|
||||||
|
- основные gap-и: `Q12/Q13/Q27` -> `unsupported`, `Q26` -> drift в `counterparty_population_and_roles`, `Q31/Q32` -> drift в anchor-required lookup ветки.
|
||||||
|
- Batch-2 lifecycle Phase-B resolver hotpass (2026-04-08):
|
||||||
|
- report: `docs/ADDRESS/address_query/wave1_batch2_phaseB_resolver_hotpass_2026-04-08.md`
|
||||||
|
- фактический результат: `route match 6/6` на `Q12/Q13/Q26/Q27/Q31/Q32`
|
||||||
|
- кодовый gate: `addressQueryRuntimeM23.test.ts = 210/210`, `build=PASS`.
|
||||||
- `COMPOUND_FACTUAL_QUERY` остается detection-only (без multi-intent execution).
|
- `COMPOUND_FACTUAL_QUERY` остается detection-only (без multi-intent execution).
|
||||||
- Финальные gate-артефакты стабильности:
|
- Финальные gate-артефакты стабильности:
|
||||||
- stress `102/102`: `docs/ADDRESS/runs/2026-04-02_Address_Slang_Live_Stress_2026-04-02_12-57-27/run_summary.json`
|
- stress `102/102`: `docs/ADDRESS/runs/2026-04-02_Address_Slang_Live_Stress_2026-04-02_12-57-27/run_summary.json`
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,15 @@ Batch-1 можно переводить в runtime только после за
|
||||||
- [x] Контрольный nightly recheck (`2026-04-08 10:51`) закрыт в `PASS`
|
- [x] Контрольный nightly recheck (`2026-04-08 10:51`) закрыт в `PASS`
|
||||||
run: `docs/ADDRESS/runs/2026-04-08_Address_Nightly_Regression_2026-04-08_10-51-20/nightly_summary.json`
|
run: `docs/ADDRESS/runs/2026-04-08_Address_Nightly_Regression_2026-04-08_10-51-20/nightly_summary.json`
|
||||||
детали: `stress_102=102/102`, `followup_25=25/25`, comparator PASS.
|
детали: `stress_102=102/102`, `followup_25=25/25`, comparator PASS.
|
||||||
|
- [x] Batch-2 lifecycle Phase A стартован:
|
||||||
|
- `domain_general_batch2_lifecycle_card_v1.md`
|
||||||
|
- `docs/ADDRESS/question_sets/domain_general_batch2_lifecycle_acceptance_2026-04-08_phaseA.json`
|
||||||
|
- `wave1_batch2_phaseA_probe_report_2026-04-08.md`
|
||||||
|
- `step4_wave1_batch2_phaseA_backlog_v1.md`
|
||||||
|
- [x] Batch-2 Phase-B progress:
|
||||||
|
- resolver drift по `Q12/Q13/Q26/Q27/Q31/Q32` закрыт
|
||||||
|
- `addressQueryRuntimeM23.test.ts = 210/210`, `build=PASS`
|
||||||
|
- live hotpass `wave1_batch2_phaseB_resolver_hotpass_2026-04-08.md` (`route match 6/6`)
|
||||||
- [x] Phase B закрыт.
|
- [x] Phase B закрыт.
|
||||||
- [x] Phase C закрыт.
|
- [x] Phase C закрыт.
|
||||||
|
|
||||||
|
|
@ -69,4 +78,4 @@ Batch-1 можно переводить в runtime только после за
|
||||||
|
|
||||||
1. Начинать можно, но строго по фазам выше.
|
1. Начинать можно, но строго по фазам выше.
|
||||||
2. Прямое включение Batch-1 intents в production-path без Phase B/C — запрещено.
|
2. Прямое включение Batch-1 intents в production-path без Phase B/C — запрещено.
|
||||||
3. Точка входа в работу: контрольный nightly уже зафиксирован в `PASS`, следующий шаг — старт Batch-2 lifecycle (`Q8..Q13 + Q26 + Q27 + Q31 + Q32`) по тем же gate-правилам.
|
3. Точка входа в работу: Batch-2 уже в `Phase A active`; следующий шаг — выполнить Batch-2 Phase B и закрыть domain gate/глобальный comparator.
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
# Step-4 Wave-1 Batch-1 — Phase A/B Backlog V1
|
# Step-4 Wave-1 Batch-1 — Phase A/B Backlog V1
|
||||||
|
|
||||||
Дата: 2026-04-02
|
Дата: 2026-04-02
|
||||||
Статус: `active`
|
Статус: `closed` (historical backlog, фактическое закрытие Batch-1/Batch-3 зафиксировано в gate reports)
|
||||||
Scope: `Q1..Q7 + Q28`
|
Scope: `Q1..Q7 + Q28`
|
||||||
|
|
||||||
|
> Примечание на 2026-04-08: файл сохранен как исторический backlog старта Wave-1.
|
||||||
|
> Текущий рабочий backlog для новой волны: `step4_wave1_batch2_phaseA_backlog_v1.md`.
|
||||||
|
|
||||||
## 1. Phase A (Design/Contract) — старт
|
## 1. Phase A (Design/Contract) — старт
|
||||||
|
|
||||||
- [x] Зафиксирован master checker: `step4_wave1_batch1_master_checker_v1.md`
|
- [x] Зафиксирован master checker: `step4_wave1_batch1_master_checker_v1.md`
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
# Step-4 Wave-1 Batch-2 — Phase A/B Backlog V1
|
||||||
|
|
||||||
|
Дата: 2026-04-08
|
||||||
|
Статус: `active`
|
||||||
|
Scope: `Q8..Q13 + Q26 + Q27 + Q31 + Q32`
|
||||||
|
|
||||||
|
## 1. Phase A (Design/Contract) — статус
|
||||||
|
|
||||||
|
- [x] Зафиксирован вход в Batch-2 из master checker: `step4_wave1_batch1_master_checker_v1.md`
|
||||||
|
- [x] Зафиксирована domain card: `domain_general_batch2_lifecycle_card_v1.md`
|
||||||
|
- [x] Сформирован acceptance набор: `domain_general_batch2_lifecycle_acceptance_2026-04-08_phaseA.json`
|
||||||
|
- [x] Выполнен Phase-A probe и зафиксированы gap-ы: `wave1_batch2_phaseA_probe_report_2026-04-08.md`
|
||||||
|
- [ ] Добавить explicit negative-пары (близкие формулировки для anti-drift на lookup intent-ы)
|
||||||
|
|
||||||
|
## 2. Phase B (Runtime Prep) — задачи по коду
|
||||||
|
|
||||||
|
### 2.1 Resolver / Decompose
|
||||||
|
|
||||||
|
- [x] `llm_normalizer/backend/src/services/addressIntentResolver.ts`
|
||||||
|
Добавить сигналы lifecycle для `Q12/Q13/Q27`:
|
||||||
|
- `только один раз`, `single activity`, `one-time`
|
||||||
|
- `дольше всех`, `longest-running`
|
||||||
|
- `давно не использовались` (supplier lifecycle)
|
||||||
|
- [x] `llm_normalizer/backend/src/services/addressIntentResolver.ts`
|
||||||
|
Зафиксировать priority rule:
|
||||||
|
`counterparty_activity_lifecycle` > `counterparty_population_and_roles`
|
||||||
|
для сегментационных формулировок (`регулярные/эпизодические`, `исчезли`, `новые`, `long-term`).
|
||||||
|
- [x] `llm_normalizer/backend/src/services/addressIntentResolver.ts`
|
||||||
|
Добавить contract lifecycle routing:
|
||||||
|
- stale contract phrasing -> `contract_usage_overview`
|
||||||
|
- multi-contract/active contract phrasing -> `contract_usage_and_value`
|
||||||
|
- [ ] `llm_normalizer/backend/src/services/address_runtime/decomposeStage.ts`
|
||||||
|
Усилить follow-up carryover для Batch-2 chain:
|
||||||
|
`а кто новые`, `а кто потом исчез`, `а теперь за 2021`, `и какие договоры активны`.
|
||||||
|
|
||||||
|
### 2.2 Filter / Recipe / Compose
|
||||||
|
|
||||||
|
- [ ] `llm_normalizer/backend/src/services/addressFilterExtractor.ts`
|
||||||
|
Нормализовать lifecycle period cues (`после <год>`, `за <год>`, `впервые в <год>`).
|
||||||
|
- [ ] `llm_normalizer/backend/src/services/address_runtime/composeStage.ts`
|
||||||
|
Добавить стабильные summary-профили для:
|
||||||
|
- new counterparties
|
||||||
|
- lost counterparties
|
||||||
|
- one-time counterparties
|
||||||
|
- long-running counterparties
|
||||||
|
- regular vs episodic suppliers
|
||||||
|
- stale suppliers/contracts
|
||||||
|
- [ ] `llm_normalizer/backend/src/services/address_runtime/composeStage.ts`
|
||||||
|
Для `contract_usage_and_value` добавить блок multi-contract структуры:
|
||||||
|
`контрагент -> количество договоров -> активные/неактивные`.
|
||||||
|
|
||||||
|
### 2.3 Tests / Gates
|
||||||
|
|
||||||
|
- [x] `llm_normalizer/backend/tests/addressQueryRuntimeM23.test.ts`
|
||||||
|
Добавить regression-кейсы под `Q12/Q13/Q26/Q27/Q31/Q32`.
|
||||||
|
- [ ] `llm_normalizer/backend/tests/assistantAddressFollowupContext.test.ts`
|
||||||
|
Добавить lifecycle follow-up chains для переключения года и сегментов.
|
||||||
|
- [x] Кодовый gate:
|
||||||
|
- `npm --prefix llm_normalizer/backend run test -- addressQueryRuntimeM23.test.ts --testTimeout 20000`
|
||||||
|
- `npm --prefix llm_normalizer/backend run build`
|
||||||
|
- [x] Быстрый live hotpass по проблемным маршрутам:
|
||||||
|
- report: `wave1_batch2_phaseB_resolver_hotpass_2026-04-08.md`
|
||||||
|
- result: `route match 6/6`
|
||||||
|
|
||||||
|
## 3. Phase C (Gate) — критерии закрытия
|
||||||
|
|
||||||
|
- [ ] Domain run-pack по
|
||||||
|
`docs/ADDRESS/question_sets/domain_general_batch2_lifecycle_acceptance_2026-04-08_phaseA.json`:
|
||||||
|
- `strict_pass(route)=100%`
|
||||||
|
- `false_factual_rate=0`
|
||||||
|
- `execution_error_rate=0`
|
||||||
|
- [ ] Global non-regression:
|
||||||
|
- `address_slang_stress_full_2026-04-02.json`
|
||||||
|
- `address_followup_context_chains_2026-04-02.json`
|
||||||
|
обе метрики не ниже baseline (`102/102`, `25/25`).
|
||||||
|
- [ ] Comparator PASS against latest green nightly:
|
||||||
|
`docs/ADDRESS/runs/2026-04-08_Address_Nightly_Regression_2026-04-08_10-51-20/nightly_summary.json`
|
||||||
|
|
||||||
|
## 4. Текущий приоритет (следующий кодовый шаг)
|
||||||
|
|
||||||
|
1. Закрыть follow-up carryover для lifecycle/contract lifecycle chain.
|
||||||
|
2. Дожать compose-представления для `stale`/`one-time`/`longest-running`/`regular-vs-episodic`.
|
||||||
|
3. Прогнать полный Batch-2 domain gate pack + global comparator.
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
# Wave-1 Batch-2 Phase-A Probe Report
|
||||||
|
|
||||||
|
Дата: 2026-04-08
|
||||||
|
Контур: `question_mode=address_query`
|
||||||
|
Цель: зафиксировать текущий фактический coverage Batch-2 перед Phase-B implementation.
|
||||||
|
|
||||||
|
## 1. Probe set
|
||||||
|
|
||||||
|
Проверены 10 representative-вопросов:
|
||||||
|
|
||||||
|
- `Q8..Q13` (customer lifecycle)
|
||||||
|
- `Q26..Q27` (supplier lifecycle)
|
||||||
|
- `Q31..Q32` (contract lifecycle/structure)
|
||||||
|
|
||||||
|
## 2. Контур прогона
|
||||||
|
|
||||||
|
Probe выполнен через временный `tsx` harness к `AddressQueryService` с 10 representative-кейсами.
|
||||||
|
Временный script удален после фиксации результата в отчете.
|
||||||
|
|
||||||
|
## 3. Результат
|
||||||
|
|
||||||
|
- `semantic_match = 4/10`
|
||||||
|
- `route coverage = partial`
|
||||||
|
- `execution_error = 0` (в probe-срезе)
|
||||||
|
|
||||||
|
## 4. Детализация по кейсам
|
||||||
|
|
||||||
|
| Q | expected_intent | detected_intent | status | note |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Q8 | `counterparty_activity_lifecycle` | `counterparty_activity_lifecycle` | PASS | factual list |
|
||||||
|
| Q9 | `counterparty_activity_lifecycle` | `counterparty_activity_lifecycle` | PASS | factual list |
|
||||||
|
| Q10 | `counterparty_activity_lifecycle` | `counterparty_activity_lifecycle` | PASS | factual list |
|
||||||
|
| Q11 | `counterparty_activity_lifecycle` | `counterparty_activity_lifecycle` | PASS | factual list |
|
||||||
|
| Q12 | `counterparty_activity_lifecycle` | `unknown` | FAIL | `unsupported` |
|
||||||
|
| Q13 | `counterparty_activity_lifecycle` | `unknown` | FAIL | `unsupported` |
|
||||||
|
| Q26 | `counterparty_activity_lifecycle` | `counterparty_population_and_roles` | FAIL | role-split intent hijack |
|
||||||
|
| Q27 | `counterparty_activity_lifecycle` | `unknown` | FAIL | `unsupported` |
|
||||||
|
| Q31 | `contract_usage_overview` | `list_documents_by_contract` | FAIL | `missing_anchor` drift to lookup |
|
||||||
|
| Q32 | `contract_usage_and_value` | `list_contracts_by_counterparty` | FAIL | `missing_anchor` drift to lookup |
|
||||||
|
|
||||||
|
## 5. Выводы для Phase B
|
||||||
|
|
||||||
|
1. Lifecycle клиентского слоя (`Q8..Q11`) базово работает.
|
||||||
|
2. Не закрыты важные lifecycle сегменты:
|
||||||
|
`one-time`, `longest-running`, `stale suppliers`.
|
||||||
|
3. Есть конфликт маршрутов между lifecycle intent-ом и population/lookup intent-ами:
|
||||||
|
- `Q26` уходит в `counterparty_population_and_roles`;
|
||||||
|
- `Q31/Q32` уходит в anchor-required lookup ветки.
|
||||||
|
|
||||||
|
## 6. Приоритеты исправлений
|
||||||
|
|
||||||
|
1. Resolver-сигналы для `Q12/Q13/Q27` -> `counterparty_activity_lifecycle`.
|
||||||
|
2. Resolver-priority rule: lifecycle segmentation > role population split.
|
||||||
|
3. Contract lifecycle routing:
|
||||||
|
- `stale contracts` -> `contract_usage_overview`;
|
||||||
|
- `multi-contract active map` -> `contract_usage_and_value`.
|
||||||
|
4. Follow-up carryover для lifecycle chain без обязательных anchor-фильтров.
|
||||||
|
|
||||||
|
## 7. Решение
|
||||||
|
|
||||||
|
`READY_FOR_PHASE_B_IMPLEMENTATION`
|
||||||
|
Фаза A закрыта как design/probe baseline; следующий шаг — runtime hardening и domain live-gate Batch-2.
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
# Wave-1 Batch-2 Phase-B Resolver Hotpass
|
||||||
|
|
||||||
|
Дата: 2026-04-08
|
||||||
|
Контур: `question_mode=address_query`
|
||||||
|
Цель: подтвердить устранение resolver drift по критичным Batch-2 lifecycle формулировкам.
|
||||||
|
|
||||||
|
## 1. Проверочный набор
|
||||||
|
|
||||||
|
Проверены бывшие проблемные формулировки:
|
||||||
|
|
||||||
|
1. `Q12` one-time counterparties
|
||||||
|
2. `Q13` longest-running counterparties
|
||||||
|
3. `Q26` regular vs episodic suppliers
|
||||||
|
4. `Q27` stale suppliers
|
||||||
|
5. `Q31` stale contracts
|
||||||
|
6. `Q32` multi-contract counterparties + active contracts
|
||||||
|
|
||||||
|
## 2. Факт результата
|
||||||
|
|
||||||
|
- `route match = 6/6`
|
||||||
|
- `reply_type = factual` по всем 6 кейсам
|
||||||
|
- `mcp_call_status = matched_non_empty` по всем 6 кейсам
|
||||||
|
|
||||||
|
## 3. Детализация
|
||||||
|
|
||||||
|
| case | detected_intent | selected_recipe | status |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| Q12 one-time | `counterparty_activity_lifecycle` | `address_counterparty_activity_lifecycle_v1` | PASS |
|
||||||
|
| Q13 longest-running | `counterparty_activity_lifecycle` | `address_counterparty_activity_lifecycle_v1` | PASS |
|
||||||
|
| Q26 regular/episodic | `counterparty_activity_lifecycle` | `address_counterparty_activity_lifecycle_v1` | PASS |
|
||||||
|
| Q27 stale suppliers | `counterparty_activity_lifecycle` | `address_counterparty_activity_lifecycle_v1` | PASS |
|
||||||
|
| Q31 stale contracts | `contract_usage_overview` | `address_contract_usage_overview_v1` | PASS |
|
||||||
|
| Q32 multi-contract active map | `contract_usage_and_value` | `address_contract_usage_and_value_v1` | PASS |
|
||||||
|
|
||||||
|
## 4. Примечание
|
||||||
|
|
||||||
|
Это не финальный domain gate Batch-2.
|
||||||
|
Следующий шаг: закрыть оставшиеся Phase-B задачи (follow-up carryover + compose нюансы), затем прогнать полный Batch-2 acceptance pack и global comparator.
|
||||||
|
|
@ -0,0 +1,398 @@
|
||||||
|
# ADDRESS Test Questions (обновлено 2026-04-02)
|
||||||
|
|
||||||
|
Важно:
|
||||||
|
1. Цепочки `FOLLOW-UP` прогоняй в одной сессии подряд.
|
||||||
|
2. Блоки `SINGLE` можно гонять по отдельности.
|
||||||
|
3. Для проверок смотри не только ответ, но и `technical_debug_payload_json`.
|
||||||
|
|
||||||
|
## SINGLE: Документы по контрагенту
|
||||||
|
1. Покажи документы по СВК за 2020 год
|
||||||
|
2. свк доки за 20й
|
||||||
|
3. что по свк за 2020 выведи все доки плиз
|
||||||
|
4. Какие документы по контрагенту СВК за весь период
|
||||||
|
5. какие есть доки по свк с 2000 по 2025 год
|
||||||
|
6. Покажи документы по контрагенту СВК
|
||||||
|
|
||||||
|
## SINGLE: Банковские операции
|
||||||
|
7. Покажи банковские операции по СВК за 2020
|
||||||
|
8. Какие платежи по СВК в 2020
|
||||||
|
9. Покажи банковские операции по контрагенту СВК за весь период
|
||||||
|
|
||||||
|
## SINGLE: Договор
|
||||||
|
10. Покажи документы по договору 19/15 за 2020
|
||||||
|
11. Покажи документы по договору 19/15
|
||||||
|
12. Покажи банковские операции по договору 19/15
|
||||||
|
13. Есть ли долг по договору 19/15 на 2020-07-31
|
||||||
|
14. Покажи операции по договору 19/15 за весь период
|
||||||
|
|
||||||
|
## SINGLE: Сальдо / остаток
|
||||||
|
15. Покажи сальдо по счету 60.01 на дату 2020-07-31
|
||||||
|
16. Какой остаток по счету 60 на 2020.05
|
||||||
|
17. Какой остаток по счету 60 на 2020 май
|
||||||
|
18. Какие документы формируют остаток по счету 60.01 на 2020-07-31
|
||||||
|
19. Какой остаток по счету 62 на сегодня
|
||||||
|
|
||||||
|
## FOLLOW-UP CHAIN A (одна сессия)
|
||||||
|
20. Покажи документы по СВК за 2020
|
||||||
|
21. а теперь только за май 2020
|
||||||
|
22. а за все время?
|
||||||
|
23. а по счету 60.01 на ту же дату
|
||||||
|
|
||||||
|
## FOLLOW-UP CHAIN B (одна сессия)
|
||||||
|
24. Покажи банковские операции по договору 19/15
|
||||||
|
25. а за 2020 год
|
||||||
|
26. а теперь только за май 2020
|
||||||
|
27. а по счету 51 на ту же дату
|
||||||
|
|
||||||
|
## FOLLOW-UP CHAIN C (одна сессия)
|
||||||
|
28. Какой остаток по счету 60 на 2020.05
|
||||||
|
29. а теперь по 60.01
|
||||||
|
30. а на ту же дату по 62
|
||||||
|
|
||||||
|
## NOISY / TYPO
|
||||||
|
31. бля епт покажи доки по свк за 20й
|
||||||
|
32. свк 20 год - покажи доки плс
|
||||||
|
33. покажи банк опер по дог 19/15 пж
|
||||||
|
34. остаток 60 на 2020 май покеж
|
||||||
|
35. по свк за весь период че есть
|
||||||
|
|
||||||
|
## NEGATIVE / LIMIT CASE
|
||||||
|
36. Покажи технические константы конфигурации
|
||||||
|
37. кто президент США
|
||||||
|
## SINGLE: Дебиторка / Кредиторка
|
||||||
|
38. Кто нам должен на 2020-12-31
|
||||||
|
39. Кому мы должны на 2020-12-31
|
||||||
|
40. Покажи дебиторскую задолженность за 2020
|
||||||
|
41. Покажи кредиторскую задолженность за 2020
|
||||||
|
|
||||||
|
## SINGLE: Незакрытые договоры / открытые позиции
|
||||||
|
42. Покажи незакрытые договоры на 2020-12-31
|
||||||
|
43. Какие открытые договоры есть на 2020-12-31
|
||||||
|
44. Покажи хвосты по контрагенту СВК на 2020-12-31
|
||||||
|
45. Есть ли незакрытые позиции по договору 19/15 на 2020-12-31
|
||||||
|
46. Покажи открытые позиции по договору 19/15
|
||||||
|
|
||||||
|
## FOLLOW-UP CHAIN D (одна сессия)
|
||||||
|
47. Покажи документы по контрагенту СВК за 2020
|
||||||
|
48. а только за июль 2020
|
||||||
|
49. а теперь банковские операции
|
||||||
|
50. а за весь период
|
||||||
|
51. а сальдо по счету 51 на ту же дату
|
||||||
|
|
||||||
|
## FOLLOW-UP CHAIN E (одна сессия)
|
||||||
|
52. Покажи незакрытые позиции по контрагенту СВК
|
||||||
|
53. а на 2020-12-31
|
||||||
|
54. а теперь по договору 19/15
|
||||||
|
55. а только банковские операции
|
||||||
|
56. а за май 2020
|
||||||
|
|
||||||
|
## EN / Transliteration Stress
|
||||||
|
57. show documents by counterparty svk for 2020
|
||||||
|
58. show bank operations by contract 19/15
|
||||||
|
59. kakoi ostatok po schetu 60.01 na 2020-07-31
|
||||||
|
60. kto nam dolzhen na 2020-12-31
|
||||||
|
|
||||||
|
## SUPPORTED FULL POOL (AUTO, 2026-04-08)
|
||||||
|
|
||||||
|
Срез: 2026-04-08
|
||||||
|
Принцип: включены только вопросы из покрытых доменов/наборов, которые прогонялись в рамках текущего runtime-контура.
|
||||||
|
|
||||||
|
Источники:
|
||||||
|
- docs/ADDRESS/question_sets/address_slang_stress_full_2026-04-02.json
|
||||||
|
- docs/ADDRESS/question_sets/address_followup_context_chains_2026-04-02.json
|
||||||
|
- docs/ADDRESS/question_sets/domain_contracts_open_items_acceptance_2026-04-02.json
|
||||||
|
- docs/ADDRESS/question_sets/domain_general_batch1_acceptance_2026-04-02_phaseA.json
|
||||||
|
- docs/ADDRESS/question_sets/temp_batch3_value_top20_2026-04-02.json
|
||||||
|
- docs/ADDRESS/question_sets/temp_batch2_q8_q9_2026-04-02.json
|
||||||
|
- docs/ADDRESS/question_sets/temp_contracts_zhukovka_targeted_2026-04-02.json
|
||||||
|
- docs/ADDRESS/question_sets/temp_supplier_count_targeted_2026-04-02.json
|
||||||
|
- docs/ADDRESS/question_sets/temp_supplier_client_followup_targeted_2026-04-02.json
|
||||||
|
- docs/ADDRESS/question_sets/address_contract_19_15_postfix_2026-04-02.json
|
||||||
|
|
||||||
|
- Всего уникальных поддерживаемых формулировок в этом пуле: 212
|
||||||
|
|
||||||
|
### Документы по контрагенту (`list_documents_by_counterparty`) — 22
|
||||||
|
1. свк доки за 2020 покаж пж
|
||||||
|
2. покеж все доки по свк за 20 год
|
||||||
|
3. дай список документов по свк за 2020
|
||||||
|
4. какие у свк есть доки за 2020?
|
||||||
|
5. че по свк по докам за 2020 год
|
||||||
|
6. ёпт покажи доки по свк за 2020
|
||||||
|
7. бля, доки свк 2020 вывали
|
||||||
|
8. svk docs for 2020 please
|
||||||
|
9. docs by counterparty svk year 2020
|
||||||
|
10. по контрагенту свк покаж документы за 2020
|
||||||
|
11. плс доки по свк 2020
|
||||||
|
12. свк док за 2020 гони
|
||||||
|
13. свк доки кинь за 2020
|
||||||
|
14. по свк все документы за 20й год
|
||||||
|
15. пж вывали доки контрагент свк 2020
|
||||||
|
16. svk poka docy za 2020
|
||||||
|
17. какие доки по компании свк за 2020
|
||||||
|
18. бля покаж свк документы 2020
|
||||||
|
19. Покажи документы по СВК за 2020
|
||||||
|
20. а теперь только за май 2020
|
||||||
|
21. а теперь документы по нему
|
||||||
|
22. покажи документы все по жуковке 51
|
||||||
|
|
||||||
|
### Банковские операции по контрагенту (`bank_operations_by_counterparty`) — 18
|
||||||
|
1. по свк банковские операции за 2020 покаж
|
||||||
|
2. свк выписка банка 2020
|
||||||
|
3. платежи по свк за 2020 выведи
|
||||||
|
4. оплаты по свк за 2020
|
||||||
|
5. свк банк опер за 2020
|
||||||
|
6. че у свк по банку за 2020
|
||||||
|
7. свк списания/поступления за 2020
|
||||||
|
8. bank ops by svk for 2020
|
||||||
|
9. transactions by counterparty svk 2020
|
||||||
|
10. бля, по свк банковские платежки 2020
|
||||||
|
11. свк банк операции за 2020
|
||||||
|
12. по свк выписку банка за 2020 выведи
|
||||||
|
13. свк платежки за 2020
|
||||||
|
14. bank ops svk 2020
|
||||||
|
15. транзакции по свк за 2020
|
||||||
|
16. ёпт по свк че по банку 2020
|
||||||
|
17. Покажи банковские операции по СВК за 2020
|
||||||
|
18. а теперь только ноябрь 2020
|
||||||
|
|
||||||
|
### Договоры по контрагенту (`list_contracts_by_counterparty`) — 2
|
||||||
|
1. покажи договора все по жуковке 51
|
||||||
|
2. покажи договора по свк
|
||||||
|
|
||||||
|
### Документы по договору (`list_documents_by_contract`) — 16
|
||||||
|
1. покажи документы по договору 19/15 за 2020
|
||||||
|
2. доки по дог. 19/15 за 2020
|
||||||
|
3. какие документы по контракту 19/15
|
||||||
|
4. docs by contract 19/15 year 2020
|
||||||
|
5. бля, покажи по договору 19/15 доки
|
||||||
|
6. договор 19/15 документы
|
||||||
|
7. плс документы договор №19/15
|
||||||
|
8. покеж документы по 19/15
|
||||||
|
9. доки по договору 19/15 за 2020
|
||||||
|
10. покажи документы контракт 19/15
|
||||||
|
11. docs by contract 19/15 2020
|
||||||
|
12. по дог 19/15 какие документы
|
||||||
|
13. договор 19/15 выведи доки
|
||||||
|
14. нах покажи документы по 19/15
|
||||||
|
15. покажи документы по этому же договору
|
||||||
|
16. а документы по этому же договору за тот же период
|
||||||
|
|
||||||
|
### Банковские операции по договору (`bank_operations_by_contract`) — 14
|
||||||
|
1. банковские операции по договору 19/15
|
||||||
|
2. платежи по договору 19/15
|
||||||
|
3. выписка по договору 19/15
|
||||||
|
4. bank ops by contract 19/15
|
||||||
|
5. ёпт, покажи банк операции по дог 19/15
|
||||||
|
6. по контракту 19/15 платежки
|
||||||
|
7. банк операции по договору 19/15
|
||||||
|
8. платежки по дог 19/15
|
||||||
|
9. выписка по контракту 19/15
|
||||||
|
10. покажи банк опер по дог 19/15 пж
|
||||||
|
11. епт транзакции договор 19/15
|
||||||
|
12. а теперь банковские операции
|
||||||
|
13. а теперь только за 2020
|
||||||
|
14. Покажи банковские операции по договору 19/15
|
||||||
|
|
||||||
|
### Остаток / сальдо по счету (`account_balance_snapshot`) — 31
|
||||||
|
1. сальдо по счету 60.01 на дату 2020-07-31
|
||||||
|
2. остаток по счету 60.01 на 2020.05
|
||||||
|
3. покажи остаток по 60.01 за май 2020
|
||||||
|
4. счет 60 остаток на май 2020
|
||||||
|
5. баланс account 60.01 as of 2020-07-31
|
||||||
|
6. 60.01 saldo на 31.07.2020
|
||||||
|
7. сколько на счете 60 на конец 2020-05
|
||||||
|
8. дай остаток 60.02 на 2020-12-31
|
||||||
|
9. епт, сальдо по счету 62.01 на 2020-12-31
|
||||||
|
10. плс остаток по счету 51 на 2020-06-30
|
||||||
|
11. как там по счету 60.01 на 2020.07?
|
||||||
|
12. сальдо 60 на 2020
|
||||||
|
13. покажи сальдо по счету 60 за 2020
|
||||||
|
14. а теперь только май 2020
|
||||||
|
15. ок, теперь 2020.05
|
||||||
|
16. теперь на 2020-07-31
|
||||||
|
17. остаток по 60.01 на 2020-07-31
|
||||||
|
18. сальдо 60.01 на 31.07.2020
|
||||||
|
19. что на счете 60 на 2020.05
|
||||||
|
20. дай остаток 62.01 на 2020 май
|
||||||
|
21. saldo account 60 as of 2020-12-31
|
||||||
|
22. плиз остаток по счету 51 на 2020-06-30
|
||||||
|
23. скока по 60.02 на конец 2020-12
|
||||||
|
24. бля сальдо 60.01 на 2020-05-31
|
||||||
|
25. а по счету 60.01 на ту же дату
|
||||||
|
26. а на ту же дату по 62.01
|
||||||
|
27. и остаток по 51 на ту же дату
|
||||||
|
28. Покажи сальдо по счету 60 на 2020-12-31
|
||||||
|
29. а на ту же дату по 62
|
||||||
|
30. вернись на 2020-12-31 по 60
|
||||||
|
31. а по счету 51 на ту же дату
|
||||||
|
|
||||||
|
### Документы, формирующие остаток (`documents_forming_balance`) — 16
|
||||||
|
1. какие документы формируют остаток по счету 60.01 на 2020-07-31
|
||||||
|
2. из чего состоит остаток по счету 60 на 2020.05
|
||||||
|
3. раскрой остаток 60.01 по документам на конец июля 2020
|
||||||
|
4. доки под остатком 60.01 на 2020-07-31
|
||||||
|
5. documents forming balance for account 60.01 as of 2020-07-31
|
||||||
|
6. бля, какие доки формируют остаток 60.01 на 2020-05-31
|
||||||
|
7. по счету 62.01 раскрой остаток документами на 2020-12-31
|
||||||
|
8. из чего остаток по счету 51 на 2020-06-30
|
||||||
|
9. из чего остаток 60.01 на 2020-07-31
|
||||||
|
10. какие документы формируют остаток по 60.01 на 2020-07-31
|
||||||
|
11. docs forming balance 60.01 as of 2020-07-31
|
||||||
|
12. раскидай остаток 62.01 по докам на 2020-12-31
|
||||||
|
13. по счету 51 раскрой остаток документами на 2020-06-30
|
||||||
|
14. бля из чего состоит остаток по 60.01 на 2020-05-31
|
||||||
|
15. раскрой остаток по 62.01 документами на ту же дату
|
||||||
|
16. раскрой 62 документами на ту же дату
|
||||||
|
|
||||||
|
### Открытые позиции / долг (`open_items_by_counterparty_or_contract`) — 15
|
||||||
|
1. есть ли открытые позиции по договору 19/15 на 2020-12-31
|
||||||
|
2. а теперь открытые позиции по нему
|
||||||
|
3. а теперь на 2020-12-31
|
||||||
|
4. Есть ли долг по договору 19/15 на 2020-07-31
|
||||||
|
5. Есть ли незакрытые позиции по договору 19/15 на 2020-12-31
|
||||||
|
6. Покажи открытые позиции по договору 19/15
|
||||||
|
7. по дог 19/15 есть хвосты на 2020-12-31
|
||||||
|
8. долг по дог 19/15 на 2020-12-31 есть?
|
||||||
|
9. open items by contract 19/15 as of 2020-12-31
|
||||||
|
10. есть ли долг по договору 19/15 на 31.12.2020
|
||||||
|
11. покажи открытые позиции по дог 19/15 на 2020-12-31 пж
|
||||||
|
12. а теперь есть ли долг по договору 19/15 на 2020-12-31
|
||||||
|
13. Есть ли незакрытые позиции по договору 19/15 на 2020-11-30
|
||||||
|
14. Есть ли незакрытые позиции по договору 19/15 на 2022-12-31
|
||||||
|
15. Есть ли незакрытые позиции по договору 19/15 на 2015-12-31
|
||||||
|
|
||||||
|
### Незакрытые договоры (`list_open_contracts`) — 9
|
||||||
|
1. Покажи незакрытые договоры на 2020-12-31
|
||||||
|
2. Show open contracts as of 2020-12-31
|
||||||
|
3. Покажи незакрытые договоры на конец 2020-12-31
|
||||||
|
4. list open contracts for 2020-12-31
|
||||||
|
5. покажи незакрытые договоры на 2020-12-31 пж
|
||||||
|
6. незакрытые договоры на 2020-12-31 гони
|
||||||
|
7. open contracts 2020-12-31 pls
|
||||||
|
8. show open contracts for 2020.12.31
|
||||||
|
9. незакрытые договоры 2020-12-31
|
||||||
|
|
||||||
|
### Покрытие периода и активность (`period_coverage_profile`) — 10
|
||||||
|
1. За какие годы в базе есть данные?
|
||||||
|
2. Какой год самый активный по количеству документов?
|
||||||
|
3. Какой месяц самый активный по количеству операций?
|
||||||
|
4. Покажи профиль данных по базе: диапазон лет, топ год и топ месяц активности.
|
||||||
|
5. за какие года база ваще живая?
|
||||||
|
6. какой год тут самый движовый по докам
|
||||||
|
7. какой месяц прям пик по операциям?
|
||||||
|
8. покажи по базе years/top year/top month, только без воды
|
||||||
|
9. а какой год самый активный по документам?
|
||||||
|
10. а теперь месяц-пик по операциям
|
||||||
|
|
||||||
|
### Типы документов и разделы учета (`document_type_and_account_section_profile`) — 5
|
||||||
|
1. Какие типы документов используются чаще всего в базе?
|
||||||
|
2. Какие разделы учета наиболее заполнены и какие почти не используются?
|
||||||
|
3. Сформируй сводку по типам документов и их доле в общем объеме.
|
||||||
|
4. каких доков у нас больше всего крутится?
|
||||||
|
5. какие разделы учета жирные, а какие мертвые?
|
||||||
|
|
||||||
|
### Контрагенты и роли (`counterparty_population_and_roles`) — 13
|
||||||
|
1. Сколько всего уникальных контрагентов в базе?
|
||||||
|
2. Сколько у нас заказчиков, поставщиков и смешанных контрагентов?
|
||||||
|
3. Сколько контрагентов активны как клиенты и как поставщики?
|
||||||
|
4. скок уник контрагентов вообще есть
|
||||||
|
5. разбей контров на клиентов/поставщиков/смешанных
|
||||||
|
6. а теперь разбей их на заказчиков и поставщиков
|
||||||
|
7. скока всего контрагентов в базе
|
||||||
|
8. скока поставщиков
|
||||||
|
9. скока поставщиков в базе
|
||||||
|
10. скока заказчиков в базе
|
||||||
|
11. скок поставщиков в базе
|
||||||
|
12. скок клиентов
|
||||||
|
13. скок клиентов в базе
|
||||||
|
|
||||||
|
### Активность заказчиков по периодам (`counterparty_activity_lifecycle`) — 5
|
||||||
|
1. Какие заказчики работали с нами в 2020 году?
|
||||||
|
2. Какие заказчики работали с нами за все время?
|
||||||
|
3. какие клиенты у нас были активны в 2020?
|
||||||
|
4. выведи активных клиентов за все время
|
||||||
|
5. а за все время?
|
||||||
|
|
||||||
|
### Использование договорной базы (`contract_usage_overview`) — 5
|
||||||
|
1. Сколько всего договоров заведено и сколько из них реально использовались?
|
||||||
|
2. Дай обзор договорной базы: total договоров и used договоров.
|
||||||
|
3. договоров сколько всего и сколько реально юзались?
|
||||||
|
4. чо по договорной базе: total vs used
|
||||||
|
5. и сразу сколько всего договоров и сколько used
|
||||||
|
|
||||||
|
### Заказчики и поступления (value, top-20) (`customer_revenue_and_payments`) — 17
|
||||||
|
1. Покажи топ-20 заказчиков по сумме поступлений за все время.
|
||||||
|
2. Покажи топ-20 заказчиков по сумме поступлений за 2020 год.
|
||||||
|
3. Покажи топ-20 заказчиков по количеству входящих платежных операций за все время.
|
||||||
|
4. Покажи топ-20 заказчиков по максимальной сумме одной входящей операции за все время.
|
||||||
|
5. Покажи топ-20 заказчиков по среднему чеку среди активных клиентов (минимум 3 входящие операции).
|
||||||
|
6. Покажи топ-20 самых крупных разовых сделок по поступлениям (дата, контрагент, документ, сумма).
|
||||||
|
7. Покажи топ-20 самых маленьких разовых сделок по поступлениям среди активных заказчиков.
|
||||||
|
8. какие клиенты самые доходные, выдай топ-20
|
||||||
|
9. топ-20 заказчиков по деньгам за все время
|
||||||
|
10. за 20й год кто нам больше всего занес, топ-20
|
||||||
|
11. кто платит чаще всего, дай топ-20
|
||||||
|
12. покажи топ-20 самых жирных сделок по поступлениям
|
||||||
|
13. покажи топ-20 самых маленьких сделок по бюджету
|
||||||
|
14. Теперь только за 2020 год, тоже топ-20.
|
||||||
|
15. И отдельно покажи топ-20 по частоте входящих платежей.
|
||||||
|
16. Покажи топ-20 самых крупных разовых сделок по поступлениям.
|
||||||
|
17. А теперь топ-20 самых маленьких сделок по бюджету среди активных заказчиков.
|
||||||
|
|
||||||
|
### Поставщики и выплаты (value, top-20) (`supplier_payouts_profile`) — 10
|
||||||
|
1. Покажи топ-20 поставщиков по сумме выплат за все время.
|
||||||
|
2. Покажи топ-20 поставщиков по сумме выплат за 2020 год.
|
||||||
|
3. Покажи топ-20 поставщиков по количеству исходящих платежных операций за все время.
|
||||||
|
4. Покажи топ-20 самых крупных разовых выплат поставщикам (дата, контрагент, документ, сумма).
|
||||||
|
5. кому мы больше всего сгрузили денег, топ-20 поставщиков
|
||||||
|
6. топ-20 поставщиков по выплатам за все время
|
||||||
|
7. за 2020 год кому ушло больше всего денег, топ-20
|
||||||
|
8. поставщики с максимальным числом выплат, топ-20
|
||||||
|
9. Теперь за 2020 год, тоже топ-20.
|
||||||
|
10. И дай топ-20 поставщиков по количеству выплат.
|
||||||
|
|
||||||
|
### Договоры и суммы (value, top-20) (`contract_usage_and_value`) — 4
|
||||||
|
1. Покажи топ-20 договоров по сумме оборота за все время.
|
||||||
|
2. Покажи топ-20 договоров с минимальным бюджетом среди активных договоров.
|
||||||
|
3. договоры по обороту ранкни и дай топ-20
|
||||||
|
4. покажи топ-20 договоров с самым мелким бюджетом, но только активные
|
||||||
|
|
||||||
|
## FOLLOW-UP CHAINS (из `address_followup_context_chains_2026-04-02.json`)
|
||||||
|
Важно: вопросы внутри каждой цепочки гонять в одной сессии подряд.
|
||||||
|
|
||||||
|
### session: `chain_docs_svk_a`
|
||||||
|
1. Покажи документы по СВК за 2020
|
||||||
|
2. а теперь только за май 2020
|
||||||
|
3. а по счету 60.01 на ту же дату
|
||||||
|
4. а на ту же дату по 62.01
|
||||||
|
5. раскрой остаток по 62.01 документами на ту же дату
|
||||||
|
|
||||||
|
### session: `chain_bank_svk_b`
|
||||||
|
1. Покажи банковские операции по СВК за 2020
|
||||||
|
2. а теперь только ноябрь 2020
|
||||||
|
3. а теперь документы по нему
|
||||||
|
4. и остаток по 51 на ту же дату
|
||||||
|
5. а теперь только май 2020
|
||||||
|
|
||||||
|
### session: `chain_balance_c`
|
||||||
|
1. Покажи сальдо по счету 60 на 2020-12-31
|
||||||
|
2. а теперь только май 2020
|
||||||
|
3. а на ту же дату по 62
|
||||||
|
4. раскрой 62 документами на ту же дату
|
||||||
|
5. вернись на 2020-12-31 по 60
|
||||||
|
|
||||||
|
### session: `chain_contract_d`
|
||||||
|
1. Покажи документы по договору 19/15 за 2020
|
||||||
|
2. а теперь банковские операции
|
||||||
|
3. а теперь только за 2020
|
||||||
|
4. есть ли открытые позиции по договору 19/15 на 2020-12-31
|
||||||
|
5. покажи документы по этому же договору
|
||||||
|
|
||||||
|
### session: `chain_contract_e`
|
||||||
|
1. Покажи банковские операции по договору 19/15
|
||||||
|
2. а теперь открытые позиции по нему
|
||||||
|
3. а теперь на 2020-12-31
|
||||||
|
4. а по счету 51 на ту же дату
|
||||||
|
5. а документы по этому же договору за тот же период
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,266 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "B2_C001",
|
||||||
|
"group": "canonical",
|
||||||
|
"text": "Какие заказчики работали с нами в 2020 году?",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_C002",
|
||||||
|
"group": "canonical",
|
||||||
|
"text": "Какие заказчики работали с нами за все время?",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_C003",
|
||||||
|
"group": "canonical",
|
||||||
|
"text": "Какие заказчики появились у нас впервые в 2020 году?",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_C004",
|
||||||
|
"group": "canonical",
|
||||||
|
"text": "Какие заказчики были активны в 2020 году, но дальше перестали встречаться?",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_C005",
|
||||||
|
"group": "canonical",
|
||||||
|
"text": "Какие контрагенты работали с нами только один раз за все время?",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_C006",
|
||||||
|
"group": "canonical",
|
||||||
|
"text": "Какие контрагенты работают с нами дольше всего по периоду активности?",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_C007",
|
||||||
|
"group": "canonical",
|
||||||
|
"text": "Раздели поставщиков на регулярных и эпизодических по частоте операций.",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_C008",
|
||||||
|
"group": "canonical",
|
||||||
|
"text": "Какие поставщики давно не использовались в операционной активности?",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_C009",
|
||||||
|
"group": "canonical",
|
||||||
|
"text": "Какие договоры давно не использовались (stale contracts)?",
|
||||||
|
"expected_intent": "contract_usage_overview",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_C010",
|
||||||
|
"group": "canonical",
|
||||||
|
"text": "Покажи контрагентов с несколькими договорами и укажи, какие договоры у них активны.",
|
||||||
|
"expected_intent": "contract_usage_and_value",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_C011",
|
||||||
|
"group": "canonical",
|
||||||
|
"text": "Какие заказчики работали с нами в 2021 году?",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_C012",
|
||||||
|
"group": "canonical",
|
||||||
|
"text": "Какие заказчики впервые появились у нас в 2021 году?",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_N001",
|
||||||
|
"group": "noisy_slang",
|
||||||
|
"text": "какие клиенты были активны в 20м",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_N002",
|
||||||
|
"group": "noisy_slang",
|
||||||
|
"text": "выведи всех заков за все время",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_N003",
|
||||||
|
"group": "noisy_slang",
|
||||||
|
"text": "кто к нам пришел впервые в 2020",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_N004",
|
||||||
|
"group": "noisy_slang",
|
||||||
|
"text": "кто был активен в 2020 и потом отвалился",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_N005",
|
||||||
|
"group": "noisy_slang",
|
||||||
|
"text": "кто с нами был ровно один раз и пропал",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_N006",
|
||||||
|
"group": "noisy_slang",
|
||||||
|
"text": "самые старые по сотрудничеству кто",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_N007",
|
||||||
|
"group": "noisy_slang",
|
||||||
|
"text": "разбей поставщиков на регуляр и разовые",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_N008",
|
||||||
|
"group": "noisy_slang",
|
||||||
|
"text": "какие поставщики давно мертвые",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_N009",
|
||||||
|
"group": "noisy_slang",
|
||||||
|
"text": "какие договоры уже протухли и не двигаются",
|
||||||
|
"expected_intent": "contract_usage_overview",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_N010",
|
||||||
|
"group": "noisy_slang",
|
||||||
|
"text": "у кого несколько договоров и какие из них рабочие",
|
||||||
|
"expected_intent": "contract_usage_and_value",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_N011",
|
||||||
|
"group": "noisy_slang",
|
||||||
|
"text": "новые клиенты за 21й год",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_N012",
|
||||||
|
"group": "noisy_slang",
|
||||||
|
"text": "клиенты которые исчезли после 21 года",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_F001",
|
||||||
|
"group": "followup_chain",
|
||||||
|
"session": "b2_customer_lifecycle_chain",
|
||||||
|
"text": "Какие заказчики работали с нами в 2020 году?",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_F002",
|
||||||
|
"group": "followup_chain",
|
||||||
|
"session": "b2_customer_lifecycle_chain",
|
||||||
|
"text": "А кто из них новые?",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_F003",
|
||||||
|
"group": "followup_chain",
|
||||||
|
"session": "b2_customer_lifecycle_chain",
|
||||||
|
"text": "А кто потом исчез?",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_F004",
|
||||||
|
"group": "followup_chain",
|
||||||
|
"session": "b2_customer_lifecycle_chain",
|
||||||
|
"text": "И кто был только один раз?",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_F005",
|
||||||
|
"group": "followup_chain",
|
||||||
|
"session": "b2_supplier_lifecycle_chain",
|
||||||
|
"text": "Раздели поставщиков на регулярных и эпизодических.",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_F006",
|
||||||
|
"group": "followup_chain",
|
||||||
|
"session": "b2_supplier_lifecycle_chain",
|
||||||
|
"text": "Теперь покажи тех, кто давно не использовался.",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_F007",
|
||||||
|
"group": "followup_chain",
|
||||||
|
"session": "b2_contract_lifecycle_chain",
|
||||||
|
"text": "Какие договоры давно не использовались?",
|
||||||
|
"expected_intent": "contract_usage_overview",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_F008",
|
||||||
|
"group": "followup_chain",
|
||||||
|
"session": "b2_contract_lifecycle_chain",
|
||||||
|
"text": "Теперь покажи контрагентов с несколькими договорами.",
|
||||||
|
"expected_intent": "contract_usage_and_value",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_F009",
|
||||||
|
"group": "followup_chain",
|
||||||
|
"session": "b2_contract_lifecycle_chain",
|
||||||
|
"text": "И у них какие договоры сейчас активны?",
|
||||||
|
"expected_intent": "contract_usage_and_value",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_F010",
|
||||||
|
"group": "followup_chain",
|
||||||
|
"session": "b2_year_switch_chain",
|
||||||
|
"text": "Какие заказчики работали с нами в 2020 году?",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_F011",
|
||||||
|
"group": "followup_chain",
|
||||||
|
"session": "b2_year_switch_chain",
|
||||||
|
"text": "Теперь за 2021.",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "B2_F012",
|
||||||
|
"group": "followup_chain",
|
||||||
|
"session": "b2_year_switch_chain",
|
||||||
|
"text": "А кто новые в этом году?",
|
||||||
|
"expected_intent": "counterparty_activity_lifecycle",
|
||||||
|
"expected_mode": "address_query"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
# Graphify for Codex in `NDC_1C`
|
||||||
|
|
||||||
|
This repository now has project-level setup for `graphify` (knowledge graph workflow for Codex).
|
||||||
|
|
||||||
|
## What was added
|
||||||
|
|
||||||
|
- `AGENTS.md` with graph-first Codex rules.
|
||||||
|
- `.graphifyignore` tuned for this repository.
|
||||||
|
- `.gitignore` rules for graphify temporary/build outputs.
|
||||||
|
- `scripts/setup_graphify_codex.ps1` bootstrap script.
|
||||||
|
|
||||||
|
## One-command setup (Windows)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
powershell -ExecutionPolicy Bypass -File .\scripts\setup_graphify_codex.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# do not reinstall pip package
|
||||||
|
powershell -ExecutionPolicy Bypass -File .\scripts\setup_graphify_codex.ps1 -SkipPipInstall
|
||||||
|
|
||||||
|
# also install graphify git hooks (post-commit/post-checkout)
|
||||||
|
powershell -ExecutionPolicy Bypass -File .\scripts\setup_graphify_codex.ps1 -InstallGitHooks
|
||||||
|
```
|
||||||
|
|
||||||
|
## Codex usage
|
||||||
|
|
||||||
|
In Codex chat (skill trigger uses `$`):
|
||||||
|
|
||||||
|
```text
|
||||||
|
$graphify .
|
||||||
|
$graphify . --update
|
||||||
|
$graphify query "what connects routing to runtime?"
|
||||||
|
```
|
||||||
|
|
||||||
|
Main outputs are created in `graphify-out/`:
|
||||||
|
|
||||||
|
- `graphify-out/graph.json`
|
||||||
|
- `graphify-out/GRAPH_REPORT.md`
|
||||||
|
- `graphify-out/graph.html`
|
||||||
|
|
||||||
|
## Important Codex config
|
||||||
|
|
||||||
|
For parallel semantic extraction, make sure `~/.codex/config.toml` contains:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[features]
|
||||||
|
multi_agent = true
|
||||||
|
```
|
||||||
|
|
@ -236,12 +236,27 @@ const COUNTERPARTY_ACTIVITY_LIFECYCLE_HINTS = [
|
||||||
"какие заказчики активны",
|
"какие заказчики активны",
|
||||||
"какие клиенты работали",
|
"какие клиенты работали",
|
||||||
"какие клиенты активны",
|
"какие клиенты активны",
|
||||||
|
"какие контрагенты работали",
|
||||||
|
"какие поставщики работали",
|
||||||
"список заказчиков",
|
"список заказчиков",
|
||||||
"список клиентов",
|
"список клиентов",
|
||||||
"список заказчиков за все время",
|
"список заказчиков за все время",
|
||||||
"список клиентов за все время",
|
"список клиентов за все время",
|
||||||
"список активных заказчиков",
|
"список активных заказчиков",
|
||||||
"список активных клиентов",
|
"список активных клиентов",
|
||||||
|
"новые заказчики",
|
||||||
|
"новые клиенты",
|
||||||
|
"новые контрагенты",
|
||||||
|
"впервые в",
|
||||||
|
"кто исчез",
|
||||||
|
"кто ушел",
|
||||||
|
"кто ушёл",
|
||||||
|
"только один раз",
|
||||||
|
"дольше всех",
|
||||||
|
"долгоживущие контрагенты",
|
||||||
|
"регулярные поставщики",
|
||||||
|
"эпизодические поставщики",
|
||||||
|
"давно не использовались поставщики",
|
||||||
"active customers",
|
"active customers",
|
||||||
"customer activity list",
|
"customer activity list",
|
||||||
"counterparty lifecycle"
|
"counterparty lifecycle"
|
||||||
|
|
@ -255,6 +270,12 @@ const CONTRACT_USAGE_OVERVIEW_HINTS = [
|
||||||
"договоры total vs used",
|
"договоры total vs used",
|
||||||
"обзор договорной базы",
|
"обзор договорной базы",
|
||||||
"договорная база total used",
|
"договорная база total used",
|
||||||
|
"неиспользуемые договоры",
|
||||||
|
"давно не использовались договоры",
|
||||||
|
"мертвые договоры",
|
||||||
|
"мёртвые договоры",
|
||||||
|
"stale contracts",
|
||||||
|
"unused contracts",
|
||||||
"contracts total used",
|
"contracts total used",
|
||||||
"contract usage overview"
|
"contract usage overview"
|
||||||
];
|
];
|
||||||
|
|
@ -296,6 +317,11 @@ const CONTRACT_USAGE_AND_VALUE_HINTS = [
|
||||||
"договоры с минимальным бюджетом",
|
"договоры с минимальным бюджетом",
|
||||||
"договоры с самым маленьким бюджетом",
|
"договоры с самым маленьким бюджетом",
|
||||||
"активные договоры по бюджету",
|
"активные договоры по бюджету",
|
||||||
|
"контрагенты с несколькими договорами",
|
||||||
|
"несколько договоров у контрагента",
|
||||||
|
"мультидоговорные контрагенты",
|
||||||
|
"какие договоры активны",
|
||||||
|
"рабочие договоры",
|
||||||
"contracts by turnover",
|
"contracts by turnover",
|
||||||
"contracts by budget"
|
"contracts by budget"
|
||||||
];
|
];
|
||||||
|
|
@ -506,6 +532,9 @@ function hasDocumentTypeAndAccountSectionProfileSignal(text) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
function hasCounterpartyPopulationAndRolesSignal(text) {
|
function hasCounterpartyPopulationAndRolesSignal(text) {
|
||||||
|
if (hasLifecycleSegmentationSignal(text)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (hasAny(text, COUNTERPARTY_POPULATION_AND_ROLES_HINTS)) {
|
if (hasAny(text, COUNTERPARTY_POPULATION_AND_ROLES_HINTS)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -520,6 +549,9 @@ function hasCounterpartyPopulationAndRolesSignal(text) {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
function hasLifecycleSegmentationSignal(text) {
|
||||||
|
return /(?:вперв|нов(?:ые|ых|ые\s+контрагент|ые\s+клиент|ые\s+заказчик)|исчез|ушед|ушл|только\s+один\s+раз|однораз|дольше\s+всех|долгожив|регулярн|эпизодич|давно\s+не\s+использ|неиспольз|потом\s+перестал)/iu.test(text);
|
||||||
|
}
|
||||||
function hasCounterpartyActivityLifecycleSignal(text) {
|
function hasCounterpartyActivityLifecycleSignal(text) {
|
||||||
if (hasDocumentSignal(text) || hasBankOperationSignal(text)) {
|
if (hasDocumentSignal(text) || hasBankOperationSignal(text)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -530,19 +562,22 @@ function hasCounterpartyActivityLifecycleSignal(text) {
|
||||||
if (/(?:сколько|скока|скок)\s+/iu.test(text)) {
|
if (/(?:сколько|скока|скок)\s+/iu.test(text)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const hasCustomerLexeme = /(?:заказчик(?:ов|а|и)?|клиент(?:ов|а|ы)?|покупател(?:ей|я|и)?|customer(?:s)?|client(?:s)?)/iu.test(text);
|
const hasCounterpartyLexeme = /(?:заказчик(?:ов|а|и)?|клиент(?:ов|а|ы)?|покупател(?:ей|я|и)?|контрагент(?:ов|а|ы)?|поставщик(?:ов|а|и)?|customer(?:s)?|client(?:s)?|counterpart(?:y|ies)|supplier(?:s)?|vendor(?:s)?)/iu.test(text);
|
||||||
const hasActivityLexeme = /(?:работал(?:и)?|активн(?:ые|ых|а|о)?|сотрудничал(?:и)?|были\s+в\s+работе|active)/iu.test(text);
|
const hasActivityLexeme = /(?:работал(?:и)?|активн(?:ые|ых|а|о)?|сотрудничал(?:и)?|были\s+в\s+работе|active|использ(?:овал(?:и|ось)?|уются|ован(?:ы|о)?))/iu.test(text);
|
||||||
const hasTimeWindowLexeme = /(?:за\s+вс[её]\s+время|all\s+time|\b(?:19|20)\d{2}\b|(?:^|[^\d])\d{2}\s*(?:г(?:од|ода)?|г)(?:[^\p{L}\p{N}]|$)|в\s+конкретн(?:ом|ый)\s+год|за\s+год|в\s+году)/iu.test(text);
|
const hasTimeWindowLexeme = /(?:за\s+вс[её]\s+время|all\s+time|\b(?:19|20)\d{2}\b|(?:^|[^\d])\d{2}\s*(?:г(?:од|ода)?|г)(?:[^\p{L}\p{N}]|$)|в\s+конкретн(?:ом|ый)\s+год|за\s+год|в\s+году)/iu.test(text);
|
||||||
const hasListVerb = /(?:какие|кто|покажи|выведи|список|list|show)/iu.test(text);
|
const hasListVerb = /(?:какие|кто|покажи|выведи|список|list|show)/iu.test(text);
|
||||||
const hasRosterQualifier = /(?:у\s+нас|вообще|в\s+баз[еы]|какие\s+есть|кто\s+есть|who\s+are)/iu.test(text);
|
const hasRosterQualifier = /(?:у\s+нас|вообще|в\s+баз[еы]|какие\s+есть|кто\s+есть|who\s+are)/iu.test(text);
|
||||||
const hasListWithWindow = hasCustomerLexeme && hasListVerb && hasTimeWindowLexeme;
|
const hasListWithWindow = hasCounterpartyLexeme && hasListVerb && hasTimeWindowLexeme;
|
||||||
if (hasListWithWindow) {
|
if (hasListWithWindow) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (hasCustomerLexeme && hasListVerb && hasRosterQualifier) {
|
if (hasCounterpartyLexeme && hasListVerb && hasRosterQualifier) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return hasCustomerLexeme && hasActivityLexeme && (hasTimeWindowLexeme || hasListVerb);
|
if (hasCounterpartyLexeme && hasLifecycleSegmentationSignal(text)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return hasCounterpartyLexeme && hasActivityLexeme && (hasTimeWindowLexeme || hasListVerb);
|
||||||
}
|
}
|
||||||
function hasContractUsageOverviewSignal(text) {
|
function hasContractUsageOverviewSignal(text) {
|
||||||
if (hasAny(text, CONTRACT_USAGE_OVERVIEW_HINTS)) {
|
if (hasAny(text, CONTRACT_USAGE_OVERVIEW_HINTS)) {
|
||||||
|
|
@ -557,6 +592,9 @@ function hasContractUsageOverviewSignal(text) {
|
||||||
if (/(?:total\s+vs\s+used|used\s+vs\s+total).*(?:договор|contract)?/iu.test(text)) {
|
if (/(?:total\s+vs\s+used|used\s+vs\s+total).*(?:договор|contract)?/iu.test(text)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (/(?:какие\s+договор(?:ы|а)?).*(?:давно\s+не\s+использ|неиспольз|протух|мертв|мёртв|stale|unused)/iu.test(text)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
function hasCustomerRevenueAndPaymentsSignal(text) {
|
function hasCustomerRevenueAndPaymentsSignal(text) {
|
||||||
|
|
@ -636,9 +674,10 @@ function hasContractUsageAndValueSignal(text) {
|
||||||
if (hasContractUsageOverviewSignal(text)) {
|
if (hasContractUsageOverviewSignal(text)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const asksStructure = /(?:нескольк(?:ими|их|ие|о)?\s+договор|мультидоговор|контрагент(?:ов|ы)?.*нескольк(?:ими|их|ие|о)\s+договор|какие\s+договор(?:ы|а)?\s+активн|рабоч(?:ие|их)\s+договор)/iu.test(text);
|
||||||
const asksValue = /(?:оборот|бюджет|сумм|стоим|value|turnover|amount|revenue|крупн|мелк|миним|максим)/iu.test(text);
|
const asksValue = /(?:оборот|бюджет|сумм|стоим|value|turnover|amount|revenue|крупн|мелк|миним|максим)/iu.test(text);
|
||||||
const asksRank = /(?:топ|top|ранк|rank|сам(?:ый|ая|ое|ые))/iu.test(text);
|
const asksRank = /(?:топ|top|ранк|rank|сам(?:ый|ая|ое|ые))/iu.test(text);
|
||||||
return asksValue || asksRank;
|
return asksStructure || asksValue || asksRank;
|
||||||
}
|
}
|
||||||
function hasContractListByCounterpartySignal(text) {
|
function hasContractListByCounterpartySignal(text) {
|
||||||
const hasContractLexeme = /(?:договор(?:а|у|ом|е|ы)?|contracts?|contract)/iu.test(text);
|
const hasContractLexeme = /(?:договор(?:а|у|ом|е|ы)?|contracts?|contract)/iu.test(text);
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@ const BANK_DOCS_QUERY_TEMPLATE = `
|
||||||
"" КАК СчетДт,
|
"" КАК СчетДт,
|
||||||
"" КАК СчетКт,
|
"" КАК СчетКт,
|
||||||
БанкСписание.СуммаДокумента КАК Сумма,
|
БанкСписание.СуммаДокумента КАК Сумма,
|
||||||
ПРЕДСТАВЛЕНИЕ(БанкСписание.Контрагент) КАК Контрагент
|
ПРЕДСТАВЛЕНИЕ(БанкСписание.Контрагент) КАК Контрагент,
|
||||||
|
ПРЕДСТАВЛЕНИЕ(БанкСписание.ДоговорКонтрагента) КАК Договор
|
||||||
ИЗ
|
ИЗ
|
||||||
Документ.СписаниеСРасчетногоСчета КАК БанкСписание
|
Документ.СписаниеСРасчетногоСчета КАК БанкСписание
|
||||||
__WHERE_OUT__
|
__WHERE_OUT__
|
||||||
|
|
@ -33,7 +34,8 @@ __WHERE_OUT__
|
||||||
"" КАК СчетДт,
|
"" КАК СчетДт,
|
||||||
"" КАК СчетКт,
|
"" КАК СчетКт,
|
||||||
БанкПоступление.СуммаДокумента КАК Сумма,
|
БанкПоступление.СуммаДокумента КАК Сумма,
|
||||||
ПРЕДСТАВЛЕНИЕ(БанкПоступление.Контрагент) КАК Контрагент
|
ПРЕДСТАВЛЕНИЕ(БанкПоступление.Контрагент) КАК Контрагент,
|
||||||
|
ПРЕДСТАВЛЕНИЕ(БанкПоступление.ДоговорКонтрагента) КАК Договор
|
||||||
ИЗ
|
ИЗ
|
||||||
Документ.ПоступлениеНаРасчетныйСчет КАК БанкПоступление
|
Документ.ПоступлениеНаРасчетныйСчет КАК БанкПоступление
|
||||||
__WHERE_IN__
|
__WHERE_IN__
|
||||||
|
|
@ -460,7 +462,8 @@ const BASE_RECIPES = [
|
||||||
optional_filters: ["as_of_date", "counterparty", "contract", "limit"],
|
optional_filters: ["as_of_date", "counterparty", "contract", "limit"],
|
||||||
default_limit: 96,
|
default_limit: 96,
|
||||||
account_scope: ["60", "62", "76"],
|
account_scope: ["60", "62", "76"],
|
||||||
account_scope_mode: "preferred"
|
account_scope_mode: "preferred",
|
||||||
|
query_template: "bank_docs"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
recipe_id: "address_documents_by_counterparty_v1",
|
recipe_id: "address_documents_by_counterparty_v1",
|
||||||
|
|
|
||||||
|
|
@ -2771,6 +2771,41 @@ function isLowQualityPredecomposeCounterpartyAnchor(value) {
|
||||||
});
|
});
|
||||||
return meaningful.length === 0;
|
return meaningful.length === 0;
|
||||||
}
|
}
|
||||||
|
function normalizePredecomposeCounterpartyAnchorTokensForMatch(value) {
|
||||||
|
return normalizePredecomposeAnchorTokens(value).filter((token) => {
|
||||||
|
if (token.length < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (/^(?:19|20)\d{2}$/.test(token)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !ADDRESS_PREDECOMPOSE_LOW_QUALITY_COUNTERPARTY_TOKENS.has(token);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function hasCounterpartyAnchorSubstitution(sourceValue, candidateValue) {
|
||||||
|
const sourceNormalized = String(sourceValue ?? "").trim().toLowerCase().replace(/ё/g, "е");
|
||||||
|
const candidateNormalized = String(candidateValue ?? "").trim().toLowerCase().replace(/ё/g, "е");
|
||||||
|
if (!sourceNormalized || !candidateNormalized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (sourceNormalized === candidateNormalized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (sourceNormalized.includes(candidateNormalized) || candidateNormalized.includes(sourceNormalized)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const sourceTokens = new Set(normalizePredecomposeCounterpartyAnchorTokensForMatch(sourceNormalized));
|
||||||
|
const candidateTokens = normalizePredecomposeCounterpartyAnchorTokensForMatch(candidateNormalized);
|
||||||
|
if (sourceTokens.size === 0 || candidateTokens.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const token of candidateTokens) {
|
||||||
|
if (sourceTokens.has(token)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
function isLowQualityPredecomposeContractAnchor(value) {
|
function isLowQualityPredecomposeContractAnchor(value) {
|
||||||
const normalized = String(value ?? "").trim().toLowerCase().replace(/ё/g, "е");
|
const normalized = String(value ?? "").trim().toLowerCase().replace(/ё/g, "е");
|
||||||
if (!normalized) {
|
if (!normalized) {
|
||||||
|
|
@ -3003,6 +3038,27 @@ async function runAddressLlmPreDecompose(normalizerService, payload, userMessage
|
||||||
sanitizedUserMessage
|
sanitizedUserMessage
|
||||||
}, userMessage);
|
}, userMessage);
|
||||||
}
|
}
|
||||||
|
const counterpartyAnchorSubstitutedByCandidate = sameIntentForAnchorSafety &&
|
||||||
|
sourceAnchorQuality.anchorType === "counterparty" &&
|
||||||
|
candidateAnchorQuality.anchorType === "counterparty" &&
|
||||||
|
sourceAnchorQuality.quality >= 2 &&
|
||||||
|
candidateAnchorQuality.quality >= 2 &&
|
||||||
|
Boolean(sourceAnchorQuality.anchorValue) &&
|
||||||
|
Boolean(candidateAnchorQuality.anchorValue) &&
|
||||||
|
hasCounterpartyAnchorSubstitution(sourceAnchorQuality.anchorValue ?? "", candidateAnchorQuality.anchorValue ?? "");
|
||||||
|
if (counterpartyAnchorSubstitutedByCandidate) {
|
||||||
|
return attachAddressPredecomposeContract({
|
||||||
|
...baseMeta,
|
||||||
|
attempted: true,
|
||||||
|
applied: false,
|
||||||
|
traceId: normalized?.trace_id ?? null,
|
||||||
|
llmCanonicalCandidateDetected: true,
|
||||||
|
effectiveMessage: userMessage,
|
||||||
|
reason: "normalized_fragment_rejected_anchor_substitution",
|
||||||
|
fallbackRuleHit: null,
|
||||||
|
sanitizedUserMessage
|
||||||
|
}, userMessage);
|
||||||
|
}
|
||||||
if (fallbackCandidate) {
|
if (fallbackCandidate) {
|
||||||
const fallbackAnchorQuality = evaluateAddressAnchorQuality(String(fallbackCandidate.candidate ?? ""));
|
const fallbackAnchorQuality = evaluateAddressAnchorQuality(String(fallbackCandidate.candidate ?? ""));
|
||||||
const fallbackPreferredForAnchorSafety = sameIntentForAnchorSafety &&
|
const fallbackPreferredForAnchorSafety = sameIntentForAnchorSafety &&
|
||||||
|
|
|
||||||
|
|
@ -247,12 +247,27 @@ const COUNTERPARTY_ACTIVITY_LIFECYCLE_HINTS = [
|
||||||
"какие заказчики активны",
|
"какие заказчики активны",
|
||||||
"какие клиенты работали",
|
"какие клиенты работали",
|
||||||
"какие клиенты активны",
|
"какие клиенты активны",
|
||||||
|
"какие контрагенты работали",
|
||||||
|
"какие поставщики работали",
|
||||||
"список заказчиков",
|
"список заказчиков",
|
||||||
"список клиентов",
|
"список клиентов",
|
||||||
"список заказчиков за все время",
|
"список заказчиков за все время",
|
||||||
"список клиентов за все время",
|
"список клиентов за все время",
|
||||||
"список активных заказчиков",
|
"список активных заказчиков",
|
||||||
"список активных клиентов",
|
"список активных клиентов",
|
||||||
|
"новые заказчики",
|
||||||
|
"новые клиенты",
|
||||||
|
"новые контрагенты",
|
||||||
|
"впервые в",
|
||||||
|
"кто исчез",
|
||||||
|
"кто ушел",
|
||||||
|
"кто ушёл",
|
||||||
|
"только один раз",
|
||||||
|
"дольше всех",
|
||||||
|
"долгоживущие контрагенты",
|
||||||
|
"регулярные поставщики",
|
||||||
|
"эпизодические поставщики",
|
||||||
|
"давно не использовались поставщики",
|
||||||
"active customers",
|
"active customers",
|
||||||
"customer activity list",
|
"customer activity list",
|
||||||
"counterparty lifecycle"
|
"counterparty lifecycle"
|
||||||
|
|
@ -267,6 +282,12 @@ const CONTRACT_USAGE_OVERVIEW_HINTS = [
|
||||||
"договоры total vs used",
|
"договоры total vs used",
|
||||||
"обзор договорной базы",
|
"обзор договорной базы",
|
||||||
"договорная база total used",
|
"договорная база total used",
|
||||||
|
"неиспользуемые договоры",
|
||||||
|
"давно не использовались договоры",
|
||||||
|
"мертвые договоры",
|
||||||
|
"мёртвые договоры",
|
||||||
|
"stale contracts",
|
||||||
|
"unused contracts",
|
||||||
"contracts total used",
|
"contracts total used",
|
||||||
"contract usage overview"
|
"contract usage overview"
|
||||||
];
|
];
|
||||||
|
|
@ -311,6 +332,11 @@ const CONTRACT_USAGE_AND_VALUE_HINTS = [
|
||||||
"договоры с минимальным бюджетом",
|
"договоры с минимальным бюджетом",
|
||||||
"договоры с самым маленьким бюджетом",
|
"договоры с самым маленьким бюджетом",
|
||||||
"активные договоры по бюджету",
|
"активные договоры по бюджету",
|
||||||
|
"контрагенты с несколькими договорами",
|
||||||
|
"несколько договоров у контрагента",
|
||||||
|
"мультидоговорные контрагенты",
|
||||||
|
"какие договоры активны",
|
||||||
|
"рабочие договоры",
|
||||||
"contracts by turnover",
|
"contracts by turnover",
|
||||||
"contracts by budget"
|
"contracts by budget"
|
||||||
];
|
];
|
||||||
|
|
@ -552,6 +578,9 @@ function hasDocumentTypeAndAccountSectionProfileSignal(text: string): boolean {
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasCounterpartyPopulationAndRolesSignal(text: string): boolean {
|
function hasCounterpartyPopulationAndRolesSignal(text: string): boolean {
|
||||||
|
if (hasLifecycleSegmentationSignal(text)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (hasAny(text, COUNTERPARTY_POPULATION_AND_ROLES_HINTS)) {
|
if (hasAny(text, COUNTERPARTY_POPULATION_AND_ROLES_HINTS)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -575,6 +604,12 @@ function hasCounterpartyPopulationAndRolesSignal(text: string): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasLifecycleSegmentationSignal(text: string): boolean {
|
||||||
|
return /(?:вперв|нов(?:ые|ых|ые\s+контрагент|ые\s+клиент|ые\s+заказчик)|исчез|ушед|ушл|только\s+один\s+раз|однораз|дольше\s+всех|долгожив|регулярн|эпизодич|давно\s+не\s+использ|неиспольз|потом\s+перестал)/iu.test(
|
||||||
|
text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function hasCounterpartyActivityLifecycleSignal(text: string): boolean {
|
function hasCounterpartyActivityLifecycleSignal(text: string): boolean {
|
||||||
if (hasDocumentSignal(text) || hasBankOperationSignal(text)) {
|
if (hasDocumentSignal(text) || hasBankOperationSignal(text)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -585,25 +620,31 @@ function hasCounterpartyActivityLifecycleSignal(text: string): boolean {
|
||||||
if (/(?:сколько|скока|скок)\s+/iu.test(text)) {
|
if (/(?:сколько|скока|скок)\s+/iu.test(text)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const hasCustomerLexeme = /(?:заказчик(?:ов|а|и)?|клиент(?:ов|а|ы)?|покупател(?:ей|я|и)?|customer(?:s)?|client(?:s)?)/iu.test(
|
const hasCounterpartyLexeme = /(?:заказчик(?:ов|а|и)?|клиент(?:ов|а|ы)?|покупател(?:ей|я|и)?|контрагент(?:ов|а|ы)?|поставщик(?:ов|а|и)?|customer(?:s)?|client(?:s)?|counterpart(?:y|ies)|supplier(?:s)?|vendor(?:s)?)/iu.test(
|
||||||
|
text
|
||||||
|
);
|
||||||
|
const hasActivityLexeme =
|
||||||
|
/(?:работал(?:и)?|активн(?:ые|ых|а|о)?|сотрудничал(?:и)?|были\s+в\s+работе|active|использ(?:овал(?:и|ось)?|уются|ован(?:ы|о)?))/iu.test(
|
||||||
text
|
text
|
||||||
);
|
);
|
||||||
const hasActivityLexeme = /(?:работал(?:и)?|активн(?:ые|ых|а|о)?|сотрудничал(?:и)?|были\s+в\s+работе|active)/iu.test(text);
|
|
||||||
const hasTimeWindowLexeme =
|
const hasTimeWindowLexeme =
|
||||||
/(?:за\s+вс[её]\s+время|all\s+time|\b(?:19|20)\d{2}\b|(?:^|[^\d])\d{2}\s*(?:г(?:од|ода)?|г)(?:[^\p{L}\p{N}]|$)|в\s+конкретн(?:ом|ый)\s+год|за\s+год|в\s+году)/iu.test(
|
/(?:за\s+вс[её]\s+время|all\s+time|\b(?:19|20)\d{2}\b|(?:^|[^\d])\d{2}\s*(?:г(?:од|ода)?|г)(?:[^\p{L}\p{N}]|$)|в\s+конкретн(?:ом|ый)\s+год|за\s+год|в\s+году)/iu.test(
|
||||||
text
|
text
|
||||||
);
|
);
|
||||||
const hasListVerb = /(?:какие|кто|покажи|выведи|список|list|show)/iu.test(text);
|
const hasListVerb = /(?:какие|кто|покажи|выведи|список|list|show)/iu.test(text);
|
||||||
const hasRosterQualifier = /(?:у\s+нас|вообще|в\s+баз[еы]|какие\s+есть|кто\s+есть|who\s+are)/iu.test(text);
|
const hasRosterQualifier = /(?:у\s+нас|вообще|в\s+баз[еы]|какие\s+есть|кто\s+есть|who\s+are)/iu.test(text);
|
||||||
const hasListWithWindow = hasCustomerLexeme && hasListVerb && hasTimeWindowLexeme;
|
const hasListWithWindow = hasCounterpartyLexeme && hasListVerb && hasTimeWindowLexeme;
|
||||||
if (hasListWithWindow) {
|
if (hasListWithWindow) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (hasCustomerLexeme && hasListVerb && hasRosterQualifier) {
|
if (hasCounterpartyLexeme && hasListVerb && hasRosterQualifier) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (hasCounterpartyLexeme && hasLifecycleSegmentationSignal(text)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasCustomerLexeme && hasActivityLexeme && (hasTimeWindowLexeme || hasListVerb);
|
return hasCounterpartyLexeme && hasActivityLexeme && (hasTimeWindowLexeme || hasListVerb);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasContractUsageOverviewSignal(text: string): boolean {
|
function hasContractUsageOverviewSignal(text: string): boolean {
|
||||||
|
|
@ -625,6 +666,9 @@ function hasContractUsageOverviewSignal(text: string): boolean {
|
||||||
if (/(?:total\s+vs\s+used|used\s+vs\s+total).*(?:договор|contract)?/iu.test(text)) {
|
if (/(?:total\s+vs\s+used|used\s+vs\s+total).*(?:договор|contract)?/iu.test(text)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (/(?:какие\s+договор(?:ы|а)?).*(?:давно\s+не\s+использ|неиспольз|протух|мертв|мёртв|stale|unused)/iu.test(text)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -724,10 +768,13 @@ function hasContractUsageAndValueSignal(text: string): boolean {
|
||||||
if (hasContractUsageOverviewSignal(text)) {
|
if (hasContractUsageOverviewSignal(text)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const asksStructure = /(?:нескольк(?:ими|их|ие|о)?\s+договор|мультидоговор|контрагент(?:ов|ы)?.*нескольк(?:ими|их|ие|о)\s+договор|какие\s+договор(?:ы|а)?\s+активн|рабоч(?:ие|их)\s+договор)/iu.test(
|
||||||
|
text
|
||||||
|
);
|
||||||
const asksValue =
|
const asksValue =
|
||||||
/(?:оборот|бюджет|сумм|стоим|value|turnover|amount|revenue|крупн|мелк|миним|максим)/iu.test(text);
|
/(?:оборот|бюджет|сумм|стоим|value|turnover|amount|revenue|крупн|мелк|миним|максим)/iu.test(text);
|
||||||
const asksRank = /(?:топ|top|ранк|rank|сам(?:ый|ая|ое|ые))/iu.test(text);
|
const asksRank = /(?:топ|top|ранк|rank|сам(?:ый|ая|ое|ые))/iu.test(text);
|
||||||
return asksValue || asksRank;
|
return asksStructure || asksValue || asksRank;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasContractListByCounterpartySignal(text: string): boolean {
|
function hasContractListByCounterpartySignal(text: string): boolean {
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,8 @@ const BANK_DOCS_QUERY_TEMPLATE = `
|
||||||
"" КАК СчетДт,
|
"" КАК СчетДт,
|
||||||
"" КАК СчетКт,
|
"" КАК СчетКт,
|
||||||
БанкСписание.СуммаДокумента КАК Сумма,
|
БанкСписание.СуммаДокумента КАК Сумма,
|
||||||
ПРЕДСТАВЛЕНИЕ(БанкСписание.Контрагент) КАК Контрагент
|
ПРЕДСТАВЛЕНИЕ(БанкСписание.Контрагент) КАК Контрагент,
|
||||||
|
ПРЕДСТАВЛЕНИЕ(БанкСписание.ДоговорКонтрагента) КАК Договор
|
||||||
ИЗ
|
ИЗ
|
||||||
Документ.СписаниеСРасчетногоСчета КАК БанкСписание
|
Документ.СписаниеСРасчетногоСчета КАК БанкСписание
|
||||||
__WHERE_OUT__
|
__WHERE_OUT__
|
||||||
|
|
@ -37,7 +38,8 @@ __WHERE_OUT__
|
||||||
"" КАК СчетДт,
|
"" КАК СчетДт,
|
||||||
"" КАК СчетКт,
|
"" КАК СчетКт,
|
||||||
БанкПоступление.СуммаДокумента КАК Сумма,
|
БанкПоступление.СуммаДокумента КАК Сумма,
|
||||||
ПРЕДСТАВЛЕНИЕ(БанкПоступление.Контрагент) КАК Контрагент
|
ПРЕДСТАВЛЕНИЕ(БанкПоступление.Контрагент) КАК Контрагент,
|
||||||
|
ПРЕДСТАВЛЕНИЕ(БанкПоступление.ДоговорКонтрагента) КАК Договор
|
||||||
ИЗ
|
ИЗ
|
||||||
Документ.ПоступлениеНаРасчетныйСчет КАК БанкПоступление
|
Документ.ПоступлениеНаРасчетныйСчет КАК БанкПоступление
|
||||||
__WHERE_IN__
|
__WHERE_IN__
|
||||||
|
|
@ -474,7 +476,8 @@ const BASE_RECIPES: AddressRecipeDefinition[] = [
|
||||||
optional_filters: ["as_of_date", "counterparty", "contract", "limit"],
|
optional_filters: ["as_of_date", "counterparty", "contract", "limit"],
|
||||||
default_limit: 96,
|
default_limit: 96,
|
||||||
account_scope: ["60", "62", "76"],
|
account_scope: ["60", "62", "76"],
|
||||||
account_scope_mode: "preferred"
|
account_scope_mode: "preferred",
|
||||||
|
query_template: "bank_docs"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
recipe_id: "address_documents_by_counterparty_v1",
|
recipe_id: "address_documents_by_counterparty_v1",
|
||||||
|
|
|
||||||
|
|
@ -2732,6 +2732,41 @@ function isLowQualityPredecomposeCounterpartyAnchor(value) {
|
||||||
});
|
});
|
||||||
return meaningful.length === 0;
|
return meaningful.length === 0;
|
||||||
}
|
}
|
||||||
|
function normalizePredecomposeCounterpartyAnchorTokensForMatch(value) {
|
||||||
|
return normalizePredecomposeAnchorTokens(value).filter((token) => {
|
||||||
|
if (token.length < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (/^(?:19|20)\d{2}$/.test(token)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !ADDRESS_PREDECOMPOSE_LOW_QUALITY_COUNTERPARTY_TOKENS.has(token);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function hasCounterpartyAnchorSubstitution(sourceValue, candidateValue) {
|
||||||
|
const sourceNormalized = String(sourceValue ?? "").trim().toLowerCase().replace(/ё/g, "е");
|
||||||
|
const candidateNormalized = String(candidateValue ?? "").trim().toLowerCase().replace(/ё/g, "е");
|
||||||
|
if (!sourceNormalized || !candidateNormalized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (sourceNormalized === candidateNormalized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (sourceNormalized.includes(candidateNormalized) || candidateNormalized.includes(sourceNormalized)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const sourceTokens = new Set(normalizePredecomposeCounterpartyAnchorTokensForMatch(sourceNormalized));
|
||||||
|
const candidateTokens = normalizePredecomposeCounterpartyAnchorTokensForMatch(candidateNormalized);
|
||||||
|
if (sourceTokens.size === 0 || candidateTokens.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const token of candidateTokens) {
|
||||||
|
if (sourceTokens.has(token)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
function isLowQualityPredecomposeContractAnchor(value) {
|
function isLowQualityPredecomposeContractAnchor(value) {
|
||||||
const normalized = String(value ?? "").trim().toLowerCase().replace(/ё/g, "е");
|
const normalized = String(value ?? "").trim().toLowerCase().replace(/ё/g, "е");
|
||||||
if (!normalized) {
|
if (!normalized) {
|
||||||
|
|
@ -2964,6 +2999,27 @@ async function runAddressLlmPreDecompose(normalizerService, payload, userMessage
|
||||||
sanitizedUserMessage
|
sanitizedUserMessage
|
||||||
}, userMessage);
|
}, userMessage);
|
||||||
}
|
}
|
||||||
|
const counterpartyAnchorSubstitutedByCandidate = sameIntentForAnchorSafety &&
|
||||||
|
sourceAnchorQuality.anchorType === "counterparty" &&
|
||||||
|
candidateAnchorQuality.anchorType === "counterparty" &&
|
||||||
|
sourceAnchorQuality.quality >= 2 &&
|
||||||
|
candidateAnchorQuality.quality >= 2 &&
|
||||||
|
Boolean(sourceAnchorQuality.anchorValue) &&
|
||||||
|
Boolean(candidateAnchorQuality.anchorValue) &&
|
||||||
|
hasCounterpartyAnchorSubstitution(sourceAnchorQuality.anchorValue ?? "", candidateAnchorQuality.anchorValue ?? "");
|
||||||
|
if (counterpartyAnchorSubstitutedByCandidate) {
|
||||||
|
return attachAddressPredecomposeContract({
|
||||||
|
...baseMeta,
|
||||||
|
attempted: true,
|
||||||
|
applied: false,
|
||||||
|
traceId: normalized?.trace_id ?? null,
|
||||||
|
llmCanonicalCandidateDetected: true,
|
||||||
|
effectiveMessage: userMessage,
|
||||||
|
reason: "normalized_fragment_rejected_anchor_substitution",
|
||||||
|
fallbackRuleHit: null,
|
||||||
|
sanitizedUserMessage
|
||||||
|
}, userMessage);
|
||||||
|
}
|
||||||
if (fallbackCandidate) {
|
if (fallbackCandidate) {
|
||||||
const fallbackAnchorQuality = evaluateAddressAnchorQuality(String(fallbackCandidate.candidate ?? ""));
|
const fallbackAnchorQuality = evaluateAddressAnchorQuality(String(fallbackCandidate.candidate ?? ""));
|
||||||
const fallbackPreferredForAnchorSafety = sameIntentForAnchorSafety &&
|
const fallbackPreferredForAnchorSafety = sameIntentForAnchorSafety &&
|
||||||
|
|
|
||||||
|
|
@ -1383,11 +1383,36 @@ describe("address intent resolver expansion (M2.3a)", () => {
|
||||||
expect(result.intent).toBe("counterparty_activity_lifecycle");
|
expect(result.intent).toBe("counterparty_activity_lifecycle");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("resolves counterparty lifecycle intent for one-time counterparties wording", () => {
|
||||||
|
const result = resolveAddressIntent("Какие контрагенты работали с нами только один раз за все время?");
|
||||||
|
expect(result.intent).toBe("counterparty_activity_lifecycle");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("resolves counterparty lifecycle intent for longest-running counterparties wording", () => {
|
||||||
|
const result = resolveAddressIntent("Какие контрагенты работают с нами дольше всех?");
|
||||||
|
expect(result.intent).toBe("counterparty_activity_lifecycle");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("resolves supplier lifecycle segmentation wording into lifecycle intent", () => {
|
||||||
|
const result = resolveAddressIntent("Раздели поставщиков на регулярных и эпизодических по активности.");
|
||||||
|
expect(result.intent).toBe("counterparty_activity_lifecycle");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("resolves stale suppliers wording into lifecycle intent", () => {
|
||||||
|
const result = resolveAddressIntent("Какие поставщики давно не использовались?");
|
||||||
|
expect(result.intent).toBe("counterparty_activity_lifecycle");
|
||||||
|
});
|
||||||
|
|
||||||
it("resolves contract usage overview intent", () => {
|
it("resolves contract usage overview intent", () => {
|
||||||
const result = resolveAddressIntent("Сколько всего договоров заведено и сколько из них реально использовались?");
|
const result = resolveAddressIntent("Сколько всего договоров заведено и сколько из них реально использовались?");
|
||||||
expect(result.intent).toBe("contract_usage_overview");
|
expect(result.intent).toBe("contract_usage_overview");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("resolves stale contracts wording into contract usage overview intent", () => {
|
||||||
|
const result = resolveAddressIntent("Какие договоры давно не использовались?");
|
||||||
|
expect(result.intent).toBe("contract_usage_overview");
|
||||||
|
});
|
||||||
|
|
||||||
it("resolves customer revenue/payout ranking intent", () => {
|
it("resolves customer revenue/payout ranking intent", () => {
|
||||||
const result = resolveAddressIntent("какие клиенты самые доходные, выдай топ-20");
|
const result = resolveAddressIntent("какие клиенты самые доходные, выдай топ-20");
|
||||||
expect(result.intent).toBe("customer_revenue_and_payments");
|
expect(result.intent).toBe("customer_revenue_and_payments");
|
||||||
|
|
@ -1418,6 +1443,11 @@ describe("address intent resolver expansion (M2.3a)", () => {
|
||||||
expect(result.intent).toBe("contract_usage_and_value");
|
expect(result.intent).toBe("contract_usage_and_value");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("resolves multi-contract counterparties wording into contract usage and value intent", () => {
|
||||||
|
const result = resolveAddressIntent("Покажи контрагентов с несколькими договорами и какие из договоров активны.");
|
||||||
|
expect(result.intent).toBe("contract_usage_and_value");
|
||||||
|
});
|
||||||
|
|
||||||
it("resolves contracts-by-counterparty intent from list wording", () => {
|
it("resolves contracts-by-counterparty intent from list wording", () => {
|
||||||
const result = resolveAddressIntent("покажи договора все по жуковке 51");
|
const result = resolveAddressIntent("покажи договора все по жуковке 51");
|
||||||
expect(result.intent).toBe("list_contracts_by_counterparty");
|
expect(result.intent).toBe("list_contracts_by_counterparty");
|
||||||
|
|
@ -2017,6 +2047,36 @@ describe("address query limited taxonomy and stage diagnostics", () => {
|
||||||
expect(["FACTUAL_LIST", "LIMITED_WITH_REASON", "FACTUAL_SUMMARY"]).toContain(result?.response_type);
|
expect(["FACTUAL_LIST", "LIMITED_WITH_REASON", "FACTUAL_SUMMARY"]).toContain(result?.response_type);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("routes one-time counterparties wording into lifecycle aggregate recipe", async () => {
|
||||||
|
const service = new AddressQueryService();
|
||||||
|
const result = await service.tryHandle("Какие контрагенты работали с нами только один раз за все время?");
|
||||||
|
expect(result?.handled).toBe(true);
|
||||||
|
expect(result?.debug.detected_intent).toBe("counterparty_activity_lifecycle");
|
||||||
|
expect(result?.debug.selected_recipe).toBe("address_counterparty_activity_lifecycle_v1");
|
||||||
|
expect(result?.debug.mcp_call_status).not.toBe("skipped");
|
||||||
|
expect(["FACTUAL_LIST", "LIMITED_WITH_REASON", "FACTUAL_SUMMARY"]).toContain(result?.response_type);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("routes stale contracts wording into contract usage overview recipe", async () => {
|
||||||
|
const service = new AddressQueryService();
|
||||||
|
const result = await service.tryHandle("Какие договоры давно не использовались?");
|
||||||
|
expect(result?.handled).toBe(true);
|
||||||
|
expect(result?.debug.detected_intent).toBe("contract_usage_overview");
|
||||||
|
expect(result?.debug.selected_recipe).toBe("address_contract_usage_overview_v1");
|
||||||
|
expect(result?.debug.mcp_call_status).not.toBe("skipped");
|
||||||
|
expect(["FACTUAL_LIST", "LIMITED_WITH_REASON", "FACTUAL_SUMMARY"]).toContain(result?.response_type);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("routes multi-contract counterparties wording into contract usage and value recipe", async () => {
|
||||||
|
const service = new AddressQueryService();
|
||||||
|
const result = await service.tryHandle("Покажи контрагентов с несколькими договорами и какие из договоров активны.");
|
||||||
|
expect(result?.handled).toBe(true);
|
||||||
|
expect(result?.debug.detected_intent).toBe("contract_usage_and_value");
|
||||||
|
expect(result?.debug.selected_recipe).toBe("address_contract_usage_and_value_v1");
|
||||||
|
expect(result?.debug.mcp_call_status).not.toBe("skipped");
|
||||||
|
expect(["FACTUAL_LIST", "LIMITED_WITH_REASON", "FACTUAL_SUMMARY"]).toContain(result?.response_type);
|
||||||
|
});
|
||||||
|
|
||||||
it("returns missing_anchor for open items without concrete counterparty/contract anchor", async () => {
|
it("returns missing_anchor for open items without concrete counterparty/contract anchor", async () => {
|
||||||
const service = new AddressQueryService();
|
const service = new AddressQueryService();
|
||||||
const result = await service.tryHandle("show open items by contract");
|
const result = await service.tryHandle("show open items by contract");
|
||||||
|
|
@ -2510,6 +2570,22 @@ describe("address recipe catalog counterparty filtering", () => {
|
||||||
expect(plan.limit).toBe(1000);
|
expect(plan.limit).toBe(1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses bank-doc profile with contract projection for open-items anchor matching", () => {
|
||||||
|
const selected = selectAddressRecipe("open_items_by_counterparty_or_contract", {
|
||||||
|
counterparty: "СВК",
|
||||||
|
as_of_date: "2020-12-31"
|
||||||
|
});
|
||||||
|
expect(selected.selected_recipe).toBeTruthy();
|
||||||
|
const plan = buildAddressRecipePlan(selected.selected_recipe!, {
|
||||||
|
counterparty: "СВК",
|
||||||
|
as_of_date: "2020-12-31"
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(plan.query).toContain("Документ.СписаниеСРасчетногоСчета");
|
||||||
|
expect(plan.query).toContain("Документ.ПоступлениеНаРасчетныйСчет");
|
||||||
|
expect(plan.query).toContain("ПРЕДСТАВЛЕНИЕ(БанкПоступление.ДоговорКонтрагента) КАК Договор");
|
||||||
|
});
|
||||||
|
|
||||||
it("allows extended limit for open-contracts intent", () => {
|
it("allows extended limit for open-contracts intent", () => {
|
||||||
const selected = selectAddressRecipe("list_open_contracts", {
|
const selected = selectAddressRecipe("list_open_contracts", {
|
||||||
as_of_date: "2020-12-31",
|
as_of_date: "2020-12-31",
|
||||||
|
|
|
||||||
|
|
@ -348,6 +348,100 @@ describe("assistant address llm pre-decompose candidate preference", () => {
|
||||||
expect(response.debug?.llm_decomposition_reason).not.toBe("normalized_fragment_applied");
|
expect(response.debug?.llm_decomposition_reason).not.toBe("normalized_fragment_applied");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("rejects llm fragment when counterparty anchor is substituted by unrelated noun", async () => {
|
||||||
|
const calls: Array<{ message: string }> = [];
|
||||||
|
const addressQueryService = {
|
||||||
|
tryHandle: vi.fn(async (message: string) => {
|
||||||
|
calls.push({ message });
|
||||||
|
return buildAddressLaneResult(message);
|
||||||
|
})
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const normalizerService = {
|
||||||
|
normalize: vi.fn(async () => ({
|
||||||
|
trace_id: "norm-predecompose-anchor-substitution",
|
||||||
|
ok: true,
|
||||||
|
normalized: {
|
||||||
|
schema_version: "normalized_query_v2_0_2",
|
||||||
|
user_message_raw: "свк доки за 20й",
|
||||||
|
message_in_scope: true,
|
||||||
|
scope_confidence: "medium",
|
||||||
|
contains_multiple_tasks: false,
|
||||||
|
fragments: [
|
||||||
|
{
|
||||||
|
fragment_id: "F1",
|
||||||
|
raw_fragment_text: "свк доки за 20й",
|
||||||
|
normalized_fragment_text: "сканирование документов за 20-й период",
|
||||||
|
domain_relevance: "in_scope",
|
||||||
|
business_scope: "company_specific_accounting",
|
||||||
|
entity_hints: [],
|
||||||
|
account_hints: [],
|
||||||
|
document_hints: ["документы"],
|
||||||
|
register_hints: [],
|
||||||
|
time_scope: {
|
||||||
|
type: "explicit",
|
||||||
|
value: "2020",
|
||||||
|
confidence: "high"
|
||||||
|
},
|
||||||
|
flags: {
|
||||||
|
has_multi_entity_scope: false,
|
||||||
|
asks_for_chain_explanation: false,
|
||||||
|
asks_for_ranking_or_top: false,
|
||||||
|
asks_for_period_summary: false,
|
||||||
|
asks_for_rule_check: false,
|
||||||
|
asks_for_anomaly_scan: false,
|
||||||
|
asks_for_exact_object_trace: false,
|
||||||
|
asks_for_evidence: false,
|
||||||
|
mentions_period_close_context: false
|
||||||
|
},
|
||||||
|
candidate_labels: ["simple_factual"],
|
||||||
|
confidence: "medium",
|
||||||
|
execution_readiness: "executable",
|
||||||
|
clarification_reason: null,
|
||||||
|
soft_assumption_used: [],
|
||||||
|
route_status: "routed",
|
||||||
|
no_route_reason: null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
discarded_fragments: [],
|
||||||
|
global_notes: {
|
||||||
|
needs_clarification: false,
|
||||||
|
clarification_reason: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
raw_model_output: null,
|
||||||
|
validation: { passed: true, errors: [] },
|
||||||
|
usage: { input_tokens: 1, output_tokens: 1, total_tokens: 2 },
|
||||||
|
latency_ms: 10,
|
||||||
|
prompt_version: "normalizer_v2_0_2",
|
||||||
|
schema_version: "v2_0_2",
|
||||||
|
request_count_for_case: 1
|
||||||
|
}))
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const sessions = new AssistantSessionStore();
|
||||||
|
const service = new AssistantService(
|
||||||
|
normalizerService,
|
||||||
|
sessions as any,
|
||||||
|
{} as any,
|
||||||
|
{ persistSession: vi.fn() } as any,
|
||||||
|
addressQueryService
|
||||||
|
);
|
||||||
|
|
||||||
|
const response = await service.handleMessage({
|
||||||
|
session_id: `asst-predecompose-anchor-substitution-${Date.now()}`,
|
||||||
|
user_message: "свк доки за 20й",
|
||||||
|
llmProvider: "local",
|
||||||
|
useMock: false
|
||||||
|
} as any);
|
||||||
|
|
||||||
|
expect(response.ok).toBe(true);
|
||||||
|
expect(calls).toHaveLength(1);
|
||||||
|
expect(calls[0].message.toLowerCase()).toContain("свк");
|
||||||
|
expect(calls[0].message.toLowerCase()).not.toContain("сканирование");
|
||||||
|
expect(response.debug?.llm_decomposition_reason).toBe("normalized_fragment_rejected_anchor_substitution");
|
||||||
|
});
|
||||||
|
|
||||||
it("rejects follow-up intent injection when llm adds documents to same-date account prompt", async () => {
|
it("rejects follow-up intent injection when llm adds documents to same-date account prompt", async () => {
|
||||||
const calls: Array<{ message: string }> = [];
|
const calls: Array<{ message: string }> = [];
|
||||||
const addressQueryService = {
|
const addressQueryService = {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
param(
|
||||||
|
[switch]$SkipPipInstall,
|
||||||
|
[switch]$InstallGitHooks
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
||||||
|
Set-Location $repoRoot
|
||||||
|
|
||||||
|
if (-not $SkipPipInstall) {
|
||||||
|
py -m pip install --user graphifyy
|
||||||
|
}
|
||||||
|
|
||||||
|
py -m graphify install --platform codex
|
||||||
|
py -m graphify codex install
|
||||||
|
|
||||||
|
if ($InstallGitHooks) {
|
||||||
|
py -m graphify hook install
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Graphify configured for Codex in $repoRoot"
|
||||||
|
Write-Host "Use these commands inside Codex:"
|
||||||
|
Write-Host " `$graphify ."
|
||||||
|
Write-Host " `$graphify . --update"
|
||||||
Loading…
Reference in New Issue