From 3f7caae668f6b8d78ddff6b25f5440a8abe11308 Mon Sep 17 00:00:00 2001 From: dctouch Date: Fri, 1 May 2026 13:17:09 +0300 Subject: [PATCH] =?UTF-8?q?Planner=20Autonomy:=20=D0=B7=D0=B0=D0=BA=D1=80?= =?UTF-8?q?=D0=B5=D0=BF=D0=B8=D1=82=D1=8C=20boundary=20inventory=20templat?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...anner_autonomy_consolidation_2026-05-01.md | 13 ++++ .../11 - architecture_turnaround/README.md | 6 +- .../assistantMcpDiscoveryAnswerAdapter.js | 14 ++++ .../assistantMcpDiscoveryAnswerAdapter.ts | 15 ++++ ...assistantMcpDiscoveryRuntimeBridge.test.ts | 68 +++++++++++++++++++ 5 files changed, 114 insertions(+), 2 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 fca5a74..83868ae 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 @@ -89,6 +89,12 @@ These templates are now first-class catalog chain descriptors and can be selecte The live MCP pilot intentionally marks these new inventory templates as `inventory_route_template_v1` / unsupported for live generic pilot execution until the exact inventory runtime paths are explicitly bridged into the bounded MCP executor. This keeps the architecture honest: route fabric exists, but runtime execution is still gated by the existing exact inventory capabilities and future bridging work. +The runtime answer boundary now makes that distinction explicit for inventory templates: + +- unsupported inventory route templates get a user-facing "template selected, live execution not yet bridged" answer instead of a generic checked-sources fallback; +- `must_not_claim` forbids presenting inventory planning as executed stock, supplier, purchase, or sale evidence; +- technical unsupported-pilot limitation text is filtered out of user-facing lines, while existing bounded unknowns for lifecycle/value-flow remain intact. + ## Why This Matters This reduces the pressure to add one hard route per user wording. @@ -139,6 +145,13 @@ Latest validation after the inventory catalog-template lift: - `npm.cmd run build`: passed - graphify rebuild: `5912 nodes`, `12833 edges`, `138 communities` +Latest validation after the inventory runtime-boundary hardening: + +- targeted runtime-bridge/answer-adapter/pilot-executor tests: passed, `68 passed`, `1 skipped` +- full MCP-discovery suite: passed, `277 passed`, `9 skipped` +- `npm.cmd run build`: passed +- graphify rebuild: `5913 nodes`, `12837 edges`, `138 communities` + ## Next Step The next safe step is to continue from catalog-instantiated inventory templates into runtime bridging and broader reviewed scoring. diff --git a/docs/ARCH/11 - architecture_turnaround/README.md b/docs/ARCH/11 - architecture_turnaround/README.md index 6d0b7f0..0ca778f 100644 --- a/docs/ARCH/11 - architecture_turnaround/README.md +++ b/docs/ARCH/11 - architecture_turnaround/README.md @@ -77,6 +77,7 @@ It now documents a turnaround that is already operational in code, already mater - current-turn value-flow aggregate questions can override narrower supported exact routes when the user asks for totals/net/payment amounts; - broad business evaluation remains in the deterministic living-chat bridge instead of being displaced by generic metadata discovery; - inventory stock snapshot, supplier overlap, purchase provenance, and sale trace are now reviewed catalog chain templates, while live generic MCP pilot execution remains explicitly gated until the exact inventory runtime evidence is bridged safely; + - 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; - live map sync: [20 - planner_autonomy_consolidation_2026-05-01.md](./20%20-%20planner_autonomy_consolidation_2026-05-01.md) Current honest status: @@ -88,8 +89,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: `~68%` for the declared module, with catalog-fabric, value-flow arbitration, lifecycle bounded inference, broad-evaluation bridge, and inventory catalog templates validated, but live inventory-template bridging and broader unfamiliar 1C asks still pending -- graph snapshot after latest rebuild: `5912 nodes`, `12833 edges`, `138 communities` +- Planner Autonomy Consolidation progress: `~70%` for the declared module, with catalog-fabric, value-flow arbitration, lifecycle bounded inference, broad-evaluation bridge, inventory catalog templates, and inventory runtime-boundary honesty validated, but live inventory-template bridging and broader unfamiliar 1C asks still pending +- graph snapshot after latest rebuild: `5913 nodes`, `12837 edges`, `138 communities` - current breakpoint: - the validated hot paths are no longer structurally broken; - flagship continuity collapse is no longer the primary risk; @@ -130,6 +131,7 @@ Latest live proof now includes: - broad-evaluation bridge continuity accepted: `address_truth_harness_phase21_net_followup_after_broad_eval_planner_lifecycle_rerun2` accepted `3/3` and `address_truth_harness_phase22_broad_business_evaluation_bridge_planner_lifecycle_rerun2` accepted `3/3` - latest local Planner Autonomy slice accepted: full MCP-discovery suite passed `268/268` with `9` skipped; broad MCP/living-chat/route/meaning slice passed `305/305` with `9` skipped; build passed - inventory template lift accepted locally: catalog/data-need/planner/turn-input slice passed `139/139` with `6` skipped; full MCP-discovery slice passed `276/276` with `9` skipped; build passed; graphify stayed at `5912 nodes`, `12833 edges`, `138 communities` +- inventory runtime-boundary hardening accepted locally: runtime-bridge/answer-adapter/pilot-executor slice passed `68/68` with `1` skipped; full MCP-discovery slice passed `277/277` with `9` skipped; build passed; graphify rebuilt to `5913 nodes`, `12837 edges`, `138 communities` Current architectural reading: diff --git a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryAnswerAdapter.js b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryAnswerAdapter.js index c52b63e..eceaf5c 100644 --- a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryAnswerAdapter.js +++ b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryAnswerAdapter.js @@ -46,6 +46,7 @@ function isInternalMechanicsLine(value) { text.includes("runtime_") || text.includes("planner_") || text.includes("catalog_") || + text.includes("scope is not implemented yet") || text.includes("needs more scope before execution") || text.includes("mcp_execution_performed")); } @@ -97,6 +98,9 @@ function isMovementPilot(pilot) { function isMetadataPilot(pilot) { return pilot.pilot_scope === "metadata_inspection_v1"; } +function isInventoryTemplatePilot(pilot) { + return pilot.pilot_scope === "inventory_route_template_v1"; +} function isCatalogDrilldownPilot(pilot) { return (isMetadataPilot(pilot) && (pilot.reason_codes.includes("planner_selected_catalog_drilldown_from_confirmed_metadata_surface_ref") || @@ -292,6 +296,9 @@ function headlineFor(mode, pilot) { if (isEntityResolutionPilot(pilot) && mode === "confirmed_with_bounded_inference") { return "По каталогу 1С найден вероятный контрагент; это заземление сущности для следующего шага, а не еще бизнес-ответ по данным."; } + if (isInventoryTemplatePilot(pilot) && mode === "checked_sources_only") { + return "Инвентарный route-template уже выбран, но live-исполнение этого generic MCP контура еще не подключено; складской/товарный факт не подтвержден."; + } if (isEntityResolutionPilot(pilot) && mode === "needs_clarification") { return "По каталогу 1С нашлось несколько похожих контрагентов, и без уточнения нельзя честно выбрать правильную сущность."; } @@ -422,6 +429,9 @@ function nextStepFor(mode, pilot) { if (mode === "needs_clarification") { return "Уточните контрагента, период или организацию, и я смогу выполнить проверку по 1С."; } + if (mode === "checked_sources_only" && isInventoryTemplatePilot(pilot)) { + return "Следующий шаг - связать inventory route-template с exact inventory runtime и затем проверить live-прогоном."; + } if (mode === "confirmed_with_bounded_inference" && pilot.derived_metadata_surface) { const surface = pilot.derived_metadata_surface; if (surface.ambiguity_detected && surface.ambiguity_entity_sets.length > 0) { @@ -475,6 +485,10 @@ function buildMustNotClaim(pilot) { claims.push("Do not claim legal identity uniqueness when several catalog candidates are still plausible."); claims.push("Do not imply that the resolved entity has already been used in a downstream data probe."); } + if (isInventoryTemplatePilot(pilot)) { + claims.push("Do not present inventory route-template planning as executed stock, supplier, purchase, or sale evidence."); + claims.push("Do not expose inventory_route_template_v1 or MCP primitive names in the user answer."); + } if (pilot.evidence.confirmed_facts.length === 0) { claims.push("Do not claim a confirmed business fact when confirmed_facts is empty."); } diff --git a/llm_normalizer/backend/src/services/assistantMcpDiscoveryAnswerAdapter.ts b/llm_normalizer/backend/src/services/assistantMcpDiscoveryAnswerAdapter.ts index 8b8469a..a4e0951 100644 --- a/llm_normalizer/backend/src/services/assistantMcpDiscoveryAnswerAdapter.ts +++ b/llm_normalizer/backend/src/services/assistantMcpDiscoveryAnswerAdapter.ts @@ -73,6 +73,7 @@ function isInternalMechanicsLine(value: string): boolean { text.includes("runtime_") || text.includes("planner_") || text.includes("catalog_") || + text.includes("scope is not implemented yet") || text.includes("needs more scope before execution") || text.includes("mcp_execution_performed") ); @@ -138,6 +139,10 @@ function isMetadataPilot(pilot: AssistantMcpDiscoveryPilotExecutionContract): bo return pilot.pilot_scope === "metadata_inspection_v1"; } +function isInventoryTemplatePilot(pilot: AssistantMcpDiscoveryPilotExecutionContract): boolean { + return pilot.pilot_scope === "inventory_route_template_v1"; +} + function isCatalogDrilldownPilot(pilot: AssistantMcpDiscoveryPilotExecutionContract): boolean { return ( isMetadataPilot(pilot) && @@ -386,6 +391,9 @@ function headlineFor(mode: AssistantMcpDiscoveryAnswerMode, pilot: AssistantMcpD if (isEntityResolutionPilot(pilot) && mode === "confirmed_with_bounded_inference") { return "По каталогу 1С найден вероятный контрагент; это заземление сущности для следующего шага, а не еще бизнес-ответ по данным."; } + if (isInventoryTemplatePilot(pilot) && mode === "checked_sources_only") { + return "Инвентарный route-template уже выбран, но live-исполнение этого generic MCP контура еще не подключено; складской/товарный факт не подтвержден."; + } if (isEntityResolutionPilot(pilot) && mode === "needs_clarification") { return "По каталогу 1С нашлось несколько похожих контрагентов, и без уточнения нельзя честно выбрать правильную сущность."; } @@ -523,6 +531,9 @@ function nextStepFor(mode: AssistantMcpDiscoveryAnswerMode, pilot: AssistantMcpD if (mode === "needs_clarification") { return "Уточните контрагента, период или организацию, и я смогу выполнить проверку по 1С."; } + if (mode === "checked_sources_only" && isInventoryTemplatePilot(pilot)) { + return "Следующий шаг - связать inventory route-template с exact inventory runtime и затем проверить live-прогоном."; + } if (mode === "confirmed_with_bounded_inference" && pilot.derived_metadata_surface) { const surface = pilot.derived_metadata_surface; if (surface.ambiguity_detected && surface.ambiguity_entity_sets.length > 0) { @@ -577,6 +588,10 @@ function buildMustNotClaim(pilot: AssistantMcpDiscoveryPilotExecutionContract): claims.push("Do not claim legal identity uniqueness when several catalog candidates are still plausible."); claims.push("Do not imply that the resolved entity has already been used in a downstream data probe."); } + if (isInventoryTemplatePilot(pilot)) { + claims.push("Do not present inventory route-template planning as executed stock, supplier, purchase, or sale evidence."); + claims.push("Do not expose inventory_route_template_v1 or MCP primitive names in the user answer."); + } if (pilot.evidence.confirmed_facts.length === 0) { claims.push("Do not claim a confirmed business fact when confirmed_facts is empty."); } diff --git a/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeBridge.test.ts b/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeBridge.test.ts index 2b6ea45..088e2b3 100644 --- a/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeBridge.test.ts +++ b/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeBridge.test.ts @@ -293,6 +293,74 @@ describe("assistant MCP discovery runtime bridge", () => { expect(result.reason_codes).toContain("runtime_bridge_status_checked_sources_only"); }); + it("keeps inventory catalog templates unsupported until exact runtime evidence is bridged", async () => { + const result = await runAssistantMcpDiscoveryRuntimeBridge({ + dataNeedGraph: { + schema_version: "assistant_data_need_graph_v1", + policy_owner: "assistantMcpDiscoveryDataNeedGraph", + subject_candidates: [], + business_fact_family: "inventory_stock_snapshot", + action_family: "stock_snapshot", + aggregation_need: null, + time_scope_need: "explicit_period", + comparison_need: null, + ranking_need: null, + proof_expectation: "coverage_checked_fact", + clarification_gaps: [], + decomposition_candidates: [ + "fetch_scoped_movements", + "aggregate_checked_amounts", + "probe_coverage", + "explain_evidence_basis" + ], + forbidden_overclaim_flags: ["no_raw_model_claims", "no_unchecked_stock_snapshot"], + reason_codes: ["data_need_graph_built", "data_need_graph_family_inventory_stock_snapshot"] + }, + turnMeaning: { + asked_domain_family: "inventory_stock", + asked_action_family: "stock_snapshot", + explicit_organization_scope: "OOO Alternative Plus", + explicit_date_scope: "2021-09-30" + }, + deps: buildDeps([]) + }); + const userFacing = [ + result.answer_draft.headline, + ...result.answer_draft.confirmed_lines, + ...result.answer_draft.inference_lines, + ...result.answer_draft.unknown_lines, + ...result.answer_draft.limitation_lines, + result.answer_draft.next_step_line ?? "" + ].join("\n"); + + expect(result.bridge_status).toBe("unsupported"); + expect(result.answer_draft.answer_mode).toBe("checked_sources_only"); + expect(result.pilot.pilot_scope).toBe("inventory_route_template_v1"); + expect(result.pilot.mcp_execution_performed).toBe(false); + expect(result.loop_state).toMatchObject({ + loop_status: "blocked", + selected_chain_id: "inventory_stock_snapshot", + pilot_scope: "inventory_route_template_v1", + asked_domain_family: "inventory_stock", + asked_action_family: "stock_snapshot", + explicit_organization_scope: "OOO Alternative Plus", + explicit_date_scope: "2021-09-30" + }); + expect(result.business_fact_answer_allowed).toBe(false); + expect(result.reason_codes).toContain("pilot_scope_unsupported_for_live_execution"); + expect(result.answer_draft.must_not_claim).toEqual( + expect.arrayContaining([ + "Do not present inventory route-template planning as executed stock, supplier, purchase, or sale evidence.", + "Do not expose inventory_route_template_v1 or MCP primitive names in the user answer." + ]) + ); + expect(userFacing).toContain("Инвентарный route-template"); + expect(userFacing).not.toContain("inventory_route_template_v1"); + expect(userFacing).not.toContain("query_movements"); + expect(userFacing).not.toContain("primitive"); + expect(userFacing).not.toContain("MCP discovery pilot"); + }); + it("keeps document evidence executable when the planner expands primitives from fact-axis search", async () => { const result = await runAssistantMcpDiscoveryRuntimeBridge({ dataNeedGraph: {