diff --git a/docs/ARCH/11 - architecture_turnaround/21 - current_status_canon_2026-05-01.md b/docs/ARCH/11 - architecture_turnaround/21 - current_status_canon_2026-05-01.md index 37c390e..bc66086 100644 --- a/docs/ARCH/11 - architecture_turnaround/21 - current_status_canon_2026-05-01.md +++ b/docs/ARCH/11 - architecture_turnaround/21 - current_status_canon_2026-05-01.md @@ -27,8 +27,9 @@ If another document says `78%`, `87%`, `92%`, or `85%` for a module that is now - Completed active slice: `Business Overview Trading Margin Proxy Bridge`: explicit-period business overview can include a bounded товарный sales-vs-purchase document proxy for revenue, purchase-cost trace, gross spread, and margin proxy, while clean profit/accounting финрезультат remains unclaimed. - Completed active slice: `Business Overview Inventory Sales Velocity Proxy Bridge`: when explicit-period stock and товарные sales evidence are both present, business overview can include a bounded sales-to-stock proxy while full FIFO turnover/liquidity remains unclaimed. - Completed active slice: `Business Overview Inventory Staleness Risk Proxy Bridge`: when current-turn stock aging and sales-to-stock evidence are both present, business overview can include a bounded warehouse staleness-risk proxy while confirmed obsolete stock, reserves, write-offs, and liquidation value remain unclaimed. +- Completed active slice: `Business Overview Gap-Specific Headline And Next-Step Precision`: broad company-analysis answers now name the remaining unchecked families from `missing_signal_families` instead of using stale generic profit/debt/VAT/warehouse wording after partial proxies are proven. - Next active slice: continue breadth into exact company-wide accounting profit/margin, real due-date debt aging, confirmed inventory reserve/write-off/liquidation evidence, and broader unfamiliar 1C route families only where reviewed evidence routes exist. -- Active module progress: `~83% (Open-World Bounded Autonomy Breadth)`. +- Active module progress: `~84% (Open-World Bounded Autonomy Breadth)`. ## Reporting Rule diff --git a/docs/ARCH/11 - architecture_turnaround/22 - open_world_bounded_autonomy_breadth_2026-05-01.md b/docs/ARCH/11 - architecture_turnaround/22 - open_world_bounded_autonomy_breadth_2026-05-01.md index a7efbc4..3960559 100644 --- a/docs/ARCH/11 - architecture_turnaround/22 - open_world_bounded_autonomy_breadth_2026-05-01.md +++ b/docs/ARCH/11 - architecture_turnaround/22 - open_world_bounded_autonomy_breadth_2026-05-01.md @@ -429,3 +429,26 @@ Local validation is accepted for this slice: - `npm.cmd run build`: passed. Graphify rebuild after Slice 13 code/doc sync: `6034 nodes`, `13145 edges`, `136 communities`. + +## Slice 14 - Business Overview Gap-Specific Headline And Next-Step Precision + +This slice does not add a new 1C evidence route. It tightens the user-facing semantics after Slice 13 so the assistant does not keep speaking in older broad gap labels after the runtime has already narrowed the evidence boundary. + +Implemented now: + +- the business-overview headline now describes the remaining inventory gap by the deepest confirmed state: + - no stock signal -> `склад`; + - stock only -> `полноценная складская ликвидность`; + - sales-to-stock proxy -> `FIFO-оборачиваемость/подтвержденная складская ликвидность`; + - staleness-risk proxy -> `резервы/списания/ликвидационная стоимость склада`; +- the business-overview next-step line is generated from `missing_signal_families` instead of a generic "profit/debt/VAT/warehouse" template; +- remaining checks are listed as concrete future work and explicitly separated from already confirmed overview facts. + +This is a semantic-integrity hardening slice inside the breadth module. It makes broad company-analysis answers safer for human review because the answer now explains exactly what is still missing instead of implying that the whole warehouse/liquidity domain remains equally unknown after partial proxies were proven. + +Local validation is accepted for this slice: + +- `npm.cmd test -- assistantMcpDiscoveryAnswerAdapter.test.ts`: passed `34` with `1` skipped. +- `npm.cmd run build`: passed. + +Graphify rebuild after Slice 14 code/doc sync: `6036 nodes`, `13149 edges`, `134 communities`. diff --git a/docs/ARCH/11 - architecture_turnaround/README.md b/docs/ARCH/11 - architecture_turnaround/README.md index 2d91a89..9266324 100644 --- a/docs/ARCH/11 - architecture_turnaround/README.md +++ b/docs/ARCH/11 - architecture_turnaround/README.md @@ -62,6 +62,7 @@ Status canon for planning: - The current completed breadth slice is `Business Overview Trading Margin Proxy Bridge`: explicit-period company analysis can now include товарный sales-vs-purchase document proxy for revenue, purchase-cost trace, gross spread, and margin proxy, while clean profit/accounting финрезультат remains unclaimed. - The current completed breadth slice is `Business Overview Inventory Sales Velocity Proxy Bridge`: when explicit-period stock and sales evidence are both present, company analysis can include a bounded sales-to-stock proxy while full FIFO/liquidity/obsolescence remains unclaimed. - The current completed breadth slice is `Business Overview Inventory Staleness Risk Proxy Bridge`: when current-turn stock aging and sales-to-stock evidence are both present, company analysis can include a bounded staleness-risk proxy while confirmed obsolete stock, reserves, write-offs, and liquidation value remain unclaimed. +- The current completed breadth slice is `Business Overview Gap-Specific Headline And Next-Step Precision`: business-overview answers now name remaining unchecked families from `missing_signal_families` instead of falling back to stale generic gap wording. - The next active breadth slice continues breadth into exact company-wide accounting profit/margin, real due-date debt aging, confirmed reserve/write-off/liquidation inventory evidence, and broader unfamiliar 1C route families without relaxing truth boundaries. - The short source of truth for status wording is [21 - current_status_canon_2026-05-01.md](./21%20-%20current_status_canon_2026-05-01.md). @@ -127,11 +128,11 @@ Current honest status: - pre-multidomain readiness: `~90%` - bounded-autonomy foundation readiness: `~89%` - open-world bounded-autonomy readiness: `~87%` -- active Open-World Bounded Autonomy Breadth progress: `~83%`, with business-overview evidence fusion, the reviewed `business_overview` catalog/data-need/planner route-fabric slice, the fresh multi-probe runtime bridge, the explicit-period VAT/tax fact-family bridge, the explicit-period debt-position bridge, the explicit-date inventory-position bridge, the open-settlement quality bridge accepted by live semantic replay, selected-item profitability bridged by local semantic/runtime regression tests, contract-date debt age bridged locally, analyst synthesis added to business-overview answer drafting, company-period trading margin proxy bridged locally, inventory sales-to-stock proxy bridged locally, and inventory staleness-risk proxy bridged locally; exact accounting profit/margin, true due-date debt aging/overdue, and confirmed reserve/write-off/liquidation inventory evidence are still pending +- active Open-World Bounded Autonomy Breadth progress: `~84%`, with business-overview evidence fusion, the reviewed `business_overview` catalog/data-need/planner route-fabric slice, the fresh multi-probe runtime bridge, the explicit-period VAT/tax fact-family bridge, the explicit-period debt-position bridge, the explicit-date inventory-position bridge, the open-settlement quality bridge accepted by live semantic replay, selected-item profitability bridged by local semantic/runtime regression tests, contract-date debt age bridged locally, analyst synthesis added to business-overview answer drafting, company-period trading margin proxy bridged locally, inventory sales-to-stock proxy bridged locally, inventory staleness-risk proxy bridged locally, and gap-specific answer shaping bridged locally; exact accounting profit/margin, true due-date debt aging/overdue, and confirmed reserve/write-off/liquidation inventory evidence are still pending - Post-F semantic integrity module progress: `~99%` operationally closed, with remaining risk now treated as next-slice discovery rather than an open blocker inside the closed slice - active inventory-stock breadth slice progress: `100%` for the declared scenario pack, not for arbitrary inventory questions - Planner Autonomy Consolidation progress: `100%` for the declared module, with catalog-fabric, value-flow arbitration, lifecycle bounded inference, broad-evaluation bridge, inventory catalog templates, inventory runtime-boundary honesty, exact inventory recipe bridging, unambiguous metadata-surface lane inference, catalog chain-template scoring, structured chain-match contract exposure, runtime/debug propagation, subject-aware bidirectional comparison arbitration, structured catalog-alignment verdicts, representative alignment regression guard, catalog-alignment reason-code telemetry, explicit `alignment_status` propagation, truth-harness/acceptance-matrix surfacing, soft divergence warning, `catalog_alignment_ok` acceptance invariant, step-level expected catalog-alignment assertions, phase66 and phase32 spec alignment expectations, AGENT source-catalog surfacing, generated phase83 mixed planner-brain replay spec, checked-source user-facing error sanitation, surface-grounded catalog promotion, and guarded live phase83 acceptance validated. Broader unfamiliar 1C asks are now next-module breadth work rather than an open blocker inside this declared slice -- graph snapshot after latest rebuild: `6034 nodes`, `13145 edges`, `136 communities` +- graph snapshot after latest rebuild: `6036 nodes`, `13149 edges`, `134 communities` - current regression-gate breakpoint: - the validated hot paths are no longer structurally broken; - flagship continuity collapse is no longer the primary risk; @@ -181,6 +182,7 @@ Latest live proof now includes: - business-overview contract-date debt age signal accepted locally: targeted executor/answer-adapter slice passed `65/65` with `1` skipped; full MCP-discovery slice passed `305/305` with `9` skipped; build passed; graphify rebuilt to `6016 nodes`, `13098 edges`, `139 communities`; contract-date age is surfaced as a bounded signal while due-date aging/overdue debt remains unclaimed - business-overview analyst synthesis accepted locally: answer-adapter slice passed `34/34` with `1` skipped; full MCP-discovery slice passed `305/305` with `9` skipped; build passed; graphify rebuilt to `6023 nodes`, `13112 edges`, `136 communities`; broad company-analysis drafts now include operating scale, customer concentration, risk contours, and bounded LLM-audit inference lines - business-overview inventory staleness-risk proxy accepted locally: targeted executor/answer-adapter slice passed `66/66` with `1` skipped; M23 route/runtime regression passed `412/412`; build passed; graphify rebuilt to `6034 nodes`, `13145 edges`, `136 communities`; the proxy combines stock aging and sales-to-stock ratio while confirmed obsolete stock, reserves, write-offs, and liquidation value remain unclaimed +- business-overview gap-specific answer shaping accepted locally: answer-adapter slice passed `34/34` with `1` skipped; build passed; graphify rebuilt to `6036 nodes`, `13149 edges`, `134 communities`; headline and next-step wording now follow `missing_signal_families` instead of stale generic gap labels - inventory template lift accepted locally: catalog/data-need/planner/turn-input slice passed `139/139` with `6` skipped; full MCP-discovery slice passed `276/276` with `9` skipped; build passed; graphify stayed at `5912 nodes`, `12833 edges`, `138 communities` - inventory runtime-boundary hardening accepted locally: runtime-bridge/answer-adapter/pilot-executor slice passed `68/68` with `1` skipped; full MCP-discovery slice passed `277/277` with `9` skipped; build passed; graphify rebuilt to `5913 nodes`, `12837 edges`, `138 communities` - inventory exact-runtime bridge accepted locally: runtime-bridge/answer-adapter/pilot-executor slice passed `70/70` with `1` skipped; full MCP-discovery slice passed `279/279` with `9` skipped; build passed; graphify rebuilt to `5930 nodes`, `12884 edges`, `135 communities` diff --git a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryAnswerAdapter.js b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryAnswerAdapter.js index 696c18e..1b42418 100644 --- a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryAnswerAdapter.js +++ b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryAnswerAdapter.js @@ -321,6 +321,56 @@ function metadataRouteFamilyLabelRu(routeFamily) { } return null; } +function businessOverviewInventoryUnknownLabel(overview) { + if (overview.inventory_staleness_risk_proxy) { + return "резервы/списания/ликвидационная стоимость склада"; + } + if (overview.inventory_turnover_proxy) { + return "FIFO-оборачиваемость/подтвержденная складская ликвидность"; + } + if (overview.inventory_position) { + return "полноценная складская ликвидность"; + } + return "склад"; +} +function businessOverviewNextStepLine(overview) { + const missing = new Set(overview.missing_signal_families); + const checks = []; + if (missing.has("profit_or_clean_margin")) { + checks.push("чистую прибыль через себестоимость продаж, расходы и закрытие периода"); + } + else if (missing.has("profit_or_margin")) { + checks.push("прибыль/маржу по проверенному финрезультату"); + } + if (missing.has("tax_position")) { + checks.push("НДС/налоговую позицию за явный период"); + } + if (missing.has("debt_due_date_aging_quality")) { + checks.push("договорные сроки оплаты и due-date aging"); + } + else if (missing.has("debt_open_settlement_quality")) { + checks.push("качество открытых расчетов"); + } + else if (missing.has("debt_position")) { + checks.push("долговой срез на дату"); + } + if (missing.has("inventory_reserve_liquidation_quality")) { + checks.push("резервы, списания, неликвидность и ликвидационную стоимость склада"); + } + else if (missing.has("inventory_liquidity_quality")) { + checks.push("FIFO-оборачиваемость и подтвержденную складскую ликвидность"); + } + else if (missing.has("inventory_turnover_quality")) { + checks.push("скорость продаж и оборачиваемость склада"); + } + else if (missing.has("inventory_position")) { + checks.push("складской остаток на дату"); + } + const target = checks.length > 0 + ? checks.join("; ") + : "оставшиеся непроверенные области по выбранному контуру"; + return `Следующий шаг для полного бизнес-аудита: отдельно проверить ${target}, не смешивая эти будущие проверки с уже подтвержденным обзором.`; +} function headlineFor(mode, pilot) { const askedMonthlyBreakdown = pilot.derived_bidirectional_value_flow?.aggregation_axis === "month" || pilot.derived_value_flow?.aggregation_axis === "month"; @@ -378,7 +428,7 @@ function headlineFor(mode, pilot) { unknownFamilies.push("долговой срез"); } unknownFamilies.push(overview.debt_open_settlement_quality ? "due-date просрочка" : "качество открытых расчетов"); - unknownFamilies.push(overview.inventory_position ? "полноценная складская ликвидность" : "склад"); + unknownFamilies.push(businessOverviewInventoryUnknownLabel(overview)); return `По данным 1С собран ограниченный бизнес-обзор: ${families.join(", ")} подтверждены найденными строками; ${unknownFamilies.join(", ")} остаются отдельными непроверенными областями.`; } if (isBusinessOverviewPilot(pilot) && mode === "checked_sources_only") { @@ -521,7 +571,9 @@ function nextStepFor(mode, pilot) { return "Следующий шаг - связать inventory route-template с exact inventory runtime и затем проверить live-прогоном."; } if (mode === "confirmed_with_bounded_inference" && isBusinessOverviewPilot(pilot)) { - return "Если нужен уже управленческий вывод, следующим шагом стоит отдельно проверить прибыль/маржу, долги, НДС и складскую ликвидность, а затем собрать полный бизнес-аудит."; + return pilot.derived_business_overview + ? businessOverviewNextStepLine(pilot.derived_business_overview) + : "Если нужен уже управленческий вывод, следующим шагом стоит отдельно проверить прибыль/маржу, долги, НДС и складскую ликвидность, а затем собрать полный бизнес-аудит."; } if (mode === "confirmed_with_bounded_inference" && pilot.derived_metadata_surface) { const surface = pilot.derived_metadata_surface; diff --git a/llm_normalizer/backend/src/services/assistantMcpDiscoveryAnswerAdapter.ts b/llm_normalizer/backend/src/services/assistantMcpDiscoveryAnswerAdapter.ts index 7752a81..5ad8100 100644 --- a/llm_normalizer/backend/src/services/assistantMcpDiscoveryAnswerAdapter.ts +++ b/llm_normalizer/backend/src/services/assistantMcpDiscoveryAnswerAdapter.ts @@ -421,6 +421,52 @@ function metadataRouteFamilyLabelRu( return null; } +function businessOverviewInventoryUnknownLabel(overview: BusinessOverview): string { + if (overview.inventory_staleness_risk_proxy) { + return "резервы/списания/ликвидационная стоимость склада"; + } + if (overview.inventory_turnover_proxy) { + return "FIFO-оборачиваемость/подтвержденная складская ликвидность"; + } + if (overview.inventory_position) { + return "полноценная складская ликвидность"; + } + return "склад"; +} + +function businessOverviewNextStepLine(overview: BusinessOverview): string { + const missing = new Set(overview.missing_signal_families); + const checks: string[] = []; + if (missing.has("profit_or_clean_margin")) { + checks.push("чистую прибыль через себестоимость продаж, расходы и закрытие периода"); + } else if (missing.has("profit_or_margin")) { + checks.push("прибыль/маржу по проверенному финрезультату"); + } + if (missing.has("tax_position")) { + checks.push("НДС/налоговую позицию за явный период"); + } + if (missing.has("debt_due_date_aging_quality")) { + checks.push("договорные сроки оплаты и due-date aging"); + } else if (missing.has("debt_open_settlement_quality")) { + checks.push("качество открытых расчетов"); + } else if (missing.has("debt_position")) { + checks.push("долговой срез на дату"); + } + if (missing.has("inventory_reserve_liquidation_quality")) { + checks.push("резервы, списания, неликвидность и ликвидационную стоимость склада"); + } else if (missing.has("inventory_liquidity_quality")) { + checks.push("FIFO-оборачиваемость и подтвержденную складскую ликвидность"); + } else if (missing.has("inventory_turnover_quality")) { + checks.push("скорость продаж и оборачиваемость склада"); + } else if (missing.has("inventory_position")) { + checks.push("складской остаток на дату"); + } + const target = checks.length > 0 + ? checks.join("; ") + : "оставшиеся непроверенные области по выбранному контуру"; + return `Следующий шаг для полного бизнес-аудита: отдельно проверить ${target}, не смешивая эти будущие проверки с уже подтвержденным обзором.`; +} + function headlineFor(mode: AssistantMcpDiscoveryAnswerMode, pilot: AssistantMcpDiscoveryPilotExecutionContract): string { const askedMonthlyBreakdown = pilot.derived_bidirectional_value_flow?.aggregation_axis === "month" || @@ -481,7 +527,7 @@ function headlineFor(mode: AssistantMcpDiscoveryAnswerMode, pilot: AssistantMcpD unknownFamilies.push("долговой срез"); } unknownFamilies.push(overview.debt_open_settlement_quality ? "due-date просрочка" : "качество открытых расчетов"); - unknownFamilies.push(overview.inventory_position ? "полноценная складская ликвидность" : "склад"); + unknownFamilies.push(businessOverviewInventoryUnknownLabel(overview)); return `По данным 1С собран ограниченный бизнес-обзор: ${families.join(", ")} подтверждены найденными строками; ${unknownFamilies.join(", ")} остаются отдельными непроверенными областями.`; } if (isBusinessOverviewPilot(pilot) && mode === "checked_sources_only") { @@ -631,7 +677,9 @@ function nextStepFor(mode: AssistantMcpDiscoveryAnswerMode, pilot: AssistantMcpD return "Следующий шаг - связать inventory route-template с exact inventory runtime и затем проверить live-прогоном."; } if (mode === "confirmed_with_bounded_inference" && isBusinessOverviewPilot(pilot)) { - return "Если нужен уже управленческий вывод, следующим шагом стоит отдельно проверить прибыль/маржу, долги, НДС и складскую ликвидность, а затем собрать полный бизнес-аудит."; + return pilot.derived_business_overview + ? businessOverviewNextStepLine(pilot.derived_business_overview) + : "Если нужен уже управленческий вывод, следующим шагом стоит отдельно проверить прибыль/маржу, долги, НДС и складскую ликвидность, а затем собрать полный бизнес-аудит."; } if (mode === "confirmed_with_bounded_inference" && pilot.derived_metadata_surface) { const surface = pilot.derived_metadata_surface; diff --git a/llm_normalizer/backend/tests/assistantMcpDiscoveryAnswerAdapter.test.ts b/llm_normalizer/backend/tests/assistantMcpDiscoveryAnswerAdapter.test.ts index f9c6ef9..73693a9 100644 --- a/llm_normalizer/backend/tests/assistantMcpDiscoveryAnswerAdapter.test.ts +++ b/llm_normalizer/backend/tests/assistantMcpDiscoveryAnswerAdapter.test.ts @@ -489,6 +489,8 @@ describe("assistant MCP discovery answer adapter", () => { expect(draft.headline).toContain("складской срез"); expect(draft.headline).toContain("оборотный proxy склада"); expect(draft.headline).toContain("staleness risk proxy склада"); + expect(draft.headline).toContain("резервы/списания/ликвидационная стоимость склада"); + expect(draft.headline).not.toContain("полноценная складская ликвидность"); expect(draft.confirmed_lines.join("\n")).toContain("Складской срез на 2020-12-31"); expect(draft.confirmed_lines.join("\n")).toContain("Товар А"); expect(draft.confirmed_lines.join("\n")).toContain("Оборотный proxy склада за 2020"); @@ -498,6 +500,9 @@ describe("assistant MCP discovery answer adapter", () => { expect(draft.inference_lines.join("\n")).toContain("оборотный proxy склада"); expect(draft.inference_lines.join("\n")).toContain("staleness risk proxy склада"); expect(draft.unknown_lines.join("\n")).toContain("Резервы"); + expect(draft.next_step_line).toContain("НДС/налоговую позицию за явный период"); + expect(draft.next_step_line).toContain("качество открытых расчетов"); + expect(draft.next_step_line).toContain("резервы, списания, неликвидность и ликвидационную стоимость склада"); expect(draft.reason_codes).toContain("answer_contains_business_overview_inventory_position"); expect(draft.reason_codes).toContain("answer_contains_business_overview_inventory_turnover_proxy"); expect(draft.reason_codes).toContain("answer_contains_business_overview_inventory_staleness_risk_proxy");