Planner Autonomy: закрепить boundary inventory templates
This commit is contained in:
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user