ARCH: удержать contracts pivot после payments follow-up
This commit is contained in:
parent
7e1a2edadb
commit
d7ee95286d
|
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"schema_version": "domain_truth_harness_spec_v1",
|
||||
"scenario_id": "address_truth_harness_phase76_contracts_to_payments_all_time",
|
||||
"domain": "address_phase76_contracts_to_payments_all_time",
|
||||
"title": "Phase 76 contracts to payments all-time continuity",
|
||||
"description": "Replay for a human chain where the user opens documents by counterparty, pivots to contracts, then pivots again to payments via pronoun follow-up, and finally switches to all-time scope 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_contracts_by_pronoun_followup",
|
||||
"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", "counterparty_pronoun_resolution", "integrity_guard"]
|
||||
},
|
||||
{
|
||||
"step_id": "step_03_payments_after_contracts_pivot",
|
||||
"title": "Pivot again to payments",
|
||||
"question": "А по нему платежи?",
|
||||
"allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"],
|
||||
"required_answer_patterns_all": [
|
||||
"(?i)жуковк|контрагент",
|
||||
"(?i)платеж|операц|банк|поступлен|списан"
|
||||
],
|
||||
"criticality": "critical",
|
||||
"semantic_tags": ["payments_followup", "second_pivot", "integrity_guard"]
|
||||
},
|
||||
{
|
||||
"step_id": "step_04_all_time_after_second_pivot",
|
||||
"title": "Switch to all-time scope 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)объект[а-я]* 1с"
|
||||
],
|
||||
"criticality": "critical",
|
||||
"semantic_tags": ["all_time_after_second_pivot", "payments_followup", "integrity_guard"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
{
|
||||
"schema_version": "domain_truth_harness_spec_v1",
|
||||
"scenario_id": "address_truth_harness_phase77_payments_to_contracts_year_switch",
|
||||
"domain": "address_phase77_payments_to_contracts_year_switch",
|
||||
"title": "Phase 77 payments to contracts year-switch 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 switches the year 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_year_switch_after_second_pivot",
|
||||
"title": "Switch the year after the second 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_second_pivot", "contracts_followup", "integrity_guard"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -554,6 +554,7 @@ function createAssistantTransitionPolicy(deps) {
|
|||
!shortValueFlowRetargetPrimary &&
|
||||
!shortValueFlowRetargetAlternate &&
|
||||
!hasImplicitContinuationSignal &&
|
||||
!hasSuggestedIntentPivotSignal &&
|
||||
!hasOrganizationClarificationContinuation &&
|
||||
!hasIndexReferenceSignal) {
|
||||
return null;
|
||||
|
|
@ -567,6 +568,7 @@ function createAssistantTransitionPolicy(deps) {
|
|||
!shortValueFlowRetargetPrimary &&
|
||||
!shortValueFlowRetargetAlternate &&
|
||||
!hasImplicitContinuationSignal &&
|
||||
!hasSuggestedIntentPivotSignal &&
|
||||
!hasOrganizationClarificationContinuation &&
|
||||
!hasIndexReferenceSignal) {
|
||||
return null;
|
||||
|
|
@ -683,6 +685,7 @@ function createAssistantTransitionPolicy(deps) {
|
|||
}
|
||||
hasPrimaryFollowupSignal =
|
||||
deps.hasAddressFollowupContextSignal(userMessage) ||
|
||||
hasSuggestedIntentPivotSignal ||
|
||||
Boolean(debtRoleSwapPrimary) ||
|
||||
shortValueFlowRetargetPrimary ||
|
||||
inventoryShortFollowupPrimary ||
|
||||
|
|
@ -690,6 +693,7 @@ function createAssistantTransitionPolicy(deps) {
|
|||
hasInventoryRootTemporalFollowupPrimary;
|
||||
hasAlternateFollowupSignal = deps.toNonEmptyString(alternateMessage)
|
||||
? deps.hasAddressFollowupContextSignal(alternateMessage) ||
|
||||
hasSuggestedIntentPivotSignal ||
|
||||
Boolean(debtRoleSwapAlternate) ||
|
||||
shortValueFlowRetargetAlternate ||
|
||||
inventoryShortFollowupAlternate ||
|
||||
|
|
@ -700,6 +704,7 @@ function createAssistantTransitionPolicy(deps) {
|
|||
hasPrimaryIndexReferenceSignal ||
|
||||
hasAlternateIndexReferenceSignal ||
|
||||
hasOrganizationClarificationContinuation ||
|
||||
hasSuggestedIntentPivotSignal ||
|
||||
hasImplicitContinuationSignal ||
|
||||
inventoryShortFollowupPrimary ||
|
||||
inventoryShortFollowupAlternate ||
|
||||
|
|
|
|||
|
|
@ -751,6 +751,7 @@ export function createAssistantTransitionPolicy(deps) {
|
|||
!shortValueFlowRetargetPrimary &&
|
||||
!shortValueFlowRetargetAlternate &&
|
||||
!hasImplicitContinuationSignal &&
|
||||
!hasSuggestedIntentPivotSignal &&
|
||||
!hasOrganizationClarificationContinuation &&
|
||||
!hasIndexReferenceSignal
|
||||
) {
|
||||
|
|
@ -766,6 +767,7 @@ export function createAssistantTransitionPolicy(deps) {
|
|||
!shortValueFlowRetargetPrimary &&
|
||||
!shortValueFlowRetargetAlternate &&
|
||||
!hasImplicitContinuationSignal &&
|
||||
!hasSuggestedIntentPivotSignal &&
|
||||
!hasOrganizationClarificationContinuation &&
|
||||
!hasIndexReferenceSignal
|
||||
) {
|
||||
|
|
@ -944,6 +946,7 @@ export function createAssistantTransitionPolicy(deps) {
|
|||
}
|
||||
hasPrimaryFollowupSignal =
|
||||
deps.hasAddressFollowupContextSignal(userMessage) ||
|
||||
hasSuggestedIntentPivotSignal ||
|
||||
Boolean(debtRoleSwapPrimary) ||
|
||||
shortValueFlowRetargetPrimary ||
|
||||
inventoryShortFollowupPrimary ||
|
||||
|
|
@ -951,6 +954,7 @@ export function createAssistantTransitionPolicy(deps) {
|
|||
hasInventoryRootTemporalFollowupPrimary;
|
||||
hasAlternateFollowupSignal = deps.toNonEmptyString(alternateMessage)
|
||||
? deps.hasAddressFollowupContextSignal(alternateMessage) ||
|
||||
hasSuggestedIntentPivotSignal ||
|
||||
Boolean(debtRoleSwapAlternate) ||
|
||||
shortValueFlowRetargetAlternate ||
|
||||
inventoryShortFollowupAlternate ||
|
||||
|
|
@ -961,6 +965,7 @@ export function createAssistantTransitionPolicy(deps) {
|
|||
hasPrimaryIndexReferenceSignal ||
|
||||
hasAlternateIndexReferenceSignal ||
|
||||
hasOrganizationClarificationContinuation ||
|
||||
hasSuggestedIntentPivotSignal ||
|
||||
hasImplicitContinuationSignal ||
|
||||
inventoryShortFollowupPrimary ||
|
||||
inventoryShortFollowupAlternate ||
|
||||
|
|
|
|||
|
|
@ -737,6 +737,52 @@ describe("assistantTransitionPolicy", () => {
|
|||
expect(contract.decision_reasons).toContain("suggested_intent_followup_pivot");
|
||||
});
|
||||
|
||||
it("switches from payments to suggested contracts on a pronoun follow-up even when generic follow-up signal is weak", () => {
|
||||
const policy = buildPolicy({
|
||||
findLastAddressAssistantItem: () => ({
|
||||
text: "Собран список банковских операций по контрагенту ТСЖ \\Жуковка 51\\.",
|
||||
debug: {
|
||||
detected_intent: "bank_operations_by_counterparty",
|
||||
extracted_filters: {
|
||||
counterparty: "ТСЖ \\Жуковка 51\\"
|
||||
},
|
||||
anchor_type: "counterparty",
|
||||
anchor_value_resolved: "ТСЖ \\Жуковка 51\\"
|
||||
}
|
||||
}),
|
||||
buildAddressFollowupOffer: () => ({
|
||||
enabled: true,
|
||||
source_intent: "bank_operations_by_counterparty",
|
||||
suggested_intents: ["list_documents_by_counterparty", "list_contracts_by_counterparty"]
|
||||
}),
|
||||
hasAddressFollowupContextSignal: () => false,
|
||||
hasReferentialPointer: () => true
|
||||
});
|
||||
|
||||
const carryover = policy.resolveAddressFollowupCarryoverContext("А по нему договоры?", [], null, null, null);
|
||||
|
||||
expect(carryover?.followupContext?.previous_intent).toBe("list_contracts_by_counterparty");
|
||||
expect(carryover?.followupContext?.target_intent).toBe("list_contracts_by_counterparty");
|
||||
expect(carryover?.followupContext?.previous_anchor_type).toBe("counterparty");
|
||||
expect(carryover?.hasSuggestedIntentPivotSignal).toBe(true);
|
||||
expect(carryover?.followupSelectionMode).toBe("switch_to_suggested_intent");
|
||||
|
||||
const contract = policy.buildAddressDialogContinuationContractV2(
|
||||
"А по нему договоры?",
|
||||
"Покажи договоры, связанные с указанным объектом",
|
||||
carryover,
|
||||
{
|
||||
predecomposeContract: {
|
||||
intent: "unknown"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
expect(contract.decision).toBe("switch_to_suggested");
|
||||
expect(contract.target_intent).toBe("list_contracts_by_counterparty");
|
||||
expect(contract.decision_reasons).toContain("suggested_intent_followup_pivot");
|
||||
});
|
||||
|
||||
it("keeps root-scoped carryover for foreign accounting pivot over inventory drilldown", () => {
|
||||
const policy = buildPolicy({
|
||||
findLastAddressAssistantItem: () => ({
|
||||
|
|
|
|||
Loading…
Reference in New Issue