Files
Jyotisha/frontend/tests/rectification-holdout-renderable.test.ts
T
2026-08-29 00:30:04 +08:00

213 lines
7.2 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import { applyHoldoutAnswer } from "../src/lib/rectification-agentic/core/build-state.ts";
import { decideFromDossier, rectificationFollowupCatalog } from "../src/lib/rectification-agentic/v9/decision-from-dossier.ts";
import { buildCaseInferenceState } from "../src/lib/rectification-agentic/v9/inference-adapter.ts";
import { buildMethodFollowupPlan } from "../src/lib/rectification-agentic/v9/method-followup.ts";
import { evidenceLedgerFingerprint } from "../src/lib/rectification-agentic/v9/tool-service.ts";
import type { InferenceState } from "../src/lib/rectification-agentic/core/types.ts";
const COVERED_EVIDENCE = [
{
id: "e-edu",
status: "confirmed",
domain: "education",
datePrecision: "year",
occurredFrom: "2016-01-01",
occurredTo: null,
eventKind: "education_milestone",
},
{
id: "e-career-a",
status: "confirmed",
domain: "career",
datePrecision: "year",
occurredFrom: "2018-01-01",
occurredTo: null,
eventKind: "career_entry",
},
{
id: "e-career-b",
status: "confirmed",
domain: "career",
datePrecision: "year",
occurredFrom: "2020-01-01",
occurredTo: null,
eventKind: "career_change",
},
{
id: "e-rel",
status: "confirmed",
domain: "relationship",
datePrecision: "year",
occurredFrom: "2024-01-01",
occurredTo: null,
eventKind: "relationship_start",
},
{
id: "e-fam",
status: "confirmed",
domain: "family",
datePrecision: "year",
occurredFrom: "2023-01-01",
occurredTo: null,
eventKind: "family_event",
},
{
id: "e-occ",
status: "confirmed",
domain: "occupation",
datePrecision: "unknown",
occurredFrom: null,
occurredTo: null,
eventKind: "occupation_note",
},
] as const;
function producedDossier(
evidence: readonly Readonly<{
id: string;
status: string;
domain: string;
datePrecision: string;
occurredFrom: string | null;
occurredTo: string | null;
eventKind?: string | null;
}>[],
options: { previous?: InferenceState | null } = {},
) {
const state = buildCaseInferenceState({
range: { start_time: "04:55", end_time: "05:02" },
candidates: [
{ candidateId: "05:02", time: "05:02", relativeSupport: 58 },
{ candidateId: "04:55", time: "04:55", relativeSupport: 42 },
],
evidence,
probes: [],
previous: options.previous,
});
const latest = {
resultId: "55555555-5555-4555-8555-555555555555",
candidates: state.candidates.map((item) => ({
candidateId: item.id,
time: item.time,
rank: item.rank,
relativeSupport: Math.round(item.posterior_score),
})),
representativeTime: state.representative_time,
evidenceLedgerFingerprint: evidenceLedgerFingerprint(evidence as never),
decisionReceipt: { inference_state: state },
};
return {
state,
dossier: {
evidence,
conversationSummary: { activeFocus: null, declinedSkippedTopics: [] },
latestResult: latest,
case: { acceptedTime: null },
},
};
}
function holdoutFollowup(dossier: ReturnType<typeof producedDossier>["dossier"]) {
const catalog = rectificationFollowupCatalog(dossier.latestResult, dossier.evidence);
return buildMethodFollowupPlan({
evidence: dossier.evidence,
declinedTopics: dossier.conversationSummary.declinedSkippedTopics,
sessionOutcome: "validate_holdout",
...catalog,
candidatesSeparated: true,
});
}
test("sticky holdout with unknown precision does not ask validation and can adopt", () => {
const { state, dossier: dated } = producedDossier(COVERED_EVIDENCE);
const holdout = state.events.find((item) => item.usage === "holdout");
assert.ok(holdout);
assert.notEqual(holdout.year, null);
assert.equal(decideFromDossier(dated).nextAction, "ask_holdout_validation");
const undated = COVERED_EVIDENCE.map((item) => (
item.id === holdout.id
? { ...item, datePrecision: "unknown", occurredFrom: null, occurredTo: null }
: item
));
const { state: sticky, dossier } = producedDossier(undated, { previous: state });
const stickyHoldout = sticky.events.find((item) => item.id === holdout.id);
assert.equal(stickyHoldout?.usage, "holdout");
assert.equal(stickyHoldout?.year, null);
assert.equal(stickyHoldout?.precision, "unknown");
const decision = decideFromDossier(dossier);
assert.notEqual(decision.nextAction, "ask_holdout_validation");
assert.equal(decision.nextAction, "ready_to_adopt");
assert.equal(decision.sessionOutcome, "adopt_representative");
assert.notEqual(decision.sessionOutcome, "validated_range");
assert.equal(decision.validated, false);
assert.equal(decision.canAdopt, true);
assert.equal(decision.canConfirmExactMinute, false);
});
test("dated holdout asks validation with a renderable followup card", () => {
const { dossier } = producedDossier(COVERED_EVIDENCE);
const decision = decideFromDossier(dossier);
assert.equal(decision.nextAction, "ask_holdout_validation");
assert.equal(decision.canConfirmExactMinute, false);
const plan = holdoutFollowup(dossier);
assert.ok(plan.next_followup);
assert.ok(plan.next_followup.choice_frame, "holdout card must be renderable");
assert.equal(plan.next_followup.choice_frame.scoring, false);
assert.ok(plan.next_followup.choice_frame.prompt);
});
test("passed holdout is a validated range, not a unique minute", () => {
const { state, dossier } = producedDossier(COVERED_EVIDENCE);
const passed = applyHoldoutAnswer(state, "yes");
const decided = decideFromDossier({
...dossier,
latestResult: {
...dossier.latestResult,
decisionReceipt: { inference_state: passed },
},
});
assert.equal(decided.sessionOutcome, "validated_range");
assert.equal(decided.canAdopt, true);
assert.equal(decided.validated, true);
assert.equal(decided.canConfirmExactMinute, false);
assert.notEqual(decided.nextAction, "ask_holdout_validation");
});
test("failed holdout keeps existing non-validated close or discriminate path", () => {
const { state, dossier } = producedDossier(COVERED_EVIDENCE);
const failed = applyHoldoutAnswer(state, "no");
assert.equal(failed.holdout_passed, false);
const decided = decideFromDossier({
...dossier,
latestResult: {
...dossier.latestResult,
decisionReceipt: { inference_state: failed },
},
});
assert.equal(decided.holdoutValidation, "failed");
assert.notEqual(decided.nextAction, "ask_holdout_validation");
assert.notEqual(decided.sessionOutcome, "validated_range");
assert.equal(decided.validated, false);
assert.equal(decided.canConfirmExactMinute, false);
});
test("ask_holdout_validation is only returned when the same dossier can build a holdout followup", () => {
const fixtures = [
producedDossier(COVERED_EVIDENCE).dossier,
producedDossier(COVERED_EVIDENCE.filter((item) => item.domain !== "occupation")).dossier,
];
for (const dossier of fixtures) {
const decision = decideFromDossier(dossier);
if (decision.nextAction !== "ask_holdout_validation") continue;
const plan = holdoutFollowup(dossier);
assert.ok(plan.next_followup, "ask_holdout_validation requires a holdout followup");
assert.equal(decision.canConfirmExactMinute, false);
}
});