ARCH: добавить open-scope totals по организации в MCP discovery
This commit is contained in:
@@ -114,4 +114,27 @@ describe("assistant MCP discovery data need graph", () => {
|
||||
]);
|
||||
expect(result.reason_codes).toContain("data_need_graph_comparison_incoming_vs_outgoing");
|
||||
});
|
||||
it("treats organization-scoped incoming totals as an open-scope value need rather than a missing-subject fact ask", () => {
|
||||
const result = buildAssistantMcpDiscoveryDataNeedGraph({
|
||||
semanticDataNeed: "counterparty value-flow evidence",
|
||||
rawUtterance: "сколько входящих денег за 2020 год по ООО Альтернатива Плюс?",
|
||||
turnMeaning: {
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "turnover",
|
||||
explicit_date_scope: "2020",
|
||||
explicit_organization_scope: "ООО Альтернатива Плюс"
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.business_fact_family).toBe("value_flow");
|
||||
expect(result.comparison_need).toBeNull();
|
||||
expect(result.ranking_need).toBeNull();
|
||||
expect(result.clarification_gaps).toEqual([]);
|
||||
expect(result.decomposition_candidates).toEqual([
|
||||
"collect_scoped_movements",
|
||||
"aggregate_checked_amounts",
|
||||
"probe_coverage"
|
||||
]);
|
||||
expect(result.reason_codes).toContain("data_need_graph_open_scope_total_without_subject");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -440,4 +440,38 @@ describe("assistant MCP discovery planner", () => {
|
||||
expect(result.selected_chain_summary).toContain("resolve the most relevant 1C reference");
|
||||
expect(result.proposed_primitives).toEqual(["search_business_entity", "resolve_entity_reference", "probe_coverage"]);
|
||||
});
|
||||
it("keeps organization-scoped one-sided value-flow totals executable without forcing a counterparty", () => {
|
||||
const result = planAssistantMcpDiscovery({
|
||||
dataNeedGraph: {
|
||||
schema_version: "assistant_data_need_graph_v1",
|
||||
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
|
||||
subject_candidates: [],
|
||||
business_fact_family: "value_flow",
|
||||
action_family: "turnover",
|
||||
aggregation_need: null,
|
||||
time_scope_need: "explicit_period",
|
||||
comparison_need: null,
|
||||
ranking_need: null,
|
||||
proof_expectation: "coverage_checked_fact",
|
||||
clarification_gaps: [],
|
||||
decomposition_candidates: ["collect_scoped_movements", "aggregate_checked_amounts", "probe_coverage"],
|
||||
forbidden_overclaim_flags: ["no_raw_model_claims", "no_unchecked_fact_totals"],
|
||||
reason_codes: ["data_need_graph_built", "data_need_graph_open_scope_total_without_subject"]
|
||||
},
|
||||
turnMeaning: {
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "turnover",
|
||||
explicit_date_scope: "2020",
|
||||
explicit_organization_scope: "ООО Альтернатива Плюс"
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.planner_status).toBe("ready_for_execution");
|
||||
expect(result.semantic_data_need).toBe("organization-scoped value-flow evidence");
|
||||
expect(result.selected_chain_id).toBe("value_flow");
|
||||
expect(result.proposed_primitives).toEqual(["query_movements", "aggregate_by_axis", "probe_coverage"]);
|
||||
expect(result.required_axes).toEqual(["organization", "period", "aggregate_axis", "amount", "coverage_target"]);
|
||||
expect(result.catalog_review.review_status).toBe("catalog_compatible");
|
||||
expect(result.reason_codes).toContain("planner_selected_open_scope_value_flow_total_from_data_need_graph");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -275,4 +275,45 @@ describe("assistant MCP discovery runtime bridge", () => {
|
||||
expect(userFacing).not.toContain("runtime_bridge");
|
||||
expect(userFacing).not.toContain("primitive");
|
||||
});
|
||||
it("produces a bounded one-sided value-flow answer for an organization-scoped total without inventing a counterparty", async () => {
|
||||
const result = await runAssistantMcpDiscoveryRuntimeBridge({
|
||||
dataNeedGraph: {
|
||||
schema_version: "assistant_data_need_graph_v1",
|
||||
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
|
||||
subject_candidates: [],
|
||||
business_fact_family: "value_flow",
|
||||
action_family: "turnover",
|
||||
aggregation_need: null,
|
||||
time_scope_need: "explicit_period",
|
||||
comparison_need: null,
|
||||
ranking_need: null,
|
||||
proof_expectation: "coverage_checked_fact",
|
||||
clarification_gaps: [],
|
||||
decomposition_candidates: ["collect_scoped_movements", "aggregate_checked_amounts", "probe_coverage"],
|
||||
forbidden_overclaim_flags: ["no_raw_model_claims", "no_unchecked_fact_totals"],
|
||||
reason_codes: ["data_need_graph_built", "data_need_graph_open_scope_total_without_subject"]
|
||||
},
|
||||
turnMeaning: {
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "turnover",
|
||||
explicit_date_scope: "2020",
|
||||
explicit_organization_scope: "ООО Альтернатива Плюс"
|
||||
},
|
||||
deps: buildDeps([
|
||||
{ Period: "2020-01-10T00:00:00", Amount: 3200, Counterparty: "Клиент-А" },
|
||||
{ Period: "2020-05-22T00:00:00", Amount: 1800, Counterparty: "Клиент-Б" }
|
||||
])
|
||||
});
|
||||
|
||||
expect(result.bridge_status).toBe("answer_draft_ready");
|
||||
expect(result.business_fact_answer_allowed).toBe(true);
|
||||
expect(result.planner.selected_chain_id).toBe("value_flow");
|
||||
expect(result.pilot.derived_value_flow).toMatchObject({
|
||||
counterparty: null,
|
||||
period_scope: "2020",
|
||||
total_amount: 5000
|
||||
});
|
||||
expect(result.answer_draft.confirmed_lines.join("\n")).toContain("5 000");
|
||||
expect(result.answer_draft.confirmed_lines.join("\n")).not.toContain("контрагенту");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -353,4 +353,59 @@ describe("assistant MCP discovery runtime entry point", () => {
|
||||
expect(result.turn_input.data_need_graph?.subject_candidates).toEqual([]);
|
||||
expect(result.bridge?.planner.selected_chain_id).toBe("value_flow_comparison");
|
||||
});
|
||||
it("runs raw organization-scoped incoming totals as an open value-flow chain without inventing a counterparty", async () => {
|
||||
const result = await runAssistantMcpDiscoveryRuntimeEntryPoint({
|
||||
userMessage: "сколько входящих денег за 2020 год по ООО Альтернатива Плюс?",
|
||||
predecomposeContract: {
|
||||
entities: { organization: "ООО Альтернатива Плюс" },
|
||||
period: { period_from: "2020-01-01", period_to: "2020-12-31" }
|
||||
},
|
||||
deps: buildDeps([
|
||||
{ Period: "2020-01-15T00:00:00", Amount: 2500, Counterparty: "Клиент-А" },
|
||||
{ Period: "2020-06-20T00:00:00", Amount: 1000, Counterparty: "Клиент-Б" }
|
||||
])
|
||||
});
|
||||
|
||||
expect(result.entry_status).toBe("bridge_executed");
|
||||
expect(result.discovery_attempted).toBe(true);
|
||||
expect(result.turn_input.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "turnover",
|
||||
explicit_organization_scope: "ООО Альтернатива Плюс",
|
||||
explicit_date_scope: "2020"
|
||||
});
|
||||
expect(result.turn_input.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined();
|
||||
expect(result.turn_input.data_need_graph?.subject_candidates).toEqual([]);
|
||||
expect(result.bridge?.planner.selected_chain_id).toBe("value_flow");
|
||||
expect(result.bridge?.pilot.pilot_scope).toBe("counterparty_value_flow_query_movements_v1");
|
||||
expect(result.bridge?.answer_draft.confirmed_lines.join("\n")).toContain("входящ");
|
||||
});
|
||||
|
||||
it("runs raw organization-scoped outgoing totals as an open payout chain without inventing a counterparty", async () => {
|
||||
const orgName = "ООО Альтернатива Плюс";
|
||||
const result = await runAssistantMcpDiscoveryRuntimeEntryPoint({
|
||||
userMessage: "сколько исходящих денег за 2020 год по ООО Альтернатива Плюс?",
|
||||
predecomposeContract: {
|
||||
entities: { counterparty: orgName, organization: orgName },
|
||||
period: { period_from: "2020-01-01", period_to: "2020-12-31" }
|
||||
},
|
||||
deps: buildDeps([
|
||||
{ Period: "2020-02-18T00:00:00", Amount: 900, Counterparty: "Поставщик-А" },
|
||||
{ Period: "2020-08-07T00:00:00", Amount: 300, Counterparty: "Поставщик-Б" }
|
||||
])
|
||||
});
|
||||
|
||||
expect(result.entry_status).toBe("bridge_executed");
|
||||
expect(result.discovery_attempted).toBe(true);
|
||||
expect(result.turn_input.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "payout",
|
||||
explicit_organization_scope: orgName,
|
||||
explicit_date_scope: "2020"
|
||||
});
|
||||
expect(result.turn_input.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined();
|
||||
expect(result.bridge?.planner.selected_chain_id).toBe("value_flow");
|
||||
expect(result.bridge?.pilot.pilot_scope).toBe("counterparty_supplier_payout_query_movements_v1");
|
||||
expect(result.bridge?.answer_draft.confirmed_lines.join("\n")).toContain("исход");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1377,4 +1377,49 @@ describe("assistant MCP discovery turn input adapter", () => {
|
||||
expect(result.data_need_graph?.comparison_need).toBe("incoming_vs_outgoing");
|
||||
expect(result.reason_codes).not.toContain("mcp_discovery_counterparty_from_predecompose");
|
||||
});
|
||||
it("keeps organization-scoped incoming totals in an open value-flow lane without inventing a counterparty", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "сколько входящих денег за 2020 год по ООО Альтернатива Плюс?",
|
||||
predecomposeContract: {
|
||||
entities: { organization: "ООО Альтернатива Плюс" },
|
||||
period: { period_from: "2020-01-01", period_to: "2020-12-31" }
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.should_run_discovery).toBe(true);
|
||||
expect(result.semantic_data_need).toBe("counterparty value-flow evidence");
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "turnover",
|
||||
explicit_organization_scope: "ООО Альтернатива Плюс",
|
||||
explicit_date_scope: "2020",
|
||||
unsupported_but_understood_family: "counterparty_value_or_turnover",
|
||||
stale_replay_forbidden: true
|
||||
});
|
||||
expect(result.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined();
|
||||
expect(result.data_need_graph?.subject_candidates).toEqual([]);
|
||||
expect(result.data_need_graph?.reason_codes).toContain("data_need_graph_open_scope_total_without_subject");
|
||||
});
|
||||
|
||||
it("does not treat mirrored organization/counterparty predecompose as a real subject for organization-scoped payouts", () => {
|
||||
const orgName = "ООО Альтернатива Плюс";
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "сколько исходящих денег за 2020 год по ООО Альтернатива Плюс?",
|
||||
predecomposeContract: {
|
||||
entities: { counterparty: orgName, organization: orgName },
|
||||
period: { period_from: "2020-01-01", period_to: "2020-12-31" }
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "payout",
|
||||
explicit_organization_scope: orgName,
|
||||
explicit_date_scope: "2020"
|
||||
});
|
||||
expect(result.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined();
|
||||
expect(result.data_need_graph?.subject_candidates).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user