Files
Jyotisha/frontend/tests/rectification-distinguish-contract.test.ts
T
Jesse_Chen 0eb740a6b8
Independent Staging Quality Gate / validate (push) Successful in 10m33s
Independent Staging Quality Gate / publish (push) Successful in 16m24s
fix(rectification): keep holdout, D9 probes, and asked keys on the decision boundary
Reserve a month-or-better holdout, degrade unsigned D9/D10 to existence, and treat ledger keywords as mention-only so remaining discriminators stay in the pool.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 18:04:34 +08:00

199 lines
7.4 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import { applyProbeOutcome, outcomeForAnswer } from "../src/lib/rectification-agentic/core/apply-probe-outcome.ts";
import { buildInferenceState } from "../src/lib/rectification-agentic/core/build-state.ts";
import { distinguishContractErrors } from "../src/lib/rectification-agentic/core/distinguish-contract.ts";
import { probeFromEngine } from "../src/lib/rectification-agentic/core/probes-from-engine.ts";
import { parseDiscriminatingEventProbes } from "../src/lib/rectification-agentic/v9/refinement-packet.ts";
test("CI forbids distinguish probes with empty mapping or non-positive gain", () => {
assert.deepEqual(distinguishContractErrors({
role: "distinguish",
information_gain: 0,
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"] },
],
}), ["distinguish_non_positive_information_gain"]);
assert.deepEqual(distinguishContractErrors({
role: "distinguish",
information_gain: 0.4,
candidate_ids: [],
expected_outcomes: [
{ answer_class: "yes", supports: [], conflicts: [] },
{ answer_class: "no", supports: [], conflicts: [] },
],
}), ["distinguish_empty_candidate_ids"]);
assert.deepEqual(distinguishContractErrors({
role: "distinguish",
information_gain: 0.4,
candidate_ids: ["05:00", "05:20"],
expected_outcomes: [],
}), ["distinguish_empty_expected_outcomes"]);
});
test("receipt parser drops invalid distinguish probes and known_event_quality", () => {
const parsed = parseDiscriminatingEventProbes([
{
year: 2016,
year_label: "2016 年前后",
domain: "education",
event_family: "学业变化",
source: "known_event_quality",
tracks: ["vimshottari", "narayana"],
tracks_agree: true,
unique_minute_claim: false,
user_meaning: "clarification only",
role: "distinguish",
information_gain: 0,
},
{
year: 2018,
year_label: "2018 年前后",
domain: "career",
event_family: "职责变化",
source: "dasha_activation",
tracks: ["vimshottari", "narayana"],
tracks_agree: true,
unique_minute_claim: false,
user_meaning: "engine locked year and family",
role: "distinguish",
information_gain: 0.4,
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"] },
],
},
]);
assert.equal(parsed.length, 1);
assert.equal(parsed[0]?.domain, "career");
assert.equal(parsed[0]?.source, "dasha_activation");
assert.ok((parsed[0]?.information_gain ?? 0) > 0);
});
test("receipt parser keeps engine month on dasha boundary probes", () => {
const parsed = parseDiscriminatingEventProbes([{
year: 2018,
month: 3,
year_label: "2018 年 3 月前后",
domain: "career",
event_family: "职责变化",
source: "dasha_boundary",
tracks: ["vimshottari", "narayana"],
tracks_agree: true,
unique_minute_claim: false,
user_meaning: "时间范围锁定 2018 年 3 月前后",
role: "distinguish",
information_gain: 0.4,
semantic_key: "career.2018.03.dasha_boundary",
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"] },
],
}]);
assert.equal(parsed[0]?.month, 3);
assert.equal(parsed[0]?.year_label, "2018 年 3 月前后");
assert.equal(parsed[0]?.source, "dasha_boundary");
});
test("randomized hidden mutated answers change posterior only when mapped", () => {
const probe = probeFromEngine({
year: 2018,
year_label: "2018 年前后",
domain: "career",
event_family: "职责变化",
source: "dasha_activation",
tracks: ["vimshottari", "narayana"],
tracks_agree: true,
unique_minute_claim: false,
user_meaning: "engine locked year and family",
role: "distinguish",
information_gain: 0.4,
semantic_key: "career.2018",
candidate_split_hash: "set:career:2018",
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"] },
{ answer_class: "unsure", supports: [], conflicts: [] },
],
});
assert.ok(probe);
const scores = { "05:00": 10, "05:20": 10 };
const yes = applyProbeOutcome(scores, probe, "yes");
assert.equal(yes.kind, "informative");
assert.notDeepEqual(yes.scores, scores);
assert.ok(yes.deltas["05:00"] !== 0);
const mutated = applyProbeOutcome(scores, probe, "unsure");
assert.equal(mutated.kind, "low_information");
assert.deepEqual(mutated.scores, scores);
const state = buildInferenceState({
range_start: "05:00",
range_end: "05:20",
candidates: [
{ id: "05:00", time: "05:00", relative_support: 10 },
{ id: "05:20", time: "05:20", relative_support: 10 },
],
events: [
{ id: "e1", domain: "education", year: 2016, precision: "month" },
{ id: "e2", domain: "career", year: 2018, precision: "year" },
{ id: "e3", domain: "family", year: 2020, precision: "year" },
],
probes: [probe],
answered_probes: [{
probe_id: probe.id,
semantic_key: probe.semantic_key,
candidate_split_hash: probe.candidate_split_hash,
answer_class: "unsure",
classified_from: "choice",
}],
});
assert.equal(state.last_inference_round?.kind, "low_information");
assert.deepEqual(state.last_inference_round?.scores_before, state.last_inference_round?.scores_after);
assert.equal(
state.rounds.filter((item) => item.kind === "informative").length,
0,
);
});
test("existence weak_yes shares yes mapping at half weight and never eliminates on one answer", () => {
const probe = probeFromEngine({
year: 2018,
year_label: "2018 年前后",
domain: "career",
event_family: "职责变化",
source: "dasha_activation",
tracks: ["vimshottari", "narayana"],
tracks_agree: true,
unique_minute_claim: false,
user_meaning: "时间范围锁定 2018 年前后",
role: "distinguish",
information_gain: 0.4,
semantic_key: "career.2018",
candidate_split_hash: "set:career:2018",
candidate_ids: ["05:00", "05:20"],
expected_outcomes: [
{ answer_class: "yes", supports: ["05:00"], conflicts: ["05:20"] },
{ answer_class: "weak_yes", supports: ["05:00"], conflicts: ["05:20"] },
{ answer_class: "no", supports: ["05:20"], conflicts: ["05:00"] },
{ answer_class: "unsure", supports: [], conflicts: [] },
],
});
assert.ok(probe);
assert.deepEqual(outcomeForAnswer(probe, "yes")?.supports, outcomeForAnswer(probe, "weak_yes")?.supports);
assert.deepEqual(outcomeForAnswer(probe, "yes")?.conflicts, outcomeForAnswer(probe, "weak_yes")?.conflicts);
const scores = { "05:00": 10, "05:20": 10 };
const yes = applyProbeOutcome(scores, probe, "yes");
const weak = applyProbeOutcome(scores, probe, "weak_yes");
assert.equal(yes.deltas["05:00"], 2);
assert.equal(yes.deltas["05:20"], -2);
assert.equal(weak.deltas["05:00"], 1);
assert.equal(weak.deltas["05:20"], -1);
assert.deepEqual(weak.eliminated_ids, []);
assert.equal(weak.kind, "informative");
});