Архитектура: централизовать temporal carryover precedence в continuity policy и transition glue

This commit is contained in:
2026-04-19 10:13:24 +03:00
parent 46dfef6fb6
commit ca71335499
6 changed files with 142 additions and 93 deletions
@@ -11,6 +11,8 @@ exports.resolveAddressDebugContextFacts = resolveAddressDebugContextFacts;
exports.resolveAddressDebugCarryoverFilters = resolveAddressDebugCarryoverFilters;
exports.hydrateInventoryRootFrameState = hydrateInventoryRootFrameState;
exports.buildRootScopedCarryoverFilters = buildRootScopedCarryoverFilters;
exports.shouldUseNavigationTemporalCarryover = shouldUseNavigationTemporalCarryover;
exports.applyTemporalCarryoverFilters = applyTemporalCarryoverFilters;
exports.buildInventoryRootFrameFromAddressDebug = buildInventoryRootFrameFromAddressDebug;
exports.isGroundedAddressDebug = isGroundedAddressDebug;
exports.resolveAssistantContinuitySnapshot = resolveAssistantContinuitySnapshot;
@@ -233,6 +235,38 @@ function buildRootScopedCarryoverFilters(previousFilters, inventoryRootFrame, to
}
return nextFilters;
}
function shouldUseNavigationTemporalCarryover(sourceIntentHint) {
const normalizedIntent = fallbackToNonEmptyString(sourceIntentHint);
return (normalizedIntent === "inventory_on_hand_as_of_date" ||
normalizedIntent === "inventory_supplier_stock_overlap_as_of_date" ||
normalizedIntent === "inventory_purchase_provenance_for_item" ||
normalizedIntent === "inventory_purchase_documents_for_item" ||
normalizedIntent === "inventory_sale_trace_for_item" ||
normalizedIntent === "inventory_profitability_for_item" ||
normalizedIntent === "inventory_purchase_to_sale_chain" ||
normalizedIntent === "inventory_aging_by_purchase_date" ||
normalizedIntent === "account_balance_snapshot" ||
normalizedIntent === "documents_forming_balance");
}
function applyTemporalCarryoverFilters(previousFilters, navigationDateScope, continuityTemporalScope, sourceIntentHint, toNonEmptyString = fallbackToNonEmptyString) {
const nextFilters = previousFilters && typeof previousFilters === "object" ? { ...previousFilters } : {};
if (!shouldUseNavigationTemporalCarryover(sourceIntentHint)) {
return nextFilters;
}
if (!toNonEmptyString(nextFilters.as_of_date)) {
nextFilters.as_of_date =
toNonEmptyString(navigationDateScope?.as_of_date) ?? continuityTemporalScope?.asOfDate ?? undefined;
}
if (!toNonEmptyString(nextFilters.period_from)) {
nextFilters.period_from =
toNonEmptyString(navigationDateScope?.period_from) ?? continuityTemporalScope?.periodFrom ?? undefined;
}
if (!toNonEmptyString(nextFilters.period_to)) {
nextFilters.period_to =
toNonEmptyString(navigationDateScope?.period_to) ?? continuityTemporalScope?.periodTo ?? undefined;
}
return nextFilters;
}
function buildInventoryRootFrameFromAddressDebug(debug, toNonEmptyString = fallbackToNonEmptyString) {
if (!debug || typeof debug !== "object") {
return null;
@@ -647,46 +647,7 @@ function createAssistantTransitionPolicy(deps) {
previousFilters.period_to = purchaseBridgeWindow.period_to;
}
}
const shouldBackfillPreviousDateScopeFromNavigation = sourceIntentHint === "inventory_on_hand_as_of_date" ||
sourceIntentHint === "inventory_supplier_stock_overlap_as_of_date" ||
sourceIntentHint === "inventory_purchase_provenance_for_item" ||
sourceIntentHint === "inventory_purchase_documents_for_item" ||
sourceIntentHint === "inventory_sale_trace_for_item" ||
sourceIntentHint === "inventory_profitability_for_item" ||
sourceIntentHint === "inventory_purchase_to_sale_chain" ||
sourceIntentHint === "inventory_aging_by_purchase_date" ||
sourceIntentHint === "account_balance_snapshot" ||
sourceIntentHint === "documents_forming_balance";
if (shouldBackfillPreviousDateScopeFromNavigation &&
!deps.toNonEmptyString(previousFilters.as_of_date) &&
deps.toNonEmptyString(navigationDateScope?.as_of_date)) {
previousFilters.as_of_date = deps.toNonEmptyString(navigationDateScope?.as_of_date);
}
if (shouldBackfillPreviousDateScopeFromNavigation &&
!deps.toNonEmptyString(previousFilters.as_of_date) &&
continuityTemporalScope.asOfDate) {
previousFilters.as_of_date = continuityTemporalScope.asOfDate;
}
if (shouldBackfillPreviousDateScopeFromNavigation &&
!deps.toNonEmptyString(previousFilters.period_from) &&
deps.toNonEmptyString(navigationDateScope?.period_from)) {
previousFilters.period_from = deps.toNonEmptyString(navigationDateScope?.period_from);
}
if (shouldBackfillPreviousDateScopeFromNavigation &&
!deps.toNonEmptyString(previousFilters.period_from) &&
continuityTemporalScope.periodFrom) {
previousFilters.period_from = continuityTemporalScope.periodFrom;
}
if (shouldBackfillPreviousDateScopeFromNavigation &&
!deps.toNonEmptyString(previousFilters.period_to) &&
deps.toNonEmptyString(navigationDateScope?.period_to)) {
previousFilters.period_to = deps.toNonEmptyString(navigationDateScope?.period_to);
}
if (shouldBackfillPreviousDateScopeFromNavigation &&
!deps.toNonEmptyString(previousFilters.period_to) &&
continuityTemporalScope.periodTo) {
previousFilters.period_to = continuityTemporalScope.periodTo;
}
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);
@@ -369,6 +369,50 @@ export function buildRootScopedCarryoverFilters(
return nextFilters;
}
export function shouldUseNavigationTemporalCarryover(sourceIntentHint: unknown): boolean {
const normalizedIntent = fallbackToNonEmptyString(sourceIntentHint);
return (
normalizedIntent === "inventory_on_hand_as_of_date" ||
normalizedIntent === "inventory_supplier_stock_overlap_as_of_date" ||
normalizedIntent === "inventory_purchase_provenance_for_item" ||
normalizedIntent === "inventory_purchase_documents_for_item" ||
normalizedIntent === "inventory_sale_trace_for_item" ||
normalizedIntent === "inventory_profitability_for_item" ||
normalizedIntent === "inventory_purchase_to_sale_chain" ||
normalizedIntent === "inventory_aging_by_purchase_date" ||
normalizedIntent === "account_balance_snapshot" ||
normalizedIntent === "documents_forming_balance"
);
}
export function applyTemporalCarryoverFilters(
previousFilters: Record<string, unknown> | null,
navigationDateScope: AssistantNavigationDateScope | null,
continuityTemporalScope: AssistantAddressDebugTemporalScope | null,
sourceIntentHint: unknown,
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString
): Record<string, unknown> {
const nextFilters =
previousFilters && typeof previousFilters === "object" ? { ...previousFilters } : {};
if (!shouldUseNavigationTemporalCarryover(sourceIntentHint)) {
return nextFilters;
}
if (!toNonEmptyString(nextFilters.as_of_date)) {
nextFilters.as_of_date =
toNonEmptyString(navigationDateScope?.as_of_date) ?? continuityTemporalScope?.asOfDate ?? undefined;
}
if (!toNonEmptyString(nextFilters.period_from)) {
nextFilters.period_from =
toNonEmptyString(navigationDateScope?.period_from) ?? continuityTemporalScope?.periodFrom ?? undefined;
}
if (!toNonEmptyString(nextFilters.period_to)) {
nextFilters.period_to =
toNonEmptyString(navigationDateScope?.period_to) ?? continuityTemporalScope?.periodTo ?? undefined;
}
return nextFilters;
}
export function buildInventoryRootFrameFromAddressDebug(
debug: Record<string, unknown> | null,
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString
@@ -1,5 +1,6 @@
// @ts-nocheck
import {
applyTemporalCarryoverFilters,
buildRootScopedCarryoverFilters,
buildInventoryRootFrameFromAddressDebug,
hydrateInventoryRootFrameState,
@@ -807,59 +808,13 @@ export function createAssistantTransitionPolicy(deps) {
previousFilters.period_to = purchaseBridgeWindow.period_to;
}
}
const shouldBackfillPreviousDateScopeFromNavigation =
sourceIntentHint === "inventory_on_hand_as_of_date" ||
sourceIntentHint === "inventory_supplier_stock_overlap_as_of_date" ||
sourceIntentHint === "inventory_purchase_provenance_for_item" ||
sourceIntentHint === "inventory_purchase_documents_for_item" ||
sourceIntentHint === "inventory_sale_trace_for_item" ||
sourceIntentHint === "inventory_profitability_for_item" ||
sourceIntentHint === "inventory_purchase_to_sale_chain" ||
sourceIntentHint === "inventory_aging_by_purchase_date" ||
sourceIntentHint === "account_balance_snapshot" ||
sourceIntentHint === "documents_forming_balance";
if (
shouldBackfillPreviousDateScopeFromNavigation &&
!deps.toNonEmptyString(previousFilters.as_of_date) &&
deps.toNonEmptyString(navigationDateScope?.as_of_date)
) {
previousFilters.as_of_date = deps.toNonEmptyString(navigationDateScope?.as_of_date);
}
if (
shouldBackfillPreviousDateScopeFromNavigation &&
!deps.toNonEmptyString(previousFilters.as_of_date) &&
continuityTemporalScope.asOfDate
) {
previousFilters.as_of_date = continuityTemporalScope.asOfDate;
}
if (
shouldBackfillPreviousDateScopeFromNavigation &&
!deps.toNonEmptyString(previousFilters.period_from) &&
deps.toNonEmptyString(navigationDateScope?.period_from)
) {
previousFilters.period_from = deps.toNonEmptyString(navigationDateScope?.period_from);
}
if (
shouldBackfillPreviousDateScopeFromNavigation &&
!deps.toNonEmptyString(previousFilters.period_from) &&
continuityTemporalScope.periodFrom
) {
previousFilters.period_from = continuityTemporalScope.periodFrom;
}
if (
shouldBackfillPreviousDateScopeFromNavigation &&
!deps.toNonEmptyString(previousFilters.period_to) &&
deps.toNonEmptyString(navigationDateScope?.period_to)
) {
previousFilters.period_to = deps.toNonEmptyString(navigationDateScope?.period_to);
}
if (
shouldBackfillPreviousDateScopeFromNavigation &&
!deps.toNonEmptyString(previousFilters.period_to) &&
continuityTemporalScope.periodTo
) {
previousFilters.period_to = continuityTemporalScope.periodTo;
}
previousFilters = applyTemporalCarryoverFilters(
previousFilters,
navigationDateScope,
continuityTemporalScope,
sourceIntentHint,
deps.toNonEmptyString
);
const rootContextOnlyPivot = Boolean(
(deps.isInventorySelectedObjectIntent(sourceIntentHint) || currentFrameKind === "inventory_drilldown") &&
deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage) &&
@@ -1,5 +1,6 @@
import { describe, expect, it } from "vitest";
import {
applyTemporalCarryoverFilters,
buildRootScopedCarryoverFilters,
hydrateInventoryRootFrameState,
readAddressDebugTemporalScope,
@@ -199,4 +200,52 @@ describe("assistantContinuityPolicy organization authority", () => {
period_to: "2020-03-31"
});
});
it("applies temporal carryover from navigation scope first and falls back to continuity scope", () => {
const filters = applyTemporalCarryoverFilters(
{
organization: "Org Alt"
},
{
as_of_date: "2021-03-31",
period_from: "2021-03-01"
},
{
asOfDate: "2020-12-31",
periodFrom: "2020-12-01",
periodTo: "2020-12-31"
},
"inventory_purchase_documents_for_item"
);
expect(filters).toEqual({
organization: "Org Alt",
as_of_date: "2021-03-31",
period_from: "2021-03-01",
period_to: "2020-12-31"
});
});
it("does not inject temporal carryover for unrelated intent families", () => {
const filters = applyTemporalCarryoverFilters(
{
organization: "Org Alt"
},
{
as_of_date: "2021-03-31",
period_from: "2021-03-01",
period_to: "2021-03-31"
},
{
asOfDate: "2020-12-31",
periodFrom: "2020-12-01",
periodTo: "2020-12-31"
},
"list_documents_by_counterparty"
);
expect(filters).toEqual({
organization: "Org Alt"
});
});
});