ARCH: защитить documents pivot от inventory selected-object drift
This commit is contained in:
parent
d7ee95286d
commit
5acb016573
|
|
@ -0,0 +1,65 @@
|
||||||
|
{
|
||||||
|
"schema_version": "domain_truth_harness_spec_v1",
|
||||||
|
"scenario_id": "address_truth_harness_phase78_payments_to_contracts_all_time",
|
||||||
|
"domain": "address_phase78_payments_to_contracts_all_time",
|
||||||
|
"title": "Phase 78 payments to contracts all-time continuity",
|
||||||
|
"description": "Replay for a human chain where the user opens documents by counterparty, pivots to payments, then pivots again to contracts via pronoun follow-up, and finally requests the same contracts for all available time without renaming the counterparty.",
|
||||||
|
"bindings": {},
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"step_id": "step_01_documents_by_counterparty",
|
||||||
|
"title": "Open documents for the counterparty",
|
||||||
|
"question": "Покажи документы по Жуковке 51.",
|
||||||
|
"allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)жуковк",
|
||||||
|
"(?i)документ|сч[её]т|акт|накладн|строк"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": ["documents_by_counterparty", "pivot_seed", "integrity_guard"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"step_id": "step_02_payments_by_pronoun_followup",
|
||||||
|
"title": "Pivot to payments",
|
||||||
|
"question": "А по нему платежи?",
|
||||||
|
"allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)жуковк|контрагент",
|
||||||
|
"(?i)платеж|операц|банк|поступлен|списан"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": ["payments_followup", "counterparty_pronoun_resolution", "integrity_guard"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"step_id": "step_03_contracts_after_payments_pivot",
|
||||||
|
"title": "Pivot again to contracts",
|
||||||
|
"question": "А по нему договоры?",
|
||||||
|
"allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)жуковк|контрагент",
|
||||||
|
"(?i)договор|контракт|соглаш"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": ["contracts_followup", "second_pivot", "integrity_guard"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"step_id": "step_04_all_time_after_second_pivot",
|
||||||
|
"title": "Request all available time after the second pivot",
|
||||||
|
"question": "А за все время?",
|
||||||
|
"allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)жуковк|контрагент",
|
||||||
|
"(?i)договор|контракт|соглаш"
|
||||||
|
],
|
||||||
|
"forbidden_answer_patterns": [
|
||||||
|
"(?i)уточните .* контрагент",
|
||||||
|
"(?i)уточните .* период",
|
||||||
|
"(?i)метадан",
|
||||||
|
"(?i)схем",
|
||||||
|
"(?i)объект[а-я]* 1с"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": ["all_time_after_second_pivot", "contracts_followup", "integrity_guard"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
{
|
||||||
|
"schema_version": "domain_truth_harness_spec_v1",
|
||||||
|
"scenario_id": "address_truth_harness_phase79_payments_to_contracts_to_documents_year_switch",
|
||||||
|
"domain": "address_phase79_payments_to_contracts_to_documents_year_switch",
|
||||||
|
"title": "Phase 79 payments to contracts to documents year-switch continuity",
|
||||||
|
"description": "Replay for a human chain where the user opens documents by counterparty, pivots to payments, then to contracts, then back to documents by pronoun follow-up, and finally narrows the same document contour to 2021 without renaming the counterparty.",
|
||||||
|
"bindings": {},
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"step_id": "step_01_documents_by_counterparty",
|
||||||
|
"title": "Open documents for the counterparty",
|
||||||
|
"question": "Покажи документы по Жуковке 51.",
|
||||||
|
"allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)жуковк",
|
||||||
|
"(?i)документ|сч[её]т|акт|накладн|строк"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": ["documents_by_counterparty", "pivot_seed", "integrity_guard"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"step_id": "step_02_payments_by_pronoun_followup",
|
||||||
|
"title": "Pivot to payments",
|
||||||
|
"question": "А по нему платежи?",
|
||||||
|
"allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)жуковк|контрагент",
|
||||||
|
"(?i)платеж|операц|банк|поступлен|списан"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": ["payments_followup", "counterparty_pronoun_resolution", "integrity_guard"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"step_id": "step_03_contracts_after_payments_pivot",
|
||||||
|
"title": "Pivot to contracts",
|
||||||
|
"question": "А по нему договоры?",
|
||||||
|
"allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)жуковк|контрагент",
|
||||||
|
"(?i)договор|контракт|соглаш"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": ["contracts_followup", "second_pivot", "integrity_guard"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"step_id": "step_04_documents_after_contracts_pivot",
|
||||||
|
"title": "Pivot back to documents",
|
||||||
|
"question": "А по нему документы?",
|
||||||
|
"allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)жуковк|контрагент",
|
||||||
|
"(?i)документ|сч[её]т|акт|накладн|строк"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": ["documents_followup", "third_pivot", "integrity_guard"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"step_id": "step_05_year_switch_after_third_pivot",
|
||||||
|
"title": "Switch the year after the third pivot",
|
||||||
|
"question": "А за 2021?",
|
||||||
|
"allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)2021",
|
||||||
|
"(?i)жуковк|контрагент",
|
||||||
|
"(?i)документ|сч[её]т|акт|накладн|строк"
|
||||||
|
],
|
||||||
|
"forbidden_answer_patterns": [
|
||||||
|
"(?i)уточните .* контрагент",
|
||||||
|
"(?i)метадан",
|
||||||
|
"(?i)схем",
|
||||||
|
"(?i)объект[а-я]* 1с"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": ["year_switch_after_third_pivot", "documents_followup", "integrity_guard"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -1152,7 +1152,15 @@ function deriveIntentWithFollowupContext(detectedIntent, userMessage, followupCo
|
||||||
const hasAnyPartyAnchor = hasPreviousContract || hasPreviousCounterparty;
|
const hasAnyPartyAnchor = hasPreviousContract || hasPreviousCounterparty;
|
||||||
const isVatFollowup = hasVatCue(normalizedMessage);
|
const isVatFollowup = hasVatCue(normalizedMessage);
|
||||||
const previousIsInventoryFamily = isInventoryIntent(sourceIntent ?? undefined);
|
const previousIsInventoryFamily = isInventoryIntent(sourceIntent ?? undefined);
|
||||||
const inventorySelectedObjectFollowup = hasSelectedObjectInventorySignal(normalizedMessage) || (previousIsInventoryFamily && hasFollowupSignal);
|
const rootIsInventoryFamily = isInventoryIntent(followupContext.root_intent ?? undefined);
|
||||||
|
const inventoryLineageActive = previousIsInventoryFamily ||
|
||||||
|
rootIsInventoryFamily ||
|
||||||
|
followupContext.previous_anchor_type === "item" ||
|
||||||
|
followupContext.root_anchor_type === "item" ||
|
||||||
|
followupContext.current_frame_kind === "inventory_root" ||
|
||||||
|
followupContext.current_frame_kind === "inventory_drilldown";
|
||||||
|
const inventorySelectedObjectFollowup = inventoryLineageActive &&
|
||||||
|
(hasSelectedObjectInventorySignal(normalizedMessage) || (previousIsInventoryFamily && hasFollowupSignal));
|
||||||
const inventoryPurchaseDateVatBridge = inventorySelectedObjectFollowup && hasInventoryPurchaseDateVatBridgeCue(normalizedMessage);
|
const inventoryPurchaseDateVatBridge = inventorySelectedObjectFollowup && hasInventoryPurchaseDateVatBridgeCue(normalizedMessage);
|
||||||
if (inventoryPurchaseDateVatBridge &&
|
if (inventoryPurchaseDateVatBridge &&
|
||||||
(detectedIntent.intent === "unknown" ||
|
(detectedIntent.intent === "unknown" ||
|
||||||
|
|
|
||||||
|
|
@ -1440,8 +1440,17 @@ function deriveIntentWithFollowupContext(
|
||||||
const hasAnyPartyAnchor = hasPreviousContract || hasPreviousCounterparty;
|
const hasAnyPartyAnchor = hasPreviousContract || hasPreviousCounterparty;
|
||||||
const isVatFollowup = hasVatCue(normalizedMessage);
|
const isVatFollowup = hasVatCue(normalizedMessage);
|
||||||
const previousIsInventoryFamily = isInventoryIntent(sourceIntent ?? undefined);
|
const previousIsInventoryFamily = isInventoryIntent(sourceIntent ?? undefined);
|
||||||
|
const rootIsInventoryFamily = isInventoryIntent(followupContext.root_intent ?? undefined);
|
||||||
|
const inventoryLineageActive =
|
||||||
|
previousIsInventoryFamily ||
|
||||||
|
rootIsInventoryFamily ||
|
||||||
|
followupContext.previous_anchor_type === "item" ||
|
||||||
|
followupContext.root_anchor_type === "item" ||
|
||||||
|
followupContext.current_frame_kind === "inventory_root" ||
|
||||||
|
followupContext.current_frame_kind === "inventory_drilldown";
|
||||||
const inventorySelectedObjectFollowup =
|
const inventorySelectedObjectFollowup =
|
||||||
hasSelectedObjectInventorySignal(normalizedMessage) || (previousIsInventoryFamily && hasFollowupSignal);
|
inventoryLineageActive &&
|
||||||
|
(hasSelectedObjectInventorySignal(normalizedMessage) || (previousIsInventoryFamily && hasFollowupSignal));
|
||||||
const inventoryPurchaseDateVatBridge =
|
const inventoryPurchaseDateVatBridge =
|
||||||
inventorySelectedObjectFollowup && hasInventoryPurchaseDateVatBridgeCue(normalizedMessage);
|
inventorySelectedObjectFollowup && hasInventoryPurchaseDateVatBridgeCue(normalizedMessage);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4632,6 +4632,22 @@ describe("address decompose stage follow-up carryover", () => {
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not drift into inventory selected-object documents on a counterparty contracts follow-up", () => {
|
||||||
|
const result = runAddressDecomposeStage("а по нему документы?", {
|
||||||
|
previous_intent: "list_contracts_by_counterparty",
|
||||||
|
target_intent: "list_documents_by_counterparty",
|
||||||
|
previous_filters: {
|
||||||
|
counterparty: "ТСЖ \\Жуковка 51\\"
|
||||||
|
},
|
||||||
|
previous_anchor_type: "counterparty",
|
||||||
|
previous_anchor_value: "ТСЖ \\Жуковка 51\\"
|
||||||
|
});
|
||||||
|
expect(result).not.toBeNull();
|
||||||
|
expect(result?.intent.intent).toBe("list_documents_by_counterparty");
|
||||||
|
expect(result?.filters.extracted_filters.counterparty).toBe("ТСЖ \\Жуковка 51\\");
|
||||||
|
expect(result?.baseReasons).not.toContain("intent_adjusted_to_inventory_followup_context");
|
||||||
|
});
|
||||||
|
|
||||||
it("replaces 'кроме этого документа...' pseudo-anchor with previous counterparty from follow-up context", () => {
|
it("replaces 'кроме этого документа...' pseudo-anchor with previous counterparty from follow-up context", () => {
|
||||||
const result = runAddressDecomposeStage("кроме этого документа есть еще чтото?", {
|
const result = runAddressDecomposeStage("кроме этого документа есть еще чтото?", {
|
||||||
previous_intent: "list_documents_by_counterparty",
|
previous_intent: "list_documents_by_counterparty",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue