Files
Jyotisha/frontend/tests/rectification-probe-year-dedupe-20260906.test.ts
T
Jesse_ChenandCursor 3a9ae736e1 fix(rectification): dedupe same-domain probe years and drop unanchored style cards (BUG-559)
Pass asked probe keys into the engine without changing result fingerprints, block nearby years already asked, and require a dated same-domain ledger event before rendering varga_style cards.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-06 23:03:11 +08:00

160 lines
5.8 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import {
buildMethodFollowupPlan,
datedLedgerAnchor,
existenceProbeAsked,
remainingReverseVerifyProbes,
type MethodFollowupEvidence,
} from "../src/lib/rectification-agentic/v9/method-followup.ts";
import type { DiscriminatingEventProbe } from "../src/lib/rectification-agentic/v9/refinement-packet.ts";
import type { CandidateContrastPacket } from "../src/lib/rectification-agentic/core/candidate-contrast-packet.ts";
function existenceProbe(
domain: DiscriminatingEventProbe["domain"],
year: number,
extra: { month?: number; source?: DiscriminatingEventProbe["source"]; key?: string } = {},
): DiscriminatingEventProbe {
const month = extra.month;
const source = extra.source ?? "dasha_boundary";
const key = extra.key
?? (month
? `${domain}.${year}.${String(month).padStart(2, "0")}.${source}`
: `${domain}.${year}.${source}`);
return {
year,
year_label: month ? `${year}${month} 月前后` : `${year} 年前后`,
month,
domain,
event_family: "入职、升职或职责明显加重",
source,
tracks: ["vimshottari", "narayana"],
tracks_agree: true,
unique_minute_claim: false,
user_meaning: `时间范围锁定 ${year} 年。`,
role: "distinguish",
information_gain: 1.1,
semantic_key: key,
candidate_split_hash: key,
candidate_ids: ["05:00", "05:20"],
expected_outcomes: [
{ answer_class: "yes", supports: ["05:00"], conflicts: ["05:20"] },
{ answer_class: "no", supports: ["05:20"], conflicts: ["05:00"] },
],
choice_kind: "existence",
};
}
function dated(
id: string,
domain: string,
eventKind: string,
occurredFrom: string,
): MethodFollowupEvidence {
return {
id,
status: "confirmed",
domain,
datePrecision: "month",
occurredFrom,
occurredTo: null,
eventKind,
};
}
const D10_STYLE: CandidateContrastPacket["probes"][number] = {
probeId: "contrast:varga.d10.巨蟹座/狮子座",
candidateSetVersion: "05:00-05:20",
question: "平时做事,你更接近下面哪一种?",
expectedOutcomes: [
{ outcomeId: "yes", supportsCandidateIds: ["05:00"], conflictsCandidateIds: ["05:20"] },
{ outcomeId: "weak_yes", supportsCandidateIds: ["05:20"], conflictsCandidateIds: ["05:00"] },
],
candidateSplitHash: "varga.d10.巨蟹座/狮子座",
informationGain: 1.4,
sourceFeatures: [{ technique: "D10", calculationResultId: null }],
domain: "career",
year: null,
semanticKey: "varga.d10.巨蟹座/狮子座",
choiceKind: "varga_style",
styleOptions: [
{ label: "做事以照顾人为主,在意团队里的感受", answerClass: "yes", sign: "巨蟹座" },
{ label: "习惯带头,也不排斥站到台前", answerClass: "weak_yes", sign: "狮子座" },
],
};
test("existenceProbeAsked treats the same career year and nearby years as already asked", () => {
const asked = ["career.2018.05.dasha_boundary"];
assert.equal(existenceProbeAsked(asked, "career", 2018), true);
assert.equal(existenceProbeAsked(asked, "career", 2017), true);
assert.equal(existenceProbeAsked(asked, "career", 2019), true);
assert.equal(existenceProbeAsked(asked, "career", 2020), false);
assert.equal(existenceProbeAsked(asked, "finance", 2018), false);
});
test("remaining reverse-verify probes drop same-domain nearby years after a month probe", () => {
const remaining = remainingReverseVerifyProbes(
[
existenceProbe("career", 2018, { month: 5 }),
existenceProbe("career", 2018, { source: "dasha_activation" }),
existenceProbe("career", 2017, { month: 5 }),
existenceProbe("career", 2019, { month: 5 }),
existenceProbe("career", 2020, { month: 5 }),
],
[],
new Set(),
new Set(["career.2018.05.dasha_boundary"]),
);
const years = remaining.filter((item) => item.domain === "career").map((item) => item.year);
assert.equal(years.includes(2017), false);
assert.equal(years.includes(2018), false);
assert.equal(years.includes(2019), false);
assert.equal(years.includes(2020), true);
});
test("datedLedgerAnchor names the confirmed same-domain month", () => {
const anchor = datedLedgerAnchor([
dated("e-career-month", "career", "career_entry", "2018-07-01"),
], "career");
assert.ok(anchor);
assert.equal(anchor?.label, "2018 年 7 月");
assert.equal(datedLedgerAnchor([
dated("e-edu", "education", "education_start", "2016-09-01"),
], "career"), null);
});
test("unanchored D10 varga_style cards are dropped; anchored cards mention the ledger month", () => {
const baseEvidence = [
dated("e-edu", "education", "education_start", "2016-09-01"),
dated("e-edu-2", "education", "education_completion", "2020-06-01"),
dated("e-rel", "relationship", "relationship_start", "2024-05-01"),
dated("e-fin", "finance", "finance_loss", "2021-01-01"),
];
const packet = {
candidateSetVersion: "05:00-05:20",
vargaDifferences: [] as const,
probes: [D10_STYLE],
};
const unanchored = buildMethodFollowupPlan({
evidence: baseEvidence,
contrastPacket: packet,
candidatesSeparated: false,
});
assert.equal(
unanchored.dropped_probes.some((item) => item.reason === "unanchored_varga_style"),
true,
);
assert.notEqual(unanchored.next_followup?.semantic_key, D10_STYLE.semanticKey);
const anchored = buildMethodFollowupPlan({
evidence: [...baseEvidence, dated("e-career", "career", "career_entry", "2018-07-01")],
contrastPacket: packet,
candidatesSeparated: false,
});
assert.equal(anchored.next_followup?.semantic_key, D10_STYLE.semanticKey);
assert.equal(anchored.next_followup?.choice_kind, "varga_style");
assert.match(anchored.next_followup?.user_prompt_hint ?? "", /2018 年 7 月/);
assert.doesNotMatch(anchored.next_followup?.choice_frame?.prompt ?? "", /2018/);
});