ARCH: связать grounded value-flow follow-up с document evidence lane
This commit is contained in:
parent
acacada0f6
commit
bc54cd9628
|
|
@ -0,0 +1,97 @@
|
|||
{
|
||||
"schema_version": "domain_truth_harness_spec_v1",
|
||||
"scenario_id": "address_truth_harness_phase29_value_flow_to_documents_chain",
|
||||
"domain": "address_phase29_value_flow_to_documents_chain",
|
||||
"title": "Phase 29 grounded value-flow to document evidence replay",
|
||||
"description": "Targeted AGENT replay for Big Block C where a grounded counterparty and carried period must survive a pivot from value-flow answers into document evidence without forcing the user to restate the resolved name.",
|
||||
"bindings": {},
|
||||
"steps": [
|
||||
{
|
||||
"step_id": "step_01_resolve_counterparty_alias",
|
||||
"title": "Entity resolution grounds the checked 1C counterparty from a loose alias",
|
||||
"question": "найди в 1С контрагента СВК",
|
||||
"allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"],
|
||||
"required_answer_patterns_all": ["(?i)свк", "(?i)контрагент"],
|
||||
"required_answer_patterns_any": [
|
||||
"(?i)группа\\s+свк",
|
||||
"(?i)каталог",
|
||||
"(?i)найден",
|
||||
"(?i)наиболее вероятн"
|
||||
],
|
||||
"forbidden_answer_patterns": [
|
||||
"(?i)получили",
|
||||
"(?i)заплатили",
|
||||
"(?i)нетто",
|
||||
"(?i)оборот",
|
||||
"(?i)выручк",
|
||||
"(?i)сумм(а|ы)"
|
||||
],
|
||||
"criticality": "critical",
|
||||
"semantic_tags": ["entity_resolution", "alias_grounding", "followup_anchor"]
|
||||
},
|
||||
{
|
||||
"step_id": "step_02_incoming_by_resolved_entity",
|
||||
"title": "Incoming value-flow follow-up reuses the resolved counterparty anchor",
|
||||
"question": "сколько получили по нему за 2020 год",
|
||||
"allowed_reply_types": ["factual_with_explanation", "partial_coverage"],
|
||||
"required_answer_patterns_all": ["(?i)2020", "(?i)получил|входящ|поступ", "(?i)руб"],
|
||||
"required_answer_patterns_any": ["(?i)группа\\s+свк", "(?i)свк"],
|
||||
"forbidden_answer_patterns": [
|
||||
"(?i)не найден контрагент",
|
||||
"(?i)уточните, какого контрагента",
|
||||
"(?i)по какому контрагенту"
|
||||
],
|
||||
"criticality": "critical",
|
||||
"semantic_tags": ["entity_resolution", "incoming_value_flow", "followup_reuse"]
|
||||
},
|
||||
{
|
||||
"step_id": "step_03_payout_switch_by_resolved_entity",
|
||||
"title": "Outgoing payment follow-up keeps the same grounded counterparty and checked year",
|
||||
"question": "а теперь сколько заплатили?",
|
||||
"allowed_reply_types": ["factual_with_explanation", "partial_coverage"],
|
||||
"required_answer_patterns_all": ["(?i)2020", "(?i)заплатил|исходящ|списан|платеж", "(?i)руб"],
|
||||
"required_answer_patterns_any": ["(?i)группа\\s+свк", "(?i)свк"],
|
||||
"forbidden_answer_patterns": [
|
||||
"(?i)не найден контрагент",
|
||||
"(?i)уточните, какого контрагента",
|
||||
"(?i)по какому контрагенту",
|
||||
"(?i)за какой год"
|
||||
],
|
||||
"criticality": "critical",
|
||||
"semantic_tags": ["entity_resolution", "payout_switch", "followup_reuse", "date_carryover"]
|
||||
},
|
||||
{
|
||||
"step_id": "step_04_year_switch_on_payout",
|
||||
"title": "Short year switch keeps the payout contour and grounded counterparty",
|
||||
"question": "а за 2021?",
|
||||
"allowed_reply_types": ["factual_with_explanation", "partial_coverage"],
|
||||
"required_answer_patterns_all": ["(?i)2021", "(?i)заплатил|исходящ|списан|платеж", "(?i)руб"],
|
||||
"required_answer_patterns_any": ["(?i)группа\\s+свк", "(?i)свк"],
|
||||
"forbidden_answer_patterns": [
|
||||
"(?i)не найден контрагент",
|
||||
"(?i)уточните, какого контрагента",
|
||||
"(?i)по какому контрагенту"
|
||||
],
|
||||
"criticality": "critical",
|
||||
"semantic_tags": ["entity_resolution", "payout_year_switch", "followup_reuse"]
|
||||
},
|
||||
{
|
||||
"step_id": "step_05_documents_after_value_flow",
|
||||
"title": "Document evidence follow-up keeps the same grounded counterparty after the money answer",
|
||||
"question": "а по документам?",
|
||||
"allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"],
|
||||
"required_answer_patterns_all": ["(?i)документ|счет|накладн|акт"],
|
||||
"required_answer_patterns_any": ["(?i)группа\\s+свк", "(?i)свк", "(?i)2021"],
|
||||
"forbidden_answer_patterns": [
|
||||
"(?i)не найден контрагент",
|
||||
"(?i)уточните, какого контрагента",
|
||||
"(?i)по какому контрагенту",
|
||||
"(?i)сколько получили",
|
||||
"(?i)сколько заплатили",
|
||||
"(?i)нетто"
|
||||
],
|
||||
"criticality": "critical",
|
||||
"semantic_tags": ["entity_resolution", "document_evidence", "value_flow_pivot", "followup_reuse"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -537,6 +537,19 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
|||
followupSeed.pilotScope === "counterparty_value_flow_query_movements_v1" ||
|
||||
followupSeed.pilotScope === "counterparty_supplier_payout_query_movements_v1" ||
|
||||
followupSeed.pilotScope === "counterparty_bidirectional_value_flow_query_movements_v1"));
|
||||
const groundedValueFlowEvidenceSourceApplicable = Boolean((followupSeed.counterparty || followupSeed.discoveryEntity) &&
|
||||
!rawLifecycleSignal &&
|
||||
!rawValueFlowSignal &&
|
||||
!rawMetadataSignal &&
|
||||
(followupSeed.domain === "counterparty_value" ||
|
||||
followupSeed.action === "turnover" ||
|
||||
followupSeed.action === "payout" ||
|
||||
followupSeed.action === "net_value_flow" ||
|
||||
followupSeed.pilotScope === "counterparty_value_flow_query_movements_v1" ||
|
||||
followupSeed.pilotScope === "counterparty_supplier_payout_query_movements_v1" ||
|
||||
followupSeed.pilotScope === "counterparty_bidirectional_value_flow_query_movements_v1"));
|
||||
const valueFlowGroundedDocumentFollowupApplicable = Boolean(groundedValueFlowEvidenceSourceApplicable && metadataDocumentHintSignal);
|
||||
const valueFlowGroundedMovementFollowupApplicable = Boolean(groundedValueFlowEvidenceSourceApplicable && metadataMovementHintSignal);
|
||||
const documentEvidenceGroundedMovementFollowupApplicable = Boolean(followupSeed.pilotScope === "counterparty_document_evidence_query_documents_v1" &&
|
||||
(followupSeed.counterparty || followupSeed.discoveryEntity) &&
|
||||
!rawLifecycleSignal &&
|
||||
|
|
@ -594,12 +607,14 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
|||
const metadataGroundedDocumentLaneApplicable = metadataGroundedDocumentFollowupApplicable ||
|
||||
metadataAmbiguityResolvedDocumentFollowupApplicable ||
|
||||
entityResolutionGroundedDocumentFollowupApplicable ||
|
||||
valueFlowGroundedDocumentFollowupApplicable ||
|
||||
movementEvidenceGroundedDocumentFollowupApplicable ||
|
||||
(metadataGroundedLaneContinuationApplicable && followupSeed.metadataRouteFamily === "document_evidence") ||
|
||||
metadataAmbiguityCollapsedDocumentLaneContinuationApplicable;
|
||||
const metadataGroundedMovementLaneApplicable = metadataGroundedMovementFollowupApplicable ||
|
||||
metadataAmbiguityResolvedMovementFollowupApplicable ||
|
||||
entityResolutionGroundedMovementFollowupApplicable ||
|
||||
valueFlowGroundedMovementFollowupApplicable ||
|
||||
documentEvidenceGroundedMovementFollowupApplicable ||
|
||||
(metadataGroundedLaneContinuationApplicable && followupSeed.metadataRouteFamily === "movement_evidence") ||
|
||||
metadataAmbiguityCollapsedMovementLaneContinuationApplicable;
|
||||
|
|
@ -880,6 +895,12 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
|||
if (entityResolutionGroundedMovementFollowupApplicable) {
|
||||
pushReason(reasonCodes, "mcp_discovery_entity_resolution_grounded_movement_followup");
|
||||
}
|
||||
if (valueFlowGroundedDocumentFollowupApplicable) {
|
||||
pushReason(reasonCodes, "mcp_discovery_value_flow_grounded_document_followup");
|
||||
}
|
||||
if (valueFlowGroundedMovementFollowupApplicable) {
|
||||
pushReason(reasonCodes, "mcp_discovery_value_flow_grounded_movement_followup");
|
||||
}
|
||||
if (groundedValueFlowFollowupApplicable) {
|
||||
pushReason(reasonCodes, "mcp_discovery_grounded_value_flow_followup");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -732,6 +732,25 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
|||
followupSeed.pilotScope === "counterparty_supplier_payout_query_movements_v1" ||
|
||||
followupSeed.pilotScope === "counterparty_bidirectional_value_flow_query_movements_v1")
|
||||
);
|
||||
const groundedValueFlowEvidenceSourceApplicable = Boolean(
|
||||
(followupSeed.counterparty || followupSeed.discoveryEntity) &&
|
||||
!rawLifecycleSignal &&
|
||||
!rawValueFlowSignal &&
|
||||
!rawMetadataSignal &&
|
||||
(followupSeed.domain === "counterparty_value" ||
|
||||
followupSeed.action === "turnover" ||
|
||||
followupSeed.action === "payout" ||
|
||||
followupSeed.action === "net_value_flow" ||
|
||||
followupSeed.pilotScope === "counterparty_value_flow_query_movements_v1" ||
|
||||
followupSeed.pilotScope === "counterparty_supplier_payout_query_movements_v1" ||
|
||||
followupSeed.pilotScope === "counterparty_bidirectional_value_flow_query_movements_v1")
|
||||
);
|
||||
const valueFlowGroundedDocumentFollowupApplicable = Boolean(
|
||||
groundedValueFlowEvidenceSourceApplicable && metadataDocumentHintSignal
|
||||
);
|
||||
const valueFlowGroundedMovementFollowupApplicable = Boolean(
|
||||
groundedValueFlowEvidenceSourceApplicable && metadataMovementHintSignal
|
||||
);
|
||||
const documentEvidenceGroundedMovementFollowupApplicable = Boolean(
|
||||
followupSeed.pilotScope === "counterparty_document_evidence_query_documents_v1" &&
|
||||
(followupSeed.counterparty || followupSeed.discoveryEntity) &&
|
||||
|
|
@ -802,6 +821,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
|||
metadataGroundedDocumentFollowupApplicable ||
|
||||
metadataAmbiguityResolvedDocumentFollowupApplicable ||
|
||||
entityResolutionGroundedDocumentFollowupApplicable ||
|
||||
valueFlowGroundedDocumentFollowupApplicable ||
|
||||
movementEvidenceGroundedDocumentFollowupApplicable ||
|
||||
(metadataGroundedLaneContinuationApplicable && followupSeed.metadataRouteFamily === "document_evidence") ||
|
||||
metadataAmbiguityCollapsedDocumentLaneContinuationApplicable;
|
||||
|
|
@ -809,6 +829,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
|||
metadataGroundedMovementFollowupApplicable ||
|
||||
metadataAmbiguityResolvedMovementFollowupApplicable ||
|
||||
entityResolutionGroundedMovementFollowupApplicable ||
|
||||
valueFlowGroundedMovementFollowupApplicable ||
|
||||
documentEvidenceGroundedMovementFollowupApplicable ||
|
||||
(metadataGroundedLaneContinuationApplicable && followupSeed.metadataRouteFamily === "movement_evidence") ||
|
||||
metadataAmbiguityCollapsedMovementLaneContinuationApplicable;
|
||||
|
|
@ -1105,6 +1126,12 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
|||
if (entityResolutionGroundedMovementFollowupApplicable) {
|
||||
pushReason(reasonCodes, "mcp_discovery_entity_resolution_grounded_movement_followup");
|
||||
}
|
||||
if (valueFlowGroundedDocumentFollowupApplicable) {
|
||||
pushReason(reasonCodes, "mcp_discovery_value_flow_grounded_document_followup");
|
||||
}
|
||||
if (valueFlowGroundedMovementFollowupApplicable) {
|
||||
pushReason(reasonCodes, "mcp_discovery_value_flow_grounded_movement_followup");
|
||||
}
|
||||
if (groundedValueFlowFollowupApplicable) {
|
||||
pushReason(reasonCodes, "mcp_discovery_grounded_value_flow_followup");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -422,6 +422,154 @@ describe("assistant MCP discovery turn input adapter", () => {
|
|||
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: "а по месяцам?",
|
||||
|
|
|
|||
Loading…
Reference in New Issue