import { describe, expect, it } from "vitest"; import { resolveAddressTruthGate } from "../src/services/addressTruthGatePolicy"; describe("address truth gate policy", () => { it("treats factual exact no-match as confirmed negative with reusable root scope", () => { const gate = resolveAddressTruthGate({ intent: "open_items_by_counterparty_or_contract", filters: { account: "60", period_from: "2022-08-01", period_to: "2022-08-31" }, selectedRecipe: "open_items_by_counterparty_or_contract", rowsMatched: 0, limitedReasonCategory: "empty_match", runtimeReadiness: "LIVE_QUERYABLE_WITH_LIMITS", reasons: ["open_items_account_exact_negative_response"], routeExpectationStatus: "matched", replyType: "factual" }); expect(gate.truth_gate_status).toBe("full_confirmed"); expect(gate.carryover_eligibility).toBe("root_only"); expect(gate.blocked_or_limited_explanation).toBeNull(); expect(gate.reason_codes).toContain("limited_category_empty_match"); }); it("keeps selected-item limited answers object-scoped", () => { const gate = resolveAddressTruthGate({ intent: "inventory_sale_trace_for_item", filters: { item: "Рабочая станция" }, semanticFrame: { scope_kind: "selected_object_scope", anchor_kind: "selected_object", anchor_value: "Рабочая станция", date_scope_kind: "explicit", date_basis_hint: "explicit_as_of_date", self_scope_detected: false, selected_object_scope_detected: true }, selectedRecipe: "inventory_sale_trace_for_item", rowsMatched: 0, limitedReasonCategory: "empty_match", runtimeReadiness: "LIVE_QUERYABLE_WITH_LIMITS", limitations: ["no_rows_after_recipe_and_scope_filter"], routeExpectationStatus: "matched", replyType: "partial_coverage" }); expect(gate.truth_gate_status).toBe("partial_supported"); expect(gate.carryover_eligibility).toBe("object_only"); expect(gate.blocked_or_limited_explanation).toBe("evidence_or_coverage_is_partial"); }); it("blocks missing-anchor clarifications instead of pretending they are reusable evidence", () => { const gate = resolveAddressTruthGate({ intent: "inventory_purchase_provenance_for_item", selectedRecipe: "inventory_purchase_provenance_for_item", rowsMatched: 0, limitedReasonCategory: "missing_anchor", runtimeReadiness: "LIVE_QUERYABLE_WITH_LIMITS", missingRequiredFilters: ["item"], limitations: ["missing_required_filters"], routeExpectationStatus: "matched", replyType: "partial_coverage" }); expect(gate.truth_gate_status).toBe("blocked_missing_anchor"); expect(gate.carryover_eligibility).toBe("none"); expect(gate.blocked_or_limited_explanation).toBe("required_anchor_missing"); expect(gate.reason_codes).toContain("missing_filter_item"); }); });