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
@@ -1554,6 +1554,17 @@ function repairLikelyUtf8Mojibake(text) {
function unicodeBridgeResolution(intent, confidence, reason) {
return { intent, confidence, reasons: [reason] };
}
function hasBidirectionalValueFlowComparisonSignal(text) {
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) {
const normalized = String(text ?? "").trim().toLowerCase();
if (!normalized) {
@@ -1592,6 +1603,9 @@ function resolveUnicodeAddressIntentBridge(text) {
]).has(byAnchorToken);
const hasMoneyCue = /(?:деньг|денег|выручк|доход|оборот|заработ|прин[её]с|чек|ликвидн|revenue|turnover|money)/iu.test(normalized);
const hasRankingCue = /(?:топ|ранк|сам(?:ый|ая|ое|ые)|больше\s+всего|наибольш|крупн|жирн|max|top|rank)/iu.test(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)) {
return unicodeBridgeResolution("period_coverage_profile", "high", "unicode_period_coverage_bridge_signal_detected");
}
@@ -9,6 +9,7 @@ const resolveStage_1 = require("./address_runtime/resolveStage");
const composeStage_1 = require("./address_runtime/composeStage");
const addressCapabilityPolicy_1 = require("./addressCapabilityPolicy");
const addressRouteExpectations_1 = require("./addressRouteExpectations");
const addressTextRepair_1 = require("./addressTextRepair");
const assistantOrganizationMatcher_1 = require("./assistantOrganizationMatcher");
const addressCoverageEvidencePolicy_1 = require("./addressCoverageEvidencePolicy");
const addressTruthGatePolicy_1 = require("./addressTruthGatePolicy");
@@ -1617,6 +1618,21 @@ function isOrganizationScopedInventoryIntent(intent) {
intent === "inventory_purchase_to_sale_chain" ||
intent === "inventory_aging_by_purchase_date");
}
function isOrganizationScopedValueFlowIntent(intent) {
return intent === "customer_revenue_and_payments" || intent === "supplier_payouts_profile";
}
function hasExplicitSingleOrganizationValueFlowScopeRequest(userMessage) {
const raw = String(userMessage ?? "").toLowerCase();
const repaired = (0, addressTextRepair_1.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, filters, semanticFrame) {
if (!isOrganizationScopedInventoryIntent(intent)) {
return false;
@@ -2804,6 +2820,27 @@ class AddressQueryService {
});
const knownOrganizations = (0, assistantOrganizationMatcher_1.mergeKnownOrganizations)(options.knownOrganizations ?? []);
const activeOrganization = (0, assistantOrganizationMatcher_1.normalizeOrganizationScopeValue)(options.activeOrganization ?? null);
if (isOrganizationScopedValueFlowIntent(intent.intent) &&
hasExplicitSingleOrganizationValueFlowScopeRequest(userMessage) &&
!resolvedOrganizationFromMessage) {
const clarificationFilters = { ...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: (0, addressCoverageEvidencePolicy_1.resolveAddressRequestedResultMode)(intent.intent, filters.extracted_filters, semanticFrame) ?? undefined,
filters: filters.extracted_filters
})
});
}
if (isOrganizationScopedInventoryIntent(intent.intent) &&
!toNonEmptyFilterValue(filters.extracted_filters.organization) &&
!activeOrganization &&