Post-F: закрепить open-scope и bidirectional value-flow integrity

This commit is contained in:
2026-04-24 15:21:03 +03:00
parent 9ed5435866
commit bba4717dbe
6 changed files with 165 additions and 0 deletions
@@ -1954,6 +1954,31 @@ function unicodeBridgeResolution(
return { intent, confidence, reasons: [reason] };
}
function hasBidirectionalValueFlowComparisonSignal(text: string): boolean {
const normalized = String(text ?? "").trim().toLowerCase();
if (!normalized) {
return false;
}
const hasIncomingCue = /(?:\u0432\u0445\u043e\u0434\u044f\u0449|\u043f\u043e\u0441\u0442\u0443\u043f|\u043f\u043e\u043b\u0443\u0447|inflow|incoming)/iu.test(
normalized
);
const hasOutgoingCue =
/(?:\u0438\u0441\u0445\u043e\u0434\u044f\u0449|\u0441\u043f\u0438\u0441\u0430\u043d|\u0437\u0430\u043f\u043b\u0430\u0442|\u043f\u043b\u0430\u0442\u0438\u043b|\u043e\u043f\u043b\u0430\u0442|outflow|outgoing|payout)/iu.test(
normalized
);
const hasComparisonCue =
/(?:\u0431\u043e\u043b\u044c\u0448|\u043c\u0435\u043d\u044c\u0448|\u0441\u0440\u0430\u0432|\u0438\u043b\u0438|\u043d\u0435\u0442\u0442\u043e|\u0441\u0430\u043b\u044c\u0434\u043e|vs|versus)/iu.test(
normalized
);
const hasValueFlowCue =
/(?:\u0434\u0435\u043d\u044c\u0433|\u0434\u0435\u043d\u0435\u0433|\u0434\u0435\u043d\u0435\u0436|\u043f\u043e\u0442\u043e\u043a|\u043e\u0431\u043e\u0440\u043e\u0442|money|cash|flow)/iu.test(
normalized
);
return hasIncomingCue && hasOutgoingCue && hasComparisonCue && hasValueFlowCue;
}
function resolveUnicodeAddressIntentBridge(text: string): AddressIntentResolution | null {
const normalized = String(text ?? "").trim().toLowerCase();
if (!normalized) {
@@ -2006,6 +2031,14 @@ function resolveUnicodeAddressIntentBridge(text: string): AddressIntentResolutio
normalized
);
if (hasBidirectionalValueFlowComparisonSignal(normalized)) {
return unicodeBridgeResolution(
"unknown",
"high",
"unicode_bidirectional_value_flow_deferred_to_discovery"
);
}
if (
/(?:за\s+какие\s+годы|диапазон\s+лет|покрыт(?:ие|ый)\s+период|какой\s+год.*актив|какой\s+месяц.*актив|год.*пассив|месяц.*пассив|минимальн.*док|минимальн.*операц|месяц[\s-]*пик|profile\s+period|top\s*year|top\s*month)/iu.test(
normalized
@@ -56,6 +56,7 @@ import {
resolveShadowRouteIntent
} from "./addressCapabilityPolicy";
import { evaluateAddressRouteExpectation, type AddressRouteExpectationAudit } from "./addressRouteExpectations";
import { repairAddressMojibakeText } from "./addressTextRepair";
import {
mergeKnownOrganizations,
normalizeOrganizationScopeSearchText,
@@ -1994,6 +1995,31 @@ function isOrganizationScopedInventoryIntent(intent: AddressIntent): boolean {
);
}
function isOrganizationScopedValueFlowIntent(intent: AddressIntent): boolean {
return intent === "customer_revenue_and_payments" || intent === "supplier_payouts_profile";
}
function hasExplicitSingleOrganizationValueFlowScopeRequest(userMessage: string): boolean {
const raw = String(userMessage ?? "").toLowerCase();
const repaired = repairAddressMojibakeText(raw).toLowerCase();
const normalized = `${raw} ${repaired}`;
const hasOrganizationCue = /(?:организац|компани|фирм|контур|organization|company)/iu.test(normalized);
if (!hasOrganizationCue) {
return false;
}
const hasSingleOrganizationCue =
/(?:по\s+одн(?:ой|у)\s+(?:организац|компани|фирм)|одн(?:ой|у)\s+(?:организац|компани|фирм)|one\s+(?:organization|company))/iu.test(
normalized
);
const hasClarificationCue =
/(?:если[^.?!]*(?:нужн|надо|потреб)[^.?!]*(?:организац|компани|фирм)|(?:уточн|спрос)[^.?!]*(?:организац|компани|фирм|ее|её))/iu.test(
normalized
);
return hasSingleOrganizationCue || hasClarificationCue;
}
function shouldDeferInventoryOrganizationClarification(
intent: AddressIntent,
filters: AddressFilterSet,
@@ -3480,6 +3506,29 @@ export class AddressQueryService {
});
const knownOrganizations = mergeKnownOrganizations(options.knownOrganizations ?? []);
const activeOrganization = normalizeOrganizationScopeValue(options.activeOrganization ?? null);
if (
isOrganizationScopedValueFlowIntent(intent.intent) &&
hasExplicitSingleOrganizationValueFlowScopeRequest(userMessage) &&
!resolvedOrganizationFromMessage
) {
const clarificationFilters: AddressFilterSet = { ...filters.extracted_filters };
delete clarificationFilters.organization;
return buildOrganizationClarificationExecutionResult({
mode,
shape,
intent,
filters: clarificationFilters,
organizations: knownOrganizations,
reasons: [...baseReasons, "organization_clarification_required_from_explicit_value_flow_scope"],
semanticFrame,
capabilityAudit: buildCapabilityAudit(intent.intent),
shadowRouteAudit: buildShadowRouteAudit({
intent: intent.intent,
requestedResultMode: resolveAddressRequestedResultMode(intent.intent, filters.extracted_filters, semanticFrame) ?? undefined,
filters: filters.extracted_filters
})
});
}
if (
isOrganizationScopedInventoryIntent(intent.intent) &&
!toNonEmptyFilterValue(filters.extracted_filters.organization) &&