ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Архитектурный фундамент: capability-guard, navigation state и трассируемый route-контракт
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
isCapabilityRouteBlocked,
|
||||
resolveAddressCapabilityRouteDecision,
|
||||
resolveShadowRouteIntent
|
||||
} from "../src/services/addressCapabilityPolicy";
|
||||
|
||||
describe("address capability policy", () => {
|
||||
it("maps confirmed payables intent to compute exact capability", () => {
|
||||
const decision = resolveAddressCapabilityRouteDecision("payables_confirmed_as_of_date");
|
||||
expect(decision.capability_id).toBe("confirmed_payables_as_of_date");
|
||||
expect(decision.capability_layer).toBe("compute");
|
||||
expect(decision.capability_route_mode).toBe("exact");
|
||||
expect(decision.capability_route_enabled).toBe(true);
|
||||
expect(isCapabilityRouteBlocked(decision)).toBe(false);
|
||||
});
|
||||
|
||||
it("maps document drilldown intent to navigation capability", () => {
|
||||
const decision = resolveAddressCapabilityRouteDecision("list_documents_by_contract");
|
||||
expect(decision.capability_id).toBe("documents_drilldown");
|
||||
expect(decision.capability_layer).toBe("navigation");
|
||||
expect(decision.capability_route_mode).toBe("exact");
|
||||
expect(decision.capability_route_enabled).toBe(true);
|
||||
});
|
||||
|
||||
it("maps heuristic list intents to heuristic compute route mode", () => {
|
||||
const decision = resolveAddressCapabilityRouteDecision("list_receivables_counterparties");
|
||||
expect(decision.capability_id).toBe("receivables_candidates_list");
|
||||
expect(decision.capability_layer).toBe("compute");
|
||||
expect(decision.capability_route_mode).toBe("heuristic");
|
||||
});
|
||||
|
||||
it("keeps shadow route disabled by default", () => {
|
||||
expect(resolveShadowRouteIntent("payables_confirmed_as_of_date", "confirmed_balance")).toBeNull();
|
||||
expect(resolveShadowRouteIntent("list_payables_counterparties", "confirmed_balance")).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,114 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
createEmptyAddressNavigationState,
|
||||
evolveAddressNavigationStateWithAssistantItem,
|
||||
normalizeAddressNavigationState
|
||||
} from "../src/services/addressNavigationState";
|
||||
|
||||
describe("address navigation state", () => {
|
||||
it("creates default empty state", () => {
|
||||
const state = createEmptyAddressNavigationState("asst-1", "2026-04-12T10:00:00.000Z");
|
||||
expect(state.schema_version).toBe("address_navigation_state_v1");
|
||||
expect(state.session_id).toBe("asst-1");
|
||||
expect(state.result_sets).toEqual([]);
|
||||
expect(state.navigation_history).toEqual([]);
|
||||
expect(state.session_context.active_result_set_id).toBeNull();
|
||||
});
|
||||
|
||||
it("captures result_set and focus from address assistant turn", () => {
|
||||
const base = createEmptyAddressNavigationState("asst-2", "2026-04-12T10:00:00.000Z");
|
||||
const assistantItem = {
|
||||
message_id: "msg-a1",
|
||||
session_id: "asst-2",
|
||||
role: "assistant",
|
||||
text: [
|
||||
"Топ-6 заказчиков по сумме поступлений:",
|
||||
"1. Группа | сумма: 12093465 | операций: 13",
|
||||
"4. Гамма-мебель, ООО | сумма: 471000 | операций: 2"
|
||||
].join("\n"),
|
||||
reply_type: "factual",
|
||||
created_at: "2026-04-12T10:00:10.000Z",
|
||||
trace_id: "address-123",
|
||||
debug: {
|
||||
detected_mode: "address_query",
|
||||
detected_intent: "customer_revenue_and_payments",
|
||||
selected_recipe: "address_customer_revenue_and_payments_v1",
|
||||
extracted_filters: {
|
||||
period_from: "2020-01-01",
|
||||
period_to: "2020-12-31"
|
||||
},
|
||||
anchor_type: "counterparty",
|
||||
anchor_value_resolved: "Гамма-мебель, ООО",
|
||||
dialog_continuation_contract_v2: {
|
||||
decision: "new_topic"
|
||||
}
|
||||
}
|
||||
} as any;
|
||||
|
||||
const evolved = evolveAddressNavigationStateWithAssistantItem(base, assistantItem, 2);
|
||||
expect(evolved.result_sets.length).toBe(1);
|
||||
expect(evolved.result_sets[0]?.result_set_id).toBe("rs-msg-a1");
|
||||
expect(evolved.result_sets[0]?.intent).toBe("customer_revenue_and_payments");
|
||||
expect(evolved.result_sets[0]?.entity_refs.length).toBeGreaterThan(0);
|
||||
expect(evolved.session_context.active_result_set_id).toBe("rs-msg-a1");
|
||||
expect(evolved.session_context.active_focus_object?.label).toBe("Гамма-мебель, ООО");
|
||||
expect(evolved.navigation_history[0]?.action).toBe("open");
|
||||
});
|
||||
|
||||
it("tracks drilldown event for follow-up continuation turn", () => {
|
||||
const initial = normalizeAddressNavigationState(
|
||||
{
|
||||
schema_version: "address_navigation_state_v1",
|
||||
session_id: "asst-3",
|
||||
updated_at: "2026-04-12T10:00:00.000Z",
|
||||
session_context: {
|
||||
active_result_set_id: "rs-prev",
|
||||
active_focus_object: null,
|
||||
last_confirmed_route: "address_customer_revenue_and_payments_v1",
|
||||
date_scope: {
|
||||
as_of_date: null,
|
||||
period_from: "2020-01-01",
|
||||
period_to: "2020-12-31"
|
||||
},
|
||||
organization_scope: null
|
||||
},
|
||||
result_sets: [],
|
||||
navigation_history: []
|
||||
} as any,
|
||||
"asst-3"
|
||||
);
|
||||
const assistantItem = {
|
||||
message_id: "msg-a2",
|
||||
session_id: "asst-3",
|
||||
role: "assistant",
|
||||
text: "Собран список договоров по контрагенту Гамма-мебель, ООО.",
|
||||
reply_type: "factual",
|
||||
created_at: "2026-04-12T10:02:00.000Z",
|
||||
trace_id: "address-456",
|
||||
debug: {
|
||||
detected_mode: "address_query",
|
||||
detected_intent: "list_contracts_by_counterparty",
|
||||
selected_recipe: "address_contracts_by_counterparty_v1",
|
||||
extracted_filters: {
|
||||
period_from: "2020-01-01",
|
||||
period_to: "2020-12-31",
|
||||
counterparty: "Гамма-мебель, ООО"
|
||||
},
|
||||
anchor_type: "counterparty",
|
||||
anchor_value_resolved: "Гамма-мебель, ООО",
|
||||
dialog_continuation_contract_v2: {
|
||||
decision: "continue_previous"
|
||||
}
|
||||
}
|
||||
} as any;
|
||||
|
||||
const evolved = evolveAddressNavigationStateWithAssistantItem(initial, assistantItem, 4);
|
||||
expect(evolved.navigation_history.length).toBe(1);
|
||||
expect(evolved.navigation_history[0]?.action).toBe("drilldown");
|
||||
expect(evolved.navigation_history[0]?.source_result_set_id).toBe("rs-prev");
|
||||
expect(evolved.session_context.active_result_set_id).toBe("rs-msg-a2");
|
||||
expect(evolved.session_context.active_focus_object?.object_type).toBe("counterparty");
|
||||
expect(evolved.session_context.date_scope.period_from).toBe("2020-01-01");
|
||||
expect(evolved.session_context.date_scope.period_to).toBe("2020-12-31");
|
||||
});
|
||||
});
|
||||
@@ -19,6 +19,7 @@ describe("assistant session backward compatibility", () => {
|
||||
expect(session?.session_id).toBe(sessionId);
|
||||
expect(Array.isArray(session?.items)).toBe(true);
|
||||
expect(session?.investigation_state?.schema_version).toBe("investigation_state_v1");
|
||||
expect(session?.address_navigation_state?.schema_version).toBe("address_navigation_state_v1");
|
||||
});
|
||||
|
||||
it("normalizes malformed legacy sessions with missing items array", () => {
|
||||
@@ -35,6 +36,7 @@ describe("assistant session backward compatibility", () => {
|
||||
expect(Array.isArray(ensured.items)).toBe(true);
|
||||
expect(ensured.items.length).toBe(0);
|
||||
expect(ensured.investigation_state?.schema_version).toBe("investigation_state_v1");
|
||||
expect(ensured.address_navigation_state?.schema_version).toBe("address_navigation_state_v1");
|
||||
});
|
||||
|
||||
it("preserves optional stage2 problem_unit_state in session clone flow", () => {
|
||||
@@ -73,5 +75,6 @@ describe("assistant session backward compatibility", () => {
|
||||
expect(session).toBeTruthy();
|
||||
expect(session?.investigation_state?.problem_unit_state?.active_problem_units).toEqual(["pu-1", "pu-2"]);
|
||||
expect(session?.investigation_state?.problem_unit_state?.focus_problem_types).toEqual(["broken_chain_segment"]);
|
||||
expect(session?.address_navigation_state?.schema_version).toBe("address_navigation_state_v1");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user