ARCH: стабилизировать continuity и защитить exact-ответы от discovery

This commit is contained in:
2026-04-21 18:43:05 +03:00
parent b542b65b81
commit 429bd3d8ec
8 changed files with 603 additions and 18 deletions
@@ -113,11 +113,17 @@ describe("assistant MCP discovery response policy", () => {
const result = applyAssistantMcpDiscoveryResponsePolicy({
currentReply: "stale exact route answer",
currentReplySource: "address_query_runtime_v1",
currentReplyType: "factual",
addressRuntimeMeta: {
detected_intent: "list_documents_by_counterparty",
assistant_mcp_discovery_entry_point_v1: entryPoint({
turn_input: {
adapter_status: "ready",
should_run_discovery: true
should_run_discovery: true,
turn_meaning_ref: {
asked_domain_family: "counterparty_value",
asked_action_family: "payout"
}
}
})
}
@@ -129,6 +135,94 @@ describe("assistant MCP discovery response policy", () => {
expect(result.reason_codes).not.toContain("mcp_discovery_response_policy_not_discovery_ready_address_candidate");
});
it("keeps aligned factual address lane answers when the exact lane already matched the same semantic intent", () => {
const result = applyAssistantMcpDiscoveryResponsePolicy({
currentReply: "ИП Калинин Н.М. | сумма: 216600 | операций: 2",
currentReplySource: "address_query_runtime_v1",
currentReplyType: "factual",
addressRuntimeMeta: {
detected_intent: "customer_revenue_and_payments",
assistant_mcp_discovery_entry_point_v1: entryPoint({
turn_input: {
adapter_status: "ready",
should_run_discovery: true,
turn_meaning_ref: {
asked_domain_family: "counterparty_value",
asked_action_family: "turnover"
}
}
})
}
});
expect(result.applied).toBe(false);
expect(result.decision).toBe("keep_current_reply");
expect(result.reply_text).toBe("ИП Калинин Н.М. | сумма: 216600 | операций: 2");
expect(result.reason_codes).toContain("mcp_discovery_response_policy_keep_aligned_factual_address_reply");
});
it("keeps factual address follow-up replies when they already match the continuation target intent", () => {
const result = applyAssistantMcpDiscoveryResponsePolicy({
currentReply: "ИП Калинин Н.М. | сумма: 216600 | операций: 2",
currentReplySource: "address_query_runtime_v1",
currentReplyType: "factual",
addressRuntimeMeta: {
detected_intent: "customer_revenue_and_payments",
dialogContinuationContract: {
target_intent: "customer_revenue_and_payments"
},
assistant_mcp_discovery_entry_point_v1: entryPoint({
turn_input: {
adapter_status: "ready",
should_run_discovery: true,
turn_meaning_ref: {
asked_domain_family: "counterparty_lifecycle",
asked_action_family: "activity_duration"
}
}
})
}
});
expect(result.applied).toBe(false);
expect(result.decision).toBe("keep_current_reply");
expect(result.reason_codes).toContain("mcp_discovery_response_policy_keep_factual_address_continuation_target");
});
it("keeps full-confirmed factual address replies even when discovery has a guarded candidate", () => {
const result = applyAssistantMcpDiscoveryResponsePolicy({
currentReply: "ООО Ромашка | сумма: 128000 | операций: 3",
currentReplySource: "address_query_runtime_v1",
currentReplyType: "factual",
addressRuntimeMeta: {
detected_intent: "receivables_confirmed_as_of_date",
truth_gate_contract_status: "full_confirmed",
assistant_truth_answer_policy_v1: {
truth_gate: {
coverage_status: "full",
grounding_status: "grounded",
source_truth_gate_status: "full_confirmed"
}
},
assistant_mcp_discovery_entry_point_v1: entryPoint({
turn_input: {
adapter_status: "ready",
should_run_discovery: true,
turn_meaning_ref: {
asked_domain_family: "counterparty_value",
asked_action_family: "turnover"
}
}
})
}
});
expect(result.applied).toBe(false);
expect(result.decision).toBe("keep_current_reply");
expect(result.reply_text).toBe("ООО Ромашка | сумма: 128000 | операций: 3");
expect(result.reason_codes).toContain("mcp_discovery_response_policy_keep_full_confirmed_factual_address_reply");
});
it("keeps address lane answers when discovery was not requested for the current turn", () => {
const result = applyAssistantMcpDiscoveryResponsePolicy({
currentReply: "supported exact route answer",
@@ -1013,4 +1013,123 @@ describe("assistantTransitionPolicy", () => {
expect(carryover).toBeNull();
});
it("reuses grounded MCP discovery payout context for a short year-switch follow-up", () => {
const policy = buildPolicy({
findLastAddressAssistantItem: () => null,
hasAddressFollowupContextSignal: () => true
});
const carryover = policy.resolveAddressFollowupCarryoverContext(
"а теперь за 2021?",
[
{
role: "assistant",
text: "Подтверждены исходящие платежи по Группа СВК за 2020 год.",
debug: {
execution_lane: "living_chat",
mcp_discovery_response_applied: true,
assistant_active_organization: "ООО Альтернатива Плюс",
assistant_mcp_discovery_entry_point_v1: {
schema_version: "assistant_mcp_discovery_runtime_entry_point_v1",
entry_status: "bridge_executed",
turn_input: {
turn_meaning_ref: {
asked_action_family: "payout",
explicit_entity_candidates: ["Группа СВК"],
explicit_organization_scope: "ООО Альтернатива Плюс",
explicit_date_scope: "2020"
}
},
bridge: {
bridge_status: "answer_draft_ready",
business_fact_answer_allowed: true,
pilot: {
pilot_scope: "counterparty_supplier_payout_query_movements_v1"
},
answer_draft: {
answer_mode: "confirmed_with_bounded_inference"
}
}
}
}
}
],
null,
null,
null
);
expect(carryover?.followupSelectionMode).toBe("carry_previous_intent");
expect(carryover?.followupContext?.previous_intent).toBe("supplier_payouts_profile");
expect(carryover?.followupContext?.target_intent).toBe("supplier_payouts_profile");
expect(carryover?.followupContext?.previous_discovery_pilot_scope).toBe(
"counterparty_supplier_payout_query_movements_v1"
);
expect(carryover?.followupContext?.previous_anchor_type).toBe("counterparty");
expect(carryover?.followupContext?.previous_anchor_value).toBe("Группа СВК");
expect(carryover?.followupContext?.previous_filters).toMatchObject({
counterparty: "Группа СВК",
organization: "ООО Альтернатива Плюс",
period_from: "2020-01-01",
period_to: "2020-12-31"
});
});
it("switches to VAT tax-period intent while preserving carried period filters", () => {
const policy = buildPolicy({
findLastAddressAssistantItem: () => ({
text: "Подтвержденная дебиторская задолженность на 31.05.2017 собрана.",
debug: {
detected_intent: "receivables_confirmed_as_of_date",
extracted_filters: {
organization: 'ООО "Альтернатива Плюс"',
as_of_date: "2017-05-31",
period_from: "2017-05-01",
period_to: "2017-05-31"
},
anchor_type: "organization",
anchor_value_resolved: 'ООО "Альтернатива Плюс"'
}
}),
hasAddressFollowupContextSignal: () => true,
hasReferentialPointer: (value: unknown) => /этот период/i.test(String(value ?? "")),
resolveAddressIntent: () => ({ intent: "unknown" }),
resolveAddressIntentFamily: (intent: unknown) => {
if (String(intent ?? "").startsWith("receivables_")) return "receivables";
if (String(intent ?? "").startsWith("vat_")) return "vat";
return null;
},
resolveAssistantTurnMeaning: () => ({
schema_version: "assistant_turn_meaning_v1",
asked_domain_family: "vat",
asked_action_family: "confirmed_tax_period",
explicit_intent_candidate: "vat_liability_confirmed_for_tax_period",
explicit_entity_candidates: [],
intent_override_strength: "explicit_current_turn_intent",
stale_replay_forbidden: false
})
});
const carryover = policy.resolveAddressFollowupCarryoverContext(
"а какой ндс мы должны примерно заплатить за этот период?",
[],
"Какой НДС должен быть уплачен за текущий период?",
{
predecomposeContract: {
intent: "unknown"
}
},
null
);
expect(carryover?.followupSelectionMode).toBe("carry_previous_intent");
expect(carryover?.followupContext?.previous_intent).toBe("receivables_confirmed_as_of_date");
expect(carryover?.followupContext?.target_intent).toBe("vat_liability_confirmed_for_tax_period");
expect(carryover?.followupContext?.previous_filters).toMatchObject({
organization: 'ООО "Альтернатива Плюс"',
as_of_date: "2017-05-31",
period_from: "2017-05-01",
period_to: "2017-05-31"
});
});
});
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
import { createAssistantTurnMeaningPolicy } from "../src/services/assistantTurnMeaningPolicy";
import { resolveAddressIntent } from "../src/services/addressIntentResolver";
function buildPolicy() {
function buildPolicy(overrides: Record<string, unknown> = {}) {
return createAssistantTurnMeaningPolicy({
compactWhitespace: (value: string) => String(value ?? "").replace(/\s+/g, " ").trim(),
repairAddressMojibake: (value: string) => value,
@@ -13,7 +13,8 @@ function buildPolicy() {
}
const text = String(value).trim();
return text.length > 0 ? text : null;
}
},
...overrides
});
}
@@ -55,4 +56,41 @@ describe("assistantTurnMeaningPolicy", () => {
}
]);
});
it("ignores temporal tail words in all-time revenue ranking questions", () => {
const policy = buildPolicy({
resolveAddressIntent: (text: string) =>
text.includes("\u0434\u043e\u0445\u043e\u0434\u043d\u044b\u0439")
? { intent: "customer_revenue_and_payments", confidence: "high" }
: resolveAddressIntent(text)
});
const meaning = policy.resolveAssistantTurnMeaning({
rawUserMessage:
"\u043a\u0442\u043e \u0443 \u043d\u0430\u0441 \u0441\u0430\u043c\u044b\u0439 \u0434\u043e\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u0437\u0430 \u0432\u0441\u0435 \u0432\u0440\u0435\u043c\u044f"
});
expect(meaning.explicit_intent_candidate).toBe("customer_revenue_and_payments");
expect(meaning.explicit_entity_candidates).toEqual([]);
expect(meaning.stale_replay_forbidden).toBe(false);
});
it("treats VAT period questions as supported current-turn intent", () => {
const policy = buildPolicy({
resolveAddressIntent: (text: string) =>
text.includes("\u043d\u0434\u0441")
? { intent: "vat_liability_confirmed_for_tax_period", confidence: "high" }
: resolveAddressIntent(text)
});
const meaning = policy.resolveAssistantTurnMeaning({
rawUserMessage:
"\u0430 \u043a\u0430\u043a\u043e\u0439 \u043d\u0434\u0441 \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0437\u0430\u043f\u043b\u0430\u0442\u0438\u0442\u044c \u0437\u0430 \u044d\u0442\u043e\u0442 \u043f\u0435\u0440\u0438\u043e\u0434"
});
expect(meaning.explicit_intent_candidate).toBe("vat_liability_confirmed_for_tax_period");
expect(meaning.asked_domain_family).toBe("vat");
expect(meaning.asked_action_family).toBe("confirmed_tax_period");
expect(meaning.stale_replay_forbidden).toBe(false);
});
});