import assert from "node:assert/strict"; import test from "node:test"; import { readFileSync } from "node:fs"; import { buildCandidateContrastPacket, inspectDiscriminatorProbes, isSameCandidateSplit, mentionedVargaKeysFromLedgerEvidence, remainingVargaSplits, selectDiscriminatorProbe, splitHashForCandidateSet, 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, }); assert.ok(packet.probes.some((item) => item.domain === "family" && item.choiceKind === "existence")); const inspected = inspectDiscriminatorProbes(packet); assert.equal(inspected.selected, null); assert.equal(inspected.dropped.some((item) => item.reason === "yearless_ungrounded_contrast"), true); }); 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 year already has dated evidence, not the whole domain", () => { 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")), true); const askedSameYear = 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"] }, ], }], askedKeys: ["career.2023"], 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(askedSameYear.probes.some((item) => item.semanticKey.includes("career.2023")), false); assert.ok(packet.probes.some((item) => item.semanticKey.startsWith("varga.d24."))); const inspected = inspectDiscriminatorProbes(packet); assert.equal(inspected.selected?.semanticKey.includes("career.2023"), true); assert.equal(inspected.dropped.some((item) => ( item.semantic_key.startsWith("varga.d24.") && item.reason === "yearless_ungrounded_contrast" )), true); }); test("D9 remaining split without signs stays in the packet as existence but is not a card", () => { const packet = buildCandidateContrastPacket({ candidateSetVersion: "05:00-05:04", candidateTimes: ["05:00", "05:04"], transitions: [{ layer: "d9", at: "05:04" }], }); const inPacket = packet.probes.find((item) => item.semanticKey.startsWith("varga.d9.")); assert.ok(inPacket); assert.equal(inPacket.choiceKind, "existence"); const inspected = inspectDiscriminatorProbes(packet); assert.equal(inspected.selected, null); assert.equal(inspected.dropped.some((item) => ( item.semantic_key.startsWith("varga.d9.") && item.reason === "yearless_ungrounded_contrast" )), true); }); 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\.d10\./, ); 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); assert.equal(selectDiscriminatorProbe(answeredPacket)?.semanticKey.startsWith("varga.d4.") ?? false, false); }); test("a stale candidate-set prefix is re-minted instead of stacked", () => { const current = "05:00-05:07:05:00,05:06,05:07"; const stale = "05:00-05:07:05:00,05:05,05:07"; const key = "varga.d9.05:00|05:06/05:07"; assert.equal(splitHashForCandidateSet(`${stale}:${key}`, key, current), `${current}:${key}`); assert.equal(splitHashForCandidateSet(`${current}:${key}`, key, current), `${current}:${key}`); assert.equal(splitHashForCandidateSet(null, key, current), `${current}:${key}`); // opaque engine hashes stay scoped exactly once assert.equal(splitHashForCandidateSet("f4cc4975", "career.2023", current), `${current}:f4cc4975`); assert.equal( splitHashForCandidateSet(`${current}:f4cc4975`, "career.2023", current), `${current}:f4cc4975`, ); }); test("engine probes keep one candidate-set prefix after the set changes", () => { const current = "05:00-05:07:05:00,05:06,05:07"; const stale = "05:00-05:07:05:00,05:05,05:07"; const key = "varga.d9.05:00|05:06/05:07"; const packet = buildCandidateContrastPacket({ candidateSetVersion: current, candidateTimes: ["05:00", "05:06", "05:07"], engineProbes: [{ semantic_key: key, candidate_split_hash: `${stale}:${key}`, domain: "relationship", user_meaning: "亲密关系里更接近下面哪一种相处方式?", information_gain: 1.53, choice_kind: "varga_style", expected_outcomes: [ { answer_class: "yes", supports: ["05:00"], conflicts: ["05:06", "05:07"] }, { answer_class: "no", supports: ["05:07"], conflicts: ["05:00", "05:06"] }, ], }], }); const probe = packet.probes.find((item) => item.semanticKey === key); assert.ok(probe); assert.equal(probe.candidateSplitHash, `${current}:${key}`); assert.doesNotMatch(probe.candidateSplitHash, /05:05/); }); test("split identity ignores the candidate-set prefix but not the probe", () => { const key = "varga.d9.05:00|05:06/05:07"; assert.equal(isSameCandidateSplit(`a:${key}`, `b:${key}`, key), true); assert.equal(isSameCandidateSplit(`a:${key}`, `a:varga.d10.05:00|05:06/05:07`, key), false); assert.equal(isSameCandidateSplit("f4cc4975", "a:f4cc4975", "career.2023"), false); assert.equal(isSameCandidateSplit("f4cc4975", "f4cc4975", "career.2023"), true); }); test("scoring scopes the contrast packet to the candidate set it just produced", () => { const source = readFileSync(new URL("../src/mastra/rectification-v9-tools.ts", import.meta.url), "utf8"); const packetCall = source.slice( source.indexOf("const scoredCandidateSetId = candidateSetId("), source.indexOf("const inference = buildCaseInferenceState("), ); assert.ok(packetCall.includes("candidateSetVersion: scoredCandidateSetId")); assert.doesNotMatch(packetCall, /candidateSetVersion:\s*previousInferenceFromReceipt/); });