NODEDC_1C/llm_normalizer/backend/tests/assistantMcpDiscoveryPilotE...

2047 lines
93 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { describe, expect, it, vi } from "vitest";
import { planAssistantMcpDiscovery } from "../src/services/assistantMcpDiscoveryPlanner";
import { executeAssistantMcpDiscoveryPilot } from "../src/services/assistantMcpDiscoveryPilotExecutor";
function buildDeps(rows: Array<Record<string, unknown>>, error: string | null = null) {
return {
executeAddressMcpQuery: vi.fn(async () => ({
fetched_rows: rows.length,
matched_rows: error ? 0 : rows.length,
raw_rows: rows,
rows: error ? [] : rows,
error
}))
};
}
function buildSequentialDeps(results: Array<{ rows: Array<Record<string, unknown>>; error?: string | null }>) {
const executeAddressMcpQuery = vi.fn(async () => {
const next = results.shift() ?? { rows: [] };
const rows = next.rows;
const error = next.error ?? null;
return {
fetched_rows: rows.length,
matched_rows: error ? 0 : rows.length,
raw_rows: rows,
rows: error ? [] : rows,
error
};
});
return { executeAddressMcpQuery };
}
function buildMetadataDeps(rows: Array<Record<string, unknown>>, error: string | null = null) {
return {
executeAddressMcpMetadata: vi.fn(async () => ({
fetched_rows: error ? 0 : rows.length,
raw_rows: error ? [] : rows,
rows: error ? [] : rows,
error
}))
};
}
describe("assistant MCP discovery pilot executor", () => {
it("executes only the lifecycle query_documents primitive through injected MCP deps", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_lifecycle",
asked_action_family: "activity_duration",
explicit_entity_candidates: ["SVK"]
}
});
const deps = buildDeps([
{ Период: "2020-01-15T00:00:00", Регистратор: "CP_CUSTOMER_ACTIVITY_FIRST", Контрагент: "SVK" },
{ Период: "2023-12-20T00:00:00", Регистратор: "CP_CUSTOMER_ACTIVITY", Контрагент: "SVK" }
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.mcp_execution_performed).toBe(true);
expect(result.executed_primitives).toEqual(["query_documents"]);
expect(result.skipped_primitives).toEqual(["resolve_entity_reference", "probe_coverage", "explain_evidence_basis"]);
expect(result.evidence.evidence_status).toBe("confirmed");
expect(result.evidence.confirmed_facts[0]).toContain("SVK");
expect(result.evidence.inferred_facts[0]).toContain("may be inferred");
expect(result.evidence.unknown_facts).toContain("Legal registration date is not proven by this MCP discovery pilot");
expect(result.source_rows_summary).toBe("2 MCP document rows fetched, 2 matched lifecycle scope");
expect(result.derived_activity_period).toEqual({
first_activity_date: "2020-01-15",
latest_activity_date: "2023-12-20",
matched_rows: 2,
duration_total_months: 47,
duration_years: 3,
duration_months_remainder: 11,
duration_human_ru: "3 года 11 месяцев",
inference_basis: "first_and_latest_confirmed_1c_activity_rows"
});
expect(result.reason_codes).toContain("pilot_query_documents_mcp_executed");
expect(result.reason_codes).toContain("pilot_derived_activity_period_from_confirmed_rows");
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(1);
const call = deps.executeAddressMcpQuery.mock.calls[0]?.[0];
expect(String(call?.query ?? "")).toContain("Документ.ПоступлениеНаРасчетныйСчет");
expect(call?.limit).toBeGreaterThan(0);
});
it("does not execute MCP when dry-run still needs clarification", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_value",
asked_action_family: "turnover",
explicit_entity_candidates: ["SVK"]
}
});
const deps = buildDeps([]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("skipped_needs_clarification");
expect(result.mcp_execution_performed).toBe(false);
expect(result.evidence.evidence_status).toBe("insufficient");
expect(deps.executeAddressMcpQuery).not.toHaveBeenCalled();
});
it("executes business overview as a bounded multi-probe bridge over money flow and activity evidence", 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 = buildSequentialDeps([
{
rows: [
{ Period: "2020-01-15T00:00:00", Amount: 120000, Counterparty: "Клиент А" },
{ Period: "2020-02-15T00:00:00", Amount: 80000, Counterparty: "Клиент Б" },
{ Period: "2021-03-15T00:00:00", Amount: 220000, Counterparty: "Клиент А" }
]
},
{
rows: [
{ Period: "2020-01-20T00:00:00", Amount: 150000, Counterparty: "Поставщик А" },
{ Period: "2021-03-20T00:00:00", Amount: 50000, Counterparty: "Поставщик Б" }
]
},
{
rows: [
{ Период: "2020-01-15T00:00:00", Регистратор: "Поступление 1" },
{ Период: "2020-12-15T00:00:00", Регистратор: "Поступление 2" }
]
},
{
rows: [
{ Period: "2020-01-01T00:00:00", Registrator: "DOC_TYPE_DOCS", AccountDt: "Списание с расчетного счета", Amount: 12 },
{ Period: "2020-01-01T00:00:00", Registrator: "DOC_TYPE_DOCS", AccountDt: "Поступление на расчетный счет", Amount: 8 },
{ Period: "2020-01-01T00:00:00", Registrator: "SECTION_DT_OPS", AccountDt: "60", Amount: 9 },
{ Period: "2020-01-01T00:00:00", Registrator: "SECTION_KT_OPS", AccountDt: "62", Amount: 6 }
]
},
{
rows: [
{ Period: "2020-01-01T00:00:00", Registrator: "CP_TOTAL", Amount: 412 },
{ Period: "2020-01-01T00:00:00", Registrator: "CP_CUSTOMER_ACTIVE", Amount: 145 },
{ Period: "2020-01-01T00:00:00", Registrator: "CP_SUPPLIER_ACTIVE", Amount: 94 },
{ Period: "2020-01-01T00:00:00", Registrator: "CP_MIXED_ACTIVE", Amount: 23 },
{ Period: "2020-01-01T00:00:00", Registrator: "CP_ACTIVE_UNION", Amount: 216 }
]
},
{
rows: [
{ Period: "2020-01-01T00:00:00", Registrator: "CT_TOTAL", Amount: 520 },
{ Period: "2020-01-01T00:00:00", Registrator: "CT_USED", Amount: 148 }
]
}
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(planner.planner_status).toBe("ready_for_execution");
expect(result.pilot_status).toBe("executed");
expect(result.pilot_scope).toBe("business_overview_route_template_v1");
expect(result.mcp_execution_performed).toBe(true);
expect(result.executed_primitives).toEqual(["query_movements", "query_documents"]);
expect(result.skipped_primitives).toEqual([
"aggregate_by_axis",
"probe_coverage",
"explain_evidence_basis"
]);
expect(result.derived_business_overview).toMatchObject({
organization_scope: "ООО Альтернатива Плюс",
incoming_customer_revenue: {
total_amount: 420000,
rows_with_amount: 3
},
outgoing_supplier_payout: {
total_amount: 200000,
rows_with_amount: 2
},
net_amount: 220000,
net_direction: "net_incoming"
});
expect(result.derived_business_overview?.top_customers[0]).toMatchObject({
axis_value: "Клиент А",
total_amount: 340000
});
expect(result.derived_business_overview?.top_suppliers[0]).toMatchObject({
axis_value: "Поставщик А",
total_amount: 150000
});
expect(result.derived_business_overview?.yearly_breakdown).toMatchObject([
{
year_bucket: "2020",
incoming_total_amount: 200000,
outgoing_total_amount: 150000,
net_amount: 50000
},
{
year_bucket: "2021",
incoming_total_amount: 220000,
outgoing_total_amount: 50000,
net_amount: 170000
}
]);
expect(result.derived_business_overview?.activity_period?.duration_total_months).toBe(11);
expect(result.derived_business_overview?.document_activity_profile).toMatchObject({
rows_matched: 4,
total_document_type_count: 20,
total_account_section_operations: 15
});
expect(result.derived_business_overview?.document_activity_profile?.top_document_types[0]).toMatchObject({
document_type: "Списание с расчетного счета",
count: 12,
share_pct: 60
});
expect(result.derived_business_overview?.document_activity_profile?.top_account_sections[0]).toMatchObject({
account_section: "60",
operation_count: 9,
share_pct: 60
});
expect(result.derived_business_overview?.counterparty_profile).toMatchObject({
rows_matched: 5,
total_counterparties: 412,
active_counterparties: 216,
customer_only_count: 122,
supplier_only_count: 71,
mixed_role_count: 23,
other_or_inactive_count: 196
});
expect(result.derived_business_overview?.contract_usage_profile).toMatchObject({
rows_matched: 2,
total_contracts: 520,
used_contracts: 148,
unused_contracts: 372,
used_contract_share_pct: 28.46
});
expect(result.derived_business_overview?.vendor_procurement_quality).toMatchObject({
rows_with_amount: 2,
total_outgoing_amount: 200000,
top_outgoing_share_pct: 75,
top_non_financial_supplier_share_pct: 75,
financial_institution_leads_outgoing_cash: false,
supplier_only_count: 71,
mixed_role_count: 23,
used_contracts: 148,
total_contracts: 520,
used_contract_share_pct: 28.46,
evidence_status: "reviewed_procurement_concentration",
inference_basis: "supplier_payout_concentration_counterparty_contract_profile_confirmed_1c_rows"
});
expect(result.derived_business_overview?.vendor_procurement_quality?.top_outgoing_counterparty).toMatchObject({
axis_value: "Поставщик А",
total_amount: 150000
});
expect(result.derived_business_overview?.missing_proof_families).toEqual(
expect.arrayContaining([
expect.objectContaining({
family: "accounting_profit_margin",
current_status: "reviewed_route_not_wired",
current_supported_evidence: null
})
])
);
expect(result.derived_business_overview?.missing_proof_families.map((item) => item.family)).not.toContain(
"vendor_risk_procurement_quality"
);
expect(result.evidence.confirmed_facts.join("\n")).toContain("В 1С подтверждены входящие поступления");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Самый крупный подтвержденный поставщик");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Годовая раскладка операционного денежного потока");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Профиль операционной активности");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Профиль контрагентской базы");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Договорной профиль");
expect(result.evidence.inferred_facts.join("\n")).toContain("procurement concentration proxy");
expect(result.evidence.inferred_facts.join("\n")).toContain("Самый сильный год по подтвержденным входящим поступлениям: 2021");
expect(result.evidence.unknown_facts).toContain(
"Прибыль и маржа этим бизнес-обзором не подтверждены: нужны себестоимость, расходы и закрывающие документы."
);
expect(result.reason_codes).toContain("pilot_derived_business_overview_from_confirmed_rows");
expect(result.reason_codes).toContain("pilot_derived_business_overview_top_suppliers_from_confirmed_rows");
expect(result.reason_codes).toContain("pilot_derived_business_overview_yearly_operating_breakdown_from_confirmed_rows");
expect(result.reason_codes).toContain("pilot_derived_business_overview_document_activity_profile_from_confirmed_rows");
expect(result.reason_codes).toContain("pilot_derived_business_overview_counterparty_profile_from_confirmed_rows");
expect(result.reason_codes).toContain("pilot_derived_business_overview_contract_usage_profile_from_confirmed_rows");
expect(result.reason_codes).toContain("pilot_derived_business_overview_vendor_procurement_quality_from_confirmed_rows");
expect(result.reason_codes).toContain("pilot_derived_business_overview_vendor_procurement_quality_reviewed_procurement_concentration");
expect(result.reason_codes).toContain("pilot_business_overview_missing_proof_families_recorded");
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(6);
});
it("recovers explicit-year business overview money coverage through monthly value-flow chunks", 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: "explicit_period",
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: "ООО Альтернатива Плюс",
explicit_date_scope: "2020"
}
});
const broadIncomingRows = Array.from({ length: 200 }, (_, index) => ({
Period: `2020-01-${String((index % 28) + 1).padStart(2, "0")}T00:00:00`,
Amount: 1,
Counterparty: "Клиент из широкого запроса"
}));
const broadOutgoingRows = Array.from({ length: 200 }, (_, index) => ({
Period: `2020-01-${String((index % 28) + 1).padStart(2, "0")}T00:00:00`,
Amount: 1,
Counterparty: "Поставщик из широкого запроса"
}));
const incomingMonthlyResults = Array.from({ length: 12 }, (_, index) => ({
rows: [
{
Period: `2020-${String(index + 1).padStart(2, "0")}-05T00:00:00`,
Amount: (index + 1) * 100,
Counterparty: index % 2 === 0 ? "Клиент А" : "Клиент Б"
}
]
}));
const outgoingMonthlyResults = Array.from({ length: 12 }, (_, index) => ({
rows: [
{
Period: `2020-${String(index + 1).padStart(2, "0")}-10T00:00:00`,
Amount: (index + 1) * 50,
Counterparty: index % 2 === 0 ? "Поставщик А" : "Поставщик Б"
}
]
}));
const deps = buildSequentialDeps([
{ rows: broadIncomingRows },
...incomingMonthlyResults,
{ rows: broadOutgoingRows },
...outgoingMonthlyResults
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(planner.discovery_plan.execution_budget.max_probe_count).toBe(30);
expect(result.derived_business_overview).toMatchObject({
organization_scope: "ООО Альтернатива Плюс",
period_scope: "2020",
incoming_customer_revenue: {
total_amount: 7800,
coverage_limited_by_probe_limit: false,
coverage_recovered_by_period_chunking: true,
period_chunking_granularity: "month"
},
outgoing_supplier_payout: {
total_amount: 3900,
coverage_limited_by_probe_limit: false,
coverage_recovered_by_period_chunking: true,
period_chunking_granularity: "month"
},
net_amount: 3900,
coverage_limited_by_probe_limit: false
});
expect(result.evidence.confirmed_facts).toContain(
"Денежное покрытие бизнес-обзора за год восстановлено через помесячные 1С-проверки, а не только через широкий общий запрос."
);
expect(result.evidence.unknown_facts).not.toContain(
"Полное покрытие бизнес-обзора не подтверждено: хотя бы один денежный запрос достиг верхней границы выборки."
);
expect(result.reason_codes).toContain("pilot_business_overview_incoming_monthly_period_chunking_recovered_coverage");
expect(result.reason_codes).toContain("pilot_business_overview_outgoing_monthly_period_chunking_recovered_coverage");
});
it("marks bank-like counterparties in business-overview rankings before evidence wording", 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 = buildSequentialDeps([
{
rows: [
{ Period: "2020-01-15T00:00:00", Amount: 1200000, Counterparty: "СБЕРБАНК, ПАО", ВидОперации: "Возврат от поставщика", Договор: "Депозитный договор" },
{ Period: "2020-02-15T00:00:00", Amount: 800000, Counterparty: "Группа СВК" }
]
},
{
rows: [
{ Period: "2020-01-20T00:00:00", Amount: 650000, Counterparty: "СБЕРБАНК, ПАО", ВидОперации: "ПрочееСписание", НазначениеПлатежа: "Комиссия банка за ведение счета" },
{ Period: "2020-03-20T00:00:00", Amount: 50000, Counterparty: "ООО Поставщик" }
]
},
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] }
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.derived_business_overview?.top_customers[0]).toMatchObject({
axis_value: "СБЕРБАНК, ПАО",
counterparty_role_hint: "bank_or_financial_institution",
financial_flow_hint: "loan_or_credit"
});
expect(result.derived_business_overview?.top_customers[1]).toMatchObject({
axis_value: "Группа СВК",
counterparty_role_hint: "ordinary_counterparty"
});
expect(result.derived_business_overview?.top_suppliers[0]).toMatchObject({
axis_value: "СБЕРБАНК, ПАО",
counterparty_role_hint: "bank_or_financial_institution",
financial_flow_hint: "bank_fee_or_service"
});
const confirmedFacts = result.evidence.confirmed_facts.join("\n");
const inferredFacts = result.evidence.inferred_facts.join("\n");
expect(confirmedFacts).toContain("Крупнейший входящий денежный источник");
expect(confirmedFacts).toContain("Крупнейший небанковский входящий контрагент");
expect(confirmedFacts).toContain("Крупнейший получатель исходящих денег");
expect(confirmedFacts).toContain("кредитный/заемный признак");
expect(confirmedFacts).toContain("банковской комиссии/услуг банка");
expect(confirmedFacts).not.toContain("Самый крупный подтвержденный клиент в проверенном срезе: СБЕРБАНК");
expect(confirmedFacts).not.toContain("Самый крупный подтвержденный поставщик/получатель исходящих платежей в проверенном срезе: СБЕРБАНК");
expect(inferredFacts).toContain("outgoing cash concentration proxy");
});
it("adds a checked VAT/tax family to business overview only when an explicit period is available", 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: "explicit_period",
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: "ООО Альтернатива Плюс",
explicit_date_scope: "2020"
}
});
const deps = buildSequentialDeps([
{
rows: [
{ Period: "2020-01-15T00:00:00", Amount: 120000, Counterparty: "Клиент А" }
]
},
{
rows: [
{ Period: "2020-01-20T00:00:00", Amount: 50000, Counterparty: "Поставщик А" }
]
},
{
rows: [
{ Регистратор: "VAT_BOOK_SALES", СчетДт: "68.02", Сумма: 40000 },
{ Регистратор: "VAT_BOOK_PURCHASES", СчетДт: "19", Сумма: 12000 }
]
},
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{
rows: [
{ Период: "2020-01-15T00:00:00", Регистратор: "Поступление 1" },
{ Период: "2020-12-15T00:00:00", Регистратор: "Поступление 2" }
]
},
{
rows: [
{ Period: "2020-03-01T00:00:00", Amount: 200000, Item: "Товар А", Counterparty: "Клиент А", AccountKt: "41.01" },
{ Period: "2020-02-01T00:00:00", Amount: 120000, Item: "Товар А", Counterparty: "Поставщик А", AccountDt: "41.01" }
]
}
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.derived_business_overview?.tax_position).toMatchObject({
period_scope: "2020",
rows_matched: 2,
rows_with_amount: 2,
sales_vat_amount: 40000,
purchase_vat_amount: 12000,
net_vat_amount: 28000,
net_vat_direction: "vat_to_pay"
});
expect(result.derived_business_overview?.trading_margin_proxy).toMatchObject({
period_scope: "2020",
sales_rows_with_amount: 1,
purchase_rows_with_amount: 1,
sales_revenue: 200000,
purchase_cost_proxy: 120000,
gross_spread_proxy: 80000,
margin_to_revenue_pct: 40
});
expect(result.derived_business_overview?.missing_signal_families).not.toContain("tax_position");
expect(result.derived_business_overview?.missing_signal_families).not.toContain("profit_margin");
expect(result.derived_business_overview?.missing_signal_families).toContain("accounting_profit_margin");
expect(result.derived_business_overview?.missing_proof_families).toEqual(
expect.arrayContaining([
expect.objectContaining({
family: "accounting_profit_margin",
current_status: "proxy_only_currently",
current_supported_evidence: "trading_margin_proxy_from_sales_and_purchase_document_rows"
})
])
);
expect(result.evidence.confirmed_facts.join("\n")).toContain("НДС-позиция за 2020 подтверждена");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Торговый margin proxy за 2020");
expect(result.evidence.unknown_facts.join("\n")).toContain("Чистая прибыль");
expect(result.evidence.unknown_facts.join("\n")).not.toContain("Налоговая/VAT-позиция этим бизнес-обзором не подтверждена");
expect(result.reason_codes).toContain("pilot_business_overview_tax_query_mcp_executed");
expect(result.reason_codes).toContain("pilot_derived_business_overview_tax_position_from_confirmed_rows");
expect(result.reason_codes).toContain("pilot_business_overview_trading_margin_query_mcp_executed");
expect(result.reason_codes).toContain("pilot_derived_business_overview_trading_margin_proxy_from_confirmed_rows");
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(14);
const taxCall = deps.executeAddressMcpQuery.mock.calls[2]?.[0];
const tradingMarginCall = deps.executeAddressMcpQuery.mock.calls[10]?.[0];
expect(String(taxCall?.query ?? "")).toContain("НДСЗаписиКнигиПродаж");
expect(String(taxCall?.query ?? "")).toContain("НДСЗаписиКнигиПокупок");
expect(String(tradingMarginCall?.query ?? "")).toContain("Документ.РеализацияТоваровУслуг.Товары");
expect(String(tradingMarginCall?.query ?? "")).toContain("Документ.ПоступлениеТоваровУслуг.Товары");
});
it("keeps negative trading-margin proxy signed instead of reporting an absolute spread", 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: "explicit_period",
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: "ООО Альтернатива Плюс",
explicit_date_scope: "2020"
}
});
const deps = buildSequentialDeps([
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{
rows: [
{ Period: "2020-03-01T00:00:00", Amount: 100000, Item: "Товар А", Counterparty: "Клиент А", AccountKt: "41.01" },
{ Period: "2020-02-01T00:00:00", Amount: 150000, Item: "Товар А", Counterparty: "Поставщик А", AccountDt: "41.01" }
]
}
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.derived_business_overview?.trading_margin_proxy).toMatchObject({
sales_revenue: 100000,
purchase_cost_proxy: 150000,
gross_spread_proxy: -50000,
gross_spread_proxy_human_ru: "-50 000 руб.",
margin_to_revenue_pct: -50
});
expect(result.evidence.confirmed_facts.join("\n")).toContain("валовый спред proxy -50 000 руб.");
expect(result.evidence.confirmed_facts.join("\n")).toContain("не чистая прибыль");
});
it("adds a checked debt-position family to business overview only as an as-of-date snapshot", 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: "explicit_period",
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: "ООО Альтернатива Плюс",
explicit_date_scope: "2020"
}
});
const deps = buildSequentialDeps([
{ rows: [{ Period: "2020-01-15T00:00:00", Amount: 120000, Counterparty: "Клиент А" }] },
{ rows: [{ Period: "2020-01-20T00:00:00", Amount: 50000, Counterparty: "Поставщик А" }] },
{ rows: [] },
{ rows: [] },
{
rows: [
{ Period: "2020-12-31T00:00:00", Amount: 70000, Counterparty: "Клиент А" },
{ Period: "2020-12-31T00:00:00", Amount: 30000, Counterparty: "Клиент Б" }
]
},
{
rows: [
{ Period: "2020-12-31T00:00:00", Amount: 40000, Counterparty: "Поставщик А" }
]
},
{
rows: [
{ Period: "2020-12-31T00:00:00", Amount: 90000, Counterparty: "Клиент А", Contract: "Договор А от 10.02.2019" },
{ Period: "2020-12-31T00:00:00", Amount: 30000, Counterparty: "Клиент Б", Contract: "Договор Б от 15.03.2020" }
]
},
{ rows: [] },
{ rows: [] },
{
rows: [
{ Period: "2020-01-15T00:00:00", Registrator: "Поступление 1" },
{ Period: "2020-12-15T00:00:00", Registrator: "Поступление 2" }
]
},
{ rows: [] }
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.derived_business_overview?.debt_position).toMatchObject({
as_of_date: "2020-12-31",
receivables: {
total_amount: 100000,
rows_with_amount: 2
},
payables: {
total_amount: 40000,
rows_with_amount: 1
},
net_debt_position_amount: 60000,
net_debt_position_direction: "net_receivable"
});
expect(result.derived_business_overview?.debt_position?.receivables.top_counterparties[0]).toMatchObject({
axis_value: "Клиент А",
total_amount: 70000
});
expect(result.derived_business_overview?.debt_open_settlement_quality).toMatchObject({
as_of_date: "2020-12-31",
rows_with_amount: 2,
gross_open_amount: 120000,
unique_counterparties: 2,
unique_contracts: 2,
concentration_top_contract_pct: 75
});
expect(result.derived_business_overview?.debt_open_settlement_quality?.age_signal).toMatchObject({
contracts_with_start_date: 2,
oldest_start_date: "2019-02-10",
latest_start_date: "2020-03-15",
max_age_days: 690
});
expect(result.derived_business_overview?.debt_staleness_risk_proxy).toMatchObject({
as_of_date: "2020-12-31",
oldest_contract_start_date: "2019-02-10",
max_contract_age_days: 690,
top_contract_amount: 90000,
top_contract_share_pct: 75,
risk_band: "high"
});
expect(result.derived_business_overview?.debt_open_settlement_quality?.age_signal?.top_aged_contracts[0]).toMatchObject({
contract: "Договор А от 10.02.2019",
start_date: "2019-02-10",
age_days: 690,
total_amount: 90000
});
expect(result.derived_business_overview?.missing_signal_families).not.toContain("debt_position");
expect(result.derived_business_overview?.missing_signal_families).not.toContain("debt_open_settlement_quality");
expect(result.derived_business_overview?.missing_signal_families).toContain("debt_due_date_aging_quality");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Долговая позиция на 2020-12-31");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Качество открытых расчетов на 2020-12-31");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Возрастной сигнал открытых расчетов");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Staleness risk proxy открытых расчетов");
expect(result.evidence.confirmed_facts.join("\n")).toContain("высокая зона внимания");
expect(result.evidence.confirmed_facts.join("\n")).toContain("не due-date анализ");
expect(result.evidence.unknown_facts.join("\n")).toContain("due-date");
expect(result.reason_codes).toContain("pilot_business_overview_debt_query_mcp_executed");
expect(result.reason_codes).toContain("pilot_derived_business_overview_debt_position_from_confirmed_rows");
expect(result.reason_codes).toContain("pilot_business_overview_open_contracts_query_mcp_executed");
expect(result.reason_codes).toContain("pilot_derived_business_overview_open_settlement_quality_from_confirmed_rows");
expect(result.reason_codes).toContain("pilot_derived_business_overview_debt_age_signal_from_contract_dates");
expect(result.reason_codes).toContain("pilot_derived_business_overview_debt_staleness_risk_proxy_from_confirmed_rows");
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(14);
const receivablesCall = deps.executeAddressMcpQuery.mock.calls[4]?.[0];
const payablesCall = deps.executeAddressMcpQuery.mock.calls[5]?.[0];
const openContractsCall = deps.executeAddressMcpQuery.mock.calls[6]?.[0];
expect(String(receivablesCall?.query ?? "")).toContain("62");
expect(String(payablesCall?.query ?? "")).toContain("60");
expect(String(openContractsCall?.query ?? "")).toContain("СуммаРазвернутыйОстатокКт");
});
it("checks debt due-date aging with contract payment terms before claiming overdue debt", async () => {
const planner = planAssistantMcpDiscovery({
dataNeedGraph: {
schema_version: "assistant_data_need_graph_v1",
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
subject_candidates: [],
business_fact_family: "business_overview",
action_family: "debt_due_date_boundary",
aggregation_need: null,
time_scope_need: "explicit_period",
comparison_need: null,
ranking_need: null,
proof_expectation: "due_date_aging",
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_overdue_claim"],
reason_codes: ["data_need_graph_built", "data_need_graph_family_business_overview"]
},
turnMeaning: {
asked_domain_family: "business_overview",
asked_action_family: "debt_due_date_boundary",
explicit_organization_scope: "ООО Альтернатива Плюс",
explicit_date_scope: "2020"
}
});
const deps = buildSequentialDeps([
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{
rows: [
{ Period: "2020-12-31T00:00:00", Amount: 100000, Counterparty: "Клиент А", Contract: "Договор А от 10.02.2019" }
]
},
{
rows: [
{
Period: "2020-12-31T00:00:00",
Amount: 100000,
Counterparty: "Клиент А",
Contract: "Договор А от 10.02.2019",
ДокументРасчетов: "Реализация товаров от 10.03.2020",
УстановленСрокОплаты: false,
СрокОплаты: 0
}
]
},
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] }
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.derived_business_overview?.debt_due_date_aging).toMatchObject({
as_of_date: "2020-12-31",
rows_with_amount: 1,
gross_open_amount: 100000,
rows_with_payment_terms: 0,
rows_without_payment_terms: 1,
overdue_rows: 0,
evidence_status: "no_payment_terms_configured"
});
expect(result.derived_business_overview?.missing_signal_families).not.toContain("debt_due_date_aging_quality");
expect(result.derived_business_overview?.missing_proof_families.map((item) => item.family)).not.toContain(
"debt_due_date_aging_quality"
);
expect(result.evidence.confirmed_facts.join("\n")).toContain("срок оплаты не установлен");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Подтвержденной просрочки");
expect(result.evidence.unknown_facts.join("\n")).not.toContain("due-date aging этим бизнес-обзором не подтверждены");
expect(result.reason_codes).toContain("pilot_business_overview_debt_due_date_aging_query_mcp_executed");
expect(result.reason_codes).toContain("pilot_derived_business_overview_debt_due_date_aging_from_confirmed_rows");
expect(result.reason_codes).toContain("pilot_derived_business_overview_debt_due_date_aging_no_payment_terms_configured");
const dueDateCall = deps.executeAddressMcpQuery.mock.calls[7]?.[0];
expect(String(dueDateCall?.query ?? "")).toContain("УстановленСрокОплаты");
expect(String(dueDateCall?.query ?? "")).toContain("СрокОплаты");
});
it("adds a checked inventory-position family to business overview only as an as-of-date snapshot", 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: "explicit_period",
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: "ООО Тест",
explicit_date_scope: "2020"
}
});
const deps = buildSequentialDeps([
{ rows: [{ Period: "2020-01-15T00:00:00", Amount: 120000, Counterparty: "Клиент А" }] },
{ rows: [{ Period: "2020-01-20T00:00:00", Amount: 50000, Counterparty: "Поставщик А" }] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{ rows: [] },
{
rows: [
{ Period: "2020-12-31T00:00:00", Amount: 250000, Quantity: 10, Item: "Товар А" },
{ Period: "2020-12-31T00:00:00", Amount: 50000, Quantity: 5, Item: "Товар Б" }
]
},
{
rows: [
{ Period: "2020-01-10T00:00:00", Amount: 200000, Quantity: 8, Item: "Товар А" },
{ Period: "2020-11-01T00:00:00", Amount: 50000, Quantity: 2, Item: "Товар Б" }
]
},
{
rows: [
{ Period: "2020-01-15T00:00:00", Registrator: "Поступление 1" },
{ Period: "2020-12-15T00:00:00", Registrator: "Поступление 2" }
]
},
{
rows: [
{ Period: "2020-03-01T00:00:00", Amount: 600000, Item: "Товар А", Counterparty: "Клиент А", AccountKt: "41.01" },
{ Period: "2020-02-01T00:00:00", Amount: 240000, Item: "Товар А", Counterparty: "Поставщик А", AccountDt: "41.01" }
]
}
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.derived_business_overview?.inventory_position).toMatchObject({
as_of_date: "2020-12-31",
rows_matched: 2,
rows_with_amount: 2,
rows_with_quantity: 2,
total_amount: 300000,
total_quantity: 15,
aging_signal: {
rows_matched: 2,
rows_with_purchase_date: 2,
oldest_purchase_date: "2020-01-10",
latest_purchase_date: "2020-11-01",
max_age_days: 356
}
});
expect(result.derived_business_overview?.inventory_position?.top_items[0]).toMatchObject({
item: "Товар А",
total_amount: 250000,
total_quantity: 10
});
expect(result.derived_business_overview?.inventory_turnover_proxy).toMatchObject({
period_scope: "2020",
as_of_date: "2020-12-31",
sales_revenue: 600000,
inventory_amount: 300000,
sales_to_stock_amount_ratio: 2,
stock_to_sales_revenue_pct: 50
});
expect(result.derived_business_overview?.inventory_staleness_risk_proxy).toMatchObject({
period_scope: "2020",
as_of_date: "2020-12-31",
oldest_purchase_date: "2020-01-10",
max_purchase_age_days: 356,
sales_to_stock_amount_ratio: 2,
risk_band: "watch"
});
expect(result.derived_business_overview?.missing_signal_families).not.toContain("inventory_position");
expect(result.derived_business_overview?.missing_signal_families).not.toContain("inventory_turnover_quality");
expect(result.derived_business_overview?.missing_signal_families).not.toContain("inventory_liquidity_quality");
expect(result.derived_business_overview?.missing_signal_families).toContain("inventory_reserve_liquidation_quality");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Складской срез на 2020-12-31");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Оборотный proxy склада за 2020");
expect(result.evidence.confirmed_facts.join("\n")).toContain("sales-to-stock ratio 2x");
expect(result.evidence.confirmed_facts.join("\n")).toContain("Staleness risk proxy склада");
expect(result.evidence.confirmed_facts.join("\n")).toContain("зона наблюдения");
expect(result.evidence.unknown_facts.join("\n")).toContain("Резервы");
expect(result.reason_codes).toContain("pilot_business_overview_inventory_query_mcp_executed");
expect(result.reason_codes).toContain("pilot_derived_business_overview_inventory_position_from_confirmed_rows");
expect(result.reason_codes).toContain("pilot_derived_business_overview_inventory_turnover_proxy_from_confirmed_rows");
expect(result.reason_codes).toContain("pilot_derived_business_overview_inventory_staleness_risk_proxy_from_confirmed_rows");
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(14);
const inventoryCall = deps.executeAddressMcpQuery.mock.calls[7]?.[0];
expect(inventoryCall?.account_scope).toContain("41.01");
});
it("uses the explicit selected chain id when choosing the movement pilot scope", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "movements",
asked_action_family: "list_movements",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "movement_evidence"
}
});
const deps = buildDeps([{ Period: "2020-01-15T00:00:00", Amount: 1250, Counterparty: "SVK", Registrar: "Move1" }]);
const result = await executeAssistantMcpDiscoveryPilot(
{
...planner,
reason_codes: planner.reason_codes.filter((code) => !code.startsWith("planner_selected_"))
},
deps
);
expect(result.pilot_status).toBe("executed");
expect(result.pilot_scope).toBe("counterparty_movement_evidence_query_movements_v1");
expect(result.executed_primitives).toEqual(["query_movements"]);
});
it("executes generic document evidence through query_documents", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "documents",
asked_action_family: "list_documents",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "document_evidence"
}
});
const deps = buildDeps([
{ Period: "2020-01-15T00:00:00", Counterparty: "SVK", Registrar: "Doc1" },
{ Period: "2020-03-20T00:00:00", Counterparty: "SVK", Registrar: "Doc2" }
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.pilot_scope).toBe("counterparty_document_evidence_query_documents_v1");
expect(result.executed_primitives).toEqual(["query_documents"]);
expect(result.evidence.confirmed_facts).toContain("В 1С найдены строки документов по контрагенту SVK за 2020.");
expect(result.evidence.inferred_facts).toContain(
"Срез документов по контрагенту SVK за 2020 ограничен только подтвержденными строками документов, найденными этим поиском."
);
expect(result.evidence.unknown_facts).toContain(
"Полный исторический срез документов по контрагенту SVK вне периода 2020 этим поиском не подтвержден."
);
expect(result.source_rows_summary).toBe("2 MCP document rows fetched, 2 matched document scope");
});
it("executes generic movement evidence through query_movements without deriving turnover totals", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "movements",
asked_action_family: "list_movements",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "movement_evidence"
}
});
const deps = buildDeps([
{ Period: "2020-01-15T00:00:00", Amount: 1250, Counterparty: "SVK", Registrar: "Move1" },
{ Period: "2020-03-20T00:00:00", Amount: "900,25", Counterparty: "SVK", Registrar: "Move2" }
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.pilot_scope).toBe("counterparty_movement_evidence_query_movements_v1");
expect(result.executed_primitives).toEqual(["query_movements"]);
expect(result.derived_value_flow).toBeNull();
expect(result.derived_bidirectional_value_flow).toBeNull();
expect(result.evidence.confirmed_facts).toContain("В 1С найдены строки движений по контрагенту SVK за 2020.");
expect(result.evidence.inferred_facts).toContain(
"Срез движений по контрагенту SVK за 2020 ограничен только подтвержденными строками движений, найденными этим поиском."
);
expect(result.evidence.unknown_facts).toContain(
"Полный исторический срез движений по контрагенту SVK вне периода 2020 этим поиском не подтвержден."
);
expect(result.source_rows_summary).toBe("2 MCP movement rows fetched, 2 matched movement scope");
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(1);
const call = deps.executeAddressMcpQuery.mock.calls[0]?.[0];
expect(String(call?.query ?? "")).toContain("Документ.СписаниеСРасчетногоСчета");
expect(String(call?.query ?? "")).toContain("Документ.ПоступлениеНаРасчетныйСчет");
expect(call?.limit).toBeGreaterThan(0);
});
it("executes inspect_1c_metadata and derives a confirmed metadata surface", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "metadata",
asked_action_family: "inspect_documents",
explicit_entity_candidates: ["НДС"]
}
});
const deps = buildMetadataDeps([
{
FullName: "Документ.СчетФактураВыданный",
MetaType: "Документ",
attributes: [{ Name: "Дата" }, { Name: "Организация" }]
},
{
FullName: "Документ.СчетФактураПолученный",
MetaType: "Документ",
attributes: [{ Name: "Контрагент" }]
}
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.pilot_scope).toBe("metadata_inspection_v1");
expect(result.mcp_execution_performed).toBe(true);
expect(result.executed_primitives).toEqual(["inspect_1c_metadata"]);
expect(result.evidence.evidence_status).toBe("confirmed");
expect(result.source_rows_summary).toBe("2 MCP metadata rows fetched");
expect(result.derived_metadata_surface).toMatchObject({
metadata_scope: "НДС",
requested_meta_types: ["Документ"],
matched_rows: 2,
available_entity_sets: ["Документ"],
matched_objects: ["Документ.СчетФактураВыданный", "Документ.СчетФактураПолученный"],
selected_entity_set: "Документ",
selected_surface_objects: ["Документ.СчетФактураВыданный", "Документ.СчетФактураПолученный"],
downstream_route_family: "document_evidence",
recommended_next_primitive: "query_documents",
ambiguity_detected: false,
ambiguity_entity_sets: [],
available_fields: ["Дата", "Организация", "Контрагент"],
inference_basis: "confirmed_1c_metadata_surface_rows"
});
expect(result.reason_codes).toContain("pilot_inspect_1c_metadata_mcp_executed");
expect(result.reason_codes).toContain("pilot_derived_metadata_surface_from_confirmed_rows");
expect(deps.executeAddressMcpMetadata).toHaveBeenCalledTimes(1);
expect(deps.executeAddressMcpMetadata.mock.calls[0]?.[0]).toMatchObject({
meta_type: ["Документ"],
name_mask: "НДС"
});
});
it("executes catalog drilldown through a narrowed metadata probe seeded from the confirmed surface object", async () => {
const planner = planAssistantMcpDiscovery({
metadataSurface: {
selected_entity_set: "Catalog",
selected_surface_objects: ["Catalog.Counterparties"],
downstream_route_family: "catalog_drilldown",
route_family_selection_basis: "selected_entity_set",
recommended_next_primitive: "drilldown_related_objects",
ambiguity_detected: false,
ambiguity_entity_sets: []
},
turnMeaning: {
asked_domain_family: "metadata",
asked_action_family: "inspect_catalog",
unsupported_but_understood_family: "schema_surface"
}
});
const deps = buildMetadataDeps([
{
FullName: "Catalog.Counterparties",
MetaType: "Catalog",
attributes: [{ Name: "Description" }]
},
{
FullName: "Catalog.Contracts",
MetaType: "Catalog",
attributes: [{ Name: "Owner" }]
}
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.pilot_scope).toBe("metadata_inspection_v1");
expect(result.executed_primitives).toEqual(["inspect_1c_metadata"]);
expect(result.derived_metadata_surface).toMatchObject({
metadata_scope: "Counterparties",
requested_meta_types: ["Catalog"],
available_entity_sets: ["Catalog"],
selected_entity_set: "Catalog",
downstream_route_family: "catalog_drilldown",
recommended_next_primitive: "drilldown_related_objects"
});
expect(result.reason_codes).toContain("pilot_catalog_drilldown_metadata_scope_seeded_from_surface_ref");
expect(deps.executeAddressMcpMetadata).toHaveBeenCalledTimes(1);
expect(deps.executeAddressMcpMetadata.mock.calls[0]?.[0]).toMatchObject({
meta_type: ["Catalog"],
name_mask: "Counterparties"
});
});
it("executes the full entity-resolution chain through the checked counterparty catalog slice", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "entity_resolution",
asked_action_family: "search_business_entity",
explicit_entity_candidates: ["Группа СВК"],
unsupported_but_understood_family: "entity_resolution"
}
});
const deps = buildDeps([
{ Counterparty: "Группа СВК", CounterpartyRef: "Ref-1" },
{ Counterparty: "СВК Логистика", CounterpartyRef: "Ref-2" }
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.pilot_scope).toBe("entity_resolution_search_v1");
expect(result.mcp_execution_performed).toBe(true);
expect(result.executed_primitives).toEqual([
"search_business_entity",
"resolve_entity_reference",
"probe_coverage"
]);
expect(result.skipped_primitives).toEqual([]);
expect(result.derived_entity_resolution).toMatchObject({
requested_entity: "Группа СВК",
resolution_status: "resolved",
resolved_entity: "Группа СВК",
resolved_reference: "Ref-1",
confidence: "high",
inference_basis: "catalog_counterparty_search_rows"
});
expect(result.evidence.confirmed_facts).toContain(
"В проверенном каталожном срезе 1С найден контрагент: Группа СВК"
);
expect(result.evidence.inferred_facts).toContain(
"Пока проверено только заземление сущности по каталогу 1С; документы, движения и денежные показатели еще не проверялись"
);
expect(result.evidence.unknown_facts).toContain(
"Документы, движения и денежные показатели по этому контрагенту еще не проверялись; пока был только каталожный поиск"
);
expect(result.reason_codes).toContain("pilot_search_business_entity_mcp_executed");
expect(result.reason_codes).toContain("pilot_resolve_entity_reference_from_catalog_rows");
expect(result.reason_codes).toContain("pilot_probe_coverage_executed_for_entity_resolution");
expect(result.reason_codes).toContain("pilot_entity_resolution_grounding_stable_for_downstream_probe");
expect(result.reason_codes).toContain("pilot_derived_entity_resolution_from_catalog_rows");
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(1);
});
it("keeps entity-resolution honest when several catalog candidates remain ambiguous", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "entity_resolution",
asked_action_family: "search_business_entity",
explicit_entity_candidates: ["СВК"],
unsupported_but_understood_family: "entity_resolution"
}
});
const deps = buildDeps([
{ Counterparty: "СВК-А", CounterpartyRef: "Ref-1" },
{ Counterparty: "СВК-Б", CounterpartyRef: "Ref-2" }
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.pilot_scope).toBe("entity_resolution_search_v1");
expect(result.executed_primitives).toEqual([
"search_business_entity",
"resolve_entity_reference",
"probe_coverage"
]);
expect(result.skipped_primitives).toEqual([]);
expect(result.derived_entity_resolution).toMatchObject({
requested_entity: "СВК",
resolution_status: "ambiguous",
resolved_entity: null,
ambiguity_candidates: ["СВК-А", "СВК-Б"],
confidence: "low"
});
expect(result.evidence.confirmed_facts).toEqual([]);
expect(result.evidence.unknown_facts).toContain(
"Точное заземление контрагента в 1С остается неоднозначным между вариантами: СВК-А, СВК-Б"
);
expect(result.reason_codes).toContain("pilot_resolve_entity_reference_requires_clarification");
expect(result.reason_codes).toContain("pilot_probe_coverage_executed_for_entity_resolution");
expect(result.reason_codes).toContain("pilot_entity_resolution_ambiguity_requires_clarification");
});
it("keeps metadata grounding ambiguous when several surface families compete", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "metadata",
asked_action_family: "inspect_fields",
explicit_entity_candidates: ["НДС"]
}
});
const deps = buildMetadataDeps([
{
FullName: "Документ.СчетФактураВыданный",
MetaType: "Документ",
attributes: [{ Name: "Дата" }]
},
{
FullName: "РегистрНакопления.НДСПокупок",
MetaType: "РегистрНакопления",
resources: [{ Name: "СуммаНДС" }]
}
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.derived_metadata_surface).toMatchObject({
metadata_scope: "НДС",
available_entity_sets: ["Документ", "РегистрНакопления"],
selected_entity_set: null,
downstream_route_family: null,
recommended_next_primitive: null,
ambiguity_detected: true,
ambiguity_entity_sets: ["Документ", "РегистрНакопления"]
});
expect(result.evidence.inferred_facts).toEqual([]);
expect(result.evidence.unknown_facts).toContain(
"Exact downstream metadata surface remains ambiguous across: Документ, РегистрНакопления"
);
});
it("selects a downstream lane from dominant metadata surface objects when one family clearly prevails", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "metadata",
asked_action_family: "inspect_surface",
explicit_entity_candidates: ["НДС"]
}
});
const deps = buildMetadataDeps([
{
FullName: "Документ.СчетФактураВыданный",
MetaType: "Документ",
attributes: [{ Name: "Дата" }]
},
{
FullName: "Документ.СчетФактураПолученный",
MetaType: "Документ",
attributes: [{ Name: "Контрагент" }]
},
{
FullName: "РегистрНакопления.НДСПокупок",
MetaType: "РегистрНакопления",
resources: [{ Name: "СуммаНДС" }]
}
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.derived_metadata_surface).toMatchObject({
metadata_scope: "НДС",
available_entity_sets: ["Документ", "РегистрНакопления"],
selected_entity_set: null,
selected_surface_objects: [
"Документ.СчетФактураВыданный",
"Документ.СчетФактураПолученный"
],
surface_family_scores: {
document_evidence: 2,
movement_evidence: 1,
catalog_drilldown: 0
},
downstream_route_family: "document_evidence",
route_family_selection_basis: "dominant_surface_objects",
recommended_next_primitive: "query_documents",
ambiguity_detected: false,
ambiguity_entity_sets: []
});
expect(result.reason_codes).toContain("pilot_selected_metadata_route_family_from_dominant_surface_objects");
expect(result.evidence.inferred_facts).toContain(
"A likely next checked lane may be inferred as document_evidence from the confirmed metadata surface"
);
expect(result.evidence.unknown_facts).not.toContain(
"Exact downstream metadata surface remains ambiguous across: Документ, РегистрНакопления"
);
});
it("can break a weak metadata family tie by ranking surface objects against the requested scope", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "metadata",
asked_action_family: "inspect_surface",
explicit_entity_candidates: ["НДС"]
}
});
const deps = buildMetadataDeps([
{
FullName: "Document.НДССчетФактура",
MetaType: "Document",
attributes: [{ Name: "Дата" }]
},
{
FullName: "AccumulationRegister.BankOperations",
MetaType: "AccumulationRegister",
resources: [{ Name: "Amount" }]
}
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.derived_metadata_surface).toMatchObject({
metadata_scope: "НДС",
available_entity_sets: ["Document", "AccumulationRegister"],
selected_entity_set: null,
selected_surface_objects: ["Document.НДССчетФактура"],
surface_family_scores: {
document_evidence: 1,
movement_evidence: 1,
catalog_drilldown: 0
},
downstream_route_family: "document_evidence",
route_family_selection_basis: "dominant_surface_objects",
recommended_next_primitive: "query_documents",
ambiguity_detected: false,
ambiguity_entity_sets: [],
surface_object_ranking_applied: true
});
expect(result.reason_codes).toContain("pilot_selected_metadata_route_family_from_surface_object_ranking");
});
it("keeps metadata ambiguity unresolved when surface-family scores are nearly tied", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "metadata",
asked_action_family: "inspect_surface",
explicit_entity_candidates: ["НДС"]
}
});
const deps = buildMetadataDeps([
{ FullName: "Документ.A", MetaType: "Документ" },
{ FullName: "Документ.B", MetaType: "Документ" },
{ FullName: "Документ.C", MetaType: "Документ" },
{ FullName: "Документ.D", MetaType: "Документ" },
{ FullName: "РегистрНакопления.A", MetaType: "РегистрНакопления" },
{ FullName: "РегистрНакопления.B", MetaType: "РегистрНакопления" },
{ FullName: "РегистрНакопления.C", MetaType: "РегистрНакопления" }
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.derived_metadata_surface).toMatchObject({
metadata_scope: "НДС",
selected_entity_set: null,
surface_family_scores: {
document_evidence: 4,
movement_evidence: 3,
catalog_drilldown: 0
},
downstream_route_family: null,
route_family_selection_basis: null,
recommended_next_primitive: null,
ambiguity_detected: true
});
expect(result.derived_metadata_surface?.ambiguity_entity_sets).toContain("Документ");
expect(result.derived_metadata_surface?.ambiguity_entity_sets).toContain("РегистрНакопления");
expect(result.reason_codes).not.toContain("pilot_selected_metadata_route_family_from_dominant_surface_objects");
expect(result.evidence.unknown_facts).toContain(
"Exact downstream metadata surface remains ambiguous across: Документ, РегистрНакопления"
);
});
it("infers metadata entity-set families from object names when meta type columns are absent", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "metadata",
asked_action_family: "inspect_surface",
explicit_entity_candidates: ["НДС"]
}
});
const deps = buildMetadataDeps([
{
FullName: "Документ.СчетФактураВыданный",
attributes: [{ Name: "Дата" }]
},
{
FullName: "РегистрНакопления.НДСПокупок",
resources: [{ Name: "СуммаНДС" }]
},
{
FullName: "Справочник.КодыОперацийНДС"
}
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.derived_metadata_surface).toMatchObject({
metadata_scope: "НДС",
available_entity_sets: ["Документ", "РегистрНакопления", "Справочник"],
selected_entity_set: null,
downstream_route_family: null,
recommended_next_primitive: null,
ambiguity_detected: true,
ambiguity_entity_sets: ["Документ", "РегистрНакопления", "Справочник"]
});
expect(result.evidence.unknown_facts).toContain(
"Exact downstream metadata surface remains ambiguous across: Документ, РегистрНакопления, Справочник"
);
});
it("executes value-flow query_movements and derives a guarded turnover sum", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_value",
asked_action_family: "turnover",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020"
}
});
const deps = buildDeps([
{ Period: "2020-01-15T00:00:00", Amount: 1250, Counterparty: "SVK" },
{ Period: "2020-02-20T00:00:00", Amount: "2 500,50", Counterparty: "SVK" }
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.pilot_scope).toBe("counterparty_value_flow_query_movements_v1");
expect(result.mcp_execution_performed).toBe(true);
expect(result.executed_primitives).toEqual(["query_movements"]);
expect(result.skipped_primitives).toEqual(["resolve_entity_reference", "aggregate_by_axis", "probe_coverage"]);
expect(result.evidence.evidence_status).toBe("confirmed");
expect(result.evidence.confirmed_facts[0]).toContain("value-flow rows");
expect(result.source_rows_summary).toBe("2 MCP value-flow rows fetched, 2 matched value-flow scope");
expect(result.derived_value_flow).toMatchObject({
counterparty: "SVK",
period_scope: "2020",
rows_matched: 2,
rows_with_amount: 2,
total_amount: 3750.5,
coverage_limited_by_probe_limit: false,
first_movement_date: "2020-01-15",
latest_movement_date: "2020-02-20",
inference_basis: "sum_of_confirmed_1c_value_flow_rows"
});
expect(result.reason_codes).toContain("pilot_query_movements_mcp_executed");
expect(result.reason_codes).toContain("pilot_derived_value_flow_from_confirmed_rows");
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(1);
const call = deps.executeAddressMcpQuery.mock.calls[0]?.[0];
expect(String(call?.query ?? "")).toContain("ПоступлениеНаРасчетныйСчет");
expect(call?.limit).toBeGreaterThan(0);
});
it("executes supplier payout query_movements and derives a guarded outgoing payment sum", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_value",
asked_action_family: "payout",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "counterparty_payouts_or_outflow"
}
});
const deps = buildDeps([
{ Period: "2020-03-15T00:00:00", Amount: 4100, Counterparty: "SVK" },
{ Period: "2020-04-20T00:00:00", Amount: "900,25", Counterparty: "SVK" }
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.pilot_scope).toBe("counterparty_supplier_payout_query_movements_v1");
expect(result.derived_value_flow).toMatchObject({
value_flow_direction: "outgoing_supplier_payout",
counterparty: "SVK",
period_scope: "2020",
rows_matched: 2,
rows_with_amount: 2,
total_amount: 5000.25,
coverage_limited_by_probe_limit: false,
first_movement_date: "2020-03-15",
latest_movement_date: "2020-04-20"
});
expect(result.evidence.confirmed_facts[0]).toContain("supplier-payout rows");
expect(result.evidence.inferred_facts[0]).toContain("supplier-payout total");
expect(result.evidence.unknown_facts).toContain("Full supplier-payout amount outside the checked period is not proven by this MCP discovery pilot");
expect(result.reason_codes).toContain("pilot_supplier_payout_recipe_selected");
const call = deps.executeAddressMcpQuery.mock.calls[0]?.[0];
expect(String(call?.query ?? "")).toContain("СписаниеСРасчетногоСчета");
});
it("marks value-flow coverage as limited when the probe row limit is reached", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_value",
asked_action_family: "payout",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "counterparty_payouts_or_outflow"
}
});
const rows = Array.from({ length: 200 }, (_, index) => ({
Period: `2020-01-${String((index % 28) + 1).padStart(2, "0")}T00:00:00`,
Amount: 10,
Counterparty: "SVK"
}));
const result = await executeAssistantMcpDiscoveryPilot(planner, buildDeps(rows));
expect(result.derived_value_flow?.coverage_limited_by_probe_limit).toBe(true);
expect(result.evidence.unknown_facts).toContain(
"Complete requested-period coverage is not proven by the available checked rows"
);
});
it("recovers yearly value-flow coverage by splitting a limited broad probe into monthly subprobes", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_value",
asked_action_family: "payout",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "counterparty_payouts_or_outflow"
}
});
const broadRows = Array.from({ length: 200 }, (_, index) => ({
Period: `2020-01-${String((index % 28) + 1).padStart(2, "0")}T00:00:00`,
Amount: 10,
Counterparty: "SVK"
}));
const monthlyResults = Array.from({ length: 12 }, (_, index) => ({
rows: [
{
Period: `2020-${String(index + 1).padStart(2, "0")}-05T00:00:00`,
Amount: (index + 1) * 100,
Counterparty: "SVK"
}
]
}));
const result = await executeAssistantMcpDiscoveryPilot(
planner,
buildSequentialDeps([{ rows: broadRows }, ...monthlyResults])
);
expect(result.derived_value_flow).toMatchObject({
value_flow_direction: "outgoing_supplier_payout",
coverage_limited_by_probe_limit: false,
coverage_recovered_by_period_chunking: true,
period_chunking_granularity: "month",
rows_matched: 12,
rows_with_amount: 12,
total_amount: 7800,
first_movement_date: "2020-01-05",
latest_movement_date: "2020-12-05"
});
expect(result.evidence.inferred_facts).toContain(
"Requested period coverage was recovered through monthly 1C value-flow probes"
);
expect(result.evidence.unknown_facts).not.toContain(
"Complete requested-period coverage is not proven by the available checked rows"
);
expect(result.reason_codes).toContain("pilot_monthly_period_chunking_recovered_coverage");
});
it("executes bidirectional value-flow queries and derives guarded net cash flow", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_value",
asked_action_family: "net_value_flow",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "counterparty_bidirectional_value_flow_or_netting"
}
});
const deps = buildSequentialDeps([
{
rows: [
{ Period: "2020-01-15T00:00:00", Amount: 10000, Counterparty: "SVK" },
{ Period: "2020-02-20T00:00:00", Amount: "2 500,50", Counterparty: "SVK" }
]
},
{
rows: [{ Period: "2020-03-10T00:00:00", Amount: 4000, Counterparty: "SVK" }]
}
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.pilot_scope).toBe("counterparty_bidirectional_value_flow_query_movements_v1");
expect(result.mcp_execution_performed).toBe(true);
expect(result.executed_primitives).toEqual(["query_movements"]);
expect(result.derived_value_flow).toBeNull();
expect(result.derived_bidirectional_value_flow).toMatchObject({
counterparty: "SVK",
period_scope: "2020",
net_amount: 8500.5,
net_amount_human_ru: "8 500,50 руб.",
net_direction: "net_incoming",
coverage_limited_by_probe_limit: false,
incoming_customer_revenue: {
rows_matched: 2,
rows_with_amount: 2,
total_amount: 12500.5,
first_movement_date: "2020-01-15",
latest_movement_date: "2020-02-20"
},
outgoing_supplier_payout: {
rows_matched: 1,
rows_with_amount: 1,
total_amount: 4000,
first_movement_date: "2020-03-10",
latest_movement_date: "2020-03-10"
}
});
expect(result.evidence.confirmed_facts[0]).toContain("bidirectional value-flow rows");
expect(result.evidence.inferred_facts[0]).toContain("net value-flow");
expect(result.evidence.unknown_facts).toContain(
"Full bidirectional value-flow outside the checked period is not proven by this MCP discovery pilot"
);
expect(result.reason_codes).toContain("pilot_bidirectional_value_flow_recipes_selected");
expect(result.reason_codes).toContain("pilot_derived_bidirectional_value_flow_from_confirmed_rows");
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(2);
});
it("preserves explicit date ranges when building bidirectional value-flow probes", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_value",
asked_action_family: "net_value_flow",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020-01-01..2020-12-31",
unsupported_but_understood_family: "counterparty_bidirectional_value_flow_or_netting"
}
});
const deps = buildSequentialDeps([
{
rows: [{ Period: "2020-01-15T00:00:00", Amount: 10000, Counterparty: "SVK" }]
},
{
rows: [{ Period: "2020-03-10T00:00:00", Amount: 4000, Counterparty: "SVK" }]
}
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.derived_bidirectional_value_flow?.period_scope).toBe("2020-01-01..2020-12-31");
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(2);
for (const call of deps.executeAddressMcpQuery.mock.calls) {
const query = String(call[0]?.query ?? "");
expect(query).toContain("2020, 1, 1");
expect(query).toContain("2020, 12, 31");
}
});
it("derives monthly bidirectional value-flow breakdown when the turn explicitly asks by month", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_value",
asked_action_family: "net_value_flow",
asked_aggregation_axis: "month",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "counterparty_bidirectional_value_flow_or_netting"
}
});
const deps = buildSequentialDeps([
{
rows: [
{ Period: "2020-01-15T00:00:00", Amount: 10000, Counterparty: "SVK" },
{ Period: "2020-02-20T00:00:00", Amount: "2 500,50", Counterparty: "SVK" }
]
},
{
rows: [
{ Period: "2020-01-10T00:00:00", Amount: 4000, Counterparty: "SVK" },
{ Period: "2020-02-11T00:00:00", Amount: 1000, Counterparty: "SVK" }
]
}
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.derived_bidirectional_value_flow?.aggregation_axis).toBe("month");
expect(result.derived_bidirectional_value_flow?.monthly_breakdown).toMatchObject([
{
month_bucket: "2020-01",
incoming_total_amount: 10000,
incoming_rows_with_amount: 1,
outgoing_total_amount: 4000,
outgoing_rows_with_amount: 1,
net_amount: 6000,
net_direction: "net_incoming"
},
{
month_bucket: "2020-02",
incoming_total_amount: 2500.5,
incoming_rows_with_amount: 1,
outgoing_total_amount: 1000,
outgoing_rows_with_amount: 1,
net_amount: 1500.5,
net_direction: "net_incoming"
}
]);
expect(result.derived_bidirectional_value_flow?.monthly_breakdown[0]?.incoming_total_amount_human_ru).toContain("10 000");
expect(result.derived_bidirectional_value_flow?.monthly_breakdown[0]?.net_amount_human_ru).toContain("6 000");
expect(result.derived_bidirectional_value_flow?.monthly_breakdown[1]?.incoming_total_amount_human_ru).toContain("2 500,50");
expect(result.derived_bidirectional_value_flow?.monthly_breakdown[1]?.net_amount_human_ru).toContain("1 500,50");
expect(result.evidence.inferred_facts).toContain(
"Counterparty monthly net value-flow breakdown was grouped by month over confirmed incoming and outgoing 1C rows"
);
expect(result.reason_codes).toContain("pilot_derived_bidirectional_monthly_breakdown_from_confirmed_rows");
});
it("recovers bidirectional yearly coverage when one side is rebuilt from monthly subprobes", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_value",
asked_action_family: "net_value_flow",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "counterparty_bidirectional_value_flow_or_netting"
}
});
const outgoingBroadRows = Array.from({ length: 200 }, (_, index) => ({
Period: `2020-01-${String((index % 28) + 1).padStart(2, "0")}T00:00:00`,
Amount: 10,
Counterparty: "SVK"
}));
const outgoingMonthlyResults = Array.from({ length: 12 }, (_, index) => ({
rows: [
{
Period: `2020-${String(index + 1).padStart(2, "0")}-10T00:00:00`,
Amount: (index + 1) * 50,
Counterparty: "SVK"
}
]
}));
const deps = buildSequentialDeps([
{
rows: [
{ Period: "2020-01-15T00:00:00", Amount: 10000, Counterparty: "SVK" },
{ Period: "2020-02-20T00:00:00", Amount: 10000, Counterparty: "SVK" }
]
},
{ rows: outgoingBroadRows },
...outgoingMonthlyResults
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.derived_bidirectional_value_flow).toMatchObject({
coverage_limited_by_probe_limit: false,
coverage_recovered_by_period_chunking: true,
period_chunking_granularity: "month",
net_amount: 16100,
incoming_customer_revenue: {
total_amount: 20000,
coverage_limited_by_probe_limit: false
},
outgoing_supplier_payout: {
total_amount: 3900,
coverage_limited_by_probe_limit: false,
coverage_recovered_by_period_chunking: true,
period_chunking_granularity: "month"
}
});
expect(result.evidence.inferred_facts).toContain(
"Requested period coverage for bidirectional value-flow was recovered through monthly 1C side probes"
);
expect(result.evidence.unknown_facts).not.toContain(
"Complete requested-period coverage for bidirectional value-flow is not proven by the available checked rows"
);
expect(result.reason_codes).toContain("pilot_bidirectional_outgoing_monthly_period_chunking_recovered_coverage");
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(14);
});
it("executes document-ready plans through the dedicated document pilot", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_documents",
asked_action_family: "list_documents",
explicit_entity_candidates: ["SVK"]
}
});
const deps = buildDeps([]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.pilot_scope).toBe("counterparty_document_evidence_query_documents_v1");
expect(result.mcp_execution_performed).toBe(true);
expect(result.executed_primitives).toEqual(["query_documents"]);
expect(result.reason_codes).toContain("pilot_query_documents_mcp_executed");
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(1);
});
it("keeps document and movement evidence scoped to the resolved entity and checked period", async () => {
const documentPlanner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "documents",
asked_action_family: "list_documents",
explicit_entity_candidates: ["Группа СВК"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "document_evidence"
}
});
const documentResult = await executeAssistantMcpDiscoveryPilot(
documentPlanner,
buildDeps([{ Period: "2020-01-15T00:00:00", Counterparty: "Группа СВК", Registrar: "Doc1" }])
);
expect(documentResult.evidence.confirmed_facts).toContain(
"В 1С найдены строки документов по контрагенту Группа СВК за 2020."
);
expect(documentResult.evidence.inferred_facts).toContain(
"Срез документов по контрагенту Группа СВК за 2020 ограничен только подтвержденными строками документов, найденными этим поиском."
);
expect(documentResult.evidence.unknown_facts).toContain(
"Полный исторический срез документов по контрагенту Группа СВК вне периода 2020 этим поиском не подтвержден."
);
const movementPlanner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "movements",
asked_action_family: "list_movements",
explicit_entity_candidates: ["Группа СВК"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "movement_evidence"
}
});
const movementResult = await executeAssistantMcpDiscoveryPilot(
movementPlanner,
buildDeps([{ Period: "2020-01-15T00:00:00", Counterparty: "Группа СВК", Registrar: "Move1" }])
);
expect(movementResult.evidence.confirmed_facts).toContain(
"В 1С найдены строки движений по контрагенту Группа СВК за 2020."
);
expect(movementResult.evidence.inferred_facts).toContain(
"Срез движений по контрагенту Группа СВК за 2020 ограничен только подтвержденными строками движений, найденными этим поиском."
);
expect(movementResult.evidence.unknown_facts).toContain(
"Полный исторический срез движений по контрагенту Группа СВК вне периода 2020 этим поиском не подтвержден."
);
});
it("records MCP errors as limitations without converting them into facts", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_lifecycle",
asked_action_family: "activity_duration",
explicit_entity_candidates: ["SVK"]
}
});
const deps = buildDeps([], "MCP fetch failed: timeout");
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.mcp_execution_performed).toBe(true);
expect(result.evidence.evidence_status).toBe("insufficient");
expect(result.evidence.confirmed_facts).toEqual([]);
expect(result.derived_activity_period).toBeNull();
expect(result.query_limitations).toContain("MCP fetch failed: timeout");
expect(result.reason_codes).toContain("pilot_query_documents_mcp_error");
});
it("emits Russian confirmed and bounded facts for resolved entity grounding", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "entity_resolution",
asked_action_family: "search_business_entity",
explicit_entity_candidates: ["\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a"],
unsupported_but_understood_family: "entity_resolution"
}
});
const deps = buildDeps([
{ Counterparty: "\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a", CounterpartyRef: "Ref-1" },
{ Counterparty: "\u0421\u0412\u041a \u041b\u043e\u0433\u0438\u0441\u0442\u0438\u043a\u0430", CounterpartyRef: "Ref-2" }
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.evidence.confirmed_facts.join("\n")).toContain("\u043d\u0430\u0439\u0434\u0435\u043d \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442");
expect(result.evidence.confirmed_facts.join("\n")).toContain("\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a");
expect(result.evidence.inferred_facts.join("\n")).toContain(
"\u041f\u043e\u043a\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0437\u0435\u043c\u043b\u0435\u043d\u0438\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043f\u043e \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0443 1\u0421"
);
expect(result.evidence.unknown_facts.join("\n")).toContain(
"\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u044b, \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u0438 \u0434\u0435\u043d\u0435\u0436\u043d\u044b\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0438"
);
});
it("emits Russian ambiguity boundaries for entity grounding", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "entity_resolution",
asked_action_family: "search_business_entity",
explicit_entity_candidates: ["\u0421\u0412\u041a"],
unsupported_but_understood_family: "entity_resolution"
}
});
const deps = buildDeps([
{ Counterparty: "\u0421\u0412\u041a-\u0410", CounterpartyRef: "Ref-1" },
{ Counterparty: "\u0421\u0412\u041a-\u0411", CounterpartyRef: "Ref-2" }
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.evidence.confirmed_facts).toEqual([]);
expect(result.evidence.unknown_facts.join("\n")).toContain(
"\u0422\u043e\u0447\u043d\u043e\u0435 \u0437\u0430\u0437\u0435\u043c\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430 \u0432 1\u0421 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u043d\u0435\u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u044b\u043c"
);
expect(result.evidence.unknown_facts.join("\n")).toContain("\u0421\u0412\u041a-\u0410");
expect(result.evidence.unknown_facts.join("\n")).toContain("\u0421\u0412\u041a-\u0411");
});
});