import assert from "node:assert/strict"; import test from "node:test"; import { buildCandidateContrastPacket, mentionedVargaKeysFromLedgerEvidence, remainingVargaSplits, selectDiscriminatorProbe, volunteeredDomainsFromEvidence, } from "../src/lib/rectification-agentic/core/candidate-contrast-packet.ts"; test("remaining D10 three-way outranks a skewed D24 split", () => { const packet = buildCandidateContrastPacket({ candidateSetVersion: "05:00-05:04", candidateTimes: ["05:00", "05:03", "05:04"], transitions: [ { layer: "d10", at: "05:03", from_sign: "巨蟹座", to_sign: "狮子座" }, { layer: "d10", at: "05:04", from_sign: "狮子座", to_sign: "处女座" }, { layer: "d24", at: "05:04", from_sign: "白羊座", to_sign: "金牛座" }, ], }); const probe = selectDiscriminatorProbe(packet); assert.ok(probe); assert.equal(probe.domain, "career"); assert.equal(probe.choiceKind, "varga_style"); assert.match(probe.semanticKey, /varga\.d10/); assert.doesNotMatch(probe.semanticKey, /varga\.d24/); assert.ok(packet.probes.some((item) => item.semanticKey.startsWith("varga.d24."))); assert.ok(packet.probes.some((item) => item.semanticKey.startsWith("varga.d10."))); assert.equal(probe.styleOptions?.length, 4); assert.equal(probe.expectedOutcomes.length, 4); assert.deepEqual(probe.expectedOutcomes.filter((row) => row.outcomeId !== "unsure").map((row) => row.supportsCandidateIds), [ ["05:00"], ["05:03"], ["05:04"], ]); }); test("two-way remaining D9 keeps the other minute on weak_yes, not no", () => { const packet = buildCandidateContrastPacket({ candidateSetVersion: "05:00-05:04", candidateTimes: ["05:00", "05:04"], transitions: [ { layer: "d9", at: "05:04", from_sign: "巨蟹座", to_sign: "狮子座" }, ], }); const probe = selectDiscriminatorProbe(packet); assert.ok(probe); assert.equal(probe.choiceKind, "varga_style"); assert.equal(probe.styleOptions?.length, 4); assert.deepEqual(probe.expectedOutcomes.find((row) => row.outcomeId === "yes")?.supportsCandidateIds, ["05:00"]); assert.deepEqual(probe.expectedOutcomes.find((row) => row.outcomeId === "weak_yes")?.supportsCandidateIds, ["05:04"]); assert.deepEqual(probe.expectedOutcomes.find((row) => row.outcomeId === "no")?.supportsCandidateIds, []); assert.equal(probe.styleOptions?.some((item) => item.answerClass === "unsure"), true); assert.doesNotMatch(probe.question, /不得发明年份|Opportunity/); assert.match(probe.authoringHint ?? "", /不得发明年份/); assert.match(probe.question, /相处|关系/); }); test("remaining D7 enters the pool as family existence", () => { const splits = remainingVargaSplits( ["05:00", "05:04"], [{ layer: "d7", at: "05:04", from_sign: "金牛座", to_sign: "双子座" }], ); assert.equal(splits[0]?.layer, "d7"); const packet = buildCandidateContrastPacket({ candidateSetVersion: "05:00-05:04", candidateTimes: ["05:00", "05:04"], remainingSplits: splits, }); const probe = selectDiscriminatorProbe(packet); assert.equal(probe?.domain, "family"); assert.equal(probe?.choiceKind, "existence"); assert.ok((probe?.informationGain ?? 0) > 0); assert.equal((probe?.expectedOutcomes.length ?? 0) >= 2, true); assert.match(probe?.candidateSplitHash ?? "", /05:00-05:04/); }); test("finance remaining splits stay out unless volunteered", () => { const hidden = remainingVargaSplits( ["05:00", "05:04"], [{ layer: "d2", at: "05:04" }], ); assert.equal(hidden.length, 0); const shown = remainingVargaSplits( ["05:00", "05:04"], [{ layer: "d2", at: "05:04" }], volunteeredDomainsFromEvidence([{ status: "confirmed", domain: "finance" }]), ); assert.equal(shown[0]?.layer, "d2"); }); test("existence probes leave the catalog once that domain already has dated evidence", () => { const packet = buildCandidateContrastPacket({ candidateSetVersion: "05:00-05:14", engineProbes: [{ semantic_key: "career.2023.dasha_activation", domain: "career", year: 2023, user_meaning: "时间范围锁定 2023 年前后。", information_gain: 0.56, expected_outcomes: [ { answer_class: "yes", supports: ["05:00"], conflicts: ["05:14"] }, { answer_class: "no", supports: ["05:14"], conflicts: ["05:00"] }, ], }], providedDomains: ["career"], candidateTimes: ["05:00", "05:07", "05:14"], transitions: [ { layer: "d24", at: "05:07", from_sign: "白羊座", to_sign: "金牛座" }, { layer: "d24", at: "05:14", from_sign: "金牛座", to_sign: "双子座" }, ], }); assert.equal(packet.probes.some((item) => item.semanticKey.includes("career.2023")), false); assert.match(selectDiscriminatorProbe(packet)?.semanticKey ?? "", /^varga\.d24\./); }); test("D9 remaining split without signs degrades to existence instead of dropping", () => { const packet = buildCandidateContrastPacket({ candidateSetVersion: "05:00-05:04", candidateTimes: ["05:00", "05:04"], transitions: [{ layer: "d9", at: "05:04" }], }); const probe = selectDiscriminatorProbe(packet); assert.ok(probe); assert.equal(probe.choiceKind, "existence"); assert.match(probe.semanticKey, /^varga\.d9\./); assert.equal(probe.styleOptions?.length, 4); assert.doesNotMatch(probe.question, /不得发明年份|Opportunity/); assert.ok(probe.question.trim().length >= 8); assert.deepEqual(probe.expectedOutcomes.find((row) => row.outcomeId === "yes")?.supportsCandidateIds, ["05:00"]); assert.deepEqual(probe.expectedOutcomes.find((row) => row.outcomeId === "weak_yes")?.supportsCandidateIds, ["05:00"]); assert.deepEqual(probe.expectedOutcomes.find((row) => row.outcomeId === "no")?.supportsCandidateIds, ["05:04"]); }); test("occupation mention does not skip remaining D10; answered varga.d10 still does", () => { const evidence = [{ status: "confirmed", domain: "occupation", eventKind: "occupation_note", summary: "互联网程序员 / 前端", }]; const mentioned = mentionedVargaKeysFromLedgerEvidence(evidence); assert.ok(mentioned.includes("varga.d10")); const transitions = [ { layer: "d10", at: "05:03", from_sign: "巨蟹座", to_sign: "狮子座" }, { layer: "d10", at: "05:04", from_sign: "狮子座", to_sign: "处女座" }, { layer: "d4", at: "05:04", from_sign: "金牛座", to_sign: "双子座" }, ]; const times = ["05:00", "05:03", "05:04"]; const mentionedPacket = buildCandidateContrastPacket({ candidateSetVersion: "05:00-05:04", candidateTimes: times, transitions, mentionedKeys: mentioned, }); assert.ok(mentionedPacket.probes.some((item) => item.semanticKey.startsWith("varga.d10."))); assert.match( selectDiscriminatorProbe(mentionedPacket, { mentionedKeys: mentioned })?.semanticKey ?? "", /^varga\.d4\./, ); const answeredPacket = buildCandidateContrastPacket({ candidateSetVersion: "05:00-05:04", candidateTimes: times, transitions, askedKeys: ["varga.d10"], }); assert.equal(answeredPacket.probes.some((item) => item.semanticKey.startsWith("varga.d10.")), false); });