Open-World: закрепить границу складского неликвида
This commit is contained in:
parent
264cbcee12
commit
2b2e37acce
|
|
@ -34,8 +34,9 @@ If another document says `78%`, `87%`, `92%`, or `85%` for a module that is now
|
|||
- Completed active slice: `Business Overview Earnings Wording Arbitration Bridge`: organization-level earnings/best-year/overall-turnover wording now routes to `business_overview` instead of the exact customer-value lane, while explicit customer/counterparty wording remains in `customer_revenue_and_payments`.
|
||||
- Completed active slice: `Business Overview Profit/Margin Wording Boundary Bridge`: organization-level profit, margin, financial-result, and P&L wording now routes to `business_overview` with clean-profit boundary wording, while explicit customer/item/contract routes still use exact recipes.
|
||||
- Completed active slice: `Business Overview Debt Due-Date Boundary Bridge`: organization-level overdue debt, debt quality, debt aging, due-date, and credit-risk wording now routes to `business_overview`, while explicit buyer/debtor lists stay in exact receivables routes with a due-date proof boundary.
|
||||
- Completed active slice: `Business Overview Inventory Reserve/Liquidation Boundary Bridge`: organization-level inventory reserve, write-off, obsolete-stock, and liquidation-value wording now routes to `business_overview`, while explicit item/stock lists stay in exact inventory routes with a reserve/liquidation proof boundary.
|
||||
- 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: `~94% (Open-World Bounded Autonomy Breadth)`.
|
||||
- Active module progress: `~95% (Open-World Bounded Autonomy Breadth)`.
|
||||
|
||||
## Reporting Rule
|
||||
|
||||
|
|
@ -72,7 +73,7 @@ The project is not yet a universal arbitrary-1C agent.
|
|||
|
||||
Remaining work belongs to the next breadth module:
|
||||
|
||||
- extend `business_overview` beyond money-flow/activity, customer and supplier concentration, yearly operating-flow dynamics, explicit profit/margin wording boundaries, explicit debt due-date wording boundaries, explicit-period VAT/tax, as-of-date debt position, open-settlement concentration, contract-date debt age, debt staleness-risk proxy, as-of-date inventory position, trading-margin proxy, sales-to-stock inventory proxy, and warehouse staleness-risk proxy into separately proven exact accounting profit/margin, due-date debt aging/overdue, and confirmed reserve/write-off/liquidation inventory evidence families;
|
||||
- extend `business_overview` beyond money-flow/activity, customer and supplier concentration, yearly operating-flow dynamics, explicit profit/margin wording boundaries, explicit debt due-date wording boundaries, explicit inventory reserve/liquidation wording boundaries, explicit-period VAT/tax, as-of-date debt position, open-settlement concentration, contract-date debt age, debt staleness-risk proxy, as-of-date inventory position, trading-margin proxy, sales-to-stock inventory proxy, and warehouse staleness-risk proxy into separately proven exact accounting profit/margin, due-date debt aging/overdue, and confirmed reserve/write-off/liquidation inventory evidence families;
|
||||
- broader dynamic schema traversal for unfamiliar 1C asks;
|
||||
- more primitive descriptors where live evidence proves a real gap;
|
||||
- more replay-backed domain packs that start from user business meaning, not from route convenience;
|
||||
|
|
|
|||
|
|
@ -600,3 +600,26 @@ Local validation is accepted for this slice:
|
|||
- `npm.cmd run build`: passed.
|
||||
|
||||
Graphify rebuild after Slice 20 code/doc sync: `6056 nodes`, `13195 edges`, `139 communities`.
|
||||
|
||||
## Slice 21 - Business Overview Inventory Reserve/Liquidation Boundary Bridge
|
||||
|
||||
This slice tightens the warehouse-quality boundary for reserve, write-off, obsolete-stock, and liquidation-value wording.
|
||||
|
||||
The runtime already has stock position, sales-to-stock velocity proxy, and purchase-date staleness-risk proxy. It still does not have a reviewed route that proves accounting reserves, write-offs, confirmed obsolete stock, or liquidation value. Therefore the correct behavior is to route organization-level inventory-quality questions to `business_overview`, where those facts can be named as missing/unchecked, while exact item/stock list questions remain in the reviewed inventory routes.
|
||||
|
||||
Implemented now:
|
||||
|
||||
- turn meaning policy treats organization-level inventory reserve, write-off, obsolete-stock, obsolescence, and liquidation-value wording as `broad_business_evaluation` only when the wording has inventory/warehouse scope;
|
||||
- the discovery turn-input adapter promotes the same company-level wording into `business overview evidence with bounded analyst interpretation` before exact stock recipes can steal it;
|
||||
- the address intent resolver defers organization-level inventory reserve/liquidation wording with `unicode_business_overview_inventory_reserve_liquidation_deferred_to_discovery`;
|
||||
- explicit item/stock list wording such as "which items/products/goods" or direct "what is on the warehouse" remains in exact inventory routes;
|
||||
- business-overview answer drafting keeps the already implemented boundary: staleness-risk proxy is not confirmed obsolete stock, reserve, write-off, or liquidation value.
|
||||
|
||||
This is a boundary and arbitration slice, not a true inventory-reserve engine. It prevents old exact stock routes from answering a broader warehouse-quality question with the wrong evidence shape, while preserving exact inventory lists and the existing staleness-risk proxy.
|
||||
|
||||
Local validation is accepted for this slice:
|
||||
|
||||
- `npm.cmd test -- assistantTurnMeaningPolicy.test.ts assistantMcpDiscoveryTurnInputAdapter.test.ts addressQueryRuntimeM23.test.ts`: passed `503` with `6` skipped.
|
||||
- `npm.cmd run build`: passed.
|
||||
|
||||
Graphify rebuild after Slice 21 code/doc sync: `6059 nodes`, `13201 edges`, `137 communities`.
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ This package answers the next question:
|
|||
21. [21 - current_status_canon_2026-05-01.md](./21%20-%20current_status_canon_2026-05-01.md)
|
||||
22. [22 - open_world_bounded_autonomy_breadth_2026-05-01.md](./22%20-%20open_world_bounded_autonomy_breadth_2026-05-01.md)
|
||||
|
||||
## Current Status Snapshot (2026-05-04)
|
||||
## Current Status Snapshot (2026-05-05)
|
||||
|
||||
This package is no longer planning-only.
|
||||
|
||||
|
|
@ -69,6 +69,7 @@ Status canon for planning:
|
|||
- The current completed breadth slice is `Business Overview Earnings Wording Arbitration Bridge`: organization-level earnings, best-year, and overall-turnover wording now reaches `business_overview` instead of the exact customer-value route, while explicit customer/counterparty ranking remains unchanged.
|
||||
- The current completed breadth slice is `Business Overview Profit/Margin Wording Boundary Bridge`: organization-level profit, margin, financial-result, and P&L wording now reaches `business_overview` with explicit clean-profit boundaries, while explicit customer/item/contract routes remain unchanged.
|
||||
- The current completed breadth slice is `Business Overview Debt Due-Date Boundary Bridge`: organization-level overdue debt, debt quality, debt aging, due-date, and credit-risk wording now reaches `business_overview`, while explicit buyer/debtor lists stay in exact receivables routes with a due-date proof boundary.
|
||||
- The current completed breadth slice is `Business Overview Inventory Reserve/Liquidation Boundary Bridge`: organization-level inventory reserve, write-off, obsolete-stock, and liquidation-value wording now reaches `business_overview`, while explicit item/stock lists stay in exact inventory routes with a reserve/liquidation proof boundary.
|
||||
- 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).
|
||||
|
||||
|
|
@ -134,7 +135,7 @@ 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: `~94%`, 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, debt staleness-risk proxy bridged locally, debt due-date boundary arbitration bridged locally, supplier concentration proxy bridged locally, yearly operating-flow proxy bridged locally, earnings/best-year wording arbitration bridged locally, profit/margin wording boundary arbitration 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, confirmed vendor-risk/procurement-quality analysis, and confirmed reserve/write-off/liquidation inventory evidence are still pending
|
||||
- active Open-World Bounded Autonomy Breadth progress: `~95%`, 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, debt staleness-risk proxy bridged locally, debt due-date boundary arbitration bridged locally, inventory reserve/liquidation boundary arbitration bridged locally, supplier concentration proxy bridged locally, yearly operating-flow proxy bridged locally, earnings/best-year wording arbitration bridged locally, profit/margin wording boundary arbitration 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, confirmed vendor-risk/procurement-quality analysis, 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
|
||||
|
|
|
|||
|
|
@ -1505,6 +1505,19 @@ function hasOrganizationLevelDebtDueDateOverviewBridgeSignal(text) {
|
|||
const hasCompanyScopeCue = /(?:\u0443\s+\u043d\u0430\u0441|\u043d\u0430\u0448\w*|\u043f\u043e\s+\u043a\u043e\u043c\u043f\u0430\u043d|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+\u0446\u0435\u043b\u043e\u043c|\u043e\u0431\u0449\w*|\u043a\u0430\u043a\w*|\u043f\u043e\u043a\u0430\u0436|\u0434\u0430\u0439|\u0441\u0440\u0435\u0437|\u0430\u043d\u0430\u043b\u0438\u0437|(?:19|20)\d{2}|company|business|organization|overall|our|we|us|show|give|analysis)/iu.test(normalized);
|
||||
return hasDueDateDebtCue && hasCompanyScopeCue;
|
||||
}
|
||||
function hasOrganizationLevelInventoryReserveLiquidationOverviewBridgeSignal(text) {
|
||||
const normalized = String(text ?? "").trim().toLowerCase();
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
if (/(?:\u043a\u0430\u043a\u0438\u0435\s+(?:\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442\u0443\u0440|\u043f\u043e\u0437\u0438\u0446)|\u0447\u0442\u043e\s+(?:\u043b\u0435\u0436\u0438\u0442|\u043d\u0430\s+\u0441\u043a\u043b\u0430\u0434)|which\s+(?:items|products|goods))/iu.test(normalized)) {
|
||||
return false;
|
||||
}
|
||||
const hasInventoryQualityCue = /(?:\u043d\u0435\u043b\u0438\u043a\u0432\u0438\u0434\w*|\u0440\u0435\u0437\u0435\u0440\u0432\w*|\u0441\u043f\u0438\u0441\u0430\u043d\w*|\u043b\u0438\u043a\u0432\u0438\u0434\u0430\u0446\w*|\u0443\u0441\u0442\u0430\u0440\u0435\u0432\w*|\u043e\u0431\u0435\u0441\u0446\u0435\u043d\w*|obsolete|obsolescence|reserve|write[-\s]?off|liquidation|inventory\s+quality|stock\s+quality)/iu.test(normalized);
|
||||
const hasInventoryScopeCue = /(?:\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442\u0443\u0440|inventory|stock|warehouse)/iu.test(normalized);
|
||||
const hasCompanyScopeCue = /(?:\u0443\s+\u043d\u0430\u0441|\u043d\u0430\u0448\w*|\u043f\u043e\s+\u043a\u043e\u043c\u043f\u0430\u043d|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+\u0446\u0435\u043b\u043e\u043c|\u043e\u0431\u0449\w*|\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u043a\u0430\u043a\w*|\u043f\u043e\u043a\u0430\u0436|\u0434\u0430\u0439|\u0441\u0440\u0435\u0437|\u0430\u043d\u0430\u043b\u0438\u0437|(?:19|20)\d{2}|company|business|organization|overall|warehouse|stock|inventory|our|we|us|show|give|analysis)/iu.test(normalized);
|
||||
return hasInventoryQualityCue && hasInventoryScopeCue && hasCompanyScopeCue;
|
||||
}
|
||||
function hasSpecificCounterpartyRevenueBridgeSignal(text) {
|
||||
const normalized = String(text ?? "").trim().toLowerCase();
|
||||
if (!normalized) {
|
||||
|
|
@ -1668,6 +1681,9 @@ function resolveUnicodeAddressIntentBridge(text) {
|
|||
if (hasOrganizationLevelDebtDueDateOverviewBridgeSignal(normalized)) {
|
||||
return unicodeBridgeResolution("unknown", "high", "unicode_business_overview_debt_due_date_deferred_to_discovery");
|
||||
}
|
||||
if (hasOrganizationLevelInventoryReserveLiquidationOverviewBridgeSignal(normalized)) {
|
||||
return unicodeBridgeResolution("unknown", "high", "unicode_business_overview_inventory_reserve_liquidation_deferred_to_discovery");
|
||||
}
|
||||
if (hasBidirectionalValueFlowComparisonSignal(normalized)) {
|
||||
return unicodeBridgeResolution("unknown", "high", "unicode_bidirectional_value_flow_deferred_to_discovery");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -535,8 +535,22 @@ function hasOrganizationLevelDebtDueDateOverviewSignal(text) {
|
|||
const hasCompanyScopeCue = /(?:\u0443\s+\u043d\u0430\u0441|\u043d\u0430\u0448\w*|\u043f\u043e\s+\u043a\u043e\u043c\u043f\u0430\u043d|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+\u0446\u0435\u043b\u043e\u043c|\u043e\u0431\u0449\w*|\u043a\u0430\u043a\w*|\u043f\u043e\u043a\u0430\u0436|\u0434\u0430\u0439|\u0441\u0440\u0435\u0437|\u0430\u043d\u0430\u043b\u0438\u0437|(?:19|20)\d{2}|company|business|organization|overall|our|we|us|show|give|analysis)/iu.test(text);
|
||||
return hasDueDateDebtCue && hasCompanyScopeCue;
|
||||
}
|
||||
function hasOrganizationLevelInventoryReserveLiquidationOverviewSignal(text) {
|
||||
if (!text) {
|
||||
return false;
|
||||
}
|
||||
if (/(?:\u043a\u0430\u043a\u0438\u0435\s+(?:\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442\u0443\u0440|\u043f\u043e\u0437\u0438\u0446)|\u0447\u0442\u043e\s+(?:\u043b\u0435\u0436\u0438\u0442|\u043d\u0430\s+\u0441\u043a\u043b\u0430\u0434)|which\s+(?:items|products|goods))/iu.test(text)) {
|
||||
return false;
|
||||
}
|
||||
const hasInventoryQualityCue = /(?:\u043d\u0435\u043b\u0438\u043a\u0432\u0438\u0434\w*|\u0440\u0435\u0437\u0435\u0440\u0432\w*|\u0441\u043f\u0438\u0441\u0430\u043d\w*|\u043b\u0438\u043a\u0432\u0438\u0434\u0430\u0446\w*|\u0443\u0441\u0442\u0430\u0440\u0435\u0432\w*|\u043e\u0431\u0435\u0441\u0446\u0435\u043d\w*|obsolete|obsolescence|reserve|write[-\s]?off|liquidation|inventory\s+quality|stock\s+quality)/iu.test(text);
|
||||
const hasInventoryScopeCue = /(?:\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442\u0443\u0440|inventory|stock|warehouse)/iu.test(text);
|
||||
const hasCompanyScopeCue = /(?:\u0443\s+\u043d\u0430\u0441|\u043d\u0430\u0448\w*|\u043f\u043e\s+\u043a\u043e\u043c\u043f\u0430\u043d|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+\u0446\u0435\u043b\u043e\u043c|\u043e\u0431\u0449\w*|\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u043a\u0430\u043a\w*|\u043f\u043e\u043a\u0430\u0436|\u0434\u0430\u0439|\u0441\u0440\u0435\u0437|\u0430\u043d\u0430\u043b\u0438\u0437|(?:19|20)\d{2}|company|business|organization|overall|warehouse|stock|inventory|our|we|us|show|give|analysis)/iu.test(text);
|
||||
return hasInventoryQualityCue && hasInventoryScopeCue && hasCompanyScopeCue;
|
||||
}
|
||||
function hasBusinessOverviewSignal(text) {
|
||||
if (hasOrganizationLevelEarningsOverviewSignal(text) || hasOrganizationLevelDebtDueDateOverviewSignal(text)) {
|
||||
if (hasOrganizationLevelEarningsOverviewSignal(text) ||
|
||||
hasOrganizationLevelDebtDueDateOverviewSignal(text) ||
|
||||
hasOrganizationLevelInventoryReserveLiquidationOverviewSignal(text)) {
|
||||
return true;
|
||||
}
|
||||
return /(?:\u0431\u0438\u0437\u043d\u0435\u0441[-\s]?\u043e\u0431\u0437\u043e\u0440|\u0431\u0438\u0437\u043d\u0435\u0441[-\s]?\u0430\u0443\u0434\u0438\u0442|\u043f\u043e\u043b\u043d\w*\s+\u0430\u043d\u0430\u043b\u0438\u0437\s+(?:\u043a\u043e\u043c\u043f\u0430\u043d|\u0431\u0438\u0437\u043d\u0435\u0441|\u0434\u0435\u044f\u0442\u0435\u043b)|\u0441\u0432\u043e\u0434\u043d\w*\s+\u0430\u043d\u0430\u043b\u0438\u0437\s+(?:\u043a\u043e\u043c\u043f\u0430\u043d|\u0431\u0438\u0437\u043d\u0435\u0441|\u0434\u0435\u044f\u0442\u0435\u043b)|\u043a\u0430\u043a\s+\u0442\u044b\s+\u043e\u0446\u0435\u043d(?:\u0438\u0448\u044c|\u0438)\s+\u0434\u0435\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442|\u043a\u043e\u043c\u043f\u0430\u043d(?:\u0438\u0438|\u0438\u044e|\u0438\u044f)\s+\u0432\s+\u0446\u0435\u043b\u043e\u043c|company\s+(?:analysis|overview)|business\s+(?:overview|audit)|llm[-\s]?audit|бизнес[-\s]?обзор|бизнес[-\s]?аудит)/iu.test(text);
|
||||
|
|
|
|||
|
|
@ -138,6 +138,19 @@ function hasOrganizationLevelDebtDueDateOverviewSignal(text) {
|
|||
const hasCompanyScopeCue = /(?:\u0443\s+\u043d\u0430\u0441|\u043d\u0430\u0448\w*|\u043f\u043e\s+\u043a\u043e\u043c\u043f\u0430\u043d|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+\u0446\u0435\u043b\u043e\u043c|\u043e\u0431\u0449\w*|\u043a\u0430\u043a\w*|\u043f\u043e\u043a\u0430\u0436|\u0434\u0430\u0439|\u0441\u0440\u0435\u0437|\u0430\u043d\u0430\u043b\u0438\u0437|(?:19|20)\d{2}|company|business|organization|overall|our|we|us|show|give|analysis)/iu.test(normalized);
|
||||
return hasDueDateDebtCue && hasCompanyScopeCue;
|
||||
}
|
||||
function hasOrganizationLevelInventoryReserveLiquidationOverviewSignal(text) {
|
||||
const normalized = String(text ?? "");
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
if (/(?:\u043a\u0430\u043a\u0438\u0435\s+(?:\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442\u0443\u0440|\u043f\u043e\u0437\u0438\u0446)|\u0447\u0442\u043e\s+(?:\u043b\u0435\u0436\u0438\u0442|\u043d\u0430\s+\u0441\u043a\u043b\u0430\u0434)|which\s+(?:items|products|goods))/iu.test(normalized)) {
|
||||
return false;
|
||||
}
|
||||
const hasInventoryQualityCue = /(?:\u043d\u0435\u043b\u0438\u043a\u0432\u0438\u0434\w*|\u0440\u0435\u0437\u0435\u0440\u0432\w*|\u0441\u043f\u0438\u0441\u0430\u043d\w*|\u043b\u0438\u043a\u0432\u0438\u0434\u0430\u0446\w*|\u0443\u0441\u0442\u0430\u0440\u0435\u0432\w*|\u043e\u0431\u0435\u0441\u0446\u0435\u043d\w*|obsolete|obsolescence|reserve|write[-\s]?off|liquidation|inventory\s+quality|stock\s+quality)/iu.test(normalized);
|
||||
const hasInventoryScopeCue = /(?:\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442\u0443\u0440|inventory|stock|warehouse)/iu.test(normalized);
|
||||
const hasCompanyScopeCue = /(?:\u0443\s+\u043d\u0430\u0441|\u043d\u0430\u0448\w*|\u043f\u043e\s+\u043a\u043e\u043c\u043f\u0430\u043d|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+\u0446\u0435\u043b\u043e\u043c|\u043e\u0431\u0449\w*|\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u043a\u0430\u043a\w*|\u043f\u043e\u043a\u0430\u0436|\u0434\u0430\u0439|\u0441\u0440\u0435\u0437|\u0430\u043d\u0430\u043b\u0438\u0437|(?:19|20)\d{2}|company|business|organization|overall|warehouse|stock|inventory|our|we|us|show|give|analysis)/iu.test(normalized);
|
||||
return hasInventoryQualityCue && hasInventoryScopeCue && hasCompanyScopeCue;
|
||||
}
|
||||
function detectBroadBusinessEvaluation(text) {
|
||||
const normalized = String(text ?? "");
|
||||
if (!normalized) {
|
||||
|
|
@ -163,6 +176,11 @@ function detectBroadBusinessEvaluation(text) {
|
|||
family: "broad_business_evaluation"
|
||||
};
|
||||
}
|
||||
if (hasOrganizationLevelInventoryReserveLiquidationOverviewSignal(normalized)) {
|
||||
return {
|
||||
family: "broad_business_evaluation"
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function buildEntityCandidates(counterpartyTurnover) {
|
||||
|
|
|
|||
|
|
@ -1896,6 +1896,33 @@ function hasOrganizationLevelDebtDueDateOverviewBridgeSignal(text: string): bool
|
|||
return hasDueDateDebtCue && hasCompanyScopeCue;
|
||||
}
|
||||
|
||||
function hasOrganizationLevelInventoryReserveLiquidationOverviewBridgeSignal(text: string): boolean {
|
||||
const normalized = String(text ?? "").trim().toLowerCase();
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
/(?:\u043a\u0430\u043a\u0438\u0435\s+(?:\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442\u0443\u0440|\u043f\u043e\u0437\u0438\u0446)|\u0447\u0442\u043e\s+(?:\u043b\u0435\u0436\u0438\u0442|\u043d\u0430\s+\u0441\u043a\u043b\u0430\u0434)|which\s+(?:items|products|goods))/iu.test(
|
||||
normalized
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const hasInventoryQualityCue =
|
||||
/(?:\u043d\u0435\u043b\u0438\u043a\u0432\u0438\u0434\w*|\u0440\u0435\u0437\u0435\u0440\u0432\w*|\u0441\u043f\u0438\u0441\u0430\u043d\w*|\u043b\u0438\u043a\u0432\u0438\u0434\u0430\u0446\w*|\u0443\u0441\u0442\u0430\u0440\u0435\u0432\w*|\u043e\u0431\u0435\u0441\u0446\u0435\u043d\w*|obsolete|obsolescence|reserve|write[-\s]?off|liquidation|inventory\s+quality|stock\s+quality)/iu.test(
|
||||
normalized
|
||||
);
|
||||
const hasInventoryScopeCue =
|
||||
/(?:\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442\u0443\u0440|inventory|stock|warehouse)/iu.test(
|
||||
normalized
|
||||
);
|
||||
const hasCompanyScopeCue =
|
||||
/(?:\u0443\s+\u043d\u0430\u0441|\u043d\u0430\u0448\w*|\u043f\u043e\s+\u043a\u043e\u043c\u043f\u0430\u043d|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+\u0446\u0435\u043b\u043e\u043c|\u043e\u0431\u0449\w*|\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u043a\u0430\u043a\w*|\u043f\u043e\u043a\u0430\u0436|\u0434\u0430\u0439|\u0441\u0440\u0435\u0437|\u0430\u043d\u0430\u043b\u0438\u0437|(?:19|20)\d{2}|company|business|organization|overall|warehouse|stock|inventory|our|we|us|show|give|analysis)/iu.test(
|
||||
normalized
|
||||
);
|
||||
return hasInventoryQualityCue && hasInventoryScopeCue && hasCompanyScopeCue;
|
||||
}
|
||||
|
||||
function hasSpecificCounterpartyRevenueBridgeSignal(text: string): boolean {
|
||||
const normalized = String(text ?? "").trim().toLowerCase();
|
||||
if (!normalized) {
|
||||
|
|
@ -2161,6 +2188,14 @@ function resolveUnicodeAddressIntentBridge(text: string): AddressIntentResolutio
|
|||
return unicodeBridgeResolution("unknown", "high", "unicode_business_overview_debt_due_date_deferred_to_discovery");
|
||||
}
|
||||
|
||||
if (hasOrganizationLevelInventoryReserveLiquidationOverviewBridgeSignal(normalized)) {
|
||||
return unicodeBridgeResolution(
|
||||
"unknown",
|
||||
"high",
|
||||
"unicode_business_overview_inventory_reserve_liquidation_deferred_to_discovery"
|
||||
);
|
||||
}
|
||||
|
||||
if (hasBidirectionalValueFlowComparisonSignal(normalized)) {
|
||||
return unicodeBridgeResolution(
|
||||
"unknown",
|
||||
|
|
|
|||
|
|
@ -732,8 +732,38 @@ function hasOrganizationLevelDebtDueDateOverviewSignal(text: string): boolean {
|
|||
return hasDueDateDebtCue && hasCompanyScopeCue;
|
||||
}
|
||||
|
||||
function hasOrganizationLevelInventoryReserveLiquidationOverviewSignal(text: string): boolean {
|
||||
if (!text) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
/(?:\u043a\u0430\u043a\u0438\u0435\s+(?:\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442\u0443\u0440|\u043f\u043e\u0437\u0438\u0446)|\u0447\u0442\u043e\s+(?:\u043b\u0435\u0436\u0438\u0442|\u043d\u0430\s+\u0441\u043a\u043b\u0430\u0434)|which\s+(?:items|products|goods))/iu.test(
|
||||
text
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const hasInventoryQualityCue =
|
||||
/(?:\u043d\u0435\u043b\u0438\u043a\u0432\u0438\u0434\w*|\u0440\u0435\u0437\u0435\u0440\u0432\w*|\u0441\u043f\u0438\u0441\u0430\u043d\w*|\u043b\u0438\u043a\u0432\u0438\u0434\u0430\u0446\w*|\u0443\u0441\u0442\u0430\u0440\u0435\u0432\w*|\u043e\u0431\u0435\u0441\u0446\u0435\u043d\w*|obsolete|obsolescence|reserve|write[-\s]?off|liquidation|inventory\s+quality|stock\s+quality)/iu.test(
|
||||
text
|
||||
);
|
||||
const hasInventoryScopeCue =
|
||||
/(?:\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442\u0443\u0440|inventory|stock|warehouse)/iu.test(
|
||||
text
|
||||
);
|
||||
const hasCompanyScopeCue =
|
||||
/(?:\u0443\s+\u043d\u0430\u0441|\u043d\u0430\u0448\w*|\u043f\u043e\s+\u043a\u043e\u043c\u043f\u0430\u043d|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+\u0446\u0435\u043b\u043e\u043c|\u043e\u0431\u0449\w*|\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u043a\u0430\u043a\w*|\u043f\u043e\u043a\u0430\u0436|\u0434\u0430\u0439|\u0441\u0440\u0435\u0437|\u0430\u043d\u0430\u043b\u0438\u0437|(?:19|20)\d{2}|company|business|organization|overall|warehouse|stock|inventory|our|we|us|show|give|analysis)/iu.test(
|
||||
text
|
||||
);
|
||||
return hasInventoryQualityCue && hasInventoryScopeCue && hasCompanyScopeCue;
|
||||
}
|
||||
|
||||
function hasBusinessOverviewSignal(text: string): boolean {
|
||||
if (hasOrganizationLevelEarningsOverviewSignal(text) || hasOrganizationLevelDebtDueDateOverviewSignal(text)) {
|
||||
if (
|
||||
hasOrganizationLevelEarningsOverviewSignal(text) ||
|
||||
hasOrganizationLevelDebtDueDateOverviewSignal(text) ||
|
||||
hasOrganizationLevelInventoryReserveLiquidationOverviewSignal(text)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return /(?:\u0431\u0438\u0437\u043d\u0435\u0441[-\s]?\u043e\u0431\u0437\u043e\u0440|\u0431\u0438\u0437\u043d\u0435\u0441[-\s]?\u0430\u0443\u0434\u0438\u0442|\u043f\u043e\u043b\u043d\w*\s+\u0430\u043d\u0430\u043b\u0438\u0437\s+(?:\u043a\u043e\u043c\u043f\u0430\u043d|\u0431\u0438\u0437\u043d\u0435\u0441|\u0434\u0435\u044f\u0442\u0435\u043b)|\u0441\u0432\u043e\u0434\u043d\w*\s+\u0430\u043d\u0430\u043b\u0438\u0437\s+(?:\u043a\u043e\u043c\u043f\u0430\u043d|\u0431\u0438\u0437\u043d\u0435\u0441|\u0434\u0435\u044f\u0442\u0435\u043b)|\u043a\u0430\u043a\s+\u0442\u044b\s+\u043e\u0446\u0435\u043d(?:\u0438\u0448\u044c|\u0438)\s+\u0434\u0435\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442|\u043a\u043e\u043c\u043f\u0430\u043d(?:\u0438\u0438|\u0438\u044e|\u0438\u044f)\s+\u0432\s+\u0446\u0435\u043b\u043e\u043c|company\s+(?:analysis|overview)|business\s+(?:overview|audit)|llm[-\s]?audit|бизнес[-\s]?обзор|бизнес[-\s]?аудит)/iu.test(
|
||||
|
|
|
|||
|
|
@ -169,6 +169,33 @@ function hasOrganizationLevelDebtDueDateOverviewSignal(text) {
|
|||
return hasDueDateDebtCue && hasCompanyScopeCue;
|
||||
}
|
||||
|
||||
function hasOrganizationLevelInventoryReserveLiquidationOverviewSignal(text) {
|
||||
const normalized = String(text ?? "");
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
/(?:\u043a\u0430\u043a\u0438\u0435\s+(?:\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442\u0443\u0440|\u043f\u043e\u0437\u0438\u0446)|\u0447\u0442\u043e\s+(?:\u043b\u0435\u0436\u0438\u0442|\u043d\u0430\s+\u0441\u043a\u043b\u0430\u0434)|which\s+(?:items|products|goods))/iu.test(
|
||||
normalized
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const hasInventoryQualityCue =
|
||||
/(?:\u043d\u0435\u043b\u0438\u043a\u0432\u0438\u0434\w*|\u0440\u0435\u0437\u0435\u0440\u0432\w*|\u0441\u043f\u0438\u0441\u0430\u043d\w*|\u043b\u0438\u043a\u0432\u0438\u0434\u0430\u0446\w*|\u0443\u0441\u0442\u0430\u0440\u0435\u0432\w*|\u043e\u0431\u0435\u0441\u0446\u0435\u043d\w*|obsolete|obsolescence|reserve|write[-\s]?off|liquidation|inventory\s+quality|stock\s+quality)/iu.test(
|
||||
normalized
|
||||
);
|
||||
const hasInventoryScopeCue =
|
||||
/(?:\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442\u0443\u0440|inventory|stock|warehouse)/iu.test(
|
||||
normalized
|
||||
);
|
||||
const hasCompanyScopeCue =
|
||||
/(?:\u0443\s+\u043d\u0430\u0441|\u043d\u0430\u0448\w*|\u043f\u043e\s+\u043a\u043e\u043c\u043f\u0430\u043d|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+\u0446\u0435\u043b\u043e\u043c|\u043e\u0431\u0449\w*|\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u043a\u0430\u043a\w*|\u043f\u043e\u043a\u0430\u0436|\u0434\u0430\u0439|\u0441\u0440\u0435\u0437|\u0430\u043d\u0430\u043b\u0438\u0437|(?:19|20)\d{2}|company|business|organization|overall|warehouse|stock|inventory|our|we|us|show|give|analysis)/iu.test(
|
||||
normalized
|
||||
);
|
||||
return hasInventoryQualityCue && hasInventoryScopeCue && hasCompanyScopeCue;
|
||||
}
|
||||
|
||||
function detectBroadBusinessEvaluation(text) {
|
||||
const normalized = String(text ?? "");
|
||||
if (!normalized) {
|
||||
|
|
@ -200,6 +227,11 @@ function detectBroadBusinessEvaluation(text) {
|
|||
family: "broad_business_evaluation"
|
||||
};
|
||||
}
|
||||
if (hasOrganizationLevelInventoryReserveLiquidationOverviewSignal(normalized)) {
|
||||
return {
|
||||
family: "broad_business_evaluation"
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2761,6 +2761,16 @@ describe("address intent resolver expansion (M2.3a)", () => {
|
|||
expect(result.reasons).toContain("unicode_business_overview_debt_due_date_deferred_to_discovery");
|
||||
});
|
||||
|
||||
it("defers organization-level inventory reserve/liquidation wording to business overview discovery", () => {
|
||||
const result = resolveAddressIntent(
|
||||
"\u043a\u0430\u043a\u0438\u0435 \u0443 \u043d\u0430\u0441 \u0440\u0438\u0441\u043a\u0438 \u043d\u0435\u043b\u0438\u043a\u0432\u0438\u0434\u0430 \u0438 \u0440\u0435\u0437\u0435\u0440\u0432\u044b \u043f\u043e \u0441\u043a\u043b\u0430\u0434\u0443 \u0437\u0430 2020?"
|
||||
);
|
||||
expect(result.intent).toBe("unknown");
|
||||
expect(result.reasons).toContain(
|
||||
"unicode_business_overview_inventory_reserve_liquidation_deferred_to_discovery"
|
||||
);
|
||||
});
|
||||
|
||||
it("routes reconciliation mismatch wording into open contracts intent", () => {
|
||||
const result = resolveAddressIntent(
|
||||
"Покажи контрагентов, по которым сальдо скорее всего не совпадет с их актом сверки. Может, стоит поторопиться и запросить сверку?"
|
||||
|
|
|
|||
|
|
@ -2023,6 +2023,37 @@ describe("assistant MCP discovery turn input adapter", () => {
|
|||
expect(result.data_need_graph?.clarification_gaps).toEqual([]);
|
||||
});
|
||||
|
||||
it("routes organization-level inventory reserve/liquidation wording to business overview instead of exact stock recipes", () => {
|
||||
const orgName = "\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441";
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage:
|
||||
"\u043a\u0430\u043a\u0438\u0435 \u0443 \u043d\u0430\u0441 \u0440\u0438\u0441\u043a\u0438 \u043d\u0435\u043b\u0438\u043a\u0432\u0438\u0434\u0430 \u0438 \u043b\u0438\u043a\u0432\u0438\u0434\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u0441\u043a\u043b\u0430\u0434\u0430 \u0437\u0430 2020?",
|
||||
followupContext: {
|
||||
previous_discovery_pilot_scope: "inventory_on_hand_as_of_date",
|
||||
previous_filters: {
|
||||
organization: orgName,
|
||||
as_of_date: "2026-04-23"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.should_run_discovery).toBe(true);
|
||||
expect(result.semantic_data_need).toBe("business overview evidence with bounded analyst interpretation");
|
||||
expect(result.data_need_graph?.business_fact_family).toBe("business_overview");
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "business_overview",
|
||||
asked_action_family: "broad_evaluation",
|
||||
explicit_organization_scope: orgName,
|
||||
explicit_date_scope: "2020",
|
||||
unsupported_but_understood_family: "broad_business_evaluation",
|
||||
stale_replay_forbidden: true
|
||||
});
|
||||
expect(result.reason_codes).toContain("mcp_discovery_broad_business_evaluation_route_candidate");
|
||||
expect(result.reason_codes).not.toContain("mcp_discovery_date_scope_from_followup_context");
|
||||
expect(result.data_need_graph?.clarification_gaps).toEqual([]);
|
||||
});
|
||||
|
||||
it("resumes an open-scope total clarification loop from saved state when the user resolves the pending period with all-time wording", () => {
|
||||
const orgName = "ООО Альтернатива Плюс";
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
|
|
|
|||
|
|
@ -187,5 +187,15 @@ describe("assistantTurnMeaningPolicy", () => {
|
|||
expect(overdueDebt.asked_action_family).toBe("broad_evaluation");
|
||||
expect(overdueDebt.unsupported_but_understood_family).toBe("broad_business_evaluation");
|
||||
expect(overdueDebt.reason_codes).toContain("broad_business_evaluation_current_turn_signal");
|
||||
|
||||
const inventoryReserve = policy.resolveAssistantTurnMeaning({
|
||||
rawUserMessage:
|
||||
"\u043a\u0430\u043a\u0438\u0435 \u0443 \u043d\u0430\u0441 \u0440\u0438\u0441\u043a\u0438 \u043d\u0435\u043b\u0438\u043a\u0432\u0438\u0434\u0430 \u0438 \u0440\u0435\u0437\u0435\u0440\u0432\u044b \u043f\u043e \u0441\u043a\u043b\u0430\u0434\u0443 \u0437\u0430 2020?"
|
||||
});
|
||||
expect(inventoryReserve.explicit_intent_candidate).toBeNull();
|
||||
expect(inventoryReserve.asked_domain_family).toBe("business_summary");
|
||||
expect(inventoryReserve.asked_action_family).toBe("broad_evaluation");
|
||||
expect(inventoryReserve.unsupported_but_understood_family).toBe("broad_business_evaluation");
|
||||
expect(inventoryReserve.reason_codes).toContain("broad_business_evaluation_current_turn_signal");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue