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 6bf2bb4..308ba01 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 @@ -461,6 +461,11 @@ Still open after the accepted phase12 replay: - the shared retarget contract is now explicitly UTF-8-safe, which matters because a broken regex encoding in the first extraction attempt silently collapsed short phrases like `покажи договоры по СВК` back into stale previous-intent carryover; - `assistantTransitionPolicy` no longer keeps a second local `resolveDisplayedEntityRetargetIntent(...)` owner beside the shared continuity helper, which reduces another chance that future follow-up fixes land in dead code or diverge between route retarget and anchor hydration; - targeted `assistantContinuityPolicy` and `assistantTransitionPolicy` suites are green after the move, and a fresh live rerun of `address_truth_harness_phase11_manual_followup_meta_quality` on `2026-04-19` is accepted `10/10`, including the short displayed-counterparty retarget step. +- the next continuity-authority pass now centralizes one more dense decision block from the transition hot path: + - continuity now owns `resolveInventoryFollowupPivotFlags(...)`, so inventory root pivots and explicit same-date pivots are no longer computed by a local boolean cascade inside `assistantTransitionPolicy`; + - continuity now also owns `resolveFollowupTargetIntent(...)`, so `carryover target intent` precedence for purchase-date VAT bridge, selected-object retarget, root-context carryover, same-date pivot, displayed-entity retarget, and plain previous-intent fallback is expressed in one shared helper instead of an inline ternary tower; + - this matters because root-pivot semantics and target-intent precedence are among the heaviest remaining orchestration decisions in the follow-up path, and keeping them under one shared continuity layer reduces another chance that future domain expansion reintroduces drift between carryover state and target route selection; + - targeted `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` is accepted `20/20`, which is the critical proof that the flagship mixed replay still survives after the decision-block extraction. ## Next Execution Slice (2026-04-18) diff --git a/llm_normalizer/backend/dist/services/assistantContinuityPolicy.js b/llm_normalizer/backend/dist/services/assistantContinuityPolicy.js index dcf7d5d..aef9588 100644 --- a/llm_normalizer/backend/dist/services/assistantContinuityPolicy.js +++ b/llm_normalizer/backend/dist/services/assistantContinuityPolicy.js @@ -11,6 +11,8 @@ exports.resolveAddressDebugContextFacts = resolveAddressDebugContextFacts; exports.resolveAddressDebugCarryoverFilters = resolveAddressDebugCarryoverFilters; exports.hydrateInventoryRootFrameState = hydrateInventoryRootFrameState; exports.buildRootScopedCarryoverFilters = buildRootScopedCarryoverFilters; +exports.resolveInventoryFollowupPivotFlags = resolveInventoryFollowupPivotFlags; +exports.resolveFollowupTargetIntent = resolveFollowupTargetIntent; exports.shouldUseNavigationTemporalCarryover = shouldUseNavigationTemporalCarryover; exports.applyTemporalCarryoverFilters = applyTemporalCarryoverFilters; exports.applyOrganizationCarryoverFilters = applyOrganizationCarryoverFilters; @@ -241,6 +243,49 @@ function buildRootScopedCarryoverFilters(previousFilters, inventoryRootFrame, to } return nextFilters; } +function resolveInventoryFollowupPivotFlags(inventoryRootFrame, sourceIntentHint, currentFrameKind, hasForeignAccountingPivotMessage, inventoryPurchaseDateVatBridge, hasInventoryRootTemporalFollowupPrimary, hasInventoryRootTemporalFollowupAlternate, hasInventoryRootRestatementPrimary, hasInventoryRootRestatementAlternate, hasExplicitInventorySameDatePivotPrimary, hasExplicitInventorySameDatePivotAlternate, isInventorySelectedObjectIntent, isInventoryRootFrameIntent) { + const rootContextOnlyPivot = Boolean((isInventorySelectedObjectIntent(sourceIntentHint) || currentFrameKind === "inventory_drilldown") && + hasForeignAccountingPivotMessage && + !inventoryPurchaseDateVatBridge); + const inventoryRootTemporalPivot = Boolean(inventoryRootFrame && + (isInventorySelectedObjectIntent(sourceIntentHint) || + isInventoryRootFrameIntent(sourceIntentHint) || + currentFrameKind === "inventory_drilldown" || + currentFrameKind === "inventory_root") && + (hasInventoryRootTemporalFollowupPrimary || hasInventoryRootTemporalFollowupAlternate) && + !hasForeignAccountingPivotMessage); + const inventoryRootRestatementPivot = Boolean(inventoryRootFrame && + (isInventorySelectedObjectIntent(sourceIntentHint) || + isInventoryRootFrameIntent(sourceIntentHint) || + currentFrameKind === "inventory_drilldown" || + currentFrameKind === "inventory_root" || + currentFrameKind === "generic") && + (hasInventoryRootRestatementPrimary || hasInventoryRootRestatementAlternate) && + !hasForeignAccountingPivotMessage); + const explicitInventorySameDatePivot = Boolean(!inventoryRootFrame && + (hasExplicitInventorySameDatePivotPrimary || hasExplicitInventorySameDatePivotAlternate) && + !hasForeignAccountingPivotMessage); + return { + rootScopedPivot: rootContextOnlyPivot || inventoryRootTemporalPivot || inventoryRootRestatementPivot, + explicitInventorySameDatePivot + }; +} +function resolveFollowupTargetIntent(inventoryPurchaseDateVatBridge, selectedObjectRetargetIntent, explicitIntent, sourceIntent, followupSelectionMode, inventoryRootFrameIntent, displayedEntityTargetIntent, previousIntent, explicitInventorySameDatePivot) { + if (inventoryPurchaseDateVatBridge) { + return "vat_liability_confirmed_for_tax_period"; + } + if (selectedObjectRetargetIntent && + (explicitIntent === null || explicitIntent === "inventory_on_hand_as_of_date" || explicitIntent === sourceIntent)) { + return selectedObjectRetargetIntent; + } + if (followupSelectionMode === "carry_root_context") { + return inventoryRootFrameIntent ?? displayedEntityTargetIntent ?? explicitIntent ?? previousIntent ?? undefined; + } + if (explicitInventorySameDatePivot) { + return "inventory_on_hand_as_of_date"; + } + return displayedEntityTargetIntent ?? explicitIntent ?? previousIntent ?? undefined; +} function shouldUseNavigationTemporalCarryover(sourceIntentHint) { const normalizedIntent = fallbackToNonEmptyString(sourceIntentHint); return (normalizedIntent === "inventory_on_hand_as_of_date" || diff --git a/llm_normalizer/backend/dist/services/assistantTransitionPolicy.js b/llm_normalizer/backend/dist/services/assistantTransitionPolicy.js index 4b0d06a..67f8db1 100644 --- a/llm_normalizer/backend/dist/services/assistantTransitionPolicy.js +++ b/llm_normalizer/backend/dist/services/assistantTransitionPolicy.js @@ -591,28 +591,7 @@ function createAssistantTransitionPolicy(deps) { } } previousFilters = (0, assistantContinuityPolicy_1.applyTemporalCarryoverFilters)(previousFilters, navigationDateScope, continuityTemporalScope, sourceIntentHint, deps.toNonEmptyString); - const rootContextOnlyPivot = Boolean((deps.isInventorySelectedObjectIntent(sourceIntentHint) || currentFrameKind === "inventory_drilldown") && - deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage) && - !inventoryPurchaseDateVatBridge); - const inventoryRootTemporalPivot = Boolean(inventoryRootFrame && - (deps.isInventorySelectedObjectIntent(sourceIntentHint) || - deps.isInventoryRootFrameIntent(sourceIntentHint) || - currentFrameKind === "inventory_drilldown" || - currentFrameKind === "inventory_root") && - (hasInventoryRootTemporalFollowupPrimary || hasInventoryRootTemporalFollowupAlternate) && - !deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage)); - const inventoryRootRestatementPivot = Boolean(inventoryRootFrame && - (deps.isInventorySelectedObjectIntent(sourceIntentHint) || - deps.isInventoryRootFrameIntent(sourceIntentHint) || - currentFrameKind === "inventory_drilldown" || - currentFrameKind === "inventory_root" || - currentFrameKind === "generic") && - (hasInventoryRootRestatementPrimary || hasInventoryRootRestatementAlternate) && - !deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage)); - const explicitInventorySameDatePivot = Boolean(!inventoryRootFrame && - (hasExplicitInventorySameDatePivotPrimary || hasExplicitInventorySameDatePivotAlternate) && - !deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage)); - const rootScopedPivot = rootContextOnlyPivot || inventoryRootTemporalPivot || inventoryRootRestatementPivot; + const { rootScopedPivot, explicitInventorySameDatePivot } = (0, assistantContinuityPolicy_1.resolveInventoryFollowupPivotFlags)(inventoryRootFrame, sourceIntentHint, currentFrameKind, deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage), inventoryPurchaseDateVatBridge, hasInventoryRootTemporalFollowupPrimary, hasInventoryRootTemporalFollowupAlternate, hasInventoryRootRestatementPrimary, hasInventoryRootRestatementAlternate, hasExplicitInventorySameDatePivotPrimary, hasExplicitInventorySameDatePivotAlternate, deps.isInventorySelectedObjectIntent, deps.isInventoryRootFrameIntent); if (rootScopedPivot) { previousIntent = null; previousAnchorType = null; @@ -679,18 +658,7 @@ function createAssistantTransitionPolicy(deps) { hasInventoryRootRestatementAlternate || hasSelectedObjectInventorySignalPrimary || hasSelectedObjectInventorySignalAlternate)); - const carryoverTargetIntent = inventoryPurchaseDateVatBridge - ? "vat_liability_confirmed_for_tax_period" - : selectedObjectRetargetIntent && - (explicitIntent === null || - explicitIntent === "inventory_on_hand_as_of_date" || - explicitIntent === sourceIntent) - ? selectedObjectRetargetIntent - : followupSelectionMode === "carry_root_context" - ? inventoryRootFrame?.intent ?? displayedEntityTargetIntent ?? explicitIntent ?? previousIntent ?? undefined - : explicitInventorySameDatePivot - ? "inventory_on_hand_as_of_date" - : displayedEntityTargetIntent ?? explicitIntent ?? previousIntent ?? undefined; + const carryoverTargetIntent = (0, assistantContinuityPolicy_1.resolveFollowupTargetIntent)(inventoryPurchaseDateVatBridge, selectedObjectRetargetIntent, explicitIntent, sourceIntent, followupSelectionMode, deps.toNonEmptyString(inventoryRootFrame?.intent), displayedEntityTargetIntent, previousIntent, explicitInventorySameDatePivot); return { followupContext: { previous_intent: previousIntent ?? undefined, diff --git a/llm_normalizer/backend/src/services/assistantContinuityPolicy.ts b/llm_normalizer/backend/src/services/assistantContinuityPolicy.ts index 7003104..91f542c 100644 --- a/llm_normalizer/backend/src/services/assistantContinuityPolicy.ts +++ b/llm_normalizer/backend/src/services/assistantContinuityPolicy.ts @@ -369,6 +369,93 @@ export function buildRootScopedCarryoverFilters( return nextFilters; } +export function resolveInventoryFollowupPivotFlags( + inventoryRootFrame: + | { + intent?: unknown; + } + | null + | undefined, + sourceIntentHint: string | null, + currentFrameKind: string | null, + hasForeignAccountingPivotMessage: boolean, + inventoryPurchaseDateVatBridge: boolean, + hasInventoryRootTemporalFollowupPrimary: boolean, + hasInventoryRootTemporalFollowupAlternate: boolean, + hasInventoryRootRestatementPrimary: boolean, + hasInventoryRootRestatementAlternate: boolean, + hasExplicitInventorySameDatePivotPrimary: boolean, + hasExplicitInventorySameDatePivotAlternate: boolean, + isInventorySelectedObjectIntent: (intent: unknown) => boolean, + isInventoryRootFrameIntent: (intent: unknown) => boolean +): { + rootScopedPivot: boolean; + explicitInventorySameDatePivot: boolean; +} { + const rootContextOnlyPivot = Boolean( + (isInventorySelectedObjectIntent(sourceIntentHint) || currentFrameKind === "inventory_drilldown") && + hasForeignAccountingPivotMessage && + !inventoryPurchaseDateVatBridge + ); + const inventoryRootTemporalPivot = Boolean( + inventoryRootFrame && + (isInventorySelectedObjectIntent(sourceIntentHint) || + isInventoryRootFrameIntent(sourceIntentHint) || + currentFrameKind === "inventory_drilldown" || + currentFrameKind === "inventory_root") && + (hasInventoryRootTemporalFollowupPrimary || hasInventoryRootTemporalFollowupAlternate) && + !hasForeignAccountingPivotMessage + ); + const inventoryRootRestatementPivot = Boolean( + inventoryRootFrame && + (isInventorySelectedObjectIntent(sourceIntentHint) || + isInventoryRootFrameIntent(sourceIntentHint) || + currentFrameKind === "inventory_drilldown" || + currentFrameKind === "inventory_root" || + currentFrameKind === "generic") && + (hasInventoryRootRestatementPrimary || hasInventoryRootRestatementAlternate) && + !hasForeignAccountingPivotMessage + ); + const explicitInventorySameDatePivot = Boolean( + !inventoryRootFrame && + (hasExplicitInventorySameDatePivotPrimary || hasExplicitInventorySameDatePivotAlternate) && + !hasForeignAccountingPivotMessage + ); + return { + rootScopedPivot: rootContextOnlyPivot || inventoryRootTemporalPivot || inventoryRootRestatementPivot, + explicitInventorySameDatePivot + }; +} + +export function resolveFollowupTargetIntent( + inventoryPurchaseDateVatBridge: boolean, + selectedObjectRetargetIntent: string | null, + explicitIntent: string | null, + sourceIntent: string | null, + followupSelectionMode: string | null, + inventoryRootFrameIntent: string | null, + displayedEntityTargetIntent: string | null, + previousIntent: string | null, + explicitInventorySameDatePivot: boolean +): string | undefined { + if (inventoryPurchaseDateVatBridge) { + return "vat_liability_confirmed_for_tax_period"; + } + if ( + selectedObjectRetargetIntent && + (explicitIntent === null || explicitIntent === "inventory_on_hand_as_of_date" || explicitIntent === sourceIntent) + ) { + return selectedObjectRetargetIntent; + } + if (followupSelectionMode === "carry_root_context") { + return inventoryRootFrameIntent ?? displayedEntityTargetIntent ?? explicitIntent ?? previousIntent ?? undefined; + } + if (explicitInventorySameDatePivot) { + return "inventory_on_hand_as_of_date"; + } + return displayedEntityTargetIntent ?? explicitIntent ?? previousIntent ?? undefined; +} + export function shouldUseNavigationTemporalCarryover(sourceIntentHint: unknown): boolean { const normalizedIntent = fallbackToNonEmptyString(sourceIntentHint); return ( diff --git a/llm_normalizer/backend/src/services/assistantTransitionPolicy.ts b/llm_normalizer/backend/src/services/assistantTransitionPolicy.ts index 013e235..03b5c53 100644 --- a/llm_normalizer/backend/src/services/assistantTransitionPolicy.ts +++ b/llm_normalizer/backend/src/services/assistantTransitionPolicy.ts @@ -13,6 +13,8 @@ import { resolveAddressDebugCarryoverFilters, resolveAddressDebugAnchorContext, resolveDisplayedEntityFollowupRetarget, + resolveFollowupTargetIntent, + resolveInventoryFollowupPivotFlags, resolveAssistantOrganizationAuthority } from "./assistantContinuityPolicy"; @@ -773,36 +775,21 @@ export function createAssistantTransitionPolicy(deps) { sourceIntentHint, deps.toNonEmptyString ); - const rootContextOnlyPivot = Boolean( - (deps.isInventorySelectedObjectIntent(sourceIntentHint) || currentFrameKind === "inventory_drilldown") && - deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage) && - !inventoryPurchaseDateVatBridge + const { rootScopedPivot, explicitInventorySameDatePivot } = resolveInventoryFollowupPivotFlags( + inventoryRootFrame, + sourceIntentHint, + currentFrameKind, + deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage), + inventoryPurchaseDateVatBridge, + hasInventoryRootTemporalFollowupPrimary, + hasInventoryRootTemporalFollowupAlternate, + hasInventoryRootRestatementPrimary, + hasInventoryRootRestatementAlternate, + hasExplicitInventorySameDatePivotPrimary, + hasExplicitInventorySameDatePivotAlternate, + deps.isInventorySelectedObjectIntent, + deps.isInventoryRootFrameIntent ); - const inventoryRootTemporalPivot = Boolean( - inventoryRootFrame && - (deps.isInventorySelectedObjectIntent(sourceIntentHint) || - deps.isInventoryRootFrameIntent(sourceIntentHint) || - currentFrameKind === "inventory_drilldown" || - currentFrameKind === "inventory_root") && - (hasInventoryRootTemporalFollowupPrimary || hasInventoryRootTemporalFollowupAlternate) && - !deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage) - ); - const inventoryRootRestatementPivot = Boolean( - inventoryRootFrame && - (deps.isInventorySelectedObjectIntent(sourceIntentHint) || - deps.isInventoryRootFrameIntent(sourceIntentHint) || - currentFrameKind === "inventory_drilldown" || - currentFrameKind === "inventory_root" || - currentFrameKind === "generic") && - (hasInventoryRootRestatementPrimary || hasInventoryRootRestatementAlternate) && - !deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage) - ); - const explicitInventorySameDatePivot = Boolean( - !inventoryRootFrame && - (hasExplicitInventorySameDatePivotPrimary || hasExplicitInventorySameDatePivotAlternate) && - !deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage) - ); - const rootScopedPivot = rootContextOnlyPivot || inventoryRootTemporalPivot || inventoryRootRestatementPivot; if (rootScopedPivot) { previousIntent = null; previousAnchorType = null; @@ -899,19 +886,17 @@ export function createAssistantTransitionPolicy(deps) { hasSelectedObjectInventorySignalPrimary || hasSelectedObjectInventorySignalAlternate) ); - const carryoverTargetIntent = - inventoryPurchaseDateVatBridge - ? "vat_liability_confirmed_for_tax_period" - : selectedObjectRetargetIntent && - (explicitIntent === null || - explicitIntent === "inventory_on_hand_as_of_date" || - explicitIntent === sourceIntent) - ? selectedObjectRetargetIntent - : followupSelectionMode === "carry_root_context" - ? inventoryRootFrame?.intent ?? displayedEntityTargetIntent ?? explicitIntent ?? previousIntent ?? undefined - : explicitInventorySameDatePivot - ? "inventory_on_hand_as_of_date" - : displayedEntityTargetIntent ?? explicitIntent ?? previousIntent ?? undefined; + const carryoverTargetIntent = resolveFollowupTargetIntent( + inventoryPurchaseDateVatBridge, + selectedObjectRetargetIntent, + explicitIntent, + sourceIntent, + followupSelectionMode, + deps.toNonEmptyString(inventoryRootFrame?.intent), + displayedEntityTargetIntent, + previousIntent, + explicitInventorySameDatePivot + ); return { followupContext: { previous_intent: previousIntent ?? undefined, diff --git a/llm_normalizer/backend/tests/assistantContinuityPolicy.test.ts b/llm_normalizer/backend/tests/assistantContinuityPolicy.test.ts index afe8dda..75ba6a9 100644 --- a/llm_normalizer/backend/tests/assistantContinuityPolicy.test.ts +++ b/llm_normalizer/backend/tests/assistantContinuityPolicy.test.ts @@ -12,6 +12,8 @@ import { resolveAddressDebugContextFacts, resolveAddressDebugAnchorContext, resolveDisplayedEntityFollowupRetarget, + resolveFollowupTargetIntent, + resolveInventoryFollowupPivotFlags, resolveAssistantOrganizationAuthority } from "../src/services/assistantContinuityPolicy"; @@ -254,6 +256,45 @@ describe("assistantContinuityPolicy organization authority", () => { }); }); + it("resolves inventory root pivots through one shared helper", () => { + const flags = resolveInventoryFollowupPivotFlags( + { intent: "inventory_on_hand_as_of_date" }, + "inventory_purchase_documents_for_item", + "inventory_drilldown", + false, + false, + true, + false, + false, + false, + false, + false, + (intent) => String(intent ?? "") === "inventory_purchase_documents_for_item", + (intent) => String(intent ?? "") === "inventory_on_hand_as_of_date" + ); + + expect(flags).toEqual({ + rootScopedPivot: true, + explicitInventorySameDatePivot: false + }); + }); + + it("resolves follow-up target intent precedence through one shared helper", () => { + const targetIntent = resolveFollowupTargetIntent( + false, + null, + null, + "customer_revenue_and_payments", + "carry_root_context", + "inventory_on_hand_as_of_date", + "list_contracts_by_counterparty", + "customer_revenue_and_payments", + false + ); + + expect(targetIntent).toBe("inventory_on_hand_as_of_date"); + }); + it("applies organization carryover precedence from historical to shared authority to navigation and clarification", () => { const filters = applyOrganizationCarryoverFilters( {},