Files
Jyotisha/frontend/tests/rectification-segment-opening.test.ts
T
66f087b588 feat(rectification): submit varga-resolution implementation for review
Review-only snapshot for BUG-1115 through BUG-1117; not merge-ready. New opening and append-turn PostgreSQL permission failures remain blocked. Persisted joint replay has zero completed questions; segment ordering remains off by default. The existing offline replay JSON is retained stale and unchanged after a denied overwrite, including its CRLF line endings. Browser/provider validation and final serial gates remain pending. No deployment, role permission changes, or staging/main push.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-01 08:04:04 +08:00

102 lines
6.8 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import { buildSegmentSummary, targetChartsForDomain } from "../src/lib/rectification-agentic/core/segment-summary.ts";
import { parseCaseSegmentChecks, prepareCaseSegmentChecks } from "../src/lib/rectification-agentic/v9/segment-checks.ts";
import { finalizeSuccessfulTurnExit } from "../src/lib/rectification-agentic/v9/turn-exit.ts";
import { messagesFromTurns } from "../src/lib/rectification-chat-messages.ts";
import { mergeTurnQuestions, type SnapshotTurnMessage } from "../src/lib/rectification-snapshot-messages.ts";
import type { RectificationRpcClient } from "../src/lib/rectification-agentic/v9/tool-service.ts";
// Fictional complete-window controls, not engine calibration goldens.
const range = { start_time: "09:00", end_time: "09:20" };
const snapshot = { birth_date: "2000-06-14", latitude: 40, longitude: -74, timezone_offset: -4,
reported_birth_time: "09:10", birth_time_source: "family_exact" };
const minutes = Array.from({ length: 21 }, (_, offset) => ({ offset, date: "2000-06-14",
time: `09:${String(offset).padStart(2, "0")}`, signs: { D1: 1, D9: 2, D10: 3 } }));
function summary(domain = "general", unique = true) {
return buildSegmentSummary({ minutes: minutes.map(row => unique || row.offset < 10 ? row
: { ...row, signs: { ...row.signs, D9: 4 } }), candidates: [], targets: targetChartsForDomain(domain),
windowMinutes: 21, scanComplete: true });
}
function control(domain: string | null = "general", unique = true) {
const calls: string[] = [];
let checks: unknown = null;
let status = "draft";
let turnCount = 0;
const accounting = { rpc: async (name: string, args: Record<string, unknown>) => {
calls.push(name);
if (name === "get_agentic_rectification_case_dossier") return { error: null, data: {
case: { case_id: "synthetic-case", session_id: "synthetic-session", status,
skill_name: "jyotish-birth-time-rectification", skill_version: "10.0.32", stage: "minute",
candidate_range: range, rectification_domain: domain, checks, turn_count: turnCount },
turns: [], evidence: [], conversation_summary: {}, latest_result: null } };
if (name === "get_agentic_rectification_case_compute") return { error: null, data: {
case_id: "synthetic-case", skill_version: "10.0.32", baseline_profile_fingerprint: "a".repeat(64),
baseline_birth_snapshot: snapshot, candidate_range: range } };
if (name === "write_agentic_rectification_segment_checks_v1") {
checks = args.p_checks; return { error: null, data: checks };
}
if (name === "finalize_agentic_rectification_segment_consistency_v1") {
status = "closed"; turnCount = 1;
checks = { ...(checks as object), delivered_turn_id: "synthetic-turn" };
return { error: null, data: { turn_id: "synthetic-turn" } };
}
throw new Error(`unexpected RPC ${name}`);
} } as unknown as RectificationRpcClient;
const fetchScan = (async (_url: unknown, init?: RequestInit) => {
const body = JSON.parse(String(init?.body));
assert.deepEqual(body.target_charts, targetChartsForDomain(domain));
return Response.json({ start_at: "2000-06-14T09:00", end_at: "2000-06-14T09:20", ayanamsa: "raman",
node_mode: "mean", step_minutes: 1, window_minutes: 21,
minutes: minutes.map(row => unique || row.offset < 10 ? row : { ...row, signs: { ...row.signs, D9: 4 } }) });
}) as typeof fetch;
return { accounting, calls, fetchScan };
}
test("opening checks accept only the persisted product targets, never a D1-only opt-out", () => {
for (const domain of ["education", "career", "relationship", "relocation", "finance", "health", "family"]) {
const expected = domain === "career" ? ["D1", "D10"] : domain === "relationship" ? ["D1", "D9"] : ["D1", "D9", "D10"];
assert.deepEqual(targetChartsForDomain(domain), expected);
const checks = { contract: "segment-opening-v1", domain, range_fingerprint: "a".repeat(64), status: "complete", summary: summary(domain) };
assert.ok(parseCaseSegmentChecks(checks, domain));
assert.equal(parseCaseSegmentChecks({ ...checks, summary: buildSegmentSummary({ minutes, candidates: [], targets: ["D1"],
windowMinutes: 21, scanComplete: true }) }, domain), null);
}
assert.equal(summary("general", false).no_rectification_needed, false);
});
test("full target uniqueness exits through the shared writer before any collect focus, with read-only retry", async () => {
const c = control(); const previous = globalThis.fetch; globalThis.fetch = c.fetchScan;
try {
const input = { accounting: c.accounting, userId: "synthetic-user", caseId: "synthetic-case", action: "opening" as const, segmentOpening: true as const };
const result = await finalizeSuccessfulTurnExit(input);
assert.equal(result?.segmentConsistency, true);
assert.match(result?.text ?? "", /盘型一致,不用校正/);
const scans = c.calls.filter(name => name === "write_agentic_rectification_segment_checks_v1").length;
assert.equal((await finalizeSuccessfulTurnExit(input))?.turnId, result?.turnId);
assert.equal(c.calls.filter(name => name === "write_agentic_rectification_segment_checks_v1").length, scans);
assert.ok(!c.calls.some(name => /focus|next_interview/.test(name)));
} finally { globalThis.fetch = previous; }
});
test("a nonunique target persists checks but does not claim no rectification; legacy does not scan", async () => {
const c = control("general", false); const previous = globalThis.fetch; globalThis.fetch = c.fetchScan;
try {
const checks = await prepareCaseSegmentChecks({ accounting: c.accounting, userId: "synthetic-user", caseId: "synthetic-case" });
assert.equal(checks?.summary?.no_rectification_needed, false);
assert.equal(await finalizeSuccessfulTurnExit({ accounting: c.accounting, userId: "synthetic-user", caseId: "synthetic-case", action: "opening", segmentOpening: true }), undefined);
assert.ok(!c.calls.includes("finalize_agentic_rectification_segment_consistency_v1"));
const legacy = control(null);
assert.equal(await prepareCaseSegmentChecks({ accounting: legacy.accounting, userId: "synthetic-user", caseId: "synthetic-case" }), null);
assert.deepEqual(legacy.calls, ["get_agentic_rectification_case_dossier"]);
} finally { globalThis.fetch = previous; }
});
test("consistency card hydrates onto the same server turn live and after reload", () => {
const value = summary();
const turns = [{ id: "synthetic-turn", role: "assistant" as const, text: "盘型一致,不用校正。", status: "completed", segment_consistency: value }];
const messages = messagesFromTurns(turns);
assert.deepEqual(messages[0]?.segmentConsistency, value);
assert.deepEqual(mergeTurnQuestions<SnapshotTurnMessage>([{ role: "assistant", renderKey: "live", turnId: "synthetic-turn", text: "盘型一致,不用校正。" }], turns)[0]?.segmentConsistency, value);
});