Files
Jyotisha/frontend/tests/rectification-v9-engine-contract.test.ts
T
2026-08-15 00:56:06 +08:00

289 lines
11 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import {
RectificationEngineError,
runV9CandidateScore,
runV9Diagnostics,
toEngineEvents,
type V9EngineScoreResult,
} from "../src/lib/rectification-agentic/v9/engine-client.ts";
const RANGE = { start_time: "04:50", end_time: "05:10" };
const CANDIDATE_ID = "88888888-8888-4888-8888-888888888881";
const SECOND_CANDIDATE_ID = "88888888-8888-4888-8888-888888888882";
const THIRD_CANDIDATE_ID = "88888888-8888-4888-8888-888888888883";
const DECISION_RECEIPT = {
receipt_version: "candidate-decision-receipt-v2",
contract_version: "v2",
event_contract_version: "rectification-event-contract-v2",
policy_version: "rectification-candidate-policy-v2",
decision_policy_version: "rectification-candidate-policy-v2",
display_allowed: true,
selection_allowed: true,
acceptance_allowed: true,
confirmation_allowed: false,
accept_allowed: true,
confirm_allowed: false,
representative_candidate_id: CANDIDATE_ID,
representative_time: "04:50",
overall_confidence: "high",
margin_percent: 42.5,
};
const EXECUTION_LEDGER = [
{ ledger_version: "rectification-execution-ledger-v2", stage: "technique_layer", method: "d1-rashi", status: "executed", source: "python-engine" },
{ ledger_version: "rectification-execution-ledger-v2", stage: "technique_layer", method: "gochara", status: "executed", source: "python-engine" },
{ ledger_version: "rectification-execution-ledger-v2", stage: "technique_layer", method: "d24-chaturvimshamsha", status: "not_executed", source: "python-engine" },
];
const ENGINE_SCORE_RESPONSE_V2 = {
success: true,
endpoint: "rectification_v5_score",
result_id: "e4fbf2e0-85dc-5b42-a5a3-34e5dd4b7e62",
algorithm_version: "rectification-event-contract-v2",
event_contract_version: "rectification-event-contract-v2",
decision_policy_version: "rectification-candidate-policy-v2",
execution_ledger_version: "rectification-execution-ledger-v2",
candidate_decisions: [
{ candidate_id: CANDIDATE_ID, time: "04:50", rank: 1, relative_support: 57, tied_minute_count: 1 },
{ candidate_id: SECOND_CANDIDATE_ID, time: "04:51", rank: 3, relative_support: 18, tied_minute_count: 2 },
{ candidate_id: THIRD_CANDIDATE_ID, time: "04:52", rank: 2, relative_support: 25, tied_minute_count: 2 },
],
decision_receipt: DECISION_RECEIPT,
execution_ledger: EXECUTION_LEDGER,
diagnostics: {
primary_secondary_margin_percent: 99,
leave_one_event_out_retention_rate: 1,
},
candidate_scores: [
{ time: "04:59", score: 999999 },
],
};
const ENGINE_DIAGNOSTICS_RESPONSE_V2 = {
success: true,
endpoint: "rectification_v5_diagnostics",
result_id: "e4fbf2e0-85dc-5b42-a5a3-34e5dd4b7e62",
algorithm_version: "rectification-event-contract-v2",
event_contract_version: "rectification-event-contract-v2",
decision_policy_version: "rectification-candidate-policy-v2",
execution_ledger_version: "rectification-execution-ledger-v2",
candidate_decisions: ENGINE_SCORE_RESPONSE_V2.candidate_decisions,
diagnostics: {
primary_cluster_retention_rate: 0.86,
leave_one_event_out_retention_rate: 0.81,
leave_one_domain_out_retention_rate: 0.9,
date_sensitivity_retention_rate: 0.72,
neighbor_support_minutes: 2,
primary_secondary_margin_percent: 42.5,
unstable_event_ids: [],
most_discriminating_layers: ["vimsottari_dasha"],
candidate_splits: [{ candidate_id: SECOND_CANDIDATE_ID, width: 6 }],
},
missing_layers: ["KP_cusps"],
decision_receipt: DECISION_RECEIPT,
execution_ledger: EXECUTION_LEDGER,
};
function stubEngine(response: unknown, status = 200) {
const previous = globalThis.fetch;
globalThis.fetch = (async () => ({
ok: status >= 200 && status < 300,
status,
json: async () => response,
})) as unknown as typeof fetch;
return () => {
globalThis.fetch = previous;
};
}
const SNAPSHOT = {
birth_date: "1997-08-08",
latitude: 36.420487,
longitude: 114.209936,
timezone_offset: 8,
birth_time_source: "family_exact",
};
const EVIDENCE = [
{
id: "00000000-0000-4000-8000-000000000001",
sourceTurnId: "33333333-3333-4333-8333-333333333333",
subject: "self",
eventKind: "education_start",
domain: "education",
occurredFrom: "2016-09-01",
occurredTo: "2016-09-30",
datePrecision: "month",
summary: "大学入学",
status: "confirmed",
supersedesEvidenceId: null,
createdAt: "2026-08-12T10:00:06.000Z",
dateSource: "user_quote",
dateReliability: "month_exact",
dateCorroboration: "录取通知书",
dateConflictStatus: "none",
},
];
test("toEngineEvents preserves Event Contract v2 detailed kind and provenance", () => {
const events = toEngineEvents(EVIDENCE);
assert.equal(events.length, 1);
assert.equal(events[0]!.domain, "education");
assert.equal(events[0]!.event_kind, "education_start");
assert.equal(events[0]!.date_start, "2016-09-01");
assert.equal(events[0]!.precision, "month");
assert.equal(events[0]!.date_source, "user_quote");
assert.equal(events[0]!.date_reliability, "month_exact");
assert.equal(events[0]!.date_corroboration, "录取通知书");
assert.equal(events[0]!.date_conflict_status, "none");
assert.equal(events[0]!.source_turn_id, EVIDENCE[0]!.sourceTurnId);
assert.equal(events[0]!.subject, "self");
});
test("toEngineEvents keeps all scoreable detailed v2 kinds and drops background kinds", () => {
const detailed = [
"education_completion",
"career_entry",
"promotion",
"career_pressure",
"relationship_commitment",
"relationship_separation",
"finance_gain",
"finance_loss",
"self_health_event",
].map((eventKind, index) => ({
...EVIDENCE[0]!,
id: `00000000-0000-4000-8000-${String(index + 2).padStart(12, "0")}`,
eventKind,
domain: eventKind.startsWith("education") ? "education"
: eventKind.startsWith("career") || eventKind === "promotion" ? "career"
: eventKind.startsWith("relationship") ? "relationship"
: eventKind.startsWith("finance") ? "finance"
: "health",
}));
const background = [
{ ...EVIDENCE[0]!, id: "00000000-0000-4000-8000-000000000099", eventKind: "family_event", domain: "family" },
{ ...EVIDENCE[0]!, id: "00000000-0000-4000-8000-000000000100", eventKind: "other", domain: "other" },
];
assert.deepEqual(toEngineEvents([...detailed, ...background]).map((event) => event.event_kind), detailed.map((event) => event.eventKind));
});
test("runV9CandidateScore strictly consumes server candidate decisions and v2 receipt", async () => {
const restore = stubEngine(ENGINE_SCORE_RESPONSE_V2);
try {
const result: V9EngineScoreResult = await runV9CandidateScore({
baselineBirthSnapshot: SNAPSHOT,
candidateRange: RANGE,
events: toEngineEvents(EVIDENCE),
});
assert.deepEqual(result.candidates, [
{ candidateId: CANDIDATE_ID, time: "04:50", rank: 1, relativeSupport: 57, tiedMinuteCount: 1 },
{ candidateId: SECOND_CANDIDATE_ID, time: "04:51", rank: 3, relativeSupport: 18, tiedMinuteCount: 2 },
{ candidateId: THIRD_CANDIDATE_ID, time: "04:52", rank: 2, relativeSupport: 25, tiedMinuteCount: 2 },
], "Web must preserve server rank/support/tie instead of deriving or sorting them");
assert.equal(result.representativeCandidateId, CANDIDATE_ID);
assert.equal(result.representativeTime, "04:50");
assert.equal(result.selectionAllowed, true);
assert.equal(result.confirmationAllowed, false);
assert.equal(result.overallConfidence, "high");
assert.equal(result.policyVersion, "rectification-candidate-policy-v2");
assert.deepEqual(result.decisionReceipt, DECISION_RECEIPT);
assert.deepEqual(result.executionLedger, EXECUTION_LEDGER);
assert.deepEqual(result.executedMethods, ["d1-rashi", "gochara"], "methods come only from executed server ledger entries");
assert.equal(JSON.stringify(result).includes("999999"), false, "raw internal score must not enter the TS projection");
} finally {
restore();
}
});
test("runV9CandidateScore fails closed without a v2 decision receipt", async () => {
const missingReceipt = Object.fromEntries(
Object.entries(ENGINE_SCORE_RESPONSE_V2).filter(([key]) => key !== "decision_receipt"),
);
const restore = stubEngine(missingReceipt);
try {
await assert.rejects(
runV9CandidateScore({
baselineBirthSnapshot: SNAPSHOT,
candidateRange: RANGE,
events: toEngineEvents(EVIDENCE),
}),
(error: unknown) => error instanceof RectificationEngineError && error.code === "engine_invalid_v2_receipt",
);
} finally {
restore();
}
});
test("runV9CandidateScore fails closed on invalid server candidate UUIDs", async () => {
const restore = stubEngine({
...ENGINE_SCORE_RESPONSE_V2,
candidate_decisions: [{ ...ENGINE_SCORE_RESPONSE_V2.candidate_decisions[0], candidate_id: "04:50" }],
});
try {
await assert.rejects(
runV9CandidateScore({
baselineBirthSnapshot: SNAPSHOT,
candidateRange: RANGE,
events: toEngineEvents(EVIDENCE),
}),
(error: unknown) => error instanceof RectificationEngineError && error.code === "engine_invalid_candidate_decisions",
);
} finally {
restore();
}
});
test("runV9CandidateScore fails closed when no evidence is scoreable", async () => {
const restore = stubEngine(ENGINE_SCORE_RESPONSE_V2);
try {
await assert.rejects(
runV9CandidateScore({
baselineBirthSnapshot: SNAPSHOT,
candidateRange: RANGE,
events: toEngineEvents([{ ...EVIDENCE[0]!, eventKind: "family_event", domain: "family" }]),
}),
(error: unknown) => error instanceof RectificationEngineError && error.code === "no_scorable_evidence",
);
} finally {
restore();
}
});
test("runV9Diagnostics maps diagnostics and receipt-owned confirmation", async () => {
const restore = stubEngine(ENGINE_DIAGNOSTICS_RESPONSE_V2);
try {
const result = await runV9Diagnostics({
baselineBirthSnapshot: SNAPSHOT,
candidateRange: RANGE,
events: toEngineEvents(EVIDENCE),
});
assert.equal(result.canConfirmExactMinute, false);
assert.equal(result.missingLayers.join(","), "KP_cusps");
assert.equal(result.diagnostics.primary_secondary_margin_percent, 42.5);
assert.deepEqual(result.executedMethods, ["d1-rashi", "gochara"]);
assert.equal(result.policyVersion, "rectification-candidate-policy-v2");
} finally {
restore();
}
});
test("engine http failures surface as safe engine errors, never raw stack traces", async () => {
const restore = stubEngine({ error: "invalid event kind" }, 400);
try {
await assert.rejects(
runV9CandidateScore({
baselineBirthSnapshot: SNAPSHOT,
candidateRange: RANGE,
events: toEngineEvents(EVIDENCE),
}),
(error: unknown) => error instanceof Error && error.message.includes("invalid event kind"),
);
} finally {
restore();
}
});