АРЧ АП11 - Выделить truth и answer-shape policy в assistant runtime
This commit is contained in:
@@ -64,6 +64,16 @@ describe("assistant address lane response runtime adapter", () => {
|
||||
address_followup_offer: { suggestion: "continue_previous" },
|
||||
assistant_runtime_contract_v1: expect.objectContaining({
|
||||
schema_version: "assistant_runtime_contracts_v1"
|
||||
}),
|
||||
assistant_truth_answer_policy_v1: expect.objectContaining({
|
||||
schema_version: "assistant_truth_answer_policy_runtime_v1",
|
||||
policy_owner: "assistantTruthAnswerPolicyRuntimeAdapter"
|
||||
}),
|
||||
coverage_gate_contract: expect.objectContaining({
|
||||
schema_version: "assistant_truth_answer_policy_runtime_v1"
|
||||
}),
|
||||
answer_shape_contract: expect.objectContaining({
|
||||
reply_type: "factual"
|
||||
})
|
||||
})
|
||||
);
|
||||
@@ -107,9 +117,21 @@ describe("assistant address lane response runtime adapter", () => {
|
||||
capability_contract_id: null,
|
||||
truth_gate_contract_status: "unknown"
|
||||
}),
|
||||
assistant_truth_answer_policy_v1: expect.objectContaining({
|
||||
schema_version: "assistant_truth_answer_policy_runtime_v1"
|
||||
}),
|
||||
coverage_gate_contract: expect.objectContaining({
|
||||
coverage_status: "blocked",
|
||||
truth_mode: "unsupported"
|
||||
}),
|
||||
answer_shape_contract: expect.objectContaining({
|
||||
answer_shape: "blocked_no_answer",
|
||||
reply_type: "partial_coverage"
|
||||
}),
|
||||
transition_contract_id: null,
|
||||
capability_contract_id: null,
|
||||
truth_gate_contract_status: "unknown"
|
||||
truth_gate_contract_status: "unknown",
|
||||
carryover_eligibility: "none"
|
||||
})
|
||||
);
|
||||
expect(runtime.response).toEqual({ ok: true });
|
||||
|
||||
@@ -116,6 +116,24 @@ describe("assistant debug payload assembler", () => {
|
||||
expect(payload.address_llm_predecompose_applied).toBe(true);
|
||||
expect(payload.assistant_outcome_class_v1).toBe("FULLY_ANSWERED");
|
||||
expect(payload.answer_contract_stage4_v1?.is_stage4_shape).toBe(true);
|
||||
expect(payload.assistant_truth_answer_policy_v1).toEqual(
|
||||
expect.objectContaining({
|
||||
schema_version: "assistant_truth_answer_policy_runtime_v1",
|
||||
policy_owner: "assistantTruthAnswerPolicyRuntimeAdapter"
|
||||
})
|
||||
);
|
||||
expect(payload.coverage_gate_contract).toEqual(
|
||||
expect.objectContaining({
|
||||
coverage_status: "full",
|
||||
truth_mode: "confirmed"
|
||||
})
|
||||
);
|
||||
expect(payload.answer_shape_contract).toEqual(
|
||||
expect.objectContaining({
|
||||
answer_shape: "confirmed_factual",
|
||||
reply_type: "deep_analysis"
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("omits optional fields when they are not provided", () => {
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
attachAssistantTruthAnswerPolicy,
|
||||
resolveAssistantTruthAnswerPolicyRuntime
|
||||
} from "../src/services/assistantTruthAnswerPolicyRuntimeAdapter";
|
||||
|
||||
describe("assistant truth answer policy runtime adapter", () => {
|
||||
it("emits confirmed truth gate and factual answer shape for grounded exact results", () => {
|
||||
const policy = resolveAssistantTruthAnswerPolicyRuntime({
|
||||
addressDebug: {
|
||||
capability_id: "confirmed_inventory_on_hand_as_of_date",
|
||||
detected_intent: "inventory_on_hand_as_of_date",
|
||||
rows_matched: 3,
|
||||
route_expectation_status: "matched",
|
||||
evidence_strength: "strong"
|
||||
},
|
||||
groundingStatus: "grounded",
|
||||
replyType: "factual"
|
||||
});
|
||||
|
||||
expect(policy.truth_gate).toEqual(
|
||||
expect.objectContaining({
|
||||
schema_version: "assistant_truth_answer_policy_runtime_v1",
|
||||
policy_owner: "assistantTruthAnswerPolicyRuntimeAdapter",
|
||||
coverage_status: "full",
|
||||
grounding_status: "grounded",
|
||||
truth_mode: "confirmed",
|
||||
evidence_grade: "strong",
|
||||
source_truth_gate_status: "full_confirmed",
|
||||
carryover_eligibility: "root_only",
|
||||
blocked_or_limited_explanation: null
|
||||
})
|
||||
);
|
||||
expect(policy.answer_shape).toEqual(
|
||||
expect.objectContaining({
|
||||
answer_shape: "confirmed_factual",
|
||||
reply_type: "factual",
|
||||
capability_contract_id: "confirmed_inventory_on_hand_as_of_date",
|
||||
transition_contract_id: "T1",
|
||||
may_state_confirmed_facts: true,
|
||||
must_include_limitation: false,
|
||||
may_power_followup: true,
|
||||
required_sections: ["direct_answer", "evidence_basis"],
|
||||
downgrade_only: true
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps temporal/contextual limits as limited answer shape with explicit reason codes", () => {
|
||||
const policy = resolveAssistantTruthAnswerPolicyRuntime({
|
||||
addressDebug: {
|
||||
capability_id: "confirmed_inventory_on_hand_as_of_date",
|
||||
temporal_guard_outcome: "ambiguous_limited",
|
||||
rows_matched: 2,
|
||||
limitations: ["period_window_auto_broadened_to_available_data"]
|
||||
},
|
||||
groundingStatus: "partial",
|
||||
replyType: "partial_coverage"
|
||||
});
|
||||
|
||||
expect(policy.truth_gate.coverage_status).toBe("partial");
|
||||
expect(policy.truth_gate.truth_mode).toBe("limited");
|
||||
expect(policy.truth_gate.source_truth_gate_status).toBe("limited_temporal_or_contextual");
|
||||
expect(policy.truth_gate.blocked_or_limited_explanation).toBe("temporal_or_contextual_limit");
|
||||
expect(policy.truth_gate.reason_codes).toContain("period_window_auto_broadened_to_available_data");
|
||||
expect(policy.answer_shape.answer_shape).toBe("limited_with_reason");
|
||||
expect(policy.answer_shape.must_include_limitation).toBe(true);
|
||||
expect(policy.answer_shape.required_sections).toEqual(["direct_answer", "evidence_window", "limitations"]);
|
||||
});
|
||||
|
||||
it("blocks route expectation failures and prevents follow-up carryover", () => {
|
||||
const policy = resolveAssistantTruthAnswerPolicyRuntime({
|
||||
addressDebug: {
|
||||
capability_id: "confirmed_inventory_on_hand_as_of_date",
|
||||
route_expectation_status: "mismatch",
|
||||
route_expectation_reason: "expected_confirmed_balance_route"
|
||||
},
|
||||
groundingStatus: "route_mismatch_blocked",
|
||||
replyType: "partial_coverage"
|
||||
});
|
||||
|
||||
expect(policy.truth_gate.coverage_status).toBe("blocked");
|
||||
expect(policy.truth_gate.grounding_status).toBe("route_mismatch_blocked");
|
||||
expect(policy.truth_gate.truth_mode).toBe("unsupported");
|
||||
expect(policy.truth_gate.carryover_eligibility).toBe("none");
|
||||
expect(policy.truth_gate.reason_codes).toContain("expected_confirmed_balance_route");
|
||||
expect(policy.answer_shape.answer_shape).toBe("blocked_no_answer");
|
||||
expect(policy.answer_shape.may_state_confirmed_facts).toBe(false);
|
||||
expect(policy.answer_shape.may_power_followup).toBe(false);
|
||||
});
|
||||
|
||||
it("attaches top-level debug fields without hiding the nested contract", () => {
|
||||
const debug = attachAssistantTruthAnswerPolicy(
|
||||
{
|
||||
capability_id: "inventory_inventory_purchase_provenance_for_item",
|
||||
missing_required_filters: ["item"],
|
||||
limited_reason_category: "missing_anchor"
|
||||
},
|
||||
{
|
||||
replyType: "partial_coverage"
|
||||
}
|
||||
);
|
||||
|
||||
expect(debug.assistant_truth_answer_policy_v1.schema_version).toBe("assistant_truth_answer_policy_runtime_v1");
|
||||
expect(debug.coverage_gate_contract.truth_mode).toBe("clarification_required");
|
||||
expect(debug.answer_shape_contract.answer_shape).toBe("clarification_required");
|
||||
expect(debug.truth_mode).toBe("clarification_required");
|
||||
expect(debug.carryover_eligibility).toBe("none");
|
||||
expect(debug.answer_shape).toBe("clarification_required");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user