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 { createBirthTimeModeOutputGuard, shouldRunBirthChartWorkflow, shouldRunDeclaredWindowWorkflow, UNVERIFIED_BIRTH_TIME_NOTICE, applyBirthTimeModeToWorkflowContext, unverifiedBirthTimeNotice, } from "../src/lib/consultation-birth-time-mode.ts"; import { consultationInputSchema, runConsultationWorkflow, toAgentConsultationContext, } from "../src/mastra/consultation-workflow.ts"; const profile = Object.freeze({ name: "岳辰", birth_date: "1997-08-08", reported_birth_time: "05:30:00", active_birth_time: "05:18:00", birth_time_source: "approximate", birth_time_status: "candidate", country_code: "CN", province_code: "130000", city_code: "130400", district_code: "130406", latitude: 36.420487, longitude: 114.209936, timezone_offset: 8, }); const RANGE_INTERACTION = /按时间范围|candidate windows|not_auto_rectified/; function agentContext(rectification: Record) { return toAgentConsultationContext({ success: true, question: "事业如何", chart: { modules: {} }, routing: { primary_theme: "career" }, consumer_context: { route: "career", core_status: "ready", available_layers: ["D1", "D9", "D10"], missing_route_layers: [], hard_blockers: [], answer_policy: { can_answer_direction: true, can_answer_precise_timing: true, }, }, rectification, }); } async function chartRoute( mode: "verified_chart" | "unverified_birth_time", overrides: Record, ) { return prepareConsultationRoute({ userId: "user-1", mode, loadProfile: async () => ({ ...profile, ...overrides }), reserve: async () => "reserved", }); } test("verified_chart users send rectified accuracy and do not consume a not_auto_rectified boundary", async () => { const prepared = await chartRoute("verified_chart", { birth_time_status: "accepted", birth_time_source: "approximate", }); const toolInput = prepared.serverChart?.toolInput; assert.equal(toolInput?.declared_accuracy, "rectified"); const parsed = consultationInputSchema.parse({ ...toolInput, question: "事业如何", theme: "career", entryMode: "direct_chart", }); assert.equal(parsed.declared_accuracy, "rectified"); let requestBody = ""; const originalFetch = globalThis.fetch; globalThis.fetch = async (_input, init) => { requestBody = typeof init?.body === "string" ? init.body : ""; return new Response(JSON.stringify({ success: true, chart: {}, routing: {}, consumer_context: { route: "career", core_status: "ready", available_layers: [], missing_route_layers: [], hard_blockers: [], answer_policy: { can_answer_direction: true, can_answer_precise_timing: true }, }, }), { status: 200 }); }; try { await runConsultationWorkflow(parsed); } finally { globalThis.fetch = originalFetch; } assert.equal(JSON.parse(requestBody).declared_accuracy, "rectified"); const context = agentContext({ effective_accuracy: "rectified", summary: { headline: "出生时间风险较低,可进入完整解盘" }, enabled_vargas: { D1: "enabled", D9: "enabled", D10: "enabled" }, lagna_boundary: { is_sensitive: false }, }); assert.notEqual(context.rectification.boundary, "not_auto_rectified"); assert.doesNotMatch(JSON.stringify(context), RANGE_INTERACTION); }); test("hospital_record users send minute/hospital and never receive rectified", async () => { const prepared = await chartRoute("unverified_birth_time", { birth_time_source: "hospital_record", birth_time_status: "reported", active_birth_time: "05:18:00", }); const toolInput = prepared.serverChart?.toolInput; assert.equal(toolInput?.declared_accuracy, "minute"); assert.equal(toolInput?.time_source, "hospital"); assert.notEqual(toolInput?.declared_accuracy, "rectified"); const mapper = await import("../src/lib/consultation-route-service.ts"); assert.equal(typeof mapper.declaredBirthAccuracyFromProfile, "function"); assert.deepEqual(mapper.declaredBirthAccuracyFromProfile({ birthTimeStatus: "reported", birthTimeSource: "hospital_record", hasActiveBirthTime: true, }), { declaredAccuracy: "minute", timeSource: "hospital" }); }); test("family_exact and approximate keep the documented downgrade without range-interaction copy", async () => { const family = await chartRoute("unverified_birth_time", { birth_time_source: "family_exact", birth_time_status: "reported", active_birth_time: null, }); assert.equal(family.serverChart?.toolInput.declared_accuracy, "minute"); assert.equal(family.serverChart?.toolInput.time_source, "family_clear"); assert.notEqual(family.serverChart?.toolInput.declared_accuracy, "rectified"); const approximate = await chartRoute("unverified_birth_time", { birth_time_source: "approximate", birth_time_status: "reported", active_birth_time: null, }); assert.equal(approximate.serverChart?.toolInput.declared_accuracy, "15min"); assert.notEqual(approximate.serverChart?.toolInput.declared_accuracy, "rectified"); const familyContext = agentContext({ effective_accuracy: "5min", summary: { headline: "按填报时间排盘,分钟敏感结论已标注精度" }, enabled_vargas: { D1: "enabled", D9: "enabled", D10: "enabled" }, lagna_boundary: { is_sensitive: false }, }); assert.notEqual(familyContext.rectification.boundary, "not_auto_rectified"); assert.doesNotMatch(JSON.stringify(familyContext), RANGE_INTERACTION); const approximateContext = agentContext({ effective_accuracy: "15min", summary: { headline: "按填报时间排盘,分钟敏感结论已标注精度" }, enabled_vargas: { D1: "enabled", D9: "enabled", D10: "enabled_with_warning" }, lagna_boundary: { is_sensitive: false }, }); assert.notEqual(approximateContext.rectification.boundary, "not_auto_rectified"); assert.doesNotMatch(JSON.stringify(approximateContext), RANGE_INTERACTION); }); test("rectified accuracy is reserved for accepted or confirmed profiles with an active birth time", async () => { const mapper = await import("../src/lib/consultation-route-service.ts"); const map = mapper.declaredBirthAccuracyFromProfile; assert.equal(typeof map, "function"); assert.deepEqual(map({ birthTimeStatus: "accepted", birthTimeSource: "approximate", hasActiveBirthTime: true, }), { declaredAccuracy: "rectified", timeSource: "rectified" }); assert.deepEqual(map({ birthTimeStatus: "confirmed", birthTimeSource: "hospital_record", hasActiveBirthTime: true, }), { declaredAccuracy: "rectified", timeSource: "rectified" }); assert.notEqual(map({ birthTimeStatus: "accepted", birthTimeSource: "hospital_record", hasActiveBirthTime: false, }).declaredAccuracy, "rectified"); assert.notEqual(map({ birthTimeStatus: "candidate", birthTimeSource: "hospital_record", hasActiveBirthTime: true, }).declaredAccuracy, "rectified"); assert.notEqual(map({ birthTimeStatus: "reported", birthTimeSource: "family_exact", hasActiveBirthTime: true, }).declaredAccuracy, "rectified"); }); test("declared_birth_window and general_no_birth_time never enter the natal accuracy mapper", async () => { const windowed = await prepareConsultationRoute({ userId: "user-1", mode: "declared_birth_window", loadProfile: async () => ({ ...profile, reported_birth_time: null, active_birth_time: null, birth_time_source: "period_only", birth_time_period: "evening", birth_time_status: "reported", }), reserve: async () => "reserved", }); assert.equal(windowed.consultationMode, "declared_birth_window"); assert.equal(windowed.serverChart, null); assert.equal("declared_accuracy" in (windowed.declaredWindow?.toolInput ?? {}), false); assert.equal("time_source" in (windowed.declaredWindow?.toolInput ?? {}), false); assert.equal(shouldRunBirthChartWorkflow("declared_birth_window"), false); assert.equal(shouldRunDeclaredWindowWorkflow("declared_birth_window"), true); assert.equal(shouldRunBirthChartWorkflow("general_no_birth_time"), false); assert.equal(shouldRunDeclaredWindowWorkflow("general_no_birth_time"), false); }); test("unverified notices grade by source without changing the output guards", () => { assert.equal(unverifiedBirthTimeNotice("hospital_record"), "使用你填报的出生时间(医院记录)排盘"); assert.equal(unverifiedBirthTimeNotice("family_exact"), "使用你填报的出生时间排盘;分钟敏感结论的置信度已降低。"); assert.equal(unverifiedBirthTimeNotice("approximate"), UNVERIFIED_BIRTH_TIME_NOTICE); assert.equal(unverifiedBirthTimeNotice("unknown"), UNVERIFIED_BIRTH_TIME_NOTICE); const guarded = applyBirthTimeModeToWorkflowContext({ success: true, consumer_context: { core_status: "ready", answer_policy: { can_answer_direction: true, can_answer_precise_timing: true }, }, }, "unverified_birth_time", { birthTimeSource: "hospital_record" }); assert.equal( (guarded.consumer_context as { birth_time_notice?: string }).birth_time_notice, "使用你填报的出生时间(医院记录)排盘", ); assert.equal(guarded.consumer_context.answer_policy.can_answer_precise_timing, true); }); test("output guards and window/general instruction seams stay byte-stable", () => { const modeSource = readFileSync(new URL("../src/lib/consultation-birth-time-mode.ts", import.meta.url), "utf8"); const routeSource = readFileSync(new URL("../src/app/api/consult/route.ts", import.meta.url), "utf8"); assert.match(modeSource, /if \(mode === "general_no_birth_time"\) return guardGeneralNoBirthTimeOutput\(text\)/); assert.match( modeSource, /if \(mode === "declared_birth_window" \|\| !canAnswerPreciseTiming\) \{[\s\S]*return guardPreciseTimingOutput\(text\);/, ); assert.equal(UNVERIFIED_BIRTH_TIME_NOTICE.includes("未校正填报时间"), true); const general = createBirthTimeModeOutputGuard("general_no_birth_time", false)( "D9 在印度占星中通常用于观察婚姻与法则层面的成熟。\n你的上升是巨蟹座。", ); assert.match(general, /D9 在印度占星中通常用于观察婚姻与法则层面的成熟/); assert.doesNotMatch(general, /你的上升是巨蟹座/); const windowed = createBirthTimeModeOutputGuard("declared_birth_window", false)( "Rahu 大运为 2013年11月21日 至 2031年11月22日。", ); assert.match(windowed, /具体时间已省略/); assert.match(routeSource, /function generalNoMinuteInstruction\(hasPublicDaily: boolean\) \{/); assert.match(routeSource, /function declaredWindowInstruction\(\) \{/); assert.match( routeSource, /当前没有具体出生分钟。不得计算或推断个人星盘,也不得补 00:00、时段中点或任何候选分钟。/, ); assert.match( routeSource, /当前是声明出生窗口咨询,没有单一出生分钟。如需个人结构结论,必须调用 run-jyotish-window-consultation。/, ); });