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) => { 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([{ role: "assistant", renderKey: "live", turnId: "synthetic-turn", text: "盘型一致,不用校正。" }], turns)[0]?.segmentConsistency, value); });