NODEDC_1C/llm_normalizer/backend/tests/assistantMcpDiscoveryTurnIn...

1381 lines
64 KiB
TypeScript
Raw 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 } from "vitest";
import { buildAssistantMcpDiscoveryTurnInput } from "../src/services/assistantMcpDiscoveryTurnInputAdapter";
describe("assistant MCP discovery turn input adapter", () => {
it("maps unsupported assistant turn meaning into a discovery-ready value-flow input", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
assistantTurnMeaning: {
schema_version: "assistant_turn_meaning_v1",
asked_domain_family: "counterparty",
asked_action_family: "counterparty_value_or_turnover",
unsupported_but_understood_family: "counterparty_value_or_turnover",
stale_replay_forbidden: true,
explicit_entity_candidates: [{ type: "counterparty", value: "SVK", source: "current_turn_loose_entity_tail" }]
},
predecomposeContract: {
entities: { counterparty: "Группа СВК", 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.data_need_graph?.business_fact_family).toBe("value_flow");
expect(result.data_need_graph?.time_scope_need).toBe("explicit_period");
expect(result.turn_meaning_ref?.explicit_entity_candidates).toEqual(["SVK", "Группа СВК"]);
expect(result.turn_meaning_ref?.explicit_organization_scope).toBe("Альтернатива");
expect(result.turn_meaning_ref?.explicit_date_scope).toBe("2020");
expect(result.turn_meaning_ref?.stale_replay_forbidden).toBe(true);
});
it("bootstraps lifecycle discovery from raw user wording and predecompose scope", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "Сколько лет мы работаем с Группа СВК?",
predecomposeContract: {
entities: { counterparty: "Группа СВК" },
period: { period_from: null, period_to: null, as_of_date: null }
}
});
expect(result.adapter_status).toBe("ready");
expect(result.source_signal).toBe("predecompose_contract");
expect(result.semantic_data_need).toBe("counterparty lifecycle evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "counterparty_lifecycle",
asked_action_family: "activity_duration",
explicit_entity_candidates: ["Группа СВК"],
unsupported_but_understood_family: "counterparty_lifecycle",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_lifecycle_signal_detected");
});
it("bootstraps value-flow discovery from raw turnover wording when no exact route owns it", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "какой денежный поток был у Группа СВК за 2020 год?",
predecomposeContract: {
entities: { counterparty: "Группа СВК" },
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_entity_candidates: ["Группа СВК"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "counterparty_value_or_turnover",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_value_flow_signal_detected");
});
it("treats value-flow organization-shaped target as entity candidate when counterparty is absent", () => {
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.turn_meaning_ref?.explicit_entity_candidates).toEqual(["Группа СВК"]);
expect(result.turn_meaning_ref?.explicit_organization_scope).toBeUndefined();
});
it("keeps payout wording as outgoing supplier-payout discovery", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "сколько мы заплатили Группа СВК за 2020 год?",
predecomposeContract: {
entities: { counterparty: "Группа СВК" },
period: { period_from: "2020-01-01", period_to: "2020-12-31" }
}
});
expect(result.adapter_status).toBe("ready");
expect(result.semantic_data_need).toBe("counterparty value-flow evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "counterparty_value",
asked_action_family: "payout",
explicit_entity_candidates: ["Группа СВК"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "counterparty_payouts_or_outflow",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_payout_signal_detected");
});
it("keeps net cash wording as bidirectional value-flow discovery", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "какое нетто по деньгам с Группа СВК за 2020: сколько получили и сколько заплатили?",
predecomposeContract: {
entities: { counterparty: "Группа СВК" },
period: { period_from: "2020-01-01", period_to: "2020-12-31" }
}
});
expect(result.adapter_status).toBe("ready");
expect(result.semantic_data_need).toBe("counterparty value-flow evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "counterparty_value",
asked_action_family: "net_value_flow",
explicit_entity_candidates: ["Группа СВК"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "counterparty_bidirectional_value_flow_or_netting",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_bidirectional_value_flow_signal_detected");
expect(result.reason_codes).not.toContain("mcp_discovery_payout_signal_detected");
});
it("captures monthly aggregation as part of bidirectional value-flow meaning", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "какое нетто по деньгам с Группа СВК за 2020 год по месяцам: сколько получили и сколько заплатили помесячно?",
predecomposeContract: {
entities: { counterparty: "Группа СВК" },
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: "net_value_flow",
asked_aggregation_axis: "month",
explicit_entity_candidates: ["Группа СВК"],
explicit_date_scope: "2020"
});
expect(result.reason_codes).toContain("mcp_discovery_monthly_aggregation_signal_detected");
});
it("bootstraps metadata discovery from raw schema wording", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "какие регистры и поля есть в 1С по НДС?"
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("raw_text");
expect(result.semantic_data_need).toBe("1C metadata evidence");
expect(result.data_need_graph?.business_fact_family).toBe("schema_surface");
expect(result.data_need_graph?.decomposition_candidates).toEqual(["inspect_metadata_surface"]);
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "metadata",
asked_action_family: "inspect_fields",
unsupported_but_understood_family: "1c_metadata_surface",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_metadata_signal_detected");
});
it("treats broad 1C object wording as metadata surface discovery instead of narrowing to catalog-only", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "какие объекты 1С есть по НДС?"
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("raw_text");
expect(result.semantic_data_need).toBe("1C metadata evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "metadata",
asked_action_family: "inspect_surface",
explicit_entity_candidates: ["НДС"],
unsupported_but_understood_family: "1c_metadata_surface",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_metadata_signal_detected");
expect(result.reason_codes).toContain("mcp_discovery_metadata_scope_hint_from_raw_text");
});
it("bootstraps entity-resolution discovery from raw counterparty search wording", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "найди в 1С контрагента Группа СВК"
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("raw_text");
expect(result.semantic_data_need).toBe("entity discovery evidence");
expect(result.data_need_graph?.business_fact_family).toBe("entity_grounding");
expect(result.data_need_graph?.subject_candidates).toEqual(["Группа СВК"]);
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "entity_resolution",
asked_action_family: "search_business_entity",
explicit_entity_candidates: ["Группа СВК"],
unsupported_but_understood_family: "entity_resolution",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_signal_detected");
expect(result.reason_codes).toContain("mcp_discovery_entity_scope_from_raw_entity_search");
});
it("seeds document evidence follow-up from prior entity-resolution grounding", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "по нему документы за 2020 год",
followupContext: {
previous_discovery_pilot_scope: "entity_resolution_search_v1",
previous_anchor_type: "counterparty",
previous_anchor_value: "Группа СВК",
previous_discovery_entity_candidates: ["Группа СВК", "СВК"]
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
expect(result.semantic_data_need).toBe("document evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "documents",
asked_action_family: "list_documents",
explicit_entity_candidates: ["Группа СВК"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "document_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_grounded_document_followup");
expect(result.reason_codes).toContain("mcp_discovery_counterparty_from_followup_context");
});
it("seeds movement evidence follow-up from prior entity-resolution grounding", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "а теперь по нему движения за 2020 год",
followupContext: {
previous_discovery_pilot_scope: "entity_resolution_search_v1",
previous_discovery_entity_candidates: ["Группа СВК", "СВК"]
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
expect(result.semantic_data_need).toBe("movement evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "movements",
asked_action_family: "list_movements",
explicit_entity_candidates: ["Группа СВК"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "movement_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_grounded_movement_followup");
expect(result.reason_codes).toContain("mcp_discovery_counterparty_from_followup_context");
});
it("restarts entity-resolution when the user clarifies one ambiguous candidate", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "СВК-А",
followupContext: {
previous_discovery_pilot_scope: "entity_resolution_search_v1",
previous_discovery_entity_resolution_status: "ambiguous",
previous_discovery_entity_candidates: ["СВК", "СВК-А", "СВК-Б"],
previous_discovery_entity_ambiguity_candidates: ["СВК-А", "СВК-Б"]
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
expect(result.semantic_data_need).toBe("entity discovery evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "entity_resolution",
asked_action_family: "search_business_entity",
explicit_entity_candidates: ["СВК-А"],
unsupported_but_understood_family: "entity_resolution",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_signal_detected");
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_clarification_candidate_selected");
});
it("restarts entity-resolution when the user clarifies an ambiguous candidate by ordinal choice", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "второй вариант",
followupContext: {
previous_discovery_pilot_scope: "entity_resolution_search_v1",
previous_discovery_entity_resolution_status: "ambiguous",
previous_discovery_entity_candidates: ["СВК", "СВК-А", "СВК-Б"],
previous_discovery_entity_ambiguity_candidates: ["СВК-А", "СВК-Б"]
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
expect(result.semantic_data_need).toBe("entity discovery evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "entity_resolution",
asked_action_family: "search_business_entity",
explicit_entity_candidates: ["СВК-Б"],
unsupported_but_understood_family: "entity_resolution",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_clarification_candidate_selected");
});
it("chains an ordinal ambiguity clarification directly into value-flow follow-up intent", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "второй вариант, сколько получили за 2020 год",
followupContext: {
previous_discovery_pilot_scope: "entity_resolution_search_v1",
previous_discovery_entity_resolution_status: "ambiguous",
previous_discovery_entity_candidates: ["СВК", "СВК-А", "СВК-Б"],
previous_discovery_entity_ambiguity_candidates: ["СВК-А", "СВК-Б"]
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
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_entity_candidates: ["СВК-Б"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "counterparty_value_or_turnover",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_clarification_candidate_selected");
expect(result.reason_codes).toContain("mcp_discovery_value_flow_signal_detected");
});
it("chains an ordinal ambiguity clarification directly into document evidence follow-up intent", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "второй вариант, покажи документы за 2020 год",
followupContext: {
previous_discovery_pilot_scope: "entity_resolution_search_v1",
previous_discovery_entity_resolution_status: "ambiguous",
previous_discovery_entity_candidates: ["СВК", "СВК-А", "СВК-Б"],
previous_discovery_entity_ambiguity_candidates: ["СВК-А", "СВК-Б"]
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
expect(result.semantic_data_need).toBe("document evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "documents",
asked_action_family: "list_documents",
explicit_entity_candidates: ["СВК-Б"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "document_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_clarification_candidate_selected");
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_clarified_document_followup");
});
it("chains an ordinal ambiguity clarification directly into movement evidence follow-up intent", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "первый вариант, покажи движения за 2020 год",
followupContext: {
previous_discovery_pilot_scope: "entity_resolution_search_v1",
previous_discovery_entity_resolution_status: "ambiguous",
previous_discovery_entity_candidates: ["СВК", "СВК-А", "СВК-Б"],
previous_discovery_entity_ambiguity_candidates: ["СВК-А", "СВК-Б"]
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
expect(result.semantic_data_need).toBe("movement evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "movements",
asked_action_family: "list_movements",
explicit_entity_candidates: ["СВК-А"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "movement_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_clarification_candidate_selected");
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_clarified_movement_followup");
});
it("does not silently ground value-flow follow-ups from an ambiguous entity-resolution answer", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "сколько получили по нему за 2020 год",
followupContext: {
previous_discovery_pilot_scope: "entity_resolution_search_v1",
previous_discovery_entity_resolution_status: "ambiguous",
previous_discovery_entity_candidates: ["СВК", "СВК-А", "СВК-Б"],
previous_discovery_entity_ambiguity_candidates: ["СВК-А", "СВК-Б"]
}
});
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_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.reason_codes).not.toContain("mcp_discovery_grounded_value_flow_followup");
});
it("overrides a wrong exact document intent when a grounded document follow-up asks to switch into movements", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "а теперь по нему движения за 2020 год",
assistantTurnMeaning: {
asked_domain_family: "inventory",
asked_action_family: "purchase_documents",
explicit_intent_candidate: "inventory_purchase_documents_for_item",
explicit_entity_candidates: [{ value: "нему" }]
},
predecomposeContract: {
entities: {
counterparty: "нему"
},
period: {
period_from: "2020-01-01",
period_to: "2020-12-31"
}
},
followupContext: {
previous_discovery_pilot_scope: "counterparty_document_evidence_query_documents_v1",
previous_filters: {
counterparty: "Группа СВК",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_discovery_entity_candidates: ["Группа СВК", "СВК"]
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("assistant_turn_meaning");
expect(result.semantic_data_need).toBe("movement evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "movements",
asked_action_family: "list_movements",
explicit_entity_candidates: ["Группа СВК"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "movement_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_document_evidence_grounded_movement_followup");
expect(result.reason_codes).not.toContain("mcp_discovery_not_applicable_for_supported_exact_turn");
});
it("overrides a supported exact turnover intent when a grounded entity follow-up asks about incoming money", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "сколько получили по нему за 2020 год",
assistantTurnMeaning: {
asked_domain_family: "counterparty",
asked_action_family: "turnover",
explicit_intent_candidate: "customer_revenue_and_payments",
explicit_entity_candidates: [{ value: "нему" }]
},
predecomposeContract: {
entities: {
counterparty: "нему"
},
period: {
period_from: "2020-01-01",
period_to: "2020-12-31"
}
},
followupContext: {
previous_discovery_pilot_scope: "entity_resolution_search_v1",
previous_filters: {
counterparty: "Группа СВК"
},
previous_discovery_entity_candidates: ["Группа СВК", "СВК"]
}
});
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_entity_candidates: ["Группа СВК"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "counterparty_value_or_turnover",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_grounded_value_flow_followup");
expect(result.reason_codes).not.toContain("mcp_discovery_not_applicable_for_supported_exact_turn");
});
it("overrides a supported exact payout intent when a grounded value-flow follow-up switches from incoming to outgoing", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "а теперь сколько заплатили?",
assistantTurnMeaning: {
asked_domain_family: "counterparty",
asked_action_family: "turnover",
explicit_intent_candidate: "customer_revenue_and_payments"
},
followupContext: {
previous_discovery_pilot_scope: "counterparty_value_flow_query_movements_v1",
previous_filters: {
counterparty: "Группа СВК",
organization: "ООО Альтернатива Плюс",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "Группа СВК"
}
});
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: "payout",
explicit_entity_candidates: ["Группа СВК"],
explicit_organization_scope: "ООО Альтернатива Плюс",
explicit_date_scope: "2020",
unsupported_but_understood_family: "counterparty_payouts_or_outflow",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_grounded_value_flow_followup");
expect(result.reason_codes).toContain("mcp_discovery_payout_signal_detected");
expect(result.reason_codes).not.toContain("mcp_discovery_not_applicable_for_supported_exact_turn");
});
it("overrides a supported exact net intent when a grounded payout follow-up switches into net flow", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "а какое нетто?",
assistantTurnMeaning: {
asked_domain_family: "counterparty",
asked_action_family: "turnover",
explicit_intent_candidate: "customer_revenue_and_payments"
},
followupContext: {
previous_discovery_pilot_scope: "counterparty_supplier_payout_query_movements_v1",
previous_filters: {
counterparty: "Группа СВК",
period_from: "2021-01-01",
period_to: "2021-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "Группа СВК"
}
});
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: "net_value_flow",
explicit_entity_candidates: ["Группа СВК"],
explicit_date_scope: "2021",
unsupported_but_understood_family: "counterparty_bidirectional_value_flow_or_netting",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_grounded_value_flow_followup");
expect(result.reason_codes).toContain("mcp_discovery_bidirectional_value_flow_signal_detected");
expect(result.reason_codes).not.toContain("mcp_discovery_not_applicable_for_supported_exact_turn");
});
it.skip("switches from a grounded exact value-flow answer into document evidence without restating the counterparty", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "а по документам?",
assistantTurnMeaning: {
asked_domain_family: "counterparty",
asked_action_family: "turnover",
explicit_intent_candidate: "customer_revenue_and_payments"
},
followupContext: {
previous_intent: "customer_revenue_and_payments",
previous_filters: {
counterparty: "Группа СВК",
period_from: "2021-01-01",
period_to: "2021-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "Группа СВК"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("assistant_turn_meaning");
expect(result.semantic_data_need).toBe("document evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "documents",
asked_action_family: "list_documents",
explicit_entity_candidates: ["Группа СВК"],
explicit_date_scope: "2021",
unsupported_but_understood_family: "document_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_value_flow_grounded_document_followup");
expect(result.reason_codes).not.toContain("mcp_discovery_not_applicable_for_supported_exact_turn");
});
it.skip("switches from a grounded exact value-flow answer into movement evidence without restating the counterparty", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "а по движениям?",
assistantTurnMeaning: {
asked_domain_family: "counterparty",
asked_action_family: "turnover",
explicit_intent_candidate: "customer_revenue_and_payments"
},
followupContext: {
previous_intent: "customer_revenue_and_payments",
previous_filters: {
counterparty: "Группа СВК",
organization: "ООО Альтернатива Плюс",
period_from: "2021-01-01",
period_to: "2021-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "Группа СВК"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("assistant_turn_meaning");
expect(result.semantic_data_need).toBe("movement evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "movements",
asked_action_family: "list_movements",
explicit_entity_candidates: ["Группа СВК"],
explicit_organization_scope: "ООО Альтернатива Плюс",
explicit_date_scope: "2021",
unsupported_but_understood_family: "movement_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_value_flow_grounded_movement_followup");
expect(result.reason_codes).not.toContain("mcp_discovery_not_applicable_for_supported_exact_turn");
});
it("switches from a grounded exact value-flow answer into document evidence with a clean UTF-8 follow-up", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "а по документам?",
assistantTurnMeaning: {
asked_domain_family: "counterparty",
asked_action_family: "turnover",
explicit_intent_candidate: "customer_revenue_and_payments"
},
followupContext: {
previous_intent: "customer_revenue_and_payments",
previous_filters: {
counterparty: "Группа СВК",
period_from: "2021-01-01",
period_to: "2021-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "Группа СВК"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("assistant_turn_meaning");
expect(result.semantic_data_need).toBe("counterparty value-flow evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "documents",
asked_action_family: "list_documents",
explicit_entity_candidates: ["Группа СВК"],
explicit_date_scope: "2021",
unsupported_but_understood_family: "document_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_value_flow_grounded_document_followup");
expect(result.reason_codes).not.toContain("mcp_discovery_not_applicable_for_supported_exact_turn");
});
it("switches from a grounded exact value-flow answer into movement evidence with a clean UTF-8 follow-up", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "а по движениям?",
assistantTurnMeaning: {
asked_domain_family: "counterparty",
asked_action_family: "turnover",
explicit_intent_candidate: "customer_revenue_and_payments"
},
followupContext: {
previous_intent: "customer_revenue_and_payments",
previous_filters: {
counterparty: "Группа СВК",
organization: "ООО Альтернатива Плюс",
period_from: "2021-01-01",
period_to: "2021-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "Группа СВК"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("assistant_turn_meaning");
expect(result.semantic_data_need).toBe("counterparty value-flow evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "movements",
asked_action_family: "list_movements",
explicit_entity_candidates: ["Группа СВК"],
explicit_organization_scope: "ООО Альтернатива Плюс",
explicit_date_scope: "2021",
unsupported_but_understood_family: "movement_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_value_flow_grounded_movement_followup");
expect(result.reason_codes).not.toContain("mcp_discovery_not_applicable_for_supported_exact_turn");
});
it("seeds short monthly follow-up from prior bidirectional discovery context", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "а по месяцам?",
followupContext: {
previous_discovery_pilot_scope: "counterparty_bidirectional_value_flow_query_movements_v1",
previous_filters: {
counterparty: "Группа СВК",
organization: "ООО Альтернатива Плюс",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "Группа СВК"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "counterparty_value",
asked_action_family: "net_value_flow",
asked_aggregation_axis: "month",
explicit_entity_candidates: ["Группа СВК"],
explicit_organization_scope: "ООО Альтернатива Плюс",
explicit_date_scope: "2020",
unsupported_but_understood_family: "counterparty_bidirectional_value_flow_or_netting",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_seeded_from_followup_context");
expect(result.reason_codes).toContain("mcp_discovery_counterparty_from_followup_context");
expect(result.reason_codes).toContain("mcp_discovery_date_scope_from_followup_context");
});
it("seeds short metadata follow-up from prior metadata discovery context", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "а по регистрам?",
followupContext: {
previous_discovery_pilot_scope: "metadata_inspection_v1",
previous_filters: {
counterparty: "НДС"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "НДС"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
expect(result.semantic_data_need).toBe("1C metadata evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "metadata",
asked_action_family: "inspect_registers",
explicit_entity_candidates: ["НДС"],
unsupported_but_understood_family: "1c_metadata_surface",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_metadata_seeded_from_followup_context");
expect(result.reason_codes).toContain("mcp_discovery_counterparty_from_followup_context");
});
it("pivots grounded metadata follow-up into document evidence when the next lane is explicit", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "then documents",
followupContext: {
previous_discovery_pilot_scope: "metadata_inspection_v1",
previous_discovery_metadata_route_family: "document_evidence",
previous_discovery_metadata_selected_entity_set: "Документ",
previous_filters: {
counterparty: "SVK",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "SVK"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
expect(result.semantic_data_need).toBe("document evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "documents",
asked_action_family: "list_documents",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "document_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_metadata_grounded_document_followup");
expect(result.reason_codes).toContain("mcp_discovery_counterparty_from_followup_context");
});
it("pivots grounded metadata follow-up into movement evidence when the next lane is explicit", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "then movements",
followupContext: {
previous_discovery_pilot_scope: "metadata_inspection_v1",
previous_discovery_metadata_route_family: "movement_evidence",
previous_discovery_metadata_selected_entity_set: "РегистрНакопления",
previous_filters: {
counterparty: "SVK",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "SVK"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
expect(result.semantic_data_need).toBe("movement evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "movements",
asked_action_family: "list_movements",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "movement_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_metadata_grounded_movement_followup");
expect(result.reason_codes).toContain("mcp_discovery_counterparty_from_followup_context");
});
it("continues from grounded metadata into document evidence on a generic downstream follow-up", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "давай дальше",
followupContext: {
previous_discovery_pilot_scope: "metadata_inspection_v1",
previous_discovery_metadata_route_family: "document_evidence",
previous_discovery_metadata_selected_entity_set: "Документ",
previous_filters: {
counterparty: "SVK",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "SVK"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
expect(result.semantic_data_need).toBe("document evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "documents",
asked_action_family: "list_documents",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "document_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_metadata_grounded_lane_continuation");
});
it("continues from grounded metadata into movement evidence on a generic downstream follow-up", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "continue with data",
followupContext: {
previous_discovery_pilot_scope: "metadata_inspection_v1",
previous_discovery_metadata_route_family: "movement_evidence",
previous_discovery_metadata_selected_entity_set: "РегистрНакопления",
previous_filters: {
counterparty: "SVK",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "SVK"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
expect(result.semantic_data_need).toBe("movement evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "movements",
asked_action_family: "list_movements",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "movement_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_metadata_grounded_lane_continuation");
});
it("resolves ambiguous metadata surface into document lane when the follow-up explicitly asks for documents", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "по документам",
followupContext: {
previous_discovery_pilot_scope: "metadata_inspection_v1",
previous_discovery_metadata_ambiguity_detected: true,
previous_discovery_metadata_ambiguity_entity_sets: ["Документ", "РегистрНакопления"],
previous_filters: {
counterparty: "SVK",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "SVK"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
expect(result.semantic_data_need).toBe("document evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "documents",
asked_action_family: "list_documents",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "document_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_metadata_ambiguity_resolved_to_document_lane");
});
it("resolves ambiguous metadata surface into movement lane when the follow-up explicitly asks for movements", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "по движениям",
followupContext: {
previous_discovery_pilot_scope: "metadata_inspection_v1",
previous_discovery_metadata_ambiguity_detected: true,
previous_discovery_metadata_ambiguity_entity_sets: ["Документ", "РегистрНакопления"],
previous_filters: {
counterparty: "SVK",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "SVK"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
expect(result.semantic_data_need).toBe("movement evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "movements",
asked_action_family: "list_movements",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "movement_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_metadata_ambiguity_resolved_to_movement_lane");
});
it("resolves ambiguous metadata surface into document lane from semantic document hints", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "покажи счет-фактуры",
followupContext: {
previous_discovery_pilot_scope: "metadata_inspection_v1",
previous_discovery_metadata_ambiguity_detected: true,
previous_discovery_metadata_ambiguity_entity_sets: ["Документ", "РегистрНакопления"],
previous_filters: {
counterparty: "SVK",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "SVK"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.semantic_data_need).toBe("document evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "documents",
asked_action_family: "list_documents",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "document_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_metadata_ambiguity_resolved_to_document_lane");
});
it("resolves ambiguous metadata surface into movement lane from semantic movement hints without turning it into value-flow", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "покажи платежи",
followupContext: {
previous_discovery_pilot_scope: "metadata_inspection_v1",
previous_discovery_metadata_ambiguity_detected: true,
previous_discovery_metadata_ambiguity_entity_sets: ["Документ", "РегистрНакопления"],
previous_filters: {
counterparty: "SVK",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "SVK"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.semantic_data_need).toBe("movement evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "movements",
asked_action_family: "list_movements",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "movement_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_metadata_ambiguity_resolved_to_movement_lane");
expect(result.reason_codes).not.toContain("mcp_discovery_value_flow_signal_detected");
});
it("does not resolve metadata ambiguity into movement lane when confirmed ambiguity sets contain documents only", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "по движениям",
followupContext: {
previous_discovery_pilot_scope: "metadata_inspection_v1",
previous_discovery_metadata_ambiguity_detected: true,
previous_discovery_metadata_ambiguity_entity_sets: ["Документ"],
previous_filters: {
counterparty: "SVK",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "SVK"
}
});
expect(result.reason_codes).not.toContain("mcp_discovery_metadata_ambiguity_resolved_to_movement_lane");
});
it("continues from ambiguous metadata into document lane when ambiguity choice set collapses to documents on a generic downstream follow-up", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "continue with data",
followupContext: {
previous_discovery_pilot_scope: "metadata_inspection_v1",
previous_discovery_metadata_ambiguity_detected: true,
previous_discovery_metadata_ambiguity_entity_sets: ["Документ", "invoice"],
previous_filters: {
counterparty: "SVK",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "SVK"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.semantic_data_need).toBe("document evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "documents",
asked_action_family: "list_documents",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "document_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_metadata_ambiguity_collapsed_to_document_lane");
});
it("continues from ambiguous metadata into movement lane when ambiguity choice set collapses to movements on a generic downstream follow-up", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "continue with data",
followupContext: {
previous_discovery_pilot_scope: "metadata_inspection_v1",
previous_discovery_metadata_ambiguity_detected: true,
previous_discovery_metadata_ambiguity_entity_sets: ["РегистрНакопления", "movement"],
previous_filters: {
counterparty: "SVK",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "SVK"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.semantic_data_need).toBe("movement evidence");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "movements",
asked_action_family: "list_movements",
explicit_entity_candidates: ["SVK"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "movement_evidence",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_metadata_ambiguity_collapsed_to_movement_lane");
});
it("requires an explicit lane choice on a generic downstream follow-up when metadata ambiguity stays mixed", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "давай дальше",
followupContext: {
previous_discovery_pilot_scope: "metadata_inspection_v1",
previous_discovery_metadata_ambiguity_detected: true,
previous_discovery_metadata_ambiguity_entity_sets: ["Документ", "РегистрНакопления"],
previous_filters: {
counterparty: "SVK",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "SVK"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.source_signal).toBe("followup_context");
expect(result.semantic_data_need).toBe("metadata lane clarification");
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "metadata",
asked_action_family: "resolve_next_lane",
explicit_entity_candidates: ["SVK"],
metadata_ambiguity_entity_sets: ["Документ", "РегистрНакопления"],
explicit_date_scope: "2020",
unsupported_but_understood_family: "metadata_lane_choice_clarification",
stale_replay_forbidden: true
});
expect(result.reason_codes).toContain("mcp_discovery_metadata_ambiguity_requires_lane_choice");
});
it("switches the checked year on a short payout follow-up while keeping prior discovery counterparty", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "а теперь за 2021?",
followupContext: {
previous_discovery_pilot_scope: "counterparty_supplier_payout_query_movements_v1",
previous_filters: {
counterparty: "Группа СВК",
organization: "ООО Альтернатива Плюс",
period_from: "2020-01-01",
period_to: "2020-12-31"
},
previous_anchor_type: "counterparty",
previous_anchor_value: "Группа СВК"
}
});
expect(result.adapter_status).toBe("ready");
expect(result.should_run_discovery).toBe(true);
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "counterparty_value",
asked_action_family: "payout",
explicit_entity_candidates: ["Группа СВК"],
explicit_organization_scope: "ООО Альтернатива Плюс",
explicit_date_scope: "2021",
unsupported_but_understood_family: "counterparty_payouts_or_outflow",
stale_replay_forbidden: true
});
});
it("does not activate discovery for supported exact current-turn intent", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
assistantTurnMeaning: {
asked_domain_family: "counterparty",
asked_action_family: "list_documents",
explicit_intent_candidate: "list_documents_by_counterparty",
explicit_entity_candidates: [{ value: "SVK" }],
stale_replay_forbidden: false
}
});
expect(result.adapter_status).toBe("not_applicable");
expect(result.should_run_discovery).toBe(false);
expect(result.turn_meaning_ref).toBeNull();
expect(result.reason_codes).toContain("mcp_discovery_not_applicable_for_supported_exact_turn");
});
it("never serializes object candidates as [object Object]", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
assistantTurnMeaning: {
asked_domain_family: "counterparty",
asked_action_family: "counterparty_value_or_turnover",
unsupported_but_understood_family: "counterparty_value_or_turnover",
explicit_entity_candidates: [{ type: "counterparty", value: "SVK" }]
}
});
expect(result.turn_meaning_ref?.explicit_entity_candidates).toEqual(["SVK"]);
expect(result.turn_meaning_ref?.explicit_entity_candidates).not.toContain("[object Object]");
});
it("prefers the raw cleaned entity anchor over canonicalized turn-meaning pollution", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "\u043d\u0430\u0439\u0434\u0438 \u0432 1\u0421 \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430 \u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a",
assistantTurnMeaning: {
asked_domain_family: "counterparty",
asked_action_family: "search_business_entity",
explicit_entity_candidates: [{ value: "\u0441 \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435\u043c '\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a' \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 1\u0421" }]
},
predecomposeContract: {
entities: {
counterparty: "\u0441 \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435\u043c '\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a' \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 1\u0421"
}
}
});
expect(result.adapter_status).toBe("ready");
expect(result.turn_meaning_ref?.explicit_entity_candidates?.[0]).toBe("\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a");
expect(result.turn_meaning_ref?.explicit_entity_candidates).not.toContain(
"\u0441 \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435\u043c '\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a' \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 1\u0421"
);
});
it("does not concatenate effectiveMessage into the raw entity anchor", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "\u043d\u0430\u0439\u0434\u0438 \u0432 1\u0421 \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430 \u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a",
effectiveMessage:
"\u043d\u0430\u0439\u0442\u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c '\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a' \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 1\u0421"
});
expect(result.adapter_status).toBe("ready");
expect(result.turn_meaning_ref?.explicit_entity_candidates?.[0]).toBe("\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a");
expect(result.turn_meaning_ref?.explicit_entity_candidates).not.toContain(
"\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a \u043d\u0430\u0439\u0442\u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c '\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a'"
);
});
it("marks top-value wording as a ranking data need without inventing a missing subject gap", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "кто больше всего принес денег в 2020"
});
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.data_need_graph?.business_fact_family).toBe("value_flow");
expect(result.data_need_graph?.ranking_need).toBe("top_desc");
expect(result.data_need_graph?.clarification_gaps).toEqual([]);
expect(result.data_need_graph?.decomposition_candidates).toEqual([
"collect_scoped_movements",
"aggregate_ranked_axis_values",
"probe_coverage"
]);
});
it("keeps organization as scope for open bidirectional comparison wording instead of inventing a subject candidate", () => {
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.turn_meaning_ref).toMatchObject({
asked_domain_family: "counterparty_value",
asked_action_family: "net_value_flow",
explicit_organization_scope: "ООО Альтернатива Плюс",
explicit_date_scope: "2020"
});
expect(result.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined();
expect(result.data_need_graph?.comparison_need).toBe("incoming_vs_outgoing");
expect(result.data_need_graph?.clarification_gaps).toEqual([]);
});
it("drops organization-shaped assistant-turn entity pollution when open comparison already has explicit organization scope", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "что больше: входящие или исходящие деньги за 2020 год по ООО Альтернатива Плюс?",
assistantTurnMeaning: {
asked_domain_family: "counterparty_value",
asked_action_family: "net_value_flow",
explicit_entity_candidates: [{ value: "ООО Альтернатива Плюс" }],
explicit_organization_scope: "ООО Альтернатива Плюс",
explicit_date_scope: "2020",
unsupported_but_understood_family: "counterparty_bidirectional_value_flow_or_netting"
},
predecomposeContract: {
entities: { counterparty: "ООО Альтернатива Плюс", organization: "ООО Альтернатива Плюс" },
period: { period_from: "2020-01-01", period_to: "2020-12-31" }
}
});
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "counterparty_value",
asked_action_family: "net_value_flow",
explicit_organization_scope: "ООО Альтернатива Плюс",
explicit_date_scope: "2020"
});
expect(result.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined();
expect(result.data_need_graph?.comparison_need).toBe("incoming_vs_outgoing");
});
it.skip("treats mirrored predecompose organization and counterparty as organization scope for open comparison", () => {
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "что больше: входящие или исходящие деньги за 2020 год по ООО Альтернатива Плюс?",
predecomposeContract: {
entities: {
counterparty: "ООО Альтернатива Плюс",
organization: "ООО Альтернатива Плюс"
},
period: { period_from: "2020-01-01", period_to: "2020-12-31" }
}
});
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "counterparty_value",
asked_action_family: "net_value_flow",
explicit_organization_scope: "ООО Альтернатива Плюс",
explicit_date_scope: "2020"
});
expect(result.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined();
expect(result.data_need_graph?.subject_candidates).toEqual([]);
expect(result.data_need_graph?.comparison_need).toBe("incoming_vs_outgoing");
expect(result.reason_codes).not.toContain("mcp_discovery_counterparty_from_predecompose");
});
it.skip("treats mirrored predecompose organization and counterparty as organization scope for open comparison (utf8-safe)", () => {
const orgName = "\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441";
const result = buildAssistantMcpDiscoveryTurnInput({
userMessage: "что больше: входящие или исходящие деньги за 2020 год по ООО Альтернатива Плюс?",
predecomposeContract: {
entities: {
counterparty: orgName,
organization: orgName
},
period: { period_from: "2020-01-01", period_to: "2020-12-31" }
}
});
expect(result.turn_meaning_ref).toMatchObject({
asked_domain_family: "counterparty_value",
asked_action_family: "net_value_flow",
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([]);
expect(result.data_need_graph?.comparison_need).toBe("incoming_vs_outgoing");
expect(result.reason_codes).not.toContain("mcp_discovery_counterparty_from_predecompose");
});
});