import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import test from "node:test"; import { prepareConsultationRoute } from "../src/lib/consultation-route-service.ts"; import { applyUnreliableVargasToWorkflowContext, unreliableVargasNotice } from "../src/lib/consultation-birth-time-mode.ts"; import { loadReportCandidateRange } from "../src/lib/report-candidate-range.ts"; import { clearAdoptedChartTierCache } from "../src/lib/rectification-adopted-chart-tiers.ts"; import { buildSegmentSummary, type SegmentMinute } from "../src/lib/rectification-agentic/core/segment-summary.ts"; import { runConsultationWorkflow, toAgentConsultationContext, toModelOutput, type ConsultationInput } from "../src/mastra/consultation-workflow.ts"; // Real engine consultation_workflow response for a public Rodden-AA chart. const golden = JSON.parse(readFileSync(new URL("./fixtures/consult-evidence-card-golden.json", import.meta.url), "utf8")); const realWorkflow = golden.charts[0].workflow; const userId = "11111111-1111-4111-8111-111111111111"; const caseId = "22222222-2222-4222-8222-222222222222"; const resultId = "33333333-3333-4333-8333-333333333333"; // Explicitly fictional profile (not a real person). const profile = Object.freeze({ name: "虚构测试", birth_date: "2000-06-14", reported_birth_time: "09:10:00", active_birth_time: "09:05:00", birth_time_source: "approximate", birth_time_status: "accepted", country_code: "CN", province_code: "130000", city_code: "130400", district_code: "130406", latitude: 36.420487, longitude: 114.209936, timezone_offset: 8, }); // Explicitly fictional ±60 summary: a 121-minute window blocks D9/D10 by width. function wideSummary() { const minutes: SegmentMinute[] = Array.from({ length: 121 }, (_, offset) => ({ offset, date: "2000-06-14", time: `${String(8 + Math.floor(offset / 60)).padStart(2, "0")}:${String(offset % 60).padStart(2, "0")}`, signs: { D1: 4, D9: Math.floor(offset / 13) % 12, D10: Math.floor(offset / 12) % 12 }, })); return buildSegmentSummary({ minutes, candidates: [{ time: minutes[60]!.time, score: 10 }], windowMinutes: 121, scanComplete: true }); } function accountingClient(provenance: unknown, calls: string[] = []) { return { rpc: async (fn: string) => { calls.push(fn); if (fn === "read_report_candidate_range") return { data: { start_time: "08:00", end_time: "10:00" }, error: null }; if (fn === "get_agentic_rectification_case_dossier") return { data: { case: { case_id: caseId }, latest_result: { result_id: resultId, decision_receipt: { inference_state: { segment_summary: wideSummary() } } } }, error: null }; throw new Error(`unexpected RPC ${fn}`); }, from(table: string) { assert.equal(table, "profiles"); calls.push("profiles"); return { select: (columns: string) => { assert.equal(columns, "active_birth_provenance"); return { eq: (column: string, value: string) => { assert.equal(column, "id"); assert.equal(value, userId); return { maybeSingle: async () => ({ data: { active_birth_provenance: provenance }, error: null }) }; } }; } }; }, }; } const segmentV1 = { contract: "segment-v1", case_id: caseId, result_id: resultId }; const legacyAdoption = { contract: "candidate-v2", case_id: caseId, result_id: resultId }; test("range loader: segment-v1 adds unreliable charts; legacy returns the identical range object", async () => { clearAdoptedChartTierCache(); const segment = await loadReportCandidateRange(accountingClient(segmentV1), { userId }); assert.deepEqual(segment, { startTime: "08:00", endTime: "10:00", unreliableVargas: ["D9", "D10"] }); const legacy = await loadReportCandidateRange(accountingClient(legacyAdoption), { userId }); assert.equal(JSON.stringify(legacy), JSON.stringify({ startTime: "08:00", endTime: "10:00" })); // An rpc-only client (no profile access) and a failing profile read never drop the range. const rpcOnly = await loadReportCandidateRange({ rpc: accountingClient(segmentV1).rpc }, { userId }); assert.equal(JSON.stringify(rpcOnly), JSON.stringify({ startTime: "08:00", endTime: "10:00" })); const broken = { ...accountingClient(segmentV1), from: () => { throw new Error("boom"); } }; assert.equal(JSON.stringify(await loadReportCandidateRange(broken, { userId })), JSON.stringify({ startTime: "08:00", endTime: "10:00" })); }); test("chat tool input: segment-v1 carries unreliable_vargas; legacy tool input is byte-identical", async () => { clearAdoptedChartTierCache(); const prepare = (provenance: unknown) => prepareConsultationRoute({ userId, mode: "verified_chart", loadProfile: async () => profile, loadCandidateRange: (id) => loadReportCandidateRange(accountingClient(provenance), { userId: id }), reserve: async () => "reserved", }); const segment = await prepare(segmentV1); const legacy = await prepare(legacyAdoption); assert.deepEqual(segment.serverChart?.toolInput.unreliable_vargas, ["D9", "D10"]); assert.equal("unreliable_vargas" in (legacy.serverChart?.toolInput ?? {}), false); const rest = Object.fromEntries(Object.entries(segment.serverChart!.toolInput).filter(([key]) => key !== "unreliable_vargas")); assert.equal(JSON.stringify(rest), JSON.stringify(legacy.serverChart!.toolInput)); // Byte-identical snapshot of the legacy accepted tool input (red line 1). assert.equal(JSON.stringify(legacy.serverChart!.toolInput), '{"year":2000,"month":6,"day":14,"hour":9,"minute":5,"city":"中国 · 河北省 · 邯郸市 · 峰峰矿区","lat":36.420487,"lon":114.209936,"tz":8,"ayanamsa":"raman","declared_accuracy":"rectified","time_source":"rectified","birth_time_accuracy":"provisional","candidate_range":{"start_time":"08:00","end_time":"10:00"}}'); }); async function runWith(input: ConsultationInput) { let body = ""; const originalFetch = globalThis.fetch; globalThis.fetch = async (_url, init) => { body = typeof init?.body === "string" ? init.body : ""; return new Response(JSON.stringify(realWorkflow), { status: 200 }); }; try { return { context: await runConsultationWorkflow(input), body: JSON.parse(body) as Record }; } finally { globalThis.fetch = originalFetch; } } test("workflow: unreliable_vargas never reaches the engine; the model packet gets the policy and one sentence", async () => { const base: ConsultationInput = { year: 2000, month: 6, day: 14, hour: 9, minute: 5, lat: 39.9, lon: 116.4, tz: 8, ayanamsa: "raman", city: "北京", question: "我的婚姻怎么样?", theme: "marriage", entryMode: "direct_chart", declared_accuracy: "rectified", time_source: "rectified", birth_time_accuracy: "provisional", candidate_range: { start_time: "08:00", end_time: "10:00" }, }; const legacy = await runWith(base); const segment = await runWith({ ...base, unreliable_vargas: ["D9", "D10"] }); // The engine payload is identical with or without the server-owned field. assert.equal(JSON.stringify(segment.body), JSON.stringify(legacy.body)); assert.equal("unreliable_vargas" in segment.body, false); // Legacy context equals the untouched engine projection. assert.equal(JSON.stringify(legacy.context), JSON.stringify(applyUnreliableVargasToWorkflowContext(legacy.context, undefined))); const policy = segment.context.consumer_context.answer_policy as Record; assert.deepEqual(policy.unreliable_vargas, ["D9", "D10"]); assert.ok((policy.deterministic_claims_forbidden_for as string[]).includes("D9")); const notice = unreliableVargasNotice(["D9", "D10"]); assert.equal(notice, "你的出生时间范围里,婚恋(D9)、事业(D10)的上升会变,这几张盘判断不了;涉及它们的部分只看本命盘和大运,不按它们下结论。"); assert.ok(String(segment.context.consumer_context.user_facing_limitation).endsWith(notice)); const legacyPacket = toModelOutput(toAgentConsultationContext(legacy.context)); const segmentPacket = toModelOutput(toAgentConsultationContext(segment.context)); assert.deepEqual((segmentPacket.evidence_contract.answer_policy as Record).unreliable_vargas, ["D9", "D10"]); assert.ok(String(segmentPacket.evidence_contract.user_facing_limitation).includes("婚恋(D9)")); assert.equal("unreliable_vargas" in (legacyPacket.evidence_contract.answer_policy as Record), false); assert.ok(!String(legacyPacket.evidence_contract.user_facing_limitation ?? "").includes("婚恋(D9)")); }); test("notice wording for one chart and for D1", () => { assert.equal(unreliableVargasNotice(["D9"]), "你的出生时间范围里,婚恋(D9)的上升会变,这张盘判断不了;涉及它的部分只看本命盘和大运,不按它下结论。"); assert.match(unreliableVargasNotice(["D1", "D9"]), /不按上升和宫位下结论/); });