Planner Autonomy: поднять inventory routes в MCP catalog

This commit is contained in:
2026-05-01 13:08:21 +03:00
parent 6bfbd5cb20
commit 9243642400
15 changed files with 1162 additions and 61 deletions
@@ -34,6 +34,10 @@ describe("assistant MCP catalog index", () => {
"entity_resolution",
"document_evidence",
"movement_evidence",
"inventory_stock_snapshot",
"inventory_supplier_overlap",
"inventory_purchase_provenance",
"inventory_sale_trace",
"value_flow",
"value_flow_comparison",
"value_flow_ranking",
@@ -58,6 +62,9 @@ describe("assistant MCP catalog index", () => {
const valueFlowComparisonTemplate = getAssistantMcpCatalogChainTemplate("value_flow_comparison");
const valueFlowRankingTemplate = getAssistantMcpCatalogChainTemplate("value_flow_ranking");
const lifecycleTemplate = getAssistantMcpCatalogChainTemplate("lifecycle");
const inventorySnapshotTemplate = getAssistantMcpCatalogChainTemplate("inventory_stock_snapshot");
const inventoryProvenanceTemplate = getAssistantMcpCatalogChainTemplate("inventory_purchase_provenance");
const inventorySaleTraceTemplate = getAssistantMcpCatalogChainTemplate("inventory_sale_trace");
expect(documentTemplate.fallback_primitives).toEqual([
"resolve_entity_reference",
@@ -86,6 +93,19 @@ describe("assistant MCP catalog index", () => {
expect(lifecycleTemplate.planning_tags).toEqual(
expect.arrayContaining(["bounded_inference", "activity_window", "legal_fact_boundary"])
);
expect(inventorySnapshotTemplate.base_required_axes).toEqual(
expect.arrayContaining(["as_of_date", "warehouse", "aggregate_axis", "quantity", "coverage_target"])
);
expect(inventoryProvenanceTemplate.fallback_primitives).toEqual([
"resolve_entity_reference",
"query_documents",
"drilldown_related_objects",
"probe_coverage",
"explain_evidence_basis"
]);
expect(inventorySaleTraceTemplate.supported_action_families).toEqual(
expect.arrayContaining(["sale_trace", "purchase_to_sale_chain"])
);
});
it("can search reviewed primitives from data-need decomposition candidates", () => {
@@ -131,6 +151,53 @@ describe("assistant MCP catalog index", () => {
expect(primitives).toEqual(["resolve_entity_reference", "query_documents", "probe_coverage"]);
});
it("can search reviewed primitives for inventory stock snapshot chains", () => {
const primitives = searchAssistantMcpCatalogPrimitivesByFactAxis({
business_fact_family: "inventory_stock_snapshot",
action_family: "stock_snapshot",
required_axes: ["as_of_date", "organization", "warehouse", "aggregate_axis", "quantity", "coverage_target", "evidence_basis"]
});
expect(primitives).toEqual(
expect.arrayContaining(["query_movements", "aggregate_by_axis", "probe_coverage", "explain_evidence_basis"])
);
expect(primitives).not.toContain("query_documents");
});
it("can search reviewed primitives for inventory provenance and sale-trace chains", () => {
const provenancePrimitives = searchAssistantMcpCatalogPrimitivesByFactAxis({
business_fact_family: "inventory_purchase_provenance",
action_family: "purchase_provenance",
has_subject_candidates: true,
required_axes: ["item", "document", "supplier", "coverage_target", "evidence_basis"]
});
const saleTracePrimitives = searchAssistantMcpCatalogPrimitivesByFactAxis({
business_fact_family: "inventory_sale_trace",
action_family: "sale_trace",
has_subject_candidates: true,
required_axes: ["item", "document", "buyer", "coverage_target", "evidence_basis"]
});
expect(provenancePrimitives).toEqual(
expect.arrayContaining([
"resolve_entity_reference",
"query_documents",
"drilldown_related_objects",
"probe_coverage",
"explain_evidence_basis"
])
);
expect(saleTracePrimitives).toEqual(
expect.arrayContaining([
"resolve_entity_reference",
"query_documents",
"drilldown_related_objects",
"probe_coverage",
"explain_evidence_basis"
])
);
});
it("treats all-time organization-scoped value-flow as catalog-compatible without inventing a fake period axis", () => {
const primitives = searchAssistantMcpCatalogPrimitivesByFactAxis({
business_fact_family: "value_flow",
@@ -215,6 +282,8 @@ describe("assistant MCP catalog index", () => {
expect(review.reason_codes).toContain("catalog_required_axes_missing_for_primitive");
expect(review.missing_axes_by_primitive.query_documents).toEqual([
["document"],
["item"],
["supplier"],
["counterparty"],
["contract"],
["period", "organization"],
@@ -71,6 +71,87 @@ describe("assistant MCP discovery data need graph", () => {
expect(result.forbidden_overclaim_flags).toContain("no_unresolved_entity_claim");
});
it("builds a subjectless inventory stock snapshot graph with an as-of date gate", () => {
const result = buildAssistantMcpDiscoveryDataNeedGraph({
semanticDataNeed: "inventory stock snapshot evidence",
rawUtterance: "show stock snapshot for warehouse main as of 2021-09-30",
turnMeaning: {
asked_domain_family: "inventory_stock",
asked_action_family: "stock_snapshot",
explicit_organization_scope: "ООО Альтернатива Плюс",
explicit_date_scope: "2021-09-30"
}
});
expect(result.business_fact_family).toBe("inventory_stock_snapshot");
expect(result.subject_candidates).toEqual([]);
expect(result.clarification_gaps).toEqual([]);
expect(result.time_scope_need).toBe("explicit_period");
expect(result.decomposition_candidates).toEqual([
"fetch_scoped_movements",
"aggregate_checked_amounts",
"probe_coverage",
"explain_evidence_basis"
]);
expect(result.forbidden_overclaim_flags).toContain("no_unchecked_stock_snapshot");
});
it("keeps inventory stock snapshot blocked on an explicit as-of date when no date exists", () => {
const result = buildAssistantMcpDiscoveryDataNeedGraph({
semanticDataNeed: "inventory stock snapshot evidence",
rawUtterance: "show current stock snapshot",
turnMeaning: {
asked_domain_family: "inventory_stock",
asked_action_family: "stock_snapshot",
explicit_organization_scope: "ООО Альтернатива Плюс"
}
});
expect(result.business_fact_family).toBe("inventory_stock_snapshot");
expect(result.clarification_gaps).toEqual(["as_of_date"]);
expect(result.proof_expectation).toBe("clarification_required");
});
it("builds inventory provenance and sale-trace graphs as checked document drilldowns", () => {
const provenance = buildAssistantMcpDiscoveryDataNeedGraph({
semanticDataNeed: "inventory purchase provenance evidence",
rawUtterance: "who supplied the selected stock item",
turnMeaning: {
asked_domain_family: "inventory_stock",
asked_action_family: "purchase_provenance",
explicit_entity_candidates: ["Столешница 600"]
}
});
const saleTrace = buildAssistantMcpDiscoveryDataNeedGraph({
semanticDataNeed: "inventory sale trace evidence",
rawUtterance: "who bought the selected stock item",
turnMeaning: {
asked_domain_family: "inventory_stock",
asked_action_family: "sale_trace",
explicit_entity_candidates: ["Столешница 600"]
}
});
expect(provenance.business_fact_family).toBe("inventory_purchase_provenance");
expect(provenance.decomposition_candidates).toEqual([
"resolve_entity_reference",
"fetch_scoped_documents",
"drilldown_related_objects",
"probe_coverage",
"explain_evidence_basis"
]);
expect(provenance.forbidden_overclaim_flags).toContain("no_unproven_supplier_attribution");
expect(saleTrace.business_fact_family).toBe("inventory_sale_trace");
expect(saleTrace.decomposition_candidates).toEqual([
"resolve_entity_reference",
"fetch_scoped_documents",
"drilldown_related_objects",
"probe_coverage",
"explain_evidence_basis"
]);
expect(saleTrace.forbidden_overclaim_flags).toContain("no_unproven_buyer_or_sale_trace");
});
it("treats top-value wording as a ranking ask rather than a missing-subject fact ask", () => {
const result = buildAssistantMcpDiscoveryDataNeedGraph({
semanticDataNeed: "counterparty value-flow evidence",
@@ -683,6 +683,141 @@ describe("assistant MCP discovery planner", () => {
expect(result.reason_codes).toContain("planner_lifecycle_legal_fact_boundary_required");
});
it("instantiates inventory stock snapshot from the catalog fabric", () => {
const result = planAssistantMcpDiscovery({
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: "ООО Альтернатива Плюс",
explicit_date_scope: "2021-09-30"
}
});
expect(result.planner_status).toBe("ready_for_execution");
expect(result.selected_chain_id).toBe("inventory_stock_snapshot");
expect(result.proposed_primitives).toEqual([
"query_movements",
"aggregate_by_axis",
"probe_coverage",
"explain_evidence_basis"
]);
expect(result.required_axes).toEqual([
"organization",
"period",
"as_of_date",
"warehouse",
"aggregate_axis",
"quantity",
"coverage_target",
"evidence_basis"
]);
expect(result.reason_codes).toContain("planner_selected_inventory_stock_snapshot_from_data_need_graph");
expect(result.reason_codes).toContain("planner_instantiated_catalog_chain_template_inventory_stock_snapshot");
});
it("instantiates inventory provenance and sale-trace chains from reviewed templates", () => {
const provenance = planAssistantMcpDiscovery({
dataNeedGraph: {
schema_version: "assistant_data_need_graph_v1",
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
subject_candidates: ["Столешница 600"],
business_fact_family: "inventory_purchase_provenance",
action_family: "purchase_provenance",
aggregation_need: null,
time_scope_need: null,
comparison_need: null,
ranking_need: null,
proof_expectation: "coverage_checked_fact",
clarification_gaps: [],
decomposition_candidates: [
"resolve_entity_reference",
"fetch_scoped_documents",
"drilldown_related_objects",
"probe_coverage",
"explain_evidence_basis"
],
forbidden_overclaim_flags: ["no_raw_model_claims", "no_unproven_supplier_attribution"],
reason_codes: ["data_need_graph_built", "data_need_graph_family_inventory_purchase_provenance"]
},
turnMeaning: {
asked_domain_family: "inventory_stock",
asked_action_family: "purchase_provenance",
explicit_entity_candidates: ["Столешница 600"]
}
});
const saleTrace = planAssistantMcpDiscovery({
dataNeedGraph: {
schema_version: "assistant_data_need_graph_v1",
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
subject_candidates: ["Столешница 600"],
business_fact_family: "inventory_sale_trace",
action_family: "sale_trace",
aggregation_need: null,
time_scope_need: null,
comparison_need: null,
ranking_need: null,
proof_expectation: "coverage_checked_fact",
clarification_gaps: [],
decomposition_candidates: [
"resolve_entity_reference",
"fetch_scoped_documents",
"drilldown_related_objects",
"probe_coverage",
"explain_evidence_basis"
],
forbidden_overclaim_flags: ["no_raw_model_claims", "no_unproven_buyer_or_sale_trace"],
reason_codes: ["data_need_graph_built", "data_need_graph_family_inventory_sale_trace"]
},
turnMeaning: {
asked_domain_family: "inventory_stock",
asked_action_family: "sale_trace",
explicit_entity_candidates: ["Столешница 600"]
}
});
expect(provenance.planner_status).toBe("ready_for_execution");
expect(provenance.selected_chain_id).toBe("inventory_purchase_provenance");
expect(provenance.proposed_primitives).toEqual([
"resolve_entity_reference",
"query_documents",
"drilldown_related_objects",
"probe_coverage",
"explain_evidence_basis"
]);
expect(provenance.reason_codes).toContain("planner_instantiated_catalog_chain_template_inventory_purchase_provenance");
expect(saleTrace.planner_status).toBe("ready_for_execution");
expect(saleTrace.selected_chain_id).toBe("inventory_sale_trace");
expect(saleTrace.proposed_primitives).toEqual([
"resolve_entity_reference",
"query_documents",
"drilldown_related_objects",
"probe_coverage",
"explain_evidence_basis"
]);
expect(saleTrace.reason_codes).toContain("planner_instantiated_catalog_chain_template_inventory_sale_trace");
});
it("uses metadata-only planning when the user asks about available schema surface", () => {
const result = planAssistantMcpDiscovery({
turnMeaning: {