From f3099a2c4b33736c5d69140a4e55a59b3d016a2c Mon Sep 17 00:00:00 2001 From: dctouch Date: Sun, 19 Apr 2026 13:53:18 +0300 Subject: [PATCH] =?UTF-8?q?=D0=90=D1=80=D1=85=D0=B8=D1=82=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D1=83=D1=80=D0=B0:=20=D0=B2=D1=8B=D0=BD=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=B8=20address-vs-deep=20fallback=20arbitration=20?= =?UTF-8?q?=D0=B2=20assistantRoutePolicy=20=D0=B8=20=D1=83=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=8C=D1=88=D0=B8=D1=82=D1=8C=20top-level=20decision=20p?= =?UTF-8?q?ressure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ontinuity_stabilization_plan_2026-04-17.md | 9 ++ .../dist/services/assistantRoutePolicy.js | 117 ++++++++++----- .../src/services/assistantRoutePolicy.ts | 140 +++++++++++++----- 3 files changed, 186 insertions(+), 80 deletions(-) diff --git a/docs/ARCH/11 - architecture_turnaround/11 - continuity_stabilization_plan_2026-04-17.md b/docs/ARCH/11 - architecture_turnaround/11 - continuity_stabilization_plan_2026-04-17.md index ca1590e..d34067e 100644 --- a/docs/ARCH/11 - architecture_turnaround/11 - continuity_stabilization_plan_2026-04-17.md +++ b/docs/ARCH/11 - architecture_turnaround/11 - continuity_stabilization_plan_2026-04-17.md @@ -477,6 +477,15 @@ Still open after the accepted phase12 replay: - this matters because the top-level `run address lane vs keep chat` gate is now structurally closer to the same route-policy owner that already arbitrates memory/meta/follow-up/deep transitions, instead of remaining split across `assistantService` glue and route policy heuristics; - the route policy still accepts an override in tests, so regression coverage remains narrow and controllable, but the production runtime no longer depends on a duplicate service-local decision block; - targeted `assistantRoutePolicy`, `assistantContinuityPolicy`, and `assistantTransitionPolicy` suites are green after the move, and a fresh live rerun of `address_truth_harness_phase12_wider_saved_session_pool` on `2026-04-19` remains accepted `20/20`, which is the proof that the flagship mixed path survives after lifting the gate out of `assistantService`. +- the next route-arbitration pass now extracts one more dense decision tower from the top-level orchestration hot path: + - `assistantRoutePolicy` now owns `resolveAddressFallbackToDeepArbitration(...)`, so the four critical fallback verdicts are produced by one explicit helper instead of being recalculated as a scattered inline boolean block: + - `unsupported_address_intent_fallback_to_deep` + - `deep_analysis_signal_fallback_to_deep` + - `aggregate_analytics_signal_fallback_to_deep` + - `deep_session_continuation_fallback_to_deep` + - this matters because `address vs deep` arbitration is one of the last heavy control-plane seams in the project: it decides whether the assistant stays in exact-data mode or escalates into deep-analysis mode, and leaving that logic as a long inline branch makes future domain expansion much more likely to reintroduce contradictory fallback rules; + - the move does not change the route owner, but it makes the owner explicit and testable as one decision unit inside route policy rather than a fragile chain of local booleans; + - targeted route/continuity/transition suites remain green after the move, and a fresh live rerun of `address_truth_harness_phase12_wider_saved_session_pool` on `2026-04-19` remains accepted `20/20`, which is the proof that the flagship mixed contour survives the extraction of the deep fallback arbitration seam. ## Next Execution Slice (2026-04-18) diff --git a/llm_normalizer/backend/dist/services/assistantRoutePolicy.js b/llm_normalizer/backend/dist/services/assistantRoutePolicy.js index fb45119..3629a3b 100644 --- a/llm_normalizer/backend/dist/services/assistantRoutePolicy.js +++ b/llm_normalizer/backend/dist/services/assistantRoutePolicy.js @@ -46,6 +46,49 @@ const ADDRESS_INTENTS_ALLOW_STRICT_DEEP_INVESTIGATION_BYPASS = new Set([ function shouldBypassStrictDeepInvestigationCueForAddressIntent(intent) { return Boolean(intent && ADDRESS_INTENTS_ALLOW_STRICT_DEEP_INVESTIGATION_BYPASS.has(intent)); } +function resolveAddressFallbackToDeepArbitration(input) { + const { baseToolGateRunAddressLane, llmRuntimeUnavailableDetected, unsupportedIntentOrMode, strongDataSignal, rootContextOnlyFollowup, llmContractMode, strictDeepInvestigationCueDetected, semanticDeepInvestigationHintDetected, aggregateBusinessAnalyticsSignal, preserveAddressLaneSignal, supportedAddressRouteCandidateDetected, followupContext, followupSemanticOverrideToDeepAllowed, deepAnalysisPreferenceDetected, protectAddressLaneFromFallback, dataRetrievalSignal, vatExplainFollowupSignal, semanticAggregateShapeDetected, semanticApplyCanonicalRecommended, standaloneAddressTopicSignal, hasDeepSessionContinuationSignalDetected } = input; + const unsupportedAddressIntentFallbackToDeep = Boolean(baseToolGateRunAddressLane && + !llmRuntimeUnavailableDetected && + unsupportedIntentOrMode && + strongDataSignal && + (rootContextOnlyFollowup || + llmContractMode === "deep_analysis" || + !dataRetrievalSignal || + strictDeepInvestigationCueDetected || + semanticDeepInvestigationHintDetected || + aggregateBusinessAnalyticsSignal) && + !preserveAddressLaneSignal && + !supportedAddressRouteCandidateDetected && + (!followupContext || followupSemanticOverrideToDeepAllowed)); + const deepAnalysisSignalFallbackToDeep = Boolean(baseToolGateRunAddressLane && + !llmRuntimeUnavailableDetected && + (deepAnalysisPreferenceDetected || semanticDeepInvestigationHintDetected) && + !protectAddressLaneFromFallback && + !vatExplainFollowupSignal && + (!followupContext || !dataRetrievalSignal || followupSemanticOverrideToDeepAllowed)); + const aggregateAnalyticsFallbackToDeep = Boolean(baseToolGateRunAddressLane && + !llmRuntimeUnavailableDetected && + aggregateBusinessAnalyticsSignal && + !protectAddressLaneFromFallback && + (!followupContext || + llmContractMode === "unsupported" || + llmContractMode === null || + semanticAggregateShapeDetected || + !semanticApplyCanonicalRecommended || + standaloneAddressTopicSignal)); + const deepSessionContinuationFallbackToDeep = Boolean(!followupContext && + baseToolGateRunAddressLane && + !llmRuntimeUnavailableDetected && + !protectAddressLaneFromFallback && + hasDeepSessionContinuationSignalDetected); + return { + unsupportedAddressIntentFallbackToDeep, + deepAnalysisSignalFallbackToDeep, + aggregateAnalyticsFallbackToDeep, + deepSessionContinuationFallbackToDeep + }; +} function createAssistantRoutePolicy(deps) { const { repairAddressMojibake, findLastGroundedAddressAnswerDebug, findLastOrganizationClarificationAddressDebug, mergeKnownOrganizations, normalizeOrganizationScopeValue, resolveOrganizationSelectionFromMessage, resolveMetaSignalSet, resolveHardMetaMode, isMetaFollowupOverGroundedAnswer, isAnswerInspectionFollowupOverGroundedAnswer, hasDataRetrievalRequestSignal, hasOrganizationFactLookupSignal, hasOrganizationFactFollowupSignal, hasAggregateBusinessAnalyticsSignal, hasStandaloneAddressTopicSignal, hasOpenContractsAddressSignal, detectAddressQuestionMode, resolveAddressIntent, toNonEmptyString, hasStrictDeepInvestigationCue, hasStrongDataIntentSignal, hasAccountingSignal, hasDangerOrCoercionSignal, hasAddressFollowupContextSignal, hasShortDebtMirrorFollowupSignal, isInventorySelectedObjectIntent, hasShortInventoryObjectFollowupSignal, isGroundedInventoryContextDebug, resolveRouteMemorySignals, findLastAddressAssistantItem, resolveAddressToolGateDecision: resolveAddressToolGateDecisionOverride, hasAddressLlmPreDecomposeCandidate, hasSameDateAccountFollowupSignalForPredecompose, hasLooseAllTimeAddressLookupSignal, hasDeepAnalysisPreferenceSignal, hasDirectDeepAnalysisSignal, compactWhitespace, hasDeepSessionContinuationSignal, resolveLivingAssistantModeDecision, resolveProviderExecutionState } = deps; function resolveBaseAddressToolGateDecision(addressInputMessage, followupContext, llmPreDecomposeMeta = null, rawUserMessage = null) { @@ -778,19 +821,6 @@ function createAssistantRoutePolicy(deps) { (rootContextOnlyFollowup && resolvedIntentResolution.intent === "unknown" && (!llmContractIntent || llmContractIntent === "unknown")); - const unsupportedAddressIntentFallbackToDeep = Boolean(baseToolGate?.runAddressLane && - !llmRuntimeUnavailableDetected && - unsupportedIntentOrMode && - strongDataSignal && - (rootContextOnlyFollowup || - llmContractMode === "deep_analysis" || - !dataRetrievalSignal || - strictDeepInvestigationCueDetected || - semanticDeepInvestigationHintDetected || - aggregateBusinessAnalyticsSignal) && - !preserveAddressLaneSignal && - !supportedAddressRouteCandidateDetected && - (!followupContext || followupSemanticOverrideToDeepAllowed)); const deepAnalysisPreferenceDetected = Boolean(hasDeepAnalysisPreferenceSignal(rawUserMessage) || hasDeepAnalysisPreferenceSignal(repairedRawUserMessage) || hasDeepAnalysisPreferenceSignal(effectiveAddressUserMessage) || @@ -818,33 +848,40 @@ function createAssistantRoutePolicy(deps) { const vatEvaluativeFollowupSignal = Boolean(followupContext && toNonEmptyString(followupContext.previous_intent) === "vat_payable_forecast" && /(?:^|\s)(?:это\s+)?много\s+или\s+мало(?:\?|$)|(?:^|\s)(?:это\s+)?нормально(?:\?|$)|(?:^|\s)(?:это\s+)?плохо(?:\?|$)|(?:^|\s)(?:это\s+)?хорошо(?:\?|$)/iu.test(compactWhitespace(`${repairedRawUserMessage} ${repairedEffectiveAddressUserMessage}`))); - const deepAnalysisSignalFallbackToDeep = Boolean(baseToolGate?.runAddressLane && - !llmRuntimeUnavailableDetected && - (deepAnalysisPreferenceDetected || semanticDeepInvestigationHintDetected) && - !protectAddressLaneFromFallback && - !vatExplainFollowupSignal && - (!followupContext || !dataRetrievalSignal || followupSemanticOverrideToDeepAllowed)); - const aggregateAnalyticsFallbackToDeep = Boolean(baseToolGate?.runAddressLane && - !llmRuntimeUnavailableDetected && - aggregateBusinessAnalyticsSignal && - !protectAddressLaneFromFallback && - (!followupContext || - llmContractMode === "unsupported" || - llmContractMode === null || - semanticAggregateShapeDetected || - !semanticApplyCanonicalRecommended || - standaloneAddressTopicSignal)); - const deepSessionContinuationFallbackToDeep = Boolean(!followupContext && - baseToolGate?.runAddressLane && - !llmRuntimeUnavailableDetected && - !protectAddressLaneFromFallback && - hasDeepSessionContinuationSignal({ - rawUserMessage, - repairedRawUserMessage, - effectiveAddressUserMessage, - repairedEffectiveAddressUserMessage, - sessionItems - })); + const hasDeepSessionContinuationSignalDetected = hasDeepSessionContinuationSignal({ + rawUserMessage, + repairedRawUserMessage, + effectiveAddressUserMessage, + repairedEffectiveAddressUserMessage, + sessionItems + }); + const finalizedDeepFallbackArbitration = resolveAddressFallbackToDeepArbitration({ + baseToolGateRunAddressLane: Boolean(baseToolGate?.runAddressLane), + llmRuntimeUnavailableDetected, + unsupportedIntentOrMode, + strongDataSignal, + rootContextOnlyFollowup, + llmContractMode, + strictDeepInvestigationCueDetected, + semanticDeepInvestigationHintDetected, + aggregateBusinessAnalyticsSignal, + preserveAddressLaneSignal, + supportedAddressRouteCandidateDetected, + followupContext, + followupSemanticOverrideToDeepAllowed, + deepAnalysisPreferenceDetected, + protectAddressLaneFromFallback, + dataRetrievalSignal, + vatExplainFollowupSignal, + semanticAggregateShapeDetected, + semanticApplyCanonicalRecommended, + standaloneAddressTopicSignal, + hasDeepSessionContinuationSignalDetected + }); + const unsupportedAddressIntentFallbackToDeep = finalizedDeepFallbackArbitration.unsupportedAddressIntentFallbackToDeep; + const deepAnalysisSignalFallbackToDeep = finalizedDeepFallbackArbitration.deepAnalysisSignalFallbackToDeep; + const aggregateAnalyticsFallbackToDeep = finalizedDeepFallbackArbitration.aggregateAnalyticsFallbackToDeep; + const deepSessionContinuationFallbackToDeep = finalizedDeepFallbackArbitration.deepSessionContinuationFallbackToDeep; const hasPriorAddressAnswerContext = Boolean(lastGroundedAddressDebug || continuitySnapshot.hasGroundedAddressContext || toNonEmptyString(followupContext?.previous_intent)); diff --git a/llm_normalizer/backend/src/services/assistantRoutePolicy.ts b/llm_normalizer/backend/src/services/assistantRoutePolicy.ts index 31a0110..16b7f59 100644 --- a/llm_normalizer/backend/src/services/assistantRoutePolicy.ts +++ b/llm_normalizer/backend/src/services/assistantRoutePolicy.ts @@ -46,6 +46,72 @@ const ADDRESS_INTENTS_ALLOW_STRICT_DEEP_INVESTIGATION_BYPASS = new Set([ function shouldBypassStrictDeepInvestigationCueForAddressIntent(intent) { return Boolean(intent && ADDRESS_INTENTS_ALLOW_STRICT_DEEP_INVESTIGATION_BYPASS.has(intent)); } + +function resolveAddressFallbackToDeepArbitration(input) { + const { + baseToolGateRunAddressLane, + llmRuntimeUnavailableDetected, + unsupportedIntentOrMode, + strongDataSignal, + rootContextOnlyFollowup, + llmContractMode, + strictDeepInvestigationCueDetected, + semanticDeepInvestigationHintDetected, + aggregateBusinessAnalyticsSignal, + preserveAddressLaneSignal, + supportedAddressRouteCandidateDetected, + followupContext, + followupSemanticOverrideToDeepAllowed, + deepAnalysisPreferenceDetected, + protectAddressLaneFromFallback, + dataRetrievalSignal, + vatExplainFollowupSignal, + semanticAggregateShapeDetected, + semanticApplyCanonicalRecommended, + standaloneAddressTopicSignal, + hasDeepSessionContinuationSignalDetected + } = input; + const unsupportedAddressIntentFallbackToDeep = Boolean(baseToolGateRunAddressLane && + !llmRuntimeUnavailableDetected && + unsupportedIntentOrMode && + strongDataSignal && + (rootContextOnlyFollowup || + llmContractMode === "deep_analysis" || + !dataRetrievalSignal || + strictDeepInvestigationCueDetected || + semanticDeepInvestigationHintDetected || + aggregateBusinessAnalyticsSignal) && + !preserveAddressLaneSignal && + !supportedAddressRouteCandidateDetected && + (!followupContext || followupSemanticOverrideToDeepAllowed)); + const deepAnalysisSignalFallbackToDeep = Boolean(baseToolGateRunAddressLane && + !llmRuntimeUnavailableDetected && + (deepAnalysisPreferenceDetected || semanticDeepInvestigationHintDetected) && + !protectAddressLaneFromFallback && + !vatExplainFollowupSignal && + (!followupContext || !dataRetrievalSignal || followupSemanticOverrideToDeepAllowed)); + const aggregateAnalyticsFallbackToDeep = Boolean(baseToolGateRunAddressLane && + !llmRuntimeUnavailableDetected && + aggregateBusinessAnalyticsSignal && + !protectAddressLaneFromFallback && + (!followupContext || + llmContractMode === "unsupported" || + llmContractMode === null || + semanticAggregateShapeDetected || + !semanticApplyCanonicalRecommended || + standaloneAddressTopicSignal)); + const deepSessionContinuationFallbackToDeep = Boolean(!followupContext && + baseToolGateRunAddressLane && + !llmRuntimeUnavailableDetected && + !protectAddressLaneFromFallback && + hasDeepSessionContinuationSignalDetected); + return { + unsupportedAddressIntentFallbackToDeep, + deepAnalysisSignalFallbackToDeep, + aggregateAnalyticsFallbackToDeep, + deepSessionContinuationFallbackToDeep + }; +} export function createAssistantRoutePolicy(deps) { const { repairAddressMojibake, @@ -819,19 +885,6 @@ export function createAssistantRoutePolicy(deps) { (rootContextOnlyFollowup && resolvedIntentResolution.intent === "unknown" && (!llmContractIntent || llmContractIntent === "unknown")); - const unsupportedAddressIntentFallbackToDeep = Boolean(baseToolGate?.runAddressLane && - !llmRuntimeUnavailableDetected && - unsupportedIntentOrMode && - strongDataSignal && - (rootContextOnlyFollowup || - llmContractMode === "deep_analysis" || - !dataRetrievalSignal || - strictDeepInvestigationCueDetected || - semanticDeepInvestigationHintDetected || - aggregateBusinessAnalyticsSignal) && - !preserveAddressLaneSignal && - !supportedAddressRouteCandidateDetected && - (!followupContext || followupSemanticOverrideToDeepAllowed)); const deepAnalysisPreferenceDetected = Boolean(hasDeepAnalysisPreferenceSignal(rawUserMessage) || hasDeepAnalysisPreferenceSignal(repairedRawUserMessage) || hasDeepAnalysisPreferenceSignal(effectiveAddressUserMessage) || @@ -859,33 +912,40 @@ export function createAssistantRoutePolicy(deps) { const vatEvaluativeFollowupSignal = Boolean(followupContext && toNonEmptyString(followupContext.previous_intent) === "vat_payable_forecast" && /(?:^|\s)(?:это\s+)?много\s+или\s+мало(?:\?|$)|(?:^|\s)(?:это\s+)?нормально(?:\?|$)|(?:^|\s)(?:это\s+)?плохо(?:\?|$)|(?:^|\s)(?:это\s+)?хорошо(?:\?|$)/iu.test(compactWhitespace(`${repairedRawUserMessage} ${repairedEffectiveAddressUserMessage}`))); - const deepAnalysisSignalFallbackToDeep = Boolean(baseToolGate?.runAddressLane && - !llmRuntimeUnavailableDetected && - (deepAnalysisPreferenceDetected || semanticDeepInvestigationHintDetected) && - !protectAddressLaneFromFallback && - !vatExplainFollowupSignal && - (!followupContext || !dataRetrievalSignal || followupSemanticOverrideToDeepAllowed)); - const aggregateAnalyticsFallbackToDeep = Boolean(baseToolGate?.runAddressLane && - !llmRuntimeUnavailableDetected && - aggregateBusinessAnalyticsSignal && - !protectAddressLaneFromFallback && - (!followupContext || - llmContractMode === "unsupported" || - llmContractMode === null || - semanticAggregateShapeDetected || - !semanticApplyCanonicalRecommended || - standaloneAddressTopicSignal)); - const deepSessionContinuationFallbackToDeep = Boolean(!followupContext && - baseToolGate?.runAddressLane && - !llmRuntimeUnavailableDetected && - !protectAddressLaneFromFallback && - hasDeepSessionContinuationSignal({ - rawUserMessage, - repairedRawUserMessage, - effectiveAddressUserMessage, - repairedEffectiveAddressUserMessage, - sessionItems - })); + const hasDeepSessionContinuationSignalDetected = hasDeepSessionContinuationSignal({ + rawUserMessage, + repairedRawUserMessage, + effectiveAddressUserMessage, + repairedEffectiveAddressUserMessage, + sessionItems + }); + const finalizedDeepFallbackArbitration = resolveAddressFallbackToDeepArbitration({ + baseToolGateRunAddressLane: Boolean(baseToolGate?.runAddressLane), + llmRuntimeUnavailableDetected, + unsupportedIntentOrMode, + strongDataSignal, + rootContextOnlyFollowup, + llmContractMode, + strictDeepInvestigationCueDetected, + semanticDeepInvestigationHintDetected, + aggregateBusinessAnalyticsSignal, + preserveAddressLaneSignal, + supportedAddressRouteCandidateDetected, + followupContext, + followupSemanticOverrideToDeepAllowed, + deepAnalysisPreferenceDetected, + protectAddressLaneFromFallback, + dataRetrievalSignal, + vatExplainFollowupSignal, + semanticAggregateShapeDetected, + semanticApplyCanonicalRecommended, + standaloneAddressTopicSignal, + hasDeepSessionContinuationSignalDetected + }); + const unsupportedAddressIntentFallbackToDeep = finalizedDeepFallbackArbitration.unsupportedAddressIntentFallbackToDeep; + const deepAnalysisSignalFallbackToDeep = finalizedDeepFallbackArbitration.deepAnalysisSignalFallbackToDeep; + const aggregateAnalyticsFallbackToDeep = finalizedDeepFallbackArbitration.aggregateAnalyticsFallbackToDeep; + const deepSessionContinuationFallbackToDeep = finalizedDeepFallbackArbitration.deepSessionContinuationFallbackToDeep; const hasPriorAddressAnswerContext = Boolean(lastGroundedAddressDebug || continuitySnapshot.hasGroundedAddressContext || toNonEmptyString(followupContext?.previous_intent));