Архитектура: централизовать navigation focus authority в continuity policy и сделать phase15 replay time-stable
This commit is contained in:
parent
0e098cde38
commit
82cc5cfd1a
|
|
@ -23,7 +23,7 @@ This snapshot is based on:
|
|||
- live replay comparison between:
|
||||
- `address_truth_harness_phase12_wider_saved_session_pool_live_20260419_rerun16`
|
||||
- `address_truth_harness_phase14_counterparty_tail_resume_live_20260418_rerun2`
|
||||
- `address_truth_harness_phase15_answer_inspection_followup_live_20260418_rerun8`
|
||||
- `address_truth_harness_phase15_answer_inspection_followup_live_20260419_rerun11`
|
||||
- `address_truth_harness_phase16_multicompany_late_pivot_live_20260419_rerun10`
|
||||
- `address_truth_harness_phase17_clarification_resume_and_counterparty_tail_live_20260419_rerun5`
|
||||
- [10 - regression_breakpoint_analysis_2026-04-17.md](./10%20-%20regression_breakpoint_analysis_2026-04-17.md)
|
||||
|
|
@ -33,8 +33,8 @@ This snapshot is based on:
|
|||
|
||||
Latest graph rebuild:
|
||||
|
||||
- `5371 nodes`
|
||||
- `11523 edges`
|
||||
- `5372 nodes`
|
||||
- `11525 edges`
|
||||
- `135 communities`
|
||||
|
||||
Most relevant current god nodes for turnaround `11`:
|
||||
|
|
|
|||
|
|
@ -520,6 +520,12 @@ Latest phase17 clarification-resume evidence after the current replay hardening:
|
|||
- `decomposeStage` no longer hydrates inventory follow-up filters with the selected organization alias as a fake counterparty anchor, so hidden carryover state stays truthful;
|
||||
- targeted `assistantRoutePolicy`, `assistantAddressFollowupContext`, `addressImplicitOrganizationScope`, and `addressFollowupTemporalRegression` suites are green after the fix, and backend build stays green;
|
||||
- live replay `address_truth_harness_phase17_clarification_resume_and_counterparty_tail_live_20260419_rerun5` is accepted `10/10`, which is the current proof that clarification-resume, historical inventory continuation, and short counterparty-tail retarget are now semantically clean on a non-flagship saved-session path.
|
||||
- the next continuity-authority pass now centralizes navigation focus-state parsing for the hot selected-object path:
|
||||
- `assistantContinuityPolicy` now owns `resolveNavigationSessionContextState(...)`, which extracts `date scope`, `organization`, `active focus object`, and `active result set id` from navigation state through one shared helper;
|
||||
- `assistantTransitionPolicy` no longer reconstructs `session_context.active_focus_object` in multiple local branches for purchase-date VAT bridge detection and selected-item carryover setup;
|
||||
- this matters because selected-item continuity, purchase-date VAT bridge, and navigation-driven focus-object hints now read one shared navigation-state interpretation instead of three local parsers inside the transition hot path;
|
||||
- targeted `assistantContinuityPolicy` and `assistantTransitionPolicy` suites are green after the move (`37/37`), backend build is green, and graphify was rebuilt on the updated codebase;
|
||||
- phase15 replay has also been made time-stable for the current snapshot step, and live replay `address_truth_harness_phase15_answer_inspection_followup_live_20260419_rerun11` is accepted `9/9`, which is the semantic proof that the selected-item / answer-inspection / VAT bridge contour still survives after the focus-authority convergence pass.
|
||||
|
||||
## Next Execution Slice (2026-04-19)
|
||||
|
||||
|
|
@ -558,6 +564,34 @@ Current remaining heavy fronts before low-risk domain expansion:
|
|||
- complete the missing contour for counterparty shipped-goods / service extraction instead of relying on honest-but-limited document-list fallback;
|
||||
- keep answer shaping as secondary debt only where it materially affects acceptance, not as the primary architecture frontier.
|
||||
|
||||
Execution framing for the next level:
|
||||
|
||||
- the working target is now `90%+ pre-multidomain readiness` before controlled domain expansion begins;
|
||||
- the current honest level is `~78%`, so the remaining gap should be treated as four large iterations, not as a few cosmetic follow-ups.
|
||||
|
||||
Current four-iteration plan:
|
||||
|
||||
1. `Iteration 1 / Continuity authority completion`
|
||||
Goal:
|
||||
finish convergence toward one owner for `organization / date / root frame / focus object / clarification state` across the hot runtime path.
|
||||
Expected gain:
|
||||
`~+4%`.
|
||||
2. `Iteration 2 / Wider saved-session replay pool`
|
||||
Goal:
|
||||
widen replay breadth beyond the current flagship + phase14 + phase15 + phase16 + phase17 family set.
|
||||
Expected gain:
|
||||
`~+4%`.
|
||||
3. `Iteration 3 / Coordinator pressure reduction`
|
||||
Goal:
|
||||
reduce control-plane overload in `assistantService.ts`, `addressQueryService.ts`, and adjacent top-level orchestration seams.
|
||||
Expected gain:
|
||||
`~+2-3%`.
|
||||
4. `Iteration 4 / Critical domain-enablement gaps + final replay proof`
|
||||
Goal:
|
||||
close the remaining high-value business gaps such as `counterparty shipped goods/service` and confirm the result under replay until the system crosses the `90%` threshold honestly.
|
||||
Expected gain:
|
||||
`~+1-2%`.
|
||||
|
||||
## Ready Signal
|
||||
|
||||
The project can leave the current breakpoint when:
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ Current confidence snapshot:
|
|||
- turnaround implementation progress: `~96%`
|
||||
- exit-from-danger-zone readiness: `~91%`
|
||||
- pre-multidomain readiness: `~78%`
|
||||
- latest graph snapshot: `5371 nodes`, `11523 edges`, `135 communities`
|
||||
- latest graph snapshot: `5372 nodes`, `11525 edges`, `135 communities`
|
||||
|
||||
## What Is Already True
|
||||
|
||||
|
|
@ -139,7 +139,13 @@ The system should not be considered ready for the next level until all of the fo
|
|||
|
||||
## Recommended Next Execution Sequence
|
||||
|
||||
### Pass 18. Continuity authority completion
|
||||
The current planning assumption is:
|
||||
|
||||
- `90%+ pre-multidomain readiness` is the practical threshold for starting controlled domain expansion;
|
||||
- the project is currently around `78%`;
|
||||
- therefore the remaining gap should be treated as roughly four large iterations rather than as a handful of cosmetic fixes.
|
||||
|
||||
### Iteration 1 / Pass 18. Continuity authority completion
|
||||
|
||||
Goal:
|
||||
|
||||
|
|
@ -149,7 +155,11 @@ Target:
|
|||
|
||||
- transition / route / clarification should consume one continuity snapshot before making divergent decisions.
|
||||
|
||||
### Pass 19. Wider saved-session acceptance pool
|
||||
Expected readiness gain:
|
||||
|
||||
- `~+4%` toward pre-multidomain readiness.
|
||||
|
||||
### Iteration 2 / Pass 19. Wider saved-session acceptance pool
|
||||
|
||||
Goal:
|
||||
|
||||
|
|
@ -159,17 +169,11 @@ Target:
|
|||
|
||||
- several saved sessions covering inventory, VAT, counterparty, payables/receivables, meta interrupts, and cross-domain pivots beyond phase12 / phase16 / phase17.
|
||||
|
||||
### Pass 20. Human answer shaping cleanup
|
||||
Expected readiness gain:
|
||||
|
||||
Goal:
|
||||
- `~+4%` toward pre-multidomain readiness.
|
||||
|
||||
- remove the remaining mechanical, template-heavy feel from long exact answers.
|
||||
|
||||
Target:
|
||||
|
||||
- product-quality business answers on already-correct truth paths.
|
||||
|
||||
### Pass 21. Coordinator pressure reduction
|
||||
### Iteration 3 / Pass 20. Coordinator pressure reduction
|
||||
|
||||
Goal:
|
||||
|
||||
|
|
@ -177,7 +181,30 @@ Goal:
|
|||
|
||||
Target:
|
||||
|
||||
- less policy/service glue concentrated in `assistantService.ts` and adjacent god-modules.
|
||||
- less policy/service glue concentrated in `assistantService.ts`, `addressQueryService.ts`, and adjacent coordinator-heavy seams.
|
||||
|
||||
Expected readiness gain:
|
||||
|
||||
- `~+2-3%` toward pre-multidomain readiness.
|
||||
|
||||
### Iteration 4 / Pass 21. Critical domain-enablement gaps and final acceptance proof
|
||||
|
||||
Goal:
|
||||
|
||||
- close the remaining high-value domain gaps that still block truthful expansion claims and then prove the result on replay.
|
||||
|
||||
Target:
|
||||
|
||||
- missing business contours such as `counterparty shipped goods/service`, plus the final replay confirmation that the system is over the `90%` threshold.
|
||||
|
||||
Expected readiness gain:
|
||||
|
||||
- `~+1-2%` toward pre-multidomain readiness.
|
||||
|
||||
Secondary cleanup after those four iterations:
|
||||
|
||||
- human answer shaping cleanup where it materially affects acceptance;
|
||||
- further quality polish that should not be confused with the core readiness gate.
|
||||
|
||||
## Final Statement
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ Current honest status:
|
|||
- turnaround implementation progress: `~96%`
|
||||
- exit-from-danger-zone readiness: `~91%`
|
||||
- pre-multidomain readiness: `~78%`
|
||||
- graph snapshot after latest rebuild: `5371 nodes`, `11523 edges`, `135 communities`
|
||||
- graph snapshot after latest rebuild: `5372 nodes`, `11525 edges`, `135 communities`
|
||||
- current breakpoint:
|
||||
- the validated hot paths are no longer structurally broken;
|
||||
- flagship continuity collapse is no longer the primary risk;
|
||||
|
|
@ -65,7 +65,7 @@ Latest live proof now includes:
|
|||
|
||||
- `address_truth_harness_phase12_wider_saved_session_pool_live_20260419_rerun16` accepted `20/20`
|
||||
- `address_truth_harness_phase14_counterparty_tail_resume_live_20260418_rerun2` accepted `10/10`
|
||||
- `address_truth_harness_phase15_answer_inspection_followup_live_20260418_rerun8` accepted `9/9`
|
||||
- `address_truth_harness_phase15_answer_inspection_followup_live_20260419_rerun11` accepted `9/9`
|
||||
- `address_truth_harness_phase16_multicompany_late_pivot_live_20260419_rerun10` accepted
|
||||
- `address_truth_harness_phase17_clarification_resume_and_counterparty_tail_live_20260419_rerun5` accepted `10/10`
|
||||
|
||||
|
|
@ -74,6 +74,7 @@ Current architectural reading:
|
|||
- the system is already materially past the dangerous regression breakpoint;
|
||||
- it is now safe for continued architecture hardening and controlled domain-by-domain enablement under replay gates;
|
||||
- it is now materially closer to pre-multidomain stability, but still not safe to declare broad low-risk multi-domain expansion.
|
||||
- the practical next target is now `90%+ pre-multidomain readiness`, and the remaining gap should be treated as four large architecture iterations rather than as cosmetic cleanup.
|
||||
|
||||
For the detailed audit, current percentages, and remaining debt, read:
|
||||
|
||||
|
|
|
|||
|
|
@ -50,12 +50,12 @@
|
|||
],
|
||||
"expected_recipe": "address_inventory_on_hand_as_of_date_v1",
|
||||
"required_filters": {
|
||||
"as_of_date": "2026-04-18",
|
||||
"as_of_date": "{{runtime.today_iso}}",
|
||||
"organization": "ООО Альтернатива Плюс"
|
||||
},
|
||||
"required_direct_answer_patterns_any": [
|
||||
"(?i)на складе|остат",
|
||||
"18\\.04\\.2026"
|
||||
"{{runtime.today_dot_regex}}"
|
||||
],
|
||||
"criticality": "critical",
|
||||
"semantic_tags": [
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ exports.readAddressDebugOrganization = readAddressDebugOrganization;
|
|||
exports.readAddressDebugScopedDate = readAddressDebugScopedDate;
|
||||
exports.readAddressDebugTemporalScope = readAddressDebugTemporalScope;
|
||||
exports.resolveAddressDebugAnchorContext = resolveAddressDebugAnchorContext;
|
||||
exports.resolveNavigationSessionContextState = resolveNavigationSessionContextState;
|
||||
exports.resolveAddressDebugContextFacts = resolveAddressDebugContextFacts;
|
||||
exports.resolveAddressDebugCarryoverFilters = resolveAddressDebugCarryoverFilters;
|
||||
exports.hydrateInventoryRootFrameState = hydrateInventoryRootFrameState;
|
||||
|
|
@ -127,6 +128,23 @@ function resolveAddressDebugAnchorContext(debug, toNonEmptyString = fallbackToNo
|
|||
anchorValue: null
|
||||
};
|
||||
}
|
||||
function resolveNavigationSessionContextState(addressNavigationState, toNonEmptyString = fallbackToNonEmptyString, normalizeOrganizationScopeValue = normalizeOrganizationScopeDefault) {
|
||||
const sessionContext = toRecordObject(toRecordObject(addressNavigationState)?.session_context);
|
||||
const rawFocusObject = toRecordObject(sessionContext?.active_focus_object);
|
||||
const focusObject = rawFocusObject
|
||||
? {
|
||||
objectType: toNonEmptyString(rawFocusObject.object_type),
|
||||
label: toNonEmptyString(rawFocusObject.label),
|
||||
provenanceResultSetId: toNonEmptyString(rawFocusObject.provenance_result_set_id)
|
||||
}
|
||||
: null;
|
||||
return {
|
||||
dateScope: toRecordObject(sessionContext?.date_scope),
|
||||
organization: normalizeOrganizationScopeValue(sessionContext?.organization_scope),
|
||||
focusObject,
|
||||
activeResultSetId: toNonEmptyString(sessionContext?.active_result_set_id)
|
||||
};
|
||||
}
|
||||
function resolveAddressDebugContextFacts(debug, toNonEmptyString = fallbackToNonEmptyString) {
|
||||
return {
|
||||
item: readAddressDebugItem(debug, toNonEmptyString),
|
||||
|
|
|
|||
|
|
@ -104,17 +104,9 @@ function createAssistantTransitionPolicy(deps) {
|
|||
return computeMonthWindowFromIso(explicitFirstDateIso);
|
||||
}
|
||||
}
|
||||
const sessionContext = addressNavigationState &&
|
||||
typeof addressNavigationState === "object" &&
|
||||
addressNavigationState.session_context &&
|
||||
typeof addressNavigationState.session_context === "object"
|
||||
? addressNavigationState.session_context
|
||||
: null;
|
||||
const focusObject = sessionContext && typeof sessionContext.active_focus_object === "object"
|
||||
? sessionContext.active_focus_object
|
||||
: null;
|
||||
const preferredResultSetId = deps.toNonEmptyString(focusObject?.provenance_result_set_id) ??
|
||||
deps.toNonEmptyString(sessionContext?.active_result_set_id);
|
||||
const navigationSessionState = (0, assistantContinuityPolicy_1.resolveNavigationSessionContextState)(addressNavigationState, deps.toNonEmptyString, deps.normalizeOrganizationScopeValue);
|
||||
const focusObject = navigationSessionState.focusObject;
|
||||
const preferredResultSetId = deps.toNonEmptyString(focusObject?.provenanceResultSetId) ?? navigationSessionState.activeResultSetId;
|
||||
const resultSets = Array.isArray(addressNavigationState?.result_sets) ? addressNavigationState.result_sets : [];
|
||||
const preferredResultSet = (preferredResultSetId
|
||||
? resultSets.find((item) => deps.toNonEmptyString(item?.result_set_id) === preferredResultSetId) ?? null
|
||||
|
|
@ -331,16 +323,10 @@ function createAssistantTransitionPolicy(deps) {
|
|||
? deps.isImplicitAddressContinuationByLlm(alternateMessage, llmPreDecomposeMeta)
|
||||
: false));
|
||||
const sourceIntentHint = deps.toNonEmptyString(carryoverSourceDebug?.detected_intent);
|
||||
const navigationFocusObjectHint = addressNavigationState &&
|
||||
typeof addressNavigationState === "object" &&
|
||||
addressNavigationState.session_context &&
|
||||
typeof addressNavigationState.session_context === "object" &&
|
||||
addressNavigationState.session_context.active_focus_object &&
|
||||
typeof addressNavigationState.session_context.active_focus_object === "object"
|
||||
? addressNavigationState.session_context.active_focus_object
|
||||
: null;
|
||||
const navigationSessionState = (0, assistantContinuityPolicy_1.resolveNavigationSessionContextState)(addressNavigationState, deps.toNonEmptyString, deps.normalizeOrganizationScopeValue);
|
||||
const navigationFocusObjectHint = navigationSessionState.focusObject;
|
||||
const hasNavigationInventoryItemFocusHint = Boolean(deps.toNonEmptyString(navigationFocusObjectHint?.label) &&
|
||||
deps.toNonEmptyString(navigationFocusObjectHint?.object_type) === "item" &&
|
||||
deps.toNonEmptyString(navigationFocusObjectHint?.objectType) === "item" &&
|
||||
(sourceIntentHint === "inventory_on_hand_as_of_date" ||
|
||||
sourceIntentHint === "inventory_supplier_stock_overlap_as_of_date" ||
|
||||
deps.isInventorySelectedObjectIntent(sourceIntentHint)));
|
||||
|
|
@ -499,19 +485,10 @@ function createAssistantTransitionPolicy(deps) {
|
|||
const previousAnchorContext = (0, assistantContinuityPolicy_1.resolveAddressDebugAnchorContext)(carryoverSourceDebug, deps.toNonEmptyString);
|
||||
let previousAnchorType = previousAnchorContext.anchorType;
|
||||
let previousAnchor = previousAnchorContext.anchorValue;
|
||||
const navigationSessionContext = addressNavigationState && typeof addressNavigationState === "object"
|
||||
? addressNavigationState.session_context && typeof addressNavigationState.session_context === "object"
|
||||
? addressNavigationState.session_context
|
||||
: null
|
||||
: null;
|
||||
const navigationDateScope = navigationSessionContext && typeof navigationSessionContext.date_scope === "object"
|
||||
? navigationSessionContext.date_scope
|
||||
: null;
|
||||
const navigationOrganization = deps.normalizeOrganizationScopeValue(navigationSessionContext?.organization_scope);
|
||||
const navigationFocusObject = navigationSessionContext && typeof navigationSessionContext.active_focus_object === "object"
|
||||
? navigationSessionContext.active_focus_object
|
||||
: null;
|
||||
const navigationFocusObjectType = deps.toNonEmptyString(navigationFocusObject?.object_type);
|
||||
const navigationDateScope = navigationSessionState.dateScope;
|
||||
const navigationOrganization = navigationSessionState.organization;
|
||||
const navigationFocusObject = navigationSessionState.focusObject;
|
||||
const navigationFocusObjectType = deps.toNonEmptyString(navigationFocusObject?.objectType);
|
||||
const navigationFocusObjectLabel = deps.toNonEmptyString(navigationFocusObject?.label);
|
||||
const hasInventoryItemFocusCarryover = navigationFocusObjectType === "item" &&
|
||||
navigationFocusObjectLabel &&
|
||||
|
|
|
|||
|
|
@ -45,6 +45,19 @@ export interface AssistantNavigationDateScope {
|
|||
period_to?: unknown;
|
||||
}
|
||||
|
||||
export interface AssistantNavigationFocusObject {
|
||||
objectType: string | null;
|
||||
label: string | null;
|
||||
provenanceResultSetId: string | null;
|
||||
}
|
||||
|
||||
export interface AssistantNavigationSessionContextState {
|
||||
dateScope: AssistantNavigationDateScope | null;
|
||||
organization: string | null;
|
||||
focusObject: AssistantNavigationFocusObject | null;
|
||||
activeResultSetId: string | null;
|
||||
}
|
||||
|
||||
export interface AssistantAddressDebugAnchorContext {
|
||||
anchorType: string | null;
|
||||
anchorValue: string | null;
|
||||
|
|
@ -203,6 +216,28 @@ export function resolveAddressDebugAnchorContext(
|
|||
};
|
||||
}
|
||||
|
||||
export function resolveNavigationSessionContextState(
|
||||
addressNavigationState: unknown,
|
||||
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString,
|
||||
normalizeOrganizationScopeValue: (value: unknown) => string | null = normalizeOrganizationScopeDefault
|
||||
): AssistantNavigationSessionContextState {
|
||||
const sessionContext = toRecordObject(toRecordObject(addressNavigationState)?.session_context);
|
||||
const rawFocusObject = toRecordObject(sessionContext?.active_focus_object);
|
||||
const focusObject = rawFocusObject
|
||||
? {
|
||||
objectType: toNonEmptyString(rawFocusObject.object_type),
|
||||
label: toNonEmptyString(rawFocusObject.label),
|
||||
provenanceResultSetId: toNonEmptyString(rawFocusObject.provenance_result_set_id)
|
||||
}
|
||||
: null;
|
||||
return {
|
||||
dateScope: toRecordObject(sessionContext?.date_scope) as AssistantNavigationDateScope | null,
|
||||
organization: normalizeOrganizationScopeValue(sessionContext?.organization_scope),
|
||||
focusObject,
|
||||
activeResultSetId: toNonEmptyString(sessionContext?.active_result_set_id)
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveAddressDebugContextFacts(
|
||||
debug: Record<string, unknown> | null,
|
||||
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
readAddressDebugFilters,
|
||||
readAddressDebugItem,
|
||||
readAddressDebugTemporalScope,
|
||||
resolveNavigationSessionContextState,
|
||||
resolveAddressDebugCarryoverFilters,
|
||||
resolveAddressDebugAnchorContext,
|
||||
resolveDisplayedEntityFollowupRetarget,
|
||||
|
|
@ -145,20 +146,14 @@ export function createAssistantTransitionPolicy(deps) {
|
|||
}
|
||||
}
|
||||
|
||||
const sessionContext =
|
||||
addressNavigationState &&
|
||||
typeof addressNavigationState === "object" &&
|
||||
addressNavigationState.session_context &&
|
||||
typeof addressNavigationState.session_context === "object"
|
||||
? addressNavigationState.session_context
|
||||
: null;
|
||||
const focusObject =
|
||||
sessionContext && typeof sessionContext.active_focus_object === "object"
|
||||
? sessionContext.active_focus_object
|
||||
: null;
|
||||
const navigationSessionState = resolveNavigationSessionContextState(
|
||||
addressNavigationState,
|
||||
deps.toNonEmptyString,
|
||||
deps.normalizeOrganizationScopeValue
|
||||
);
|
||||
const focusObject = navigationSessionState.focusObject;
|
||||
const preferredResultSetId =
|
||||
deps.toNonEmptyString(focusObject?.provenance_result_set_id) ??
|
||||
deps.toNonEmptyString(sessionContext?.active_result_set_id);
|
||||
deps.toNonEmptyString(focusObject?.provenanceResultSetId) ?? navigationSessionState.activeResultSetId;
|
||||
const resultSets = Array.isArray(addressNavigationState?.result_sets) ? addressNavigationState.result_sets : [];
|
||||
const preferredResultSet =
|
||||
(preferredResultSetId
|
||||
|
|
@ -431,18 +426,15 @@ export function createAssistantTransitionPolicy(deps) {
|
|||
? deps.isImplicitAddressContinuationByLlm(alternateMessage, llmPreDecomposeMeta)
|
||||
: false));
|
||||
const sourceIntentHint = deps.toNonEmptyString(carryoverSourceDebug?.detected_intent);
|
||||
const navigationFocusObjectHint =
|
||||
addressNavigationState &&
|
||||
typeof addressNavigationState === "object" &&
|
||||
addressNavigationState.session_context &&
|
||||
typeof addressNavigationState.session_context === "object" &&
|
||||
addressNavigationState.session_context.active_focus_object &&
|
||||
typeof addressNavigationState.session_context.active_focus_object === "object"
|
||||
? addressNavigationState.session_context.active_focus_object
|
||||
: null;
|
||||
const navigationSessionState = resolveNavigationSessionContextState(
|
||||
addressNavigationState,
|
||||
deps.toNonEmptyString,
|
||||
deps.normalizeOrganizationScopeValue
|
||||
);
|
||||
const navigationFocusObjectHint = navigationSessionState.focusObject;
|
||||
const hasNavigationInventoryItemFocusHint = Boolean(
|
||||
deps.toNonEmptyString(navigationFocusObjectHint?.label) &&
|
||||
deps.toNonEmptyString(navigationFocusObjectHint?.object_type) === "item" &&
|
||||
deps.toNonEmptyString(navigationFocusObjectHint?.objectType) === "item" &&
|
||||
(sourceIntentHint === "inventory_on_hand_as_of_date" ||
|
||||
sourceIntentHint === "inventory_supplier_stock_overlap_as_of_date" ||
|
||||
deps.isInventorySelectedObjectIntent(sourceIntentHint))
|
||||
|
|
@ -643,22 +635,10 @@ export function createAssistantTransitionPolicy(deps) {
|
|||
const previousAnchorContext = resolveAddressDebugAnchorContext(carryoverSourceDebug, deps.toNonEmptyString);
|
||||
let previousAnchorType = previousAnchorContext.anchorType;
|
||||
let previousAnchor = previousAnchorContext.anchorValue;
|
||||
const navigationSessionContext =
|
||||
addressNavigationState && typeof addressNavigationState === "object"
|
||||
? addressNavigationState.session_context && typeof addressNavigationState.session_context === "object"
|
||||
? addressNavigationState.session_context
|
||||
: null
|
||||
: null;
|
||||
const navigationDateScope =
|
||||
navigationSessionContext && typeof navigationSessionContext.date_scope === "object"
|
||||
? navigationSessionContext.date_scope
|
||||
: null;
|
||||
const navigationOrganization = deps.normalizeOrganizationScopeValue(navigationSessionContext?.organization_scope);
|
||||
const navigationFocusObject =
|
||||
navigationSessionContext && typeof navigationSessionContext.active_focus_object === "object"
|
||||
? navigationSessionContext.active_focus_object
|
||||
: null;
|
||||
const navigationFocusObjectType = deps.toNonEmptyString(navigationFocusObject?.object_type);
|
||||
const navigationDateScope = navigationSessionState.dateScope;
|
||||
const navigationOrganization = navigationSessionState.organization;
|
||||
const navigationFocusObject = navigationSessionState.focusObject;
|
||||
const navigationFocusObjectType = deps.toNonEmptyString(navigationFocusObject?.objectType);
|
||||
const navigationFocusObjectLabel = deps.toNonEmptyString(navigationFocusObject?.label);
|
||||
const hasInventoryItemFocusCarryover =
|
||||
navigationFocusObjectType === "item" &&
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
buildRootScopedCarryoverFilters,
|
||||
hydrateInventoryRootFrameState,
|
||||
readAddressDebugTemporalScope,
|
||||
resolveNavigationSessionContextState,
|
||||
resolveAddressDebugCarryoverFilters,
|
||||
resolveAddressDebugContextFacts,
|
||||
resolveAddressDebugAnchorContext,
|
||||
|
|
@ -111,6 +112,40 @@ describe("assistantContinuityPolicy organization authority", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("resolves navigation session context through one shared helper", () => {
|
||||
const state = resolveNavigationSessionContextState({
|
||||
session_context: {
|
||||
organization_scope: "Org Alt",
|
||||
active_result_set_id: "rs-42",
|
||||
date_scope: {
|
||||
as_of_date: "2020-03-31",
|
||||
period_from: "2020-03-01",
|
||||
period_to: "2020-03-31"
|
||||
},
|
||||
active_focus_object: {
|
||||
object_type: "item",
|
||||
label: "Workstation",
|
||||
provenance_result_set_id: "rs-focus"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(state).toEqual({
|
||||
organization: "Org Alt",
|
||||
activeResultSetId: "rs-42",
|
||||
dateScope: {
|
||||
as_of_date: "2020-03-31",
|
||||
period_from: "2020-03-01",
|
||||
period_to: "2020-03-31"
|
||||
},
|
||||
focusObject: {
|
||||
objectType: "item",
|
||||
label: "Workstation",
|
||||
provenanceResultSetId: "rs-focus"
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves carryover temporal scope and inferred anchor from debug filters when explicit anchor fields are absent", () => {
|
||||
const debug = {
|
||||
extracted_filters: {
|
||||
|
|
|
|||
Loading…
Reference in New Issue