import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import test from "node:test"; import { inspectDiscriminatorProbes } from "../src/lib/rectification-agentic/core/candidate-contrast-packet.ts"; import { EXISTENCE_STYLE_OPTIONS, QUALITY_STYLE_OPTIONS, QUESTION_CONTRACT_VERSION, canonicalProbeQuestionContractJson, completeStyleOptions, isRenderableProbe, rankDiscriminatorScore, } from "../src/lib/rectification-agentic/v9/probe-question-contract.ts"; const GOLDEN = readFileSync(new URL("../../contracts/probe-question-v1.json", import.meta.url), "utf8"); test("existence probes complete to four answer classes without engine style_options", () => { const completed = completeStyleOptions({ choiceKind: "existence" }); assert.equal(completed.ok, true); assert.deepEqual(completed.ok ? completed.options : null, [...EXISTENCE_STYLE_OPTIONS]); assert.equal(QUESTION_CONTRACT_VERSION, "probe-question-v1"); }); test("event_quality probes use quality labels and still cover unsure", () => { const completed = completeStyleOptions({ choiceKind: "event_quality" }); assert.equal(completed.ok, true); assert.deepEqual(completed.ok ? completed.options : null, [...QUALITY_STYLE_OPTIONS]); assert.equal(completed.ok && completed.options.some((item) => item.answer_class === "unsure"), true); }); test("varga-style probes stay dynamic and fail closed without two scoring labels", () => { const rejected = completeStyleOptions({ choiceKind: "varga_style", styleOptions: [{ label: "巨蟹相处主动热情", answer_class: "yes" }], }); assert.equal(rejected.ok, false); assert.equal(rejected.ok ? null : rejected.reason, "varga_insufficient_scoring"); const completed = completeStyleOptions({ choiceKind: "varga_style", styleOptions: [ { label: "巨蟹相处主动热情", answer_class: "yes", sign: "巨蟹" }, { label: "狮子独立强势", answer_class: "weak_yes", sign: "狮子" }, ], }); assert.equal(completed.ok, true); assert.equal(completed.ok ? completed.options.length : 0, 4); assert.equal(completed.ok ? completed.options.find((item) => item.answer_class === "no")?.label : null, "都不是这些特质"); assert.equal(completed.ok ? completed.options.find((item) => item.answer_class === "unsure")?.label : null, "这段记不清楚"); }); test("illegal clock or appearance copy cannot become a renderable probe", () => { assert.equal(isRenderableProbe({ informationGain: 1.2, candidateIds: ["05:00", "05:04"], expectedOutcomeCount: 2, choiceKind: "existence", styleOptions: [ { label: "08:12 左右发生", answer_class: "yes" }, ], }).ok, true); const filled = completeStyleOptions({ choiceKind: "existence", styleOptions: [{ label: "08:12 左右发生", answer_class: "yes" }], }); assert.equal(filled.ok ? filled.options.find((item) => item.answer_class === "yes")?.label : null, "明确发生且时间吻合"); const appearance = isRenderableProbe({ informationGain: 1.2, candidateIds: ["05:00", "05:04"], expectedOutcomeCount: 2, choiceKind: "varga_style", styleOptions: [ { label: "外貌更接近第一种", answer_class: "yes" }, { label: "相处更独立", answer_class: "weak_yes" }, ], }); assert.equal(appearance.ok, false); assert.equal(appearance.ok ? null : appearance.reason, "forbidden_copy"); }); test("duplicate visible labels uniquify with an index, not answer_class", () => { const completed = completeStyleOptions({ choiceKind: "varga_style", styleOptions: [ { label: "相处主动热情", answer_class: "yes" }, { label: "相处主动热情", answer_class: "weak_yes" }, ], }); assert.equal(completed.ok, true); const labels = completed.ok ? completed.options.map((item) => item.label) : []; assert.equal(labels.includes("相处主动热情·2"), true); assert.equal(labels.some((item) => item.includes("weak_yes") || item.includes("·yes")), false); assert.equal(new Set(labels).size, 4); }); test("unrenderable contrast probes are dropped with a reason, not selected", () => { const inspected = inspectDiscriminatorProbes({ candidateSetVersion: "set", vargaDifferences: [], probes: [{ probeId: "contrast:varga.d9.a/b", candidateSetVersion: "set", question: "亲密关系里更接近下面哪一种相处方式?", expectedOutcomes: [ { outcomeId: "yes", supportsCandidateIds: ["05:00"], conflictsCandidateIds: ["05:10"] }, { outcomeId: "weak_yes", supportsCandidateIds: ["05:10"], conflictsCandidateIds: ["05:00"] }, ], candidateSplitHash: "set:varga.d9", informationGain: 1.2, sourceFeatures: [], domain: "relationship", year: null, semanticKey: "varga.d9.foo/bar", choiceKind: "varga_style", styleOptions: [ { label: "外貌更接近第一种", answerClass: "yes" }, { label: "外貌更接近第二种", answerClass: "weak_yes" }, ], }], }); assert.equal(inspected.selected, null); assert.equal(inspected.dropped[0]?.reason, "forbidden_copy"); assert.equal(inspected.dropped[0]?.semantic_key, "varga.d9.foo/bar"); }); test("TypeScript contract JSON matches the golden file byte for byte", () => { assert.equal(canonicalProbeQuestionContractJson(), GOLDEN); }); test("asked probes keep a novelty penalty so unused high-gain probes rank first", () => { const askedCareer = rankDiscriminatorScore({ informationGain: 0.56, asked: true, candidateIds: ["05:00", "05:07"], }); const unusedD24 = rankDiscriminatorScore({ informationGain: 2.5, asked: false, candidateIds: ["05:00", "05:07", "05:10"], }); assert.ok(unusedD24 > askedCareer); assert.ok(unusedD24 > 0.56); });