АРЧ АП11 - Вынести exact-lane truth gate для factual-negative и limited ответов в отдельный policy-owner

This commit is contained in:
2026-04-17 09:41:29 +03:00
parent 6b14946f7e
commit dc8dfcf237
12 changed files with 1001 additions and 154 deletions
@@ -0,0 +1,75 @@
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");
});
});
@@ -143,4 +143,27 @@ describe("assistant runtime contract registry", () => {
expect(decision.truth_gate_contract_status).toBe("limited_temporal_or_contextual");
});
it("reuses explicit exact-lane truth gate contracts for factual no-match carryover", () => {
const decision = resolveAssistantRuntimeContractShadow({
addressDebug: {
detected_intent: "open_items_by_counterparty_or_contract",
selected_recipe: "open_items_by_counterparty_or_contract",
rows_matched: 0,
address_truth_gate_v1: {
schema_version: "address_truth_gate_v1",
policy_owner: "addressTruthGatePolicy",
truth_gate_status: "full_confirmed",
carryover_eligibility: "root_only",
limited_reason_category: "empty_match",
runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS",
reason_codes: ["open_items_account_exact_negative_response"],
blocked_or_limited_explanation: null
}
}
});
expect(decision.truth_gate_contract_status).toBe("full_confirmed");
expect(decision.carryover_eligibility).toBe("root_only");
});
});
@@ -89,6 +89,34 @@ describe("assistant truth answer policy runtime adapter", () => {
expect(policy.answer_shape.may_power_followup).toBe(false);
});
it("honors explicit exact-lane truth gate contracts for factual negative answers", () => {
const policy = resolveAssistantTruthAnswerPolicyRuntime({
addressDebug: {
capability_id: "inventory_counterparty_item_flow",
rows_matched: 0,
address_truth_gate_v1: {
schema_version: "address_truth_gate_v1",
policy_owner: "addressTruthGatePolicy",
truth_gate_status: "full_confirmed",
carryover_eligibility: "root_only",
limited_reason_category: "empty_match",
runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS",
reason_codes: ["counterparty_item_flow_exact_negative_response"],
blocked_or_limited_explanation: null
}
},
replyType: "factual"
});
expect(policy.truth_gate.coverage_status).toBe("full");
expect(policy.truth_gate.grounding_status).toBe("grounded");
expect(policy.truth_gate.truth_mode).toBe("confirmed");
expect(policy.truth_gate.carryover_eligibility).toBe("root_only");
expect(policy.truth_gate.reason_codes).toContain("counterparty_item_flow_exact_negative_response");
expect(policy.answer_shape.answer_shape).toBe("confirmed_factual");
expect(policy.answer_shape.may_power_followup).toBe(true);
});
it("attaches top-level debug fields without hiding the nested contract", () => {
const debug = attachAssistantTruthAnswerPolicy(
{