import assert from "node:assert/strict"; import test from "node:test"; import { persistServerOwnedFocus, shouldSkipDiscriminatorFollowup, stableFollowupQuestionId } from "../src/lib/rectification-agentic/v9/server-focus.ts"; import { buildChoiceFrame, serverOwnedChoiceCopy } from "../src/lib/rectification-agentic/v9/choice-card.ts"; import type { MethodFollowup } from "../src/lib/rectification-agentic/v9/method-followup.ts"; import { fakeAccounting, CASE_ID, FOCUS_ID, USER_ID, activeFocusFixture } from "./rectification-v9-test-support.ts"; function discriminatorFollowup(overrides: Partial = {}): MethodFollowup { const frame = buildChoiceFrame({ method_id: "dasha_events", ask_theme: "dated_event", domain: "education", user_prompt_hint: "ask", }, { probes: [{ year: 2016, year_label: "2016 年前后", domain: "education", event_family: "高考或重要考试发挥明显失常", source: "dasha_activation", tracks: ["vimshottari", "narayana"], tracks_agree: true, unique_minute_claim: false, user_meaning: "2016 年前后高考或重要考试发挥明显失常", role: "distinguish", information_gain: 0.4, semantic_key: "education:2016", }], }); return { method_id: "dasha_events", intent: "distinguish_candidates", ask_theme: "dated_event", domain: "education", kind_hint: null, user_prompt_hint: "ask", must_not_label: false, choice_frame: frame, source: "event_probe", information_gain: 0.4, semantic_key: "education:2016", probe_year: 2016, ...overrides, }; } test("does not ask an already-answered discriminator probe again", async () => { const followup = discriminatorFollowup(); const active = activeFocusFixture({ expectedAnswerSchema: { probe_id: "education:2016", choice: serverOwnedChoiceCopy(followup.choice_frame!) }, }); const accounting = fakeAccounting({ set_agentic_rectification_conversation_focus: () => { throw new Error("should not create a second focus"); }, }); const result = await persistServerOwnedFocus({ accounting: accounting.client, userId: USER_ID, caseId: CASE_ID, activeFocus: { ...active, id: FOCUS_ID, caseId: CASE_ID, questionId: stableFollowupQuestionId(followup), intent: "distinguish_candidates", targetEvidenceId: null, targetDomain: "education", targetKind: null, expectedAnswerSchema: { probe_id: "education:2016" }, status: "active", askedAt: "2026-08-24T00:00:00.000Z", resolvedAt: null, }, decisionReceipt: { inference_state: { answered_probes: [{ probe_id: "education:2016", semantic_key: "education:2016", answer_class: "yes" }], probes: [], }, }, followup, }); assert.equal(result.status, "probe_already_answered"); assert.equal(accounting.calls.length, 0); }); test("zero information gain does not open a discriminator", () => { assert.equal( shouldSkipDiscriminatorFollowup(discriminatorFollowup({ information_gain: 0 })), "zero_information_gain", ); }); test("duplicate focus conflict does not throw", async () => { const followup = discriminatorFollowup({ source: "precision_stage", information_gain: 0.2 }); const accounting = fakeAccounting({ set_agentic_rectification_conversation_focus: () => { throw new Error("agentic_rectification_focus_idempotency_conflict"); }, }); const result = await persistServerOwnedFocus({ accounting: accounting.client, userId: USER_ID, caseId: CASE_ID, activeFocus: null, decisionReceipt: null, followup, }); assert.equal(result.status, "duplicate_focus"); }); test("contrast probe is not replaced by an already-answered education quality probe", async () => { const followup = discriminatorFollowup({ domain: "education", ask_theme: "education_style", information_gain: 0.16, semantic_key: "varga.d24.05:00/05:06|05:07", candidate_split_hash: "varga.d24.05:00/05:06|05:07", probe_year: undefined, }); const accounting = fakeAccounting({ set_agentic_rectification_conversation_focus: (_fn, args) => ({ id: FOCUS_ID, case_id: CASE_ID, question_id: args.p_question_id, intent: args.p_intent, target_evidence_id: null, target_domain: args.p_target_domain, target_kind: args.p_target_kind, expected_answer_schema: args.p_expected_answer_schema, status: "active", asked_at: "2026-08-25T00:00:00.000Z", resolved_at: null, idempotent: false, }), }); const result = await persistServerOwnedFocus({ accounting: accounting.client, userId: USER_ID, caseId: CASE_ID, activeFocus: null, decisionReceipt: { inference_state: { answered_probes: [{ probe_id: "probe:education.2016", semantic_key: "education.2016", answer_class: "yes", }], probes: [{ id: "probe:education.2016", semantic_key: "education.2016", candidate_split_hash: "education:2016", domain: "education", year: 2016, question: "发挥失常", candidate_ids: [], expected_outcomes: [], information_gain: 0, source: "known_event_quality", }], }, }, followup, }); assert.equal(result.status, "created"); assert.ok(result.focus); const schema = result.focus.expectedAnswerSchema; assert.equal(schema.semantic_key, "varga.d24.05:00/05:06|05:07"); assert.notEqual(schema.probe_id, "probe:education.2016"); assert.match(String(schema.probe_id), /varga\.d24/); });