diff --git a/docs/ARCH/11 - architecture_turnaround/21 - current_status_canon_2026-05-01.md b/docs/ARCH/11 - architecture_turnaround/21 - current_status_canon_2026-05-01.md index de04350..49c30db 100644 --- a/docs/ARCH/11 - architecture_turnaround/21 - current_status_canon_2026-05-01.md +++ b/docs/ARCH/11 - architecture_turnaround/21 - current_status_canon_2026-05-01.md @@ -14,7 +14,9 @@ If another document says `78%`, `87%`, `92%`, or `85%` for a module that is now - `Inventory Stock Open-World Breadth Proof`: `100%` for the declared inventory-stock scenario pack, not for arbitrary inventory questions. - `Planner Autonomy Consolidation`: `100%` for the declared phase83 planner-brain slice, including catalog alignment, live-readiness gating, checked-source sanitation, and accepted mixed replay. - Active next module: broader `Open-World Bounded Autonomy Breadth` over unfamiliar 1C asks, while keeping Post-F and phase83 as regression gates. -- First active slice: `Business Overview Evidence Fusion`, tracked in `22 - open_world_bounded_autonomy_breadth_2026-05-01.md`. +- Completed active slice: `Business Overview Evidence Fusion`, tracked in `22 - open_world_bounded_autonomy_breadth_2026-05-01.md`. +- Current active slice: `Business Overview Catalog Route Fabric`: the route is reviewed in catalog/data-need/planner contracts, while fresh multi-probe runtime execution remains a pending bridge. +- Active module progress: `~18% (Open-World Bounded Autonomy Breadth)`. ## Reporting Rule @@ -51,6 +53,7 @@ The project is not yet a universal arbitrary-1C agent. Remaining work belongs to the next breadth module: +- implement the fresh multi-probe `business_overview` runtime bridge behind the reviewed route-fabric contract; - broader dynamic schema traversal for unfamiliar 1C asks; - more primitive descriptors where live evidence proves a real gap; - more replay-backed domain packs that start from user business meaning, not from route convenience; diff --git a/docs/ARCH/11 - architecture_turnaround/22 - open_world_bounded_autonomy_breadth_2026-05-01.md b/docs/ARCH/11 - architecture_turnaround/22 - open_world_bounded_autonomy_breadth_2026-05-01.md index 3aa8935..ff086f0 100644 --- a/docs/ARCH/11 - architecture_turnaround/22 - open_world_bounded_autonomy_breadth_2026-05-01.md +++ b/docs/ARCH/11 - architecture_turnaround/22 - open_world_bounded_autonomy_breadth_2026-05-01.md @@ -70,12 +70,28 @@ When this bridge answers, it must: - keep profit/margin/debt/VAT as explicit missing evidence when not checked; - avoid raw MCP, planner, catalog, route, primitive, or debug wording. -### Next Slice +## Slice 2 - Business Overview Catalog Route Fabric + +This slice promotes the broad-evaluation contour from a living-chat bridge into the reviewed planner/catalog vocabulary. + +### Current Implementation Boundary + +Implemented now: + +- `business_overview` exists as a reviewed catalog chain template; +- the data-need graph recognizes broad company analysis as a bounded business-overview evidence need; +- fresh business-overview probes require an organization scope instead of silently reusing stale context; +- planner output can select `business_overview` as the catalog top match with structured alignment telemetry; +- the pilot executor exposes `business_overview_route_template_v1` as an explicit scope, but returns an unsupported runtime boundary until the fresh multi-probe bridge is implemented. + +This is deliberately not a fake runtime success. + +The assistant now has the route-fabric contract for the next slice, while the live business overview still uses the safe evidence-fusion bridge from Slice 1. + +### Still Pending Runtime Slice Promote this bridge into a real planner route: -- add a reviewed `business_overview` catalog chain template; -- let the data-need graph model broad evaluation as a composed evidence need; - run bounded fresh probes for year turnover, top customers, incoming/outgoing/net flow, debt, VAT, and inventory context where available; - return a layered analyst answer with exact evidence, bounded inference, unknowns, and recommended next probes. @@ -98,4 +114,9 @@ Initial local validation: - `npm.cmd run build`: passed. - graphify rebuild: `5977 nodes`, `12983 edges`, `137 communities`. +Business-overview route-fabric validation: + +- `npm.cmd test -- assistantMcpCatalogIndex.test.ts assistantMcpDiscoveryDataNeedGraph.test.ts assistantMcpDiscoveryPlanner.test.ts assistantMcpDiscoveryPilotExecutor.test.ts`: passed `102/102`. +- fresh multi-probe runtime execution remains intentionally pending behind `business_overview_route_template_v1`. + Graphify must be rebuilt after this code/doc slice before commit. diff --git a/docs/ARCH/11 - architecture_turnaround/README.md b/docs/ARCH/11 - architecture_turnaround/README.md index d72d942..151bcf1 100644 --- a/docs/ARCH/11 - architecture_turnaround/README.md +++ b/docs/ARCH/11 - architecture_turnaround/README.md @@ -51,6 +51,7 @@ Status canon for planning: - Planner Autonomy Consolidation is closed at `100%` for the declared phase83 planner-brain slice. - The active next module is now `Open-World Bounded Autonomy Breadth` over unfamiliar 1C asks, with Post-F and phase83 retained as semantic canaries. - The first active slice is `Business Overview Evidence Fusion`: broad company-analysis wording now produces a richer evidence-grounded business overview from confirmed MCP/session facts instead of a thin generic summary. +- The current follow-up slice is `Business Overview Catalog Route Fabric`: `business_overview` is now a reviewed catalog/data-need/planner chain, while fresh multi-probe execution remains honestly bounded behind an unsupported runtime scope until the next bridge is implemented. - The short source of truth for status wording is [21 - current_status_canon_2026-05-01.md](./21%20-%20current_status_canon_2026-05-01.md). It now documents a turnaround that is already operational in code, already materially past the acute regression breakpoint, and already moved through bounded MCP autonomy, Post-F hardening, inventory breadth proof, and the declared Planner Autonomy slice: @@ -114,8 +115,8 @@ Current honest status: - exit-from-danger-zone readiness: `~97%` - pre-multidomain readiness: `~90%` - bounded-autonomy foundation readiness: `~89%` -- open-world bounded-autonomy readiness: `~85%` -- active Open-World Bounded Autonomy Breadth progress: `~12%`, with the first business-overview evidence-fusion slice started and locally tested; fresh multi-probe planner route is still pending +- open-world bounded-autonomy readiness: `~86%` +- active Open-World Bounded Autonomy Breadth progress: `~18%`, with business-overview evidence fusion and the reviewed `business_overview` catalog/data-need/planner route-fabric slice locally tested; fresh multi-probe runtime execution is still pending - 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: `100%` 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, runtime/debug propagation, subject-aware bidirectional comparison arbitration, structured catalog-alignment verdicts, representative alignment regression guard, catalog-alignment reason-code telemetry, explicit `alignment_status` propagation, truth-harness/acceptance-matrix surfacing, soft divergence warning, `catalog_alignment_ok` acceptance invariant, step-level expected catalog-alignment assertions, phase66 and phase32 spec alignment expectations, AGENT source-catalog surfacing, generated phase83 mixed planner-brain replay spec, checked-source user-facing error sanitation, surface-grounded catalog promotion, and guarded live phase83 acceptance validated. Broader unfamiliar 1C asks are now next-module breadth work rather than an open blocker inside this declared slice @@ -159,6 +160,7 @@ Latest live proof now includes: - lifecycle/value-flow Planner Autonomy response gate accepted: `address_truth_harness_phase19_mcp_discovery_response_gate_planner_lifecycle_rerun4` accepted `8/8`, proving bounded lifecycle inference, current-turn value-flow aggregate arbitration, and sanitized evidence wording - 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 +- business-overview route-fabric slice accepted locally: catalog/data-need/planner/pilot boundary slice passed `102/102`; the pilot executor exposes `business_overview_route_template_v1` as an explicit unsupported scope until the fresh multi-probe bridge exists - 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` - inventory exact-runtime bridge accepted locally: runtime-bridge/answer-adapter/pilot-executor slice passed `70/70` with `1` skipped; full MCP-discovery slice passed `279/279` with `9` skipped; build passed; graphify rebuilt to `5930 nodes`, `12884 edges`, `135 communities` diff --git a/llm_normalizer/backend/dist/services/assistantMcpCatalogIndex.js b/llm_normalizer/backend/dist/services/assistantMcpCatalogIndex.js index 35c9a61..1de663c 100644 --- a/llm_normalizer/backend/dist/services/assistantMcpCatalogIndex.js +++ b/llm_normalizer/backend/dist/services/assistantMcpCatalogIndex.js @@ -51,6 +51,7 @@ const PRIMITIVE_CONTRACTS = [ "document_evidence", "movement_evidence", "activity_lifecycle", + "business_overview", "inventory_purchase_provenance", "inventory_sale_trace", "inventory_supplier_overlap" @@ -63,6 +64,7 @@ const PRIMITIVE_CONTRACTS = [ "list_documents", "list_movements", "activity_duration", + "broad_evaluation", "purchase_provenance", "sale_trace", "supplier_overlap" @@ -84,8 +86,22 @@ const PRIMITIVE_CONTRACTS = [ "collect_outgoing_movements", "fetch_scoped_movements" ], - supported_fact_families: ["value_flow", "movement_evidence", "inventory_stock_snapshot", "inventory_supplier_overlap"], - supported_action_families: ["turnover", "payout", "net_value_flow", "list_movements", "stock_snapshot", "supplier_overlap"], + supported_fact_families: [ + "value_flow", + "movement_evidence", + "business_overview", + "inventory_stock_snapshot", + "inventory_supplier_overlap" + ], + supported_action_families: [ + "turnover", + "payout", + "net_value_flow", + "list_movements", + "broad_evaluation", + "stock_snapshot", + "supplier_overlap" + ], planning_tags: ["movement", "comparison", "ranking", "aggregation", "monthly_aggregation"], required_axes_any_of: [ ["period", "account"], @@ -110,11 +126,19 @@ const PRIMITIVE_CONTRACTS = [ supported_fact_families: [ "document_evidence", "activity_lifecycle", + "business_overview", "inventory_purchase_provenance", "inventory_sale_trace", "inventory_supplier_overlap" ], - supported_action_families: ["list_documents", "activity_duration", "purchase_provenance", "sale_trace", "supplier_overlap"], + supported_action_families: [ + "list_documents", + "activity_duration", + "broad_evaluation", + "purchase_provenance", + "sale_trace", + "supplier_overlap" + ], planning_tags: ["document"], required_axes_any_of: [ ["document"], @@ -136,8 +160,8 @@ const PRIMITIVE_CONTRACTS = [ primitive_id: "aggregate_by_axis", purpose: "Aggregate already-scoped 1C evidence by a business axis such as counterparty, contract, or period.", decomposition_hints: ["aggregate_checked_amounts", "aggregate_ranked_axis_values", "aggregate_by_month"], - supported_fact_families: ["value_flow", "inventory_stock_snapshot", "inventory_supplier_overlap"], - supported_action_families: ["turnover", "payout", "net_value_flow", "stock_snapshot", "supplier_overlap"], + supported_fact_families: ["value_flow", "business_overview", "inventory_stock_snapshot", "inventory_supplier_overlap"], + supported_action_families: ["turnover", "payout", "net_value_flow", "broad_evaluation", "stock_snapshot", "supplier_overlap"], planning_tags: ["aggregation", "ranking", "monthly_aggregation"], required_axes_any_of: [ ["aggregate_axis", "period"], @@ -178,6 +202,7 @@ const PRIMITIVE_CONTRACTS = [ "document_evidence", "movement_evidence", "activity_lifecycle", + "business_overview", "inventory_stock_snapshot", "inventory_purchase_provenance", "inventory_sale_trace", @@ -196,6 +221,7 @@ const PRIMITIVE_CONTRACTS = [ "list_documents", "list_movements", "activity_duration", + "broad_evaluation", "stock_snapshot", "purchase_provenance", "sale_trace", @@ -216,6 +242,7 @@ const PRIMITIVE_CONTRACTS = [ decomposition_hints: ["explain_evidence_basis"], supported_fact_families: [ "activity_lifecycle", + "business_overview", "inventory_stock_snapshot", "inventory_purchase_provenance", "inventory_sale_trace", @@ -223,13 +250,14 @@ const PRIMITIVE_CONTRACTS = [ ], supported_action_families: [ "activity_duration", + "broad_evaluation", "stock_snapshot", "purchase_provenance", "sale_trace", "supplier_overlap", "purchase_to_sale_chain" ], - planning_tags: ["explanation", "inventory"], + planning_tags: ["explanation", "inventory", "business_overview", "bounded_inference"], required_axes_any_of: [["evidence_basis"], ["primitive_id"], ["source_rows_summary"]], optional_axes: ["coverage_target", "domain_family", "item", "warehouse", "as_of_date", "supplier", "buyer"], output_fact_kinds: ["confirmed_facts", "inferred_facts", "unknown_facts"], @@ -414,6 +442,24 @@ const CHAIN_TEMPLATES = [ planning_tags: ["document", "explanation", "coverage", "bounded_inference", "activity_window", "legal_fact_boundary"], safe_for_model_planning: true, requires_evidence_gate: true + }, + { + chain_id: "business_overview", + semantic_data_need: "business overview evidence with bounded analyst interpretation", + chain_summary: "Collect organization-scoped movement and document evidence, aggregate checked business signals, probe coverage, and explain profit/margin limits before giving a bounded analyst overview.", + fallback_primitives: [ + "query_movements", + "aggregate_by_axis", + "query_documents", + "probe_coverage", + "explain_evidence_basis" + ], + base_required_axes: ["organization", "aggregate_axis", "amount", "coverage_target", "evidence_basis", "profit_margin_boundary"], + supported_fact_families: ["business_overview"], + supported_action_families: ["broad_evaluation"], + planning_tags: ["business_overview", "movement", "document", "aggregation", "coverage", "explanation", "bounded_inference"], + safe_for_model_planning: true, + requires_evidence_gate: true } ]; const CHAIN_TEMPLATE_MAP = new Map(CHAIN_TEMPLATES.map((template) => [template.chain_id, template])); @@ -477,6 +523,15 @@ function tagSetFromFactAxisInput(input) { if (input.business_fact_family === "value_flow") { tags.add("movement"); } + if (input.business_fact_family === "business_overview") { + tags.add("business_overview"); + tags.add("movement"); + tags.add("document"); + tags.add("aggregation"); + tags.add("coverage"); + tags.add("explanation"); + tags.add("bounded_inference"); + } if (input.business_fact_family?.startsWith("inventory_")) { tags.add("inventory"); } diff --git a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryDataNeedGraph.js b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryDataNeedGraph.js index 9ef675d..8bdee6a 100644 --- a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryDataNeedGraph.js +++ b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryDataNeedGraph.js @@ -44,6 +44,14 @@ function businessFactFamilyFor(input) { if (combined.includes("entity discovery") || combined.includes("entity_resolution")) { return "entity_grounding"; } + if (combined.includes("broad_business_evaluation") || + combined.includes("broad_evaluation") || + combined.includes("business overview") || + combined.includes("business_overview") || + combined.includes("company analysis") || + combined.includes("business audit")) { + return "business_overview"; + } if (combined.includes("inventory") || combined.includes("stock") || combined.includes("warehouse") || @@ -113,6 +121,9 @@ function timeScopeNeedFor(input) { if (input.family === "activity_lifecycle") { return "open_activity_window"; } + if (input.family === "business_overview") { + return input.explicitDateScope ? "explicit_period" : "all_time_scope"; + } if (input.family === "inventory_stock_snapshot" || input.family === "inventory_supplier_overlap") { return input.explicitDateScope ? "explicit_period" : "as_of_date_required"; } @@ -193,6 +204,9 @@ function proofExpectationFor(input) { if (input.family === "activity_lifecycle") { return "bounded_inference"; } + if (input.family === "business_overview") { + return "bounded_inference"; + } return "coverage_checked_fact"; } function decompositionCandidatesFor(input) { @@ -264,6 +278,15 @@ function decompositionCandidatesFor(input) { pushUnique(result, "explain_evidence_basis"); return result; } + if (input.family === "business_overview") { + pushUnique(result, "collect_scoped_movements"); + pushUnique(result, "aggregate_checked_amounts"); + pushUnique(result, "aggregate_ranked_axis_values"); + pushUnique(result, "fetch_supporting_documents"); + pushUnique(result, "probe_coverage"); + pushUnique(result, "explain_evidence_basis"); + return result; + } if (input.family === "inventory_stock_snapshot") { pushUnique(result, "fetch_scoped_movements"); pushUnique(result, "aggregate_checked_amounts"); @@ -300,6 +323,11 @@ function forbiddenOverclaimFlagsFor(family) { if (family === "activity_lifecycle") { pushUnique(result, "no_legal_age_claim_without_evidence"); } + if (family === "business_overview") { + pushUnique(result, "no_unchecked_fact_totals"); + pushUnique(result, "no_unchecked_business_health_claim"); + pushUnique(result, "no_profit_or_margin_claim_without_evidence"); + } if (family === "value_flow" || family === "movement_evidence" || family === "document_evidence") { pushUnique(result, "no_unchecked_fact_totals"); } @@ -372,8 +400,14 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) { !explicitOrganizationScope) { pushUnique(clarificationGaps, "organization"); } + else if (subjectCandidates.length === 0 && + businessFactFamily === "business_overview" && + !explicitOrganizationScope) { + pushUnique(clarificationGaps, "organization"); + } else if (subjectCandidates.length === 0 && businessFactFamily !== "schema_surface" && + businessFactFamily !== "business_overview" && !openScopeWithoutSubject && !metadataScopedOpenLaneWithoutSubject && !inventoryStockSnapshotWithoutSubject) { @@ -425,6 +459,9 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) { if (allTimeScopeHint) { pushReason(reasonCodes, "data_need_graph_all_time_scope_hint"); } + if (businessFactFamily === "business_overview" && !explicitDateScope) { + pushReason(reasonCodes, "data_need_graph_business_overview_defaults_to_all_time_scope"); + } if (clarificationGaps.includes("organization")) { pushReason(reasonCodes, "data_need_graph_open_scope_total_needs_organization"); } diff --git a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryPilotExecutor.js b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryPilotExecutor.js index 88d4055..f1e9734 100644 --- a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryPilotExecutor.js +++ b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryPilotExecutor.js @@ -2065,6 +2065,8 @@ function pilotScopeForPlanner(planner) { case "value_flow_ranking": case "value_flow": return valueFlowPilotProfile(planner).scope; + case "business_overview": + return "business_overview_route_template_v1"; case "document_evidence": return "counterparty_document_evidence_query_documents_v1"; case "lifecycle": diff --git a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryPlanner.js b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryPlanner.js index 6517fdb..b012756 100644 --- a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryPlanner.js +++ b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryPlanner.js @@ -676,6 +676,31 @@ function recipeFor(input) { extraReasons: primitiveSelection.reasonCodes }); } + if (graphFactFamily === "business_overview") { + pushUnique(axes, "organization"); + pushUnique(axes, "aggregate_axis"); + pushUnique(axes, "amount"); + pushUnique(axes, "coverage_target"); + pushUnique(axes, "evidence_basis"); + pushUnique(axes, "profit_margin_boundary"); + const template = (0, assistantMcpCatalogIndex_1.getAssistantMcpCatalogChainTemplate)("business_overview"); + const primitiveSelection = selectPrimitivesFromGraphAndCatalog({ + dataNeedGraph, + fallbackPrimitives: template.fallback_primitives, + requiredAxes: axes, + metadataSurface: input.metadataSurface, + actionFamily: action || graphAction, + allowAggregateByAxis: true, + selectedChainId: "business_overview" + }); + return recipeFromCatalogChainTemplate({ + chainId: "business_overview", + axes, + primitives: primitiveSelection.primitives, + reason: "planner_selected_business_overview_from_data_need_graph", + extraReasons: primitiveSelection.reasonCodes + }); + } if (graphFactFamily === "activity_lifecycle") { pushUnique(axes, "document_date"); pushUnique(axes, "coverage_target"); diff --git a/llm_normalizer/backend/src/services/assistantMcpCatalogIndex.ts b/llm_normalizer/backend/src/services/assistantMcpCatalogIndex.ts index 0b010b3..9bd2215 100644 --- a/llm_normalizer/backend/src/services/assistantMcpCatalogIndex.ts +++ b/llm_normalizer/backend/src/services/assistantMcpCatalogIndex.ts @@ -20,6 +20,7 @@ export type AssistantMcpCatalogChainTemplateId = | "value_flow_comparison" | "value_flow_ranking" | "lifecycle" + | "business_overview" | "movement_evidence" | "document_evidence" | "entity_resolution"; @@ -110,6 +111,7 @@ const PRIMITIVE_CONTRACTS: AssistantMcpCatalogPrimitiveContract[] = [ "document_evidence", "movement_evidence", "activity_lifecycle", + "business_overview", "inventory_purchase_provenance", "inventory_sale_trace", "inventory_supplier_overlap" @@ -122,6 +124,7 @@ const PRIMITIVE_CONTRACTS: AssistantMcpCatalogPrimitiveContract[] = [ "list_documents", "list_movements", "activity_duration", + "broad_evaluation", "purchase_provenance", "sale_trace", "supplier_overlap" @@ -143,8 +146,22 @@ const PRIMITIVE_CONTRACTS: AssistantMcpCatalogPrimitiveContract[] = [ "collect_outgoing_movements", "fetch_scoped_movements" ], - supported_fact_families: ["value_flow", "movement_evidence", "inventory_stock_snapshot", "inventory_supplier_overlap"], - supported_action_families: ["turnover", "payout", "net_value_flow", "list_movements", "stock_snapshot", "supplier_overlap"], + supported_fact_families: [ + "value_flow", + "movement_evidence", + "business_overview", + "inventory_stock_snapshot", + "inventory_supplier_overlap" + ], + supported_action_families: [ + "turnover", + "payout", + "net_value_flow", + "list_movements", + "broad_evaluation", + "stock_snapshot", + "supplier_overlap" + ], planning_tags: ["movement", "comparison", "ranking", "aggregation", "monthly_aggregation"], required_axes_any_of: [ ["period", "account"], @@ -169,11 +186,19 @@ const PRIMITIVE_CONTRACTS: AssistantMcpCatalogPrimitiveContract[] = [ supported_fact_families: [ "document_evidence", "activity_lifecycle", + "business_overview", "inventory_purchase_provenance", "inventory_sale_trace", "inventory_supplier_overlap" ], - supported_action_families: ["list_documents", "activity_duration", "purchase_provenance", "sale_trace", "supplier_overlap"], + supported_action_families: [ + "list_documents", + "activity_duration", + "broad_evaluation", + "purchase_provenance", + "sale_trace", + "supplier_overlap" + ], planning_tags: ["document"], required_axes_any_of: [ ["document"], @@ -195,8 +220,8 @@ const PRIMITIVE_CONTRACTS: AssistantMcpCatalogPrimitiveContract[] = [ primitive_id: "aggregate_by_axis", purpose: "Aggregate already-scoped 1C evidence by a business axis such as counterparty, contract, or period.", decomposition_hints: ["aggregate_checked_amounts", "aggregate_ranked_axis_values", "aggregate_by_month"], - supported_fact_families: ["value_flow", "inventory_stock_snapshot", "inventory_supplier_overlap"], - supported_action_families: ["turnover", "payout", "net_value_flow", "stock_snapshot", "supplier_overlap"], + supported_fact_families: ["value_flow", "business_overview", "inventory_stock_snapshot", "inventory_supplier_overlap"], + supported_action_families: ["turnover", "payout", "net_value_flow", "broad_evaluation", "stock_snapshot", "supplier_overlap"], planning_tags: ["aggregation", "ranking", "monthly_aggregation"], required_axes_any_of: [ ["aggregate_axis", "period"], @@ -237,6 +262,7 @@ const PRIMITIVE_CONTRACTS: AssistantMcpCatalogPrimitiveContract[] = [ "document_evidence", "movement_evidence", "activity_lifecycle", + "business_overview", "inventory_stock_snapshot", "inventory_purchase_provenance", "inventory_sale_trace", @@ -255,6 +281,7 @@ const PRIMITIVE_CONTRACTS: AssistantMcpCatalogPrimitiveContract[] = [ "list_documents", "list_movements", "activity_duration", + "broad_evaluation", "stock_snapshot", "purchase_provenance", "sale_trace", @@ -275,6 +302,7 @@ const PRIMITIVE_CONTRACTS: AssistantMcpCatalogPrimitiveContract[] = [ decomposition_hints: ["explain_evidence_basis"], supported_fact_families: [ "activity_lifecycle", + "business_overview", "inventory_stock_snapshot", "inventory_purchase_provenance", "inventory_sale_trace", @@ -282,13 +310,14 @@ const PRIMITIVE_CONTRACTS: AssistantMcpCatalogPrimitiveContract[] = [ ], supported_action_families: [ "activity_duration", + "broad_evaluation", "stock_snapshot", "purchase_provenance", "sale_trace", "supplier_overlap", "purchase_to_sale_chain" ], - planning_tags: ["explanation", "inventory"], + planning_tags: ["explanation", "inventory", "business_overview", "bounded_inference"], required_axes_any_of: [["evidence_basis"], ["primitive_id"], ["source_rows_summary"]], optional_axes: ["coverage_target", "domain_family", "item", "warehouse", "as_of_date", "supplier", "buyer"], output_fact_kinds: ["confirmed_facts", "inferred_facts", "unknown_facts"], @@ -487,6 +516,25 @@ const CHAIN_TEMPLATES: AssistantMcpCatalogChainTemplateContract[] = [ planning_tags: ["document", "explanation", "coverage", "bounded_inference", "activity_window", "legal_fact_boundary"], safe_for_model_planning: true, requires_evidence_gate: true + }, + { + chain_id: "business_overview", + semantic_data_need: "business overview evidence with bounded analyst interpretation", + chain_summary: + "Collect organization-scoped movement and document evidence, aggregate checked business signals, probe coverage, and explain profit/margin limits before giving a bounded analyst overview.", + fallback_primitives: [ + "query_movements", + "aggregate_by_axis", + "query_documents", + "probe_coverage", + "explain_evidence_basis" + ], + base_required_axes: ["organization", "aggregate_axis", "amount", "coverage_target", "evidence_basis", "profit_margin_boundary"], + supported_fact_families: ["business_overview"], + supported_action_families: ["broad_evaluation"], + planning_tags: ["business_overview", "movement", "document", "aggregation", "coverage", "explanation", "bounded_inference"], + safe_for_model_planning: true, + requires_evidence_gate: true } ]; @@ -564,6 +612,15 @@ function tagSetFromFactAxisInput(input: AssistantMcpCatalogFactAxisSearchInput): if (input.business_fact_family === "value_flow") { tags.add("movement"); } + if (input.business_fact_family === "business_overview") { + tags.add("business_overview"); + tags.add("movement"); + tags.add("document"); + tags.add("aggregation"); + tags.add("coverage"); + tags.add("explanation"); + tags.add("bounded_inference"); + } if (input.business_fact_family?.startsWith("inventory_")) { tags.add("inventory"); } diff --git a/llm_normalizer/backend/src/services/assistantMcpDiscoveryDataNeedGraph.ts b/llm_normalizer/backend/src/services/assistantMcpDiscoveryDataNeedGraph.ts index aed4653..2f697af 100644 --- a/llm_normalizer/backend/src/services/assistantMcpDiscoveryDataNeedGraph.ts +++ b/llm_normalizer/backend/src/services/assistantMcpDiscoveryDataNeedGraph.ts @@ -86,6 +86,16 @@ function businessFactFamilyFor(input: { if (combined.includes("entity discovery") || combined.includes("entity_resolution")) { return "entity_grounding"; } + if ( + combined.includes("broad_business_evaluation") || + combined.includes("broad_evaluation") || + combined.includes("business overview") || + combined.includes("business_overview") || + combined.includes("company analysis") || + combined.includes("business audit") + ) { + return "business_overview"; + } if ( combined.includes("inventory") || combined.includes("stock") || @@ -174,6 +184,9 @@ function timeScopeNeedFor(input: { if (input.family === "activity_lifecycle") { return "open_activity_window"; } + if (input.family === "business_overview") { + return input.explicitDateScope ? "explicit_period" : "all_time_scope"; + } if (input.family === "inventory_stock_snapshot" || input.family === "inventory_supplier_overlap") { return input.explicitDateScope ? "explicit_period" : "as_of_date_required"; } @@ -291,6 +304,9 @@ function proofExpectationFor(input: { if (input.family === "activity_lifecycle") { return "bounded_inference"; } + if (input.family === "business_overview") { + return "bounded_inference"; + } return "coverage_checked_fact"; } @@ -370,6 +386,15 @@ function decompositionCandidatesFor(input: { pushUnique(result, "explain_evidence_basis"); return result; } + if (input.family === "business_overview") { + pushUnique(result, "collect_scoped_movements"); + pushUnique(result, "aggregate_checked_amounts"); + pushUnique(result, "aggregate_ranked_axis_values"); + pushUnique(result, "fetch_supporting_documents"); + pushUnique(result, "probe_coverage"); + pushUnique(result, "explain_evidence_basis"); + return result; + } if (input.family === "inventory_stock_snapshot") { pushUnique(result, "fetch_scoped_movements"); pushUnique(result, "aggregate_checked_amounts"); @@ -407,6 +432,11 @@ function forbiddenOverclaimFlagsFor(family: string | null): string[] { if (family === "activity_lifecycle") { pushUnique(result, "no_legal_age_claim_without_evidence"); } + if (family === "business_overview") { + pushUnique(result, "no_unchecked_fact_totals"); + pushUnique(result, "no_unchecked_business_health_claim"); + pushUnique(result, "no_profit_or_margin_claim_without_evidence"); + } if (family === "value_flow" || family === "movement_evidence" || family === "document_evidence") { pushUnique(result, "no_unchecked_fact_totals"); } @@ -487,9 +517,16 @@ export function buildAssistantMcpDiscoveryDataNeedGraph( !explicitOrganizationScope ) { pushUnique(clarificationGaps, "organization"); + } else if ( + subjectCandidates.length === 0 && + businessFactFamily === "business_overview" && + !explicitOrganizationScope + ) { + pushUnique(clarificationGaps, "organization"); } else if ( subjectCandidates.length === 0 && businessFactFamily !== "schema_surface" && + businessFactFamily !== "business_overview" && !openScopeWithoutSubject && !metadataScopedOpenLaneWithoutSubject && !inventoryStockSnapshotWithoutSubject @@ -541,6 +578,9 @@ export function buildAssistantMcpDiscoveryDataNeedGraph( if (allTimeScopeHint) { pushReason(reasonCodes, "data_need_graph_all_time_scope_hint"); } + if (businessFactFamily === "business_overview" && !explicitDateScope) { + pushReason(reasonCodes, "data_need_graph_business_overview_defaults_to_all_time_scope"); + } if (clarificationGaps.includes("organization")) { pushReason(reasonCodes, "data_need_graph_open_scope_total_needs_organization"); } diff --git a/llm_normalizer/backend/src/services/assistantMcpDiscoveryPilotExecutor.ts b/llm_normalizer/backend/src/services/assistantMcpDiscoveryPilotExecutor.ts index a92f7ef..fac9d78 100644 --- a/llm_normalizer/backend/src/services/assistantMcpDiscoveryPilotExecutor.ts +++ b/llm_normalizer/backend/src/services/assistantMcpDiscoveryPilotExecutor.ts @@ -200,6 +200,7 @@ export type AssistantMcpDiscoveryPilotScope = | "counterparty_value_flow_query_movements_v1" | "counterparty_supplier_payout_query_movements_v1" | "counterparty_bidirectional_value_flow_query_movements_v1" + | "business_overview_route_template_v1" | "inventory_route_template_v1"; export interface AssistantMcpDiscoveryPilotExecutionContract { @@ -2713,6 +2714,8 @@ function pilotScopeForPlanner(planner: AssistantMcpDiscoveryPlannerContract): As case "value_flow_ranking": case "value_flow": return valueFlowPilotProfile(planner).scope; + case "business_overview": + return "business_overview_route_template_v1"; case "document_evidence": return "counterparty_document_evidence_query_documents_v1"; case "lifecycle": diff --git a/llm_normalizer/backend/src/services/assistantMcpDiscoveryPlanner.ts b/llm_normalizer/backend/src/services/assistantMcpDiscoveryPlanner.ts index 3499ca6..448c786 100644 --- a/llm_normalizer/backend/src/services/assistantMcpDiscoveryPlanner.ts +++ b/llm_normalizer/backend/src/services/assistantMcpDiscoveryPlanner.ts @@ -66,6 +66,7 @@ export type AssistantMcpDiscoveryChainId = | "value_flow_comparison" | "value_flow_ranking" | "lifecycle" + | "business_overview" | "movement_evidence" | "document_evidence" | "entity_resolution"; @@ -922,6 +923,32 @@ function recipeFor(input: AssistantMcpDiscoveryPlannerInput): PlannerRecipe { }); } + if (graphFactFamily === "business_overview") { + pushUnique(axes, "organization"); + pushUnique(axes, "aggregate_axis"); + pushUnique(axes, "amount"); + pushUnique(axes, "coverage_target"); + pushUnique(axes, "evidence_basis"); + pushUnique(axes, "profit_margin_boundary"); + const template = getAssistantMcpCatalogChainTemplate("business_overview"); + const primitiveSelection = selectPrimitivesFromGraphAndCatalog({ + dataNeedGraph, + fallbackPrimitives: template.fallback_primitives, + requiredAxes: axes, + metadataSurface: input.metadataSurface, + actionFamily: action || graphAction, + allowAggregateByAxis: true, + selectedChainId: "business_overview" + }); + return recipeFromCatalogChainTemplate({ + chainId: "business_overview", + axes, + primitives: primitiveSelection.primitives, + reason: "planner_selected_business_overview_from_data_need_graph", + extraReasons: primitiveSelection.reasonCodes + }); + } + if (graphFactFamily === "activity_lifecycle") { pushUnique(axes, "document_date"); pushUnique(axes, "coverage_target"); diff --git a/llm_normalizer/backend/tests/assistantMcpCatalogIndex.test.ts b/llm_normalizer/backend/tests/assistantMcpCatalogIndex.test.ts index 678ae8a..ff7cd57 100644 --- a/llm_normalizer/backend/tests/assistantMcpCatalogIndex.test.ts +++ b/llm_normalizer/backend/tests/assistantMcpCatalogIndex.test.ts @@ -42,7 +42,8 @@ describe("assistant MCP catalog index", () => { "value_flow", "value_flow_comparison", "value_flow_ranking", - "lifecycle" + "lifecycle", + "business_overview" ]); for (const template of index.chain_templates) { expect(template.safe_for_model_planning).toBe(true); @@ -63,6 +64,7 @@ describe("assistant MCP catalog index", () => { const valueFlowComparisonTemplate = getAssistantMcpCatalogChainTemplate("value_flow_comparison"); const valueFlowRankingTemplate = getAssistantMcpCatalogChainTemplate("value_flow_ranking"); const lifecycleTemplate = getAssistantMcpCatalogChainTemplate("lifecycle"); + const businessOverviewTemplate = getAssistantMcpCatalogChainTemplate("business_overview"); const inventorySnapshotTemplate = getAssistantMcpCatalogChainTemplate("inventory_stock_snapshot"); const inventoryProvenanceTemplate = getAssistantMcpCatalogChainTemplate("inventory_purchase_provenance"); const inventorySaleTraceTemplate = getAssistantMcpCatalogChainTemplate("inventory_sale_trace"); @@ -94,6 +96,19 @@ describe("assistant MCP catalog index", () => { expect(lifecycleTemplate.planning_tags).toEqual( expect.arrayContaining(["bounded_inference", "activity_window", "legal_fact_boundary"]) ); + expect(businessOverviewTemplate.fallback_primitives).toEqual([ + "query_movements", + "aggregate_by_axis", + "query_documents", + "probe_coverage", + "explain_evidence_basis" + ]); + expect(businessOverviewTemplate.base_required_axes).toEqual( + expect.arrayContaining(["organization", "aggregate_axis", "coverage_target", "profit_margin_boundary"]) + ); + expect(businessOverviewTemplate.planning_tags).toEqual( + expect.arrayContaining(["business_overview", "bounded_inference", "explanation"]) + ); expect(inventorySnapshotTemplate.base_required_axes).toEqual( expect.arrayContaining(["as_of_date", "warehouse", "aggregate_axis", "quantity", "coverage_target"]) ); @@ -170,10 +185,35 @@ describe("assistant MCP catalog index", () => { ranking_need: "top_desc", required_axes: ["organization", "period", "aggregate_axis", "amount", "coverage_target"] }); + const businessOverviewTemplates = searchAssistantMcpCatalogChainTemplatesByFactAxis({ + business_fact_family: "business_overview", + action_family: "broad_evaluation", + required_axes: ["organization", "all_time_scope", "aggregate_axis", "amount", "coverage_target", "evidence_basis"] + }); expect(documentTemplates[0]).toBe("document_evidence"); expect(comparisonTemplates[0]).toBe("value_flow_comparison"); expect(rankingTemplates[0]).toBe("value_flow_ranking"); + expect(businessOverviewTemplates[0]).toBe("business_overview"); + }); + + it("can search reviewed primitives for bounded business overview chains", () => { + const primitives = searchAssistantMcpCatalogPrimitivesByFactAxis({ + business_fact_family: "business_overview", + action_family: "broad_evaluation", + required_axes: ["organization", "all_time_scope", "aggregate_axis", "amount", "coverage_target", "evidence_basis"] + }); + + expect(primitives).toEqual( + expect.arrayContaining([ + "query_movements", + "aggregate_by_axis", + "query_documents", + "probe_coverage", + "explain_evidence_basis" + ]) + ); + expect(primitives).not.toContain("search_business_entity"); }); it("can search reviewed primitives for inventory stock snapshot chains", () => { diff --git a/llm_normalizer/backend/tests/assistantMcpDiscoveryDataNeedGraph.test.ts b/llm_normalizer/backend/tests/assistantMcpDiscoveryDataNeedGraph.test.ts index 12b127d..150042b 100644 --- a/llm_normalizer/backend/tests/assistantMcpDiscoveryDataNeedGraph.test.ts +++ b/llm_normalizer/backend/tests/assistantMcpDiscoveryDataNeedGraph.test.ts @@ -71,6 +71,56 @@ describe("assistant MCP discovery data need graph", () => { expect(result.forbidden_overclaim_flags).toContain("no_unresolved_entity_claim"); }); + it("models broad business evaluation as a bounded business-overview evidence graph", () => { + const result = buildAssistantMcpDiscoveryDataNeedGraph({ + semanticDataNeed: "business overview evidence with bounded analyst interpretation", + rawUtterance: "дай полный анализ компании и LLM-аудит бизнеса", + turnMeaning: { + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + explicit_organization_scope: "ООО Альтернатива Плюс" + } + }); + + expect(result.business_fact_family).toBe("business_overview"); + expect(result.action_family).toBe("broad_evaluation"); + expect(result.time_scope_need).toBe("all_time_scope"); + expect(result.proof_expectation).toBe("bounded_inference"); + expect(result.clarification_gaps).toEqual([]); + expect(result.decomposition_candidates).toEqual([ + "collect_scoped_movements", + "aggregate_checked_amounts", + "aggregate_ranked_axis_values", + "fetch_supporting_documents", + "probe_coverage", + "explain_evidence_basis" + ]); + expect(result.forbidden_overclaim_flags).toEqual( + expect.arrayContaining([ + "no_unchecked_business_health_claim", + "no_profit_or_margin_claim_without_evidence" + ]) + ); + expect(result.reason_codes).toContain("data_need_graph_family_business_overview"); + expect(result.reason_codes).toContain("data_need_graph_business_overview_defaults_to_all_time_scope"); + }); + + it("requires organization scope before a fresh broad business overview probe", () => { + const result = buildAssistantMcpDiscoveryDataNeedGraph({ + semanticDataNeed: "business overview evidence with bounded analyst interpretation", + rawUtterance: "как оценишь деятельность компании?", + turnMeaning: { + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + unsupported_but_understood_family: "broad_business_evaluation" + } + }); + + expect(result.business_fact_family).toBe("business_overview"); + expect(result.clarification_gaps).toEqual(["organization"]); + expect(result.proof_expectation).toBe("clarification_required"); + }); + it("builds a subjectless inventory stock snapshot graph with an as-of date gate", () => { const result = buildAssistantMcpDiscoveryDataNeedGraph({ semanticDataNeed: "inventory stock snapshot evidence", diff --git a/llm_normalizer/backend/tests/assistantMcpDiscoveryPilotExecutor.test.ts b/llm_normalizer/backend/tests/assistantMcpDiscoveryPilotExecutor.test.ts index be343aa..8d7e675 100644 --- a/llm_normalizer/backend/tests/assistantMcpDiscoveryPilotExecutor.test.ts +++ b/llm_normalizer/backend/tests/assistantMcpDiscoveryPilotExecutor.test.ts @@ -103,6 +103,57 @@ describe("assistant MCP discovery pilot executor", () => { expect(deps.executeAddressMcpQuery).not.toHaveBeenCalled(); }); + it("keeps business overview as an explicit unsupported runtime scope until the fresh multi-probe bridge exists", async () => { + const planner = planAssistantMcpDiscovery({ + dataNeedGraph: { + schema_version: "assistant_data_need_graph_v1", + policy_owner: "assistantMcpDiscoveryDataNeedGraph", + subject_candidates: [], + business_fact_family: "business_overview", + action_family: "broad_evaluation", + aggregation_need: null, + time_scope_need: "all_time_scope", + comparison_need: null, + ranking_need: null, + proof_expectation: "bounded_inference", + clarification_gaps: [], + decomposition_candidates: [ + "collect_scoped_movements", + "aggregate_checked_amounts", + "aggregate_ranked_axis_values", + "fetch_supporting_documents", + "probe_coverage", + "explain_evidence_basis" + ], + forbidden_overclaim_flags: ["no_raw_model_claims", "no_profit_or_margin_claim_without_evidence"], + reason_codes: ["data_need_graph_built", "data_need_graph_family_business_overview"] + }, + turnMeaning: { + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + explicit_organization_scope: "ООО Альтернатива Плюс" + } + }); + const deps = buildDeps([]); + + const result = await executeAssistantMcpDiscoveryPilot(planner, deps); + + expect(planner.planner_status).toBe("ready_for_execution"); + expect(result.pilot_status).toBe("unsupported"); + expect(result.pilot_scope).toBe("business_overview_route_template_v1"); + expect(result.mcp_execution_performed).toBe(false); + expect(result.executed_primitives).toEqual([]); + expect(result.skipped_primitives).toEqual([ + "query_movements", + "aggregate_by_axis", + "query_documents", + "probe_coverage", + "explain_evidence_basis" + ]); + expect(result.reason_codes).toContain("pilot_scope_unsupported_for_live_execution"); + expect(deps.executeAddressMcpQuery).not.toHaveBeenCalled(); + }); + it("uses the explicit selected chain id when choosing the movement pilot scope", async () => { const planner = planAssistantMcpDiscovery({ turnMeaning: { diff --git a/llm_normalizer/backend/tests/assistantMcpDiscoveryPlanner.test.ts b/llm_normalizer/backend/tests/assistantMcpDiscoveryPlanner.test.ts index ad2c6c3..67a9ddd 100644 --- a/llm_normalizer/backend/tests/assistantMcpDiscoveryPlanner.test.ts +++ b/llm_normalizer/backend/tests/assistantMcpDiscoveryPlanner.test.ts @@ -184,6 +184,18 @@ describe("assistant MCP discovery planner", () => { } } }, + { + name: "business_overview", + expected: "business_overview", + input: { + dataNeedGraph: graph("business_overview", "broad_evaluation", { subject_candidates: [] }), + turnMeaning: { + asked_action_family: "broad_evaluation", + explicit_organization_scope: "Org", + explicit_date_scope: "2020" + } + } + }, { name: "inventory_stock_snapshot", expected: "inventory_stock_snapshot", @@ -209,6 +221,73 @@ describe("assistant MCP discovery planner", () => { } }); + it("builds a catalog-compatible business overview plan without pretending the fresh runtime probe exists yet", () => { + const result = planAssistantMcpDiscovery({ + dataNeedGraph: { + schema_version: "assistant_data_need_graph_v1", + policy_owner: "assistantMcpDiscoveryDataNeedGraph", + subject_candidates: [], + business_fact_family: "business_overview", + action_family: "broad_evaluation", + aggregation_need: null, + time_scope_need: "all_time_scope", + comparison_need: null, + ranking_need: null, + proof_expectation: "bounded_inference", + clarification_gaps: [], + decomposition_candidates: [ + "collect_scoped_movements", + "aggregate_checked_amounts", + "aggregate_ranked_axis_values", + "fetch_supporting_documents", + "probe_coverage", + "explain_evidence_basis" + ], + forbidden_overclaim_flags: [ + "no_raw_model_claims", + "no_unchecked_business_health_claim", + "no_profit_or_margin_claim_without_evidence" + ], + reason_codes: ["data_need_graph_built", "data_need_graph_family_business_overview"] + }, + turnMeaning: { + asked_domain_family: "business_overview", + asked_action_family: "broad_evaluation", + explicit_organization_scope: "ООО Альтернатива Плюс" + } + }); + + expect(result.planner_status).toBe("ready_for_execution"); + expect(result.selected_chain_id).toBe("business_overview"); + expect(result.semantic_data_need).toBe("business overview evidence with bounded analyst interpretation"); + expect(result.proposed_primitives).toEqual([ + "query_movements", + "aggregate_by_axis", + "query_documents", + "probe_coverage", + "explain_evidence_basis" + ]); + expect(result.required_axes).toEqual([ + "organization", + "all_time_scope", + "aggregate_axis", + "amount", + "coverage_target", + "evidence_basis", + "profit_margin_boundary" + ]); + expect(result.catalog_chain_template_matches[0]).toBe("business_overview"); + expect(result.catalog_chain_template_alignment).toMatchObject({ + alignment_status: "selected_matches_top", + top_chain_template_match: "business_overview", + selected_chain_template_rank: 1, + selected_chain_matches_top: true + }); + expect(result.catalog_review.review_status).toBe("catalog_compatible"); + expect(result.reason_codes).toContain("planner_selected_business_overview_from_data_need_graph"); + expect(result.reason_codes).toContain("planner_instantiated_catalog_chain_template_business_overview"); + }); + it("keeps bidirectional value-flow comparison executable when checked totals are derived without aggregate_by_axis", () => { const result = planAssistantMcpDiscovery({ dataNeedGraph: { diff --git a/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeEntryPoint.test.ts b/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeEntryPoint.test.ts index 47537f3..63bf48c 100644 --- a/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeEntryPoint.test.ts +++ b/llm_normalizer/backend/tests/assistantMcpDiscoveryRuntimeEntryPoint.test.ts @@ -134,7 +134,8 @@ describe("assistant MCP discovery runtime entry point", () => { asked_action_family: "inspect_fields" }); expect(result.bridge?.pilot.pilot_scope).toBe("metadata_inspection_v1"); - expect(result.bridge?.answer_draft.headline).toContain("метаданным 1С"); + expect(result.bridge?.answer_draft.headline).toContain("схеме 1С"); + expect(result.bridge?.answer_draft.headline).toContain("подходящие объекты"); }); it("runs the bridge for raw entity-resolution wording and executes the full grounding chain", async () => {