Open-World: закрепить границу складского неликвида

This commit is contained in:
2026-05-05 12:21:38 +03:00
parent 264cbcee12
commit 2b2e37acce
12 changed files with 227 additions and 6 deletions
@@ -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");
});
});