From 1c1383b8b5913447f6a99cb85c1156d3d13a53e8 Mon Sep 17 00:00:00 2001 From: dctouch Date: Fri, 1 May 2026 14:15:55 +0300 Subject: [PATCH] =?UTF-8?q?Planner=20Autonomy:=20=D0=BF=D1=80=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D1=89=D0=B8=D1=82=D1=8C=20catalog=20chain=20matches=20?= =?UTF-8?q?=D0=B2=20runtime=20debug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...anner_autonomy_consolidation_2026-05-01.md | 10 +++++++++- .../11 - architecture_turnaround/README.md | 7 ++++--- .../assistantMcpDiscoveryDebugAttachment.js | 16 ++++++++++++++++ .../assistantMcpDiscoveryRuntimeBridge.js | 1 + .../assistantMcpDiscoveryDebugAttachment.ts | 19 +++++++++++++++++++ .../assistantMcpDiscoveryRuntimeBridge.ts | 2 ++ ...sistantMcpDiscoveryDebugAttachment.test.ts | 8 ++++++++ ...assistantMcpDiscoveryRuntimeBridge.test.ts | 1 + 8 files changed, 60 insertions(+), 4 deletions(-) diff --git a/docs/ARCH/11 - architecture_turnaround/20 - planner_autonomy_consolidation_2026-05-01.md b/docs/ARCH/11 - architecture_turnaround/20 - planner_autonomy_consolidation_2026-05-01.md index 49f300c..e4092d3 100644 --- a/docs/ARCH/11 - architecture_turnaround/20 - planner_autonomy_consolidation_2026-05-01.md +++ b/docs/ARCH/11 - architecture_turnaround/20 - planner_autonomy_consolidation_2026-05-01.md @@ -117,6 +117,7 @@ The following consolidation step added catalog-level chain-template scoring: - ranking-shaped value-flow ranks `value_flow_ranking` above the generic value-flow template; - document/movement/inventory/lifecycle templates can now be inspected as catalog search results, not only as local planner branch constants; - `assistantMcpDiscoveryPlanner` records the top catalog chain-template match in reason codes and exposes the ranked matches as `catalog_chain_template_matches` in the planner contract while preserving existing guarded execution behavior. +- the ranked chain-template matches are now propagated into runtime loop state and debug attachment fields, so replay analysis can inspect catalog-fabric intent without parsing reason-code strings. ## Why This Matters @@ -205,9 +206,16 @@ Latest validation after structured catalog chain-template contract exposure: - `npm.cmd run build`: passed - graphify rebuild: `5939 nodes`, `12906 edges`, `138 communities` +Latest validation after runtime/debug propagation of structured chain matches: + +- targeted runtime/debug tests: passed, `18 passed` +- full MCP-discovery suite: passed, `282 passed`, `9 skipped` +- `npm.cmd run build`: passed +- graphify rebuild: `5940 nodes`, `12909 edges`, `137 communities` + ## Next Step -The next safe step is still to re-run live replay once the 1C side is actively polling the proxy. In parallel, local-only consolidation can continue by making downstream planner/runtime arbitration consume `catalog_chain_template_matches` instead of relying on reason-code strings. +The next safe step is still to re-run live replay once the 1C side is actively polling the proxy. In parallel, local-only consolidation can continue by letting selected downstream arbitration consume `catalog_chain_template_matches` where this can be done without changing exact runtime behavior. Recommended order: diff --git a/docs/ARCH/11 - architecture_turnaround/README.md b/docs/ARCH/11 - architecture_turnaround/README.md index f5e34a6..daeaf02 100644 --- a/docs/ARCH/11 - architecture_turnaround/README.md +++ b/docs/ARCH/11 - architecture_turnaround/README.md @@ -80,7 +80,7 @@ It now documents a turnaround that is already operational in code, already mater - runtime bridge and answer adapter now keep unsupported inventory route templates behind an explicit user-facing boundary instead of letting template planning look like confirmed stock/supplier/purchase/sale evidence; - inventory catalog templates now bridge through existing exact inventory recipes (`41.01` scoped stock, supplier overlap, purchase provenance, and sale trace) inside the bounded MCP discovery pilot, while missing selected-item anchors still clarify instead of guessing; - unambiguous metadata surfaces can now infer the next reviewed lane from `Document.*`, `Register.*`, or `Catalog.*` objects even before upstream labels `downstream_route_family`, while mixed surfaces still do not guess; - - catalog index now scores reviewed chain templates directly from fact/action/axis/comparison/ranking needs, and planner exposes ranked catalog chain matches in both reason codes and the structured `catalog_chain_template_matches` contract field; + - catalog index now scores reviewed chain templates directly from fact/action/axis/comparison/ranking needs, and planner/runtime/debug surfaces expose ranked catalog chain matches through the structured `catalog_chain_template_matches` contract path instead of relying only on reason-code strings; - live map sync: [20 - planner_autonomy_consolidation_2026-05-01.md](./20%20-%20planner_autonomy_consolidation_2026-05-01.md) Current honest status: @@ -92,8 +92,8 @@ Current honest status: - open-world bounded-autonomy readiness: `~85%` - Post-F semantic integrity module progress: `~99%` operationally closed, with remaining risk now treated as next-slice discovery rather than an open blocker inside the closed slice - active inventory-stock breadth slice progress: `100%` for the declared scenario pack, not for arbitrary inventory questions -- Planner Autonomy Consolidation progress: `~81%` for the declared module, with catalog-fabric, value-flow arbitration, lifecycle bounded inference, broad-evaluation bridge, inventory catalog templates, inventory runtime-boundary honesty, exact inventory recipe bridging, unambiguous metadata-surface lane inference, catalog chain-template scoring, and structured chain-match contract exposure validated locally, but live replay for the new bridge is currently blocked by missing active 1C polling and broader unfamiliar 1C asks still need replay-backed growth -- graph snapshot after latest rebuild: `5939 nodes`, `12906 edges`, `138 communities` +- Planner Autonomy Consolidation progress: `~82%` for the declared module, with catalog-fabric, value-flow arbitration, lifecycle bounded inference, broad-evaluation bridge, inventory catalog templates, inventory runtime-boundary honesty, exact inventory recipe bridging, unambiguous metadata-surface lane inference, catalog chain-template scoring, structured chain-match contract exposure, and runtime/debug propagation validated locally, but live replay for the new bridge is currently blocked by missing active 1C polling and broader unfamiliar 1C asks still need replay-backed growth +- graph snapshot after latest rebuild: `5940 nodes`, `12909 edges`, `137 communities` - current breakpoint: - the validated hot paths are no longer structurally broken; - flagship continuity collapse is no longer the primary risk; @@ -140,6 +140,7 @@ Latest live proof now includes: - live inventory exact-bridge rerun `inventory_stock_exact_bridge_live_20260501_after_runtime_bridge` is recorded as infrastructure-blocked, not accepted: route/intent/recipe/capability matched, but MCP calls aborted and direct `get_metadata` timed out while proxy health showed `active_sessions_count=0` with pending commands - catalog chain-template scoring accepted locally: catalog/planner slice passed `54/54`; full MCP-discovery slice passed `282/282` with `9` skipped; build passed; graphify rebuilt to `5938 nodes`, `12903 edges`, `139 communities` - structured chain-template planner contract accepted locally: planner slice passed `36/36`; full MCP-discovery slice passed `282/282` with `9` skipped; build passed; graphify rebuilt to `5939 nodes`, `12906 edges`, `138 communities` +- structured chain-template runtime/debug propagation accepted locally: runtime/debug slice passed `18/18`; full MCP-discovery slice passed `282/282` with `9` skipped; build passed; graphify rebuilt to `5940 nodes`, `12909 edges`, `137 communities` Current architectural reading: diff --git a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryDebugAttachment.js b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryDebugAttachment.js index 7351a56..8c24fd2 100644 --- a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryDebugAttachment.js +++ b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryDebugAttachment.js @@ -15,6 +15,19 @@ function toNonEmptyString(value) { const text = String(value).trim(); return text.length > 0 ? text : null; } +function toStringArray(value) { + if (!Array.isArray(value)) { + return []; + } + const result = []; + for (const item of value) { + const text = toNonEmptyString(item); + if (text && !result.includes(text)) { + result.push(text); + } + } + return result; +} function isMcpDiscoveryEntryPointContract(value) { const record = toRecordObject(value); return (record?.schema_version === "assistant_mcp_discovery_runtime_entry_point_v1" && @@ -32,6 +45,7 @@ function resolveEntryPoint(input) { function buildAssistantMcpDiscoveryDebugAttachmentFields(input) { const entryPoint = resolveEntryPoint(input); const bridge = toRecordObject(entryPoint?.bridge); + const planner = toRecordObject(bridge?.planner); const answerDraft = toRecordObject(bridge?.answer_draft); return { assistant_mcp_discovery_entry_point_v1: entryPoint, @@ -39,6 +53,8 @@ function buildAssistantMcpDiscoveryDebugAttachmentFields(input) { mcp_discovery_attempted: Boolean(entryPoint?.discovery_attempted), mcp_discovery_hot_runtime_wired: false, mcp_discovery_bridge_status: toNonEmptyString(bridge?.bridge_status), + mcp_discovery_selected_chain_id: toNonEmptyString(planner?.selected_chain_id), + mcp_discovery_catalog_chain_template_matches: toStringArray(planner?.catalog_chain_template_matches), mcp_discovery_answer_mode: toNonEmptyString(answerDraft?.answer_mode), mcp_discovery_business_fact_answer_allowed: bridge?.business_fact_answer_allowed === true, mcp_discovery_user_facing_response_allowed: bridge?.user_facing_response_allowed === true, diff --git a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryRuntimeBridge.js b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryRuntimeBridge.js index c82c9e4..73e9eb6 100644 --- a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryRuntimeBridge.js +++ b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryRuntimeBridge.js @@ -90,6 +90,7 @@ function buildLoopState(planner, pilot, bridgeStatus) { policy_owner: "assistantMcpDiscoveryRuntimeBridge", loop_status: loopStatusFor(bridgeStatus), selected_chain_id: planner.selected_chain_id, + catalog_chain_template_matches: [...planner.catalog_chain_template_matches], pilot_scope: pilot.pilot_scope, asked_domain_family: planner.discovery_plan.turn_meaning_ref?.asked_domain_family ?? null, asked_action_family: planner.discovery_plan.turn_meaning_ref?.asked_action_family ?? null, diff --git a/llm_normalizer/backend/src/services/assistantMcpDiscoveryDebugAttachment.ts b/llm_normalizer/backend/src/services/assistantMcpDiscoveryDebugAttachment.ts index 79ea915..e4f7751 100644 --- a/llm_normalizer/backend/src/services/assistantMcpDiscoveryDebugAttachment.ts +++ b/llm_normalizer/backend/src/services/assistantMcpDiscoveryDebugAttachment.ts @@ -6,6 +6,8 @@ export interface AssistantMcpDiscoveryDebugAttachmentFields { mcp_discovery_attempted: boolean; mcp_discovery_hot_runtime_wired: false; mcp_discovery_bridge_status: string | null; + mcp_discovery_selected_chain_id: string | null; + mcp_discovery_catalog_chain_template_matches: string[]; mcp_discovery_answer_mode: string | null; mcp_discovery_business_fact_answer_allowed: boolean; mcp_discovery_user_facing_response_allowed: boolean; @@ -32,6 +34,20 @@ function toNonEmptyString(value: unknown): string | null { return text.length > 0 ? text : null; } +function toStringArray(value: unknown): string[] { + if (!Array.isArray(value)) { + return []; + } + const result: string[] = []; + for (const item of value) { + const text = toNonEmptyString(item); + if (text && !result.includes(text)) { + result.push(text); + } + } + return result; +} + function isMcpDiscoveryEntryPointContract(value: unknown): value is AssistantMcpDiscoveryRuntimeEntryPointContract { const record = toRecordObject(value); return ( @@ -56,6 +72,7 @@ export function buildAssistantMcpDiscoveryDebugAttachmentFields( ): AssistantMcpDiscoveryDebugAttachmentFields { const entryPoint = resolveEntryPoint(input); const bridge = toRecordObject(entryPoint?.bridge); + const planner = toRecordObject(bridge?.planner); const answerDraft = toRecordObject(bridge?.answer_draft); return { @@ -64,6 +81,8 @@ export function buildAssistantMcpDiscoveryDebugAttachmentFields( mcp_discovery_attempted: Boolean(entryPoint?.discovery_attempted), mcp_discovery_hot_runtime_wired: false, mcp_discovery_bridge_status: toNonEmptyString(bridge?.bridge_status), + mcp_discovery_selected_chain_id: toNonEmptyString(planner?.selected_chain_id), + mcp_discovery_catalog_chain_template_matches: toStringArray(planner?.catalog_chain_template_matches), mcp_discovery_answer_mode: toNonEmptyString(answerDraft?.answer_mode), mcp_discovery_business_fact_answer_allowed: bridge?.business_fact_answer_allowed === true, mcp_discovery_user_facing_response_allowed: bridge?.user_facing_response_allowed === true, diff --git a/llm_normalizer/backend/src/services/assistantMcpDiscoveryRuntimeBridge.ts b/llm_normalizer/backend/src/services/assistantMcpDiscoveryRuntimeBridge.ts index 218c711..23babfc 100644 --- a/llm_normalizer/backend/src/services/assistantMcpDiscoveryRuntimeBridge.ts +++ b/llm_normalizer/backend/src/services/assistantMcpDiscoveryRuntimeBridge.ts @@ -45,6 +45,7 @@ export interface AssistantMcpDiscoveryLoopStateContract { policy_owner: "assistantMcpDiscoveryRuntimeBridge"; loop_status: AssistantMcpDiscoveryLoopStatus; selected_chain_id: AssistantMcpDiscoveryChainId; + catalog_chain_template_matches: AssistantMcpDiscoveryPlannerContract["catalog_chain_template_matches"]; pilot_scope: AssistantMcpDiscoveryPilotExecutionContract["pilot_scope"]; asked_domain_family: string | null; asked_action_family: string | null; @@ -177,6 +178,7 @@ function buildLoopState( policy_owner: "assistantMcpDiscoveryRuntimeBridge", loop_status: loopStatusFor(bridgeStatus), selected_chain_id: planner.selected_chain_id, + catalog_chain_template_matches: [...planner.catalog_chain_template_matches], pilot_scope: pilot.pilot_scope, asked_domain_family: planner.discovery_plan.turn_meaning_ref?.asked_domain_family ?? null, asked_action_family: planner.discovery_plan.turn_meaning_ref?.asked_action_family ?? null, diff --git a/llm_normalizer/backend/tests/assistantMcpDiscoveryDebugAttachment.test.ts b/llm_normalizer/backend/tests/assistantMcpDiscoveryDebugAttachment.test.ts index 5eb96fe..8f4294a 100644 --- a/llm_normalizer/backend/tests/assistantMcpDiscoveryDebugAttachment.test.ts +++ b/llm_normalizer/backend/tests/assistantMcpDiscoveryDebugAttachment.test.ts @@ -14,6 +14,10 @@ function entryPointContract(overrides: Record = {}) { user_facing_response_allowed: true, business_fact_answer_allowed: true, requires_user_clarification: false, + planner: { + selected_chain_id: "value_flow_ranking", + catalog_chain_template_matches: ["value_flow_ranking", "value_flow"] + }, answer_draft: { answer_mode: "confirmed_with_bounded_inference" } @@ -37,6 +41,8 @@ describe("assistant MCP discovery debug attachment", () => { expect(debug.mcp_discovery_attempted).toBe(true); expect(debug.mcp_discovery_hot_runtime_wired).toBe(false); expect(debug.mcp_discovery_bridge_status).toBe("answer_draft_ready"); + expect(debug.mcp_discovery_selected_chain_id).toBe("value_flow_ranking"); + expect(debug.mcp_discovery_catalog_chain_template_matches).toEqual(["value_flow_ranking", "value_flow"]); expect(debug.mcp_discovery_answer_mode).toBe("confirmed_with_bounded_inference"); expect(debug.mcp_discovery_business_fact_answer_allowed).toBe(true); expect(debug.mcp_discovery_user_facing_response_allowed).toBe(true); @@ -54,6 +60,8 @@ describe("assistant MCP discovery debug attachment", () => { expect(debug.mcp_discovery_attempted).toBe(false); expect(debug.mcp_discovery_hot_runtime_wired).toBe(false); expect(debug.mcp_discovery_bridge_status).toBeNull(); + expect(debug.mcp_discovery_selected_chain_id).toBeNull(); + expect(debug.mcp_discovery_catalog_chain_template_matches).toEqual([]); expect(debug.mcp_discovery_answer_mode).toBeNull(); expect(debug.mcp_discovery_business_fact_answer_allowed).toBe(false); expect(debug.mcp_discovery_user_facing_response_allowed).toBe(false); diff --git a/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeBridge.test.ts b/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeBridge.test.ts index 1cb209f..6bfb916 100644 --- a/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeBridge.test.ts +++ b/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeBridge.test.ts @@ -147,6 +147,7 @@ describe("assistant MCP discovery runtime bridge", () => { }); expect(result.loop_state.pending_axes).toContain("organization"); expect(result.loop_state.provided_axes).toContain("aggregate_axis"); + expect(result.loop_state.catalog_chain_template_matches[0]).toBe("value_flow_ranking"); expect(result.reason_codes).toContain("runtime_bridge_loop_state_awaiting_clarification"); });