Укрепить банковские границы денежных потоков phase97

This commit is contained in:
2026-05-13 01:53:05 +03:00
parent e997449785
commit 04e670ab76
21 changed files with 861 additions and 12 deletions
@@ -10,4 +10,13 @@ describe("address intent resolver bidirectional value-flow arbitration", () => {
expect(result.intent).toBe("unknown");
expect(result.reasons).toContain("unicode_bidirectional_value_flow_deferred_to_discovery");
});
it("keeps normalized received-paid-net funds wording out of inventory routes", () => {
const result = resolveAddressIntent(
"\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0441\u0443\u043c\u043c\u0443 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0441\u0440\u0435\u0434\u0441\u0442\u0432, \u0441\u0443\u043c\u043c\u044b \u0432\u044b\u043f\u043b\u0430\u0447\u0435\u043d\u043d\u044b\u0445 \u0441\u0440\u0435\u0434\u0441\u0442\u0432 \u0438 \u0447\u0438\u0441\u0442\u044b\u0439 \u043e\u0441\u0442\u0430\u0442\u043e\u043a (\u043d\u0435\u0442\u0442\u043e) \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430 '\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a' \u0437\u0430 2020 \u0433\u043e\u0434."
);
expect(result.intent).toBe("unknown");
expect(result.reasons).toContain("unicode_bidirectional_value_flow_deferred_to_discovery");
});
});
@@ -561,6 +561,34 @@ describe("address compose stage utf8 headers", () => {
expect(reply.text).not.toContain("live address lane");
});
it("keeps bank counterparty classification bounded for incoming revenue questions", () => {
const reply = composeFactualReply(
"bank_operations_by_counterparty",
[
{
period: "2020-12-16T16:20:51Z",
registrator: "Списание с расчетного счета 00000000293 от 16.12.2020 16:20:51",
account_dt: "0",
account_kt: "0",
amount: 60,
analytics: ["СБЕРБАНК, ПАО", "0"],
counterparty: "СБЕРБАНК, ПАО"
}
],
{
counterpartyHint: "СБЕРБАНК",
userMessage:
"А если СБЕРБАНК встречается во входящих поступлениях, это клиентская выручка или кредитный/депозитный банковский смысл?"
}
);
expect(reply.text).toContain("по СБЕРБАНК");
expect(reply.text).toContain("входящее поступление от банка в этом срезе не подтверждено");
expect(reply.text).toContain("клиентскую выручку");
expect(reply.text).toContain("Основание 1С");
expect(reply.text).toContain("вид операции/назначение платежа/договор");
});
it("renders readable russian header for contracts-by-counterparty list", () => {
const reply = composeFactualReply("list_contracts_by_counterparty", [
{
@@ -2264,6 +2292,16 @@ describe("address intent resolver expansion (M2.3a)", () => {
expect(result.intent).toBe("bank_operations_by_counterparty");
});
it("prefers explicit bank name over supplier-vs-financial comparison text", () => {
const result = extractAddressFilters(
"\u041f\u043e \u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441 \u0437\u0430 2020 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438 \u043f\u043b\u0430\u0442\u0435\u0436\u0438 \u0432 \u0421\u0411\u0415\u0420\u0411\u0410\u041d\u041a: \u044d\u0442\u043e \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a \u0438\u043b\u0438 \u0431\u0430\u043d\u043a\u043e\u0432\u0441\u043a\u0438\u0439/\u0444\u0438\u043d\u0430\u043d\u0441\u043e\u0432\u044b\u0439 \u043f\u043e\u0442\u043e\u043a?",
"bank_operations_by_counterparty"
);
expect(result.extracted_filters.counterparty).toBe("\u0421\u0411\u0415\u0420\u0411\u0410\u041d\u041a");
expect(result.warnings).toContain("counterparty_anchor_derived_from_known_financial_name");
});
it("resolves documents forming balance intent", () => {
const result = resolveAddressIntent("which documents form balance for account 62 as of 2020-07-31");
expect(result.intent).toBe("documents_forming_balance");
@@ -309,6 +309,13 @@ describe("assistant MCP discovery response candidate", () => {
entryPoint({
turn_input: {
adapter_status: "ready",
turn_meaning_ref: {
raw_message:
"Дай краткий обзор ООО Альтернатива Плюс за 2020 и отметь, если в топах есть банк, почему его нельзя читать как обычного клиента или поставщика.",
effective_message:
"Дать краткий обзор ООО Альтернатива Плюс за 2020: входящие, исходящие, нетто и банковскую границу.",
explicit_organization_scope: "ООО Альтернатива Плюс"
},
data_need_graph: {
business_fact_family: "business_overview",
ranking_need: "top_desc",
@@ -375,9 +382,12 @@ describe("assistant MCP discovery response candidate", () => {
);
expect(candidate.reply_text).toContain("в доступном проверенном срезе 1С");
expect(candidate.reply_text).toContain("по компании ООО Альтернатива Плюс");
expect(candidate.reply_text).toContain("лидирует 2015");
expect(candidate.reply_text).toContain("2015");
expect(candidate.reply_text).toContain("136 723 459,73 руб.");
expect(candidate.reply_text).toContain("банк/финансовую организацию");
expect(candidate.reply_text).toContain("нельзя автоматически читать как обычного клиента или поставщика");
expect(candidate.reply_text).toContain("не полный бухгалтерский рейтинг доходности");
expect(candidate.reply_text).toContain("не как чистую бухгалтерскую прибыль");
expect(candidate.reply_text).toContain("проверка достигла лимита строк");
@@ -1641,6 +1641,38 @@ describe("assistant MCP discovery turn input adapter", () => {
expect(result.reason_codes).not.toContain("mcp_discovery_value_flow_signal_detected");
});
it("routes plain short overview with money axes into business overview over value-flow", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage:
"\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0439 \u0432\u0437\u0440\u043e\u0441\u043b\u044b\u0439 \u043a\u0440\u0430\u0442\u043a\u0438\u0439 \u043e\u0431\u0437\u043e\u0440 \u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441 \u0437\u0430 2020: \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435, \u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0435, \u043d\u0435\u0442\u0442\u043e \u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0442\u043c\u0435\u0442\u044c, \u0435\u0441\u043b\u0438 \u0432 \u0442\u043e\u043f\u0430\u0445 \u0435\u0441\u0442\u044c \u0431\u0430\u043d\u043a.",
assistantTurnMeaning: {
asked_domain_family: "counterparty",
asked_action_family: "counterparty_value_or_turnover",
explicit_intent_candidate: "customer_revenue_and_payments",
explicit_entity_candidates: [{ value: "\u0438\u043b\u0438 \u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\u0430" }],
stale_replay_forbidden: false
},
predecomposeContract: {
entities: {
organization: "\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441"
},
period: {
period_from: "2020-01-01",
period_to: "2020-12-31"
}
}
});
expect(result.adapter_status).toBe("ready");
expect(result.data_need_graph?.business_fact_family).toBe("business_overview");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "business_overview",
explicit_date_scope: "2020"
});
expect(result.reason_codes).toContain("mcp_discovery_broad_business_evaluation_route_candidate");
expect(result.reason_codes).not.toContain("mcp_discovery_value_flow_signal_detected");
});
it("keeps explicit year out of the organization scope for raw business overview wording", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: