Архитектура: централизовать temporal carryover precedence в continuity policy и transition glue
This commit is contained in:
parent
46dfef6fb6
commit
ca71335499
|
|
@ -428,6 +428,12 @@ Still open after the accepted phase12 replay:
|
|||
- this matters because `inventoryRootFrame`, `current_frame_kind`, and `root-scoped` filter precedence now converge through one authority layer before `root_context_only` pivots are decided, which reduces another hidden chance for state drift when new domains or new follow-up families are added;
|
||||
- targeted `assistantContinuityPolicy` and `assistantTransitionPolicy` suites are green after the move, with explicit coverage for root-frame hydration from navigation scope and for previous-date precedence over a stale inventory root frame;
|
||||
- a fresh live rerun of `address_truth_harness_phase12_wider_saved_session_pool` on `2026-04-19` remained semantically stable on all repaired continuity paths and again failed only on the already-known date-sensitive `today` expectations, not on the new shared root-frame state owner.
|
||||
- the next continuity-authority pass now centralizes temporal backfill precedence for follow-up filters:
|
||||
- transition no longer holds a service-local block of `shouldBackfillPreviousDateScopeFromNavigation + six field-level ifs` for `as_of_date / period_from / period_to`;
|
||||
- shared continuity now owns that merge via `applyTemporalCarryoverFilters(...)`, while `shouldUseNavigationTemporalCarryover(...)` keeps the intent-family boundary explicit in one place;
|
||||
- this matters because navigation date scope and continuity temporal scope are now merged through one owner before transition decides pivots, instead of being backfilled ad hoc inside the hot path;
|
||||
- targeted `assistantContinuityPolicy` and `assistantTransitionPolicy` suites are green after the move, with direct helper coverage for navigation-first temporal precedence and for non-applicable intent families staying untouched;
|
||||
- a fresh live rerun of `address_truth_harness_phase12_wider_saved_session_pool` on `2026-04-19` stayed semantically stable and again failed only on the already-known date-sensitive `today` expectations, not on the new shared temporal carryover authority.
|
||||
|
||||
## Next Execution Slice (2026-04-18)
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue