Files
Jyotisha/frontend/tests/rectification-decision-authority.test.ts
T
Jesse_Chen b1173f7245 fix(web): count only training events for discrimination and split user-stop from validated range
Three collected events with a reserved holdout were stalling because the discriminator door counted holdout. Public selection_allowed still had snapshot fallbacks, and health only proved the image SHA.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-26 19:36:04 +08:00

113 lines
4.8 KiB
TypeScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
import {
decideRectification,
publicDecisionFields,
} from "../src/lib/rectification-agentic/core/rectification-decision.ts";
import { decideNextAction } from "../src/lib/rectification-agentic/core/decide-next-action.ts";
import { overlayPublicDecision } from "../src/lib/rectification-agentic/v9/decision-from-dossier.ts";
import { conversationalSessionOutcome } from "../src/lib/rectification-agentic/v9/method-followup.ts";
const SEPARATED = [
{ time: "04:48", score: 58 },
{ time: "04:49", score: 42 },
];
function readSource(relative: string) {
return readFileSync(new URL(relative, import.meta.url), "utf8");
}
test("public decision fields are derived from decideRectification", () => {
const fixtures = [
{
methodCoverageAll: false,
trainingGateOpen: false,
candidateScores: SEPARATED,
},
{
methodCoverageAll: true,
trainingGateOpen: true,
candidateScores: [
{ time: "05:00", score: 34 },
{ time: "05:01", score: 33 },
{ time: "05:02", score: 33 },
],
},
{
methodCoverageAll: true,
trainingGateOpen: true,
candidateScores: SEPARATED,
holdoutValidation: "passed" as const,
},
{
methodCoverageAll: true,
userStopped: true,
candidateScores: SEPARATED,
holdoutValidation: "not_started" as const,
},
];
for (const input of fixtures) {
const decision = decideRectification(input);
const fields = publicDecisionFields(decision);
assert.deepEqual(fields, {
type: decision.nextAction,
session_outcome: decision.sessionOutcome,
completion_status: decision.completionStatus,
validated: decision.validated,
can_offer_range: decision.canOfferRange,
can_adopt: decision.canAdopt,
can_confirm_exact_minute: decision.canConfirmExactMinute,
selection_allowed: decision.selectionAllowed,
propose_allowed: decision.proposeAllowed,
precision_stage: decision.precisionStage,
representative_time: decision.representativeTime,
credible_range: decision.credibleRange,
});
assert.equal(overlayPublicDecision({ selectionAllowed: true }, decision).selectionAllowed, fields.selection_allowed);
assert.equal(overlayPublicDecision({ selectionAllowed: true }, decision).validated, fields.validated);
assert.equal(decideNextAction(input).type, decision.nextAction);
assert.equal(conversationalSessionOutcome({
selectionAllowed: decision.selectionAllowed,
proposeAllowed: decision.proposeAllowed,
confirmationAllowed: false,
nextFollowup: null,
userStopped: input.userStopped,
candidateScores: input.candidateScores,
holdoutValidation: input.holdoutValidation,
trainingGateOpen: input.trainingGateOpen,
}), decision.sessionOutcome);
}
});
test("interview, choice, refresh and next-action all call the same reducer", () => {
const interview = readSource("../src/lib/rectification-agentic/v9/interview-state.ts");
const adapter = readSource("../src/lib/rectification-agentic/v9/decision-from-dossier.ts");
const choice = readSource("../src/lib/rectification-agentic/v9/answer-choice.ts");
const refresh = readSource("../src/lib/rectification-agentic/v9/turn-decision.ts");
const followup = readSource("../src/lib/rectification-agentic/v9/method-followup.ts");
const tools = readSource("../src/mastra/rectification-v9-tools.ts");
const caseRoute = readSource("../src/app/api/rectification/cases/[caseId]/route.ts");
assert.match(interview, /decideFromDossier\(/);
assert.match(refresh, /decideFromDossier\(/);
assert.match(choice, /decideAfterInferenceChange\(/);
assert.match(adapter, /decideRectification\(/);
assert.match(followup, /decideRectification\(/);
assert.match(tools, /decideConversationalSession\(/);
assert.match(caseRoute, /overlayPublicDecision/);
assert.match(caseRoute, /publicDecisionFields\(decision\)/);
assert.doesNotMatch(interview, /sessionOutcomeFromGate/);
assert.doesNotMatch(choice, /sessionOutcomeFromGate/);
assert.doesNotMatch(refresh, /sessionOutcomeFromGate/);
assert.doesNotMatch(tools, /sessionOutcomeFromGate/);
assert.doesNotMatch(interview, /selectionAllowed: dossier\.latestResult/);
assert.doesNotMatch(refresh, /selection_allowed: dossier\.latestResult\?\.selectionAllowed/);
assert.doesNotMatch(tools, /selection_allowed: decision\?\.selectionAllowed \?\? latest/);
assert.doesNotMatch(tools, /propose_allowed: decision\?\.proposeAllowed \?\? proposeAllowed/);
assert.match(tools, /evidence: parsed\.evidence/);
assert.match(followup, /evidence: input\.evidence/);
assert.match(adapter, /trainingGateOpen: trainingGate\.open/);
assert.match(adapter, /blockingMethodsCovered/);
});