From 59656a44a0ccf69e6187bf919bec88f3dadb3413 Mon Sep 17 00:00:00 2001 From: dctouch Date: Sat, 18 Apr 2026 21:25:18 +0300 Subject: [PATCH] =?UTF-8?q?=D0=90=D1=80=D1=85=D0=B8=D1=82=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D1=83=D1=80=D0=B0:=20=D0=BF=D1=80=D0=BE=D1=82=D1=8F?= =?UTF-8?q?=D0=BD=D1=83=D1=82=D1=8C=20shared=20organization=20authority=20?= =?UTF-8?q?=D0=B2=20data-scope=20history=20recovery=20=D0=B8=20session=20b?= =?UTF-8?q?ootstrap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ontinuity_stabilization_plan_2026-04-17.md | 6 +++ .../dist/services/assistantDataScopePolicy.js | 30 ++++----------- .../src/services/assistantDataScopePolicy.ts | 35 ++++-------------- .../tests/assistantDataScopePolicy.test.ts | 37 +++++++++++++++++++ 4 files changed, 57 insertions(+), 51 deletions(-) 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 1c0c91c..d6fe34a 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 @@ -351,6 +351,12 @@ Still open after the accepted phase12 replay: - this matters because follow-up carryover is now closer to the same continuity interpretation layer that already owns item / organization / scoped-date facts, rather than keeping a separate transition-local parser for the same runtime evidence; - targeted continuity and transition regressions now protect inferred anchor carryover when explicit `anchor_type` is absent, plus root-frame temporal fallback at the helper layer; - wide saved-session replay `address_truth_harness_phase12_wider_saved_session_pool_live_20260418_rerun7` remains accepted `20/20`, which is the critical proof that this transition-layer convergence did not reopen the broader saved-session path. +- the next organization-authority pass now removes one more local history parser from the data-scope / session-bootstrap contour: + - `assistantDataScopePolicy.extractKnownOrganizationsFromHistory` no longer rebuilds `known organizations` from raw `assistant_* / organization_candidates / extracted_filters / root_frame_context` fields on its own; + - it now reads the shared `resolveAssistantOrganizationAuthority(...)` result first and only keeps assistant-text parsing as a compatibility fallback for older free-text scope replies; + - this matters because data-scope probing, organization selection bootstrap, and the broader continuity layer are now closer to one canonical organization merge order instead of keeping a separate debug-field collector inside the scope policy; + - targeted data-scope and organization-scope tests now protect that known organizations still include assistant-side authority, grounded address context, and free-text fallback organizations; + - wide saved-session replay `address_truth_harness_phase12_wider_saved_session_pool_live_20260418_rerun8` remains accepted `20/20`, which is the critical proof that this data-scope convergence did not reopen the flagship saved-session path. ## Next Execution Slice (2026-04-18) diff --git a/llm_normalizer/backend/dist/services/assistantDataScopePolicy.js b/llm_normalizer/backend/dist/services/assistantDataScopePolicy.js index d08e4e7..8519fb7 100644 --- a/llm_normalizer/backend/dist/services/assistantDataScopePolicy.js +++ b/llm_normalizer/backend/dist/services/assistantDataScopePolicy.js @@ -180,34 +180,18 @@ function createAssistantDataScopePolicy(deps) { return Array.from(new Set(extracted)); } function extractKnownOrganizationsFromHistory(items) { - const collected = []; + const authority = (0, assistantContinuityPolicy_1.resolveAssistantOrganizationAuthority)({ + sessionItems: items, + toNonEmptyString: assistantOrganizationMatcher_1.normalizeOrganizationScopeValue, + normalizeOrganizationScopeValue: assistantOrganizationMatcher_1.normalizeOrganizationScopeValue, + mergeKnownOrganizations: assistantOrganizationMatcher_1.mergeKnownOrganizations + }); + const collected = [...authority.knownOrganizations]; for (let index = (Array.isArray(items) ? items.length : 0) - 1; index >= 0; index -= 1) { const item = Array.isArray(items) ? items[index] : null; if (!item || typeof item !== "object" || item.role !== "assistant") { continue; } - const debug = item.debug; - if (debug && typeof debug === "object") { - const directFromProbe = Array.isArray(debug.living_chat_data_scope_probe_organizations) - ? debug.living_chat_data_scope_probe_organizations - : []; - const knownFromDebug = Array.isArray(debug.assistant_known_organizations) - ? debug.assistant_known_organizations - : []; - const directFromCandidates = Array.isArray(debug.organization_candidates) ? debug.organization_candidates : []; - const directFromResolved = [ - (0, assistantOrganizationMatcher_1.normalizeOrganizationScopeValue)(debug.assistant_active_organization), - (0, assistantOrganizationMatcher_1.normalizeOrganizationScopeValue)(debug.living_chat_selected_organization), - (0, assistantOrganizationMatcher_1.normalizeOrganizationScopeValue)(debug.extracted_filters?.organization), - (0, assistantOrganizationMatcher_1.normalizeOrganizationScopeValue)(debug.address_root_frame_context?.organization) - ].filter((value) => Boolean(value)); - if (directFromProbe.length > 0 || - knownFromDebug.length > 0 || - directFromCandidates.length > 0 || - directFromResolved.length > 0) { - collected.push(...directFromProbe, ...knownFromDebug, ...directFromCandidates, ...directFromResolved); - } - } const parsedFromText = parseOrganizationsFromDataScopeAssistantText(item.text); if (parsedFromText.length > 0) { collected.push(...parsedFromText); diff --git a/llm_normalizer/backend/src/services/assistantDataScopePolicy.ts b/llm_normalizer/backend/src/services/assistantDataScopePolicy.ts index ac1bd39..482556e 100644 --- a/llm_normalizer/backend/src/services/assistantDataScopePolicy.ts +++ b/llm_normalizer/backend/src/services/assistantDataScopePolicy.ts @@ -249,39 +249,18 @@ export function createAssistantDataScopePolicy(deps: AssistantDataScopePolicyDep } function extractKnownOrganizationsFromHistory(items: unknown[]): string[] { - const collected: unknown[] = []; + const authority = resolveAssistantOrganizationAuthority({ + sessionItems: items, + toNonEmptyString: normalizeOrganizationScopeValue, + normalizeOrganizationScopeValue, + mergeKnownOrganizations + }); + const collected: unknown[] = [...authority.knownOrganizations]; for (let index = (Array.isArray(items) ? items.length : 0) - 1; index >= 0; index -= 1) { const item = Array.isArray(items) ? items[index] : null; if (!item || typeof item !== "object" || (item as { role?: string }).role !== "assistant") { continue; } - - const debug = (item as { debug?: Record }).debug; - if (debug && typeof debug === "object") { - const directFromProbe = Array.isArray(debug.living_chat_data_scope_probe_organizations) - ? debug.living_chat_data_scope_probe_organizations - : []; - const knownFromDebug = Array.isArray(debug.assistant_known_organizations) - ? debug.assistant_known_organizations - : []; - const directFromCandidates = Array.isArray(debug.organization_candidates) ? debug.organization_candidates : []; - const directFromResolved = [ - normalizeOrganizationScopeValue(debug.assistant_active_organization), - normalizeOrganizationScopeValue(debug.living_chat_selected_organization), - normalizeOrganizationScopeValue(debug.extracted_filters?.organization), - normalizeOrganizationScopeValue(debug.address_root_frame_context?.organization) - ].filter((value): value is string => Boolean(value)); - - if ( - directFromProbe.length > 0 || - knownFromDebug.length > 0 || - directFromCandidates.length > 0 || - directFromResolved.length > 0 - ) { - collected.push(...directFromProbe, ...knownFromDebug, ...directFromCandidates, ...directFromResolved); - } - } - const parsedFromText = parseOrganizationsFromDataScopeAssistantText((item as { text?: unknown }).text); if (parsedFromText.length > 0) { collected.push(...parsedFromText); diff --git a/llm_normalizer/backend/tests/assistantDataScopePolicy.test.ts b/llm_normalizer/backend/tests/assistantDataScopePolicy.test.ts index e6fcd03..181d561 100644 --- a/llm_normalizer/backend/tests/assistantDataScopePolicy.test.ts +++ b/llm_normalizer/backend/tests/assistantDataScopePolicy.test.ts @@ -11,6 +11,43 @@ function createPolicy() { } describe("assistantDataScopePolicy", () => { + it("extracts known organizations from shared assistant organization authority and assistant text fallback", () => { + const policy = createPolicy(); + + const organizations = policy.extractKnownOrganizationsFromHistory([ + { + role: "assistant", + text: "Доступны организации: Org Text, Org Extra.", + debug: { + execution_lane: "living_chat", + living_chat_selected_organization: "Org Selected", + assistant_active_organization: "Org Selected", + assistant_known_organizations: ["Org Selected", "Org Backup"], + organization_candidates: ["Org Candidate"] + } + }, + { + role: "assistant", + debug: { + execution_lane: "address_query", + answer_grounding_check: { status: "grounded" }, + extracted_filters: { + organization: "Org Grounded" + } + } + } + ]); + + expect(organizations).toEqual([ + "Org Grounded", + "Org Selected", + "Org Backup", + "Org Candidate", + "Org Text", + "Org Extra" + ]); + }); + it("recovers active organization from assistant-side living chat authority when grounded answer is absent", () => { const policy = createPolicy();