Files
Jyotisha/frontend/tests/consultation-route-service.test.ts
T
Jesse_ChenandCursor 814c924e4a
Independent Staging Quality Gate / validate (push) Successful in 9m20s
Independent Staging Quality Gate / publish (push) Successful in 6m51s
fix(rectification): exhaustion exit, explain layer, range reading, unknown-time scan (BUG-565–568)
Keep askable cards after exhaustion, explain each probe, read the adopted credible range in reports and chat, and compare declared periods before the minute grid when the clock is unknown.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-07 09:10:37 +08:00

426 lines
15 KiB
TypeScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
import {
ConsultationProfileTruthError,
prepareConsultationRoute,
} from "../src/lib/consultation-route-service.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,
});
test("route service loads complete server truth before billing and uses only reported time when unverified", async () => {
const order: string[] = [];
const prepared = await prepareConsultationRoute({
userId: "user-1",
mode: "unverified_birth_time",
async loadProfile(userId) {
assert.equal(userId, "user-1");
order.push("profile");
return profile;
},
beforeReserve({ consultationMode, serverChart }) {
order.push("plan");
assert.equal(consultationMode, "unverified_birth_time");
assert.equal(serverChart?.truth.selectedTimeKind, "reported");
return Object.freeze({ version: "consultation-plan-v2" });
},
async reserve() {
order.push("reserve");
return { reservation: "ok" };
},
});
assert.deepEqual(order, ["profile", "plan", "reserve"]);
assert.deepEqual(prepared.reservation, { reservation: "ok" });
assert.deepEqual(prepared.preReserveResult, { version: "consultation-plan-v2" });
assert.deepEqual(prepared.serverChart?.toolInput, {
year: 1997,
month: 8,
day: 8,
hour: 5,
minute: 30,
city: "中国 · 河北省 · 邯郸市 · 峰峰矿区",
lat: 36.420487,
lon: 114.209936,
tz: 8,
ayanamsa: "raman",
declared_accuracy: "15min",
time_source: "family_vague",
});
assert.equal(prepared.serverChart?.name, "岳辰");
assert.equal(prepared.serverChart?.truth.birthTimeSource, "approximate");
assert.equal(prepared.serverChart?.truth.birthTimeStatus, "candidate");
assert.deepEqual(prepared.serverChart?.truth.placeCodes, {
countryCode: "CN",
provinceCode: "130000",
cityCode: "130400",
districtCode: "130406",
});
});
test("route service passes the profile ayanamsa into both natal and declared-window tool input", async () => {
const natal = await prepareConsultationRoute({
userId: "user-1",
mode: "unverified_birth_time",
loadProfile: async () => ({ ...profile, ayanamsa: "lahiri" }),
reserve: async () => "reserved",
});
assert.equal(natal.serverChart?.toolInput.ayanamsa, "lahiri");
const windowed = await prepareConsultationRoute({
userId: "user-1",
mode: "general_no_birth_time",
loadProfile: async () => ({
...profile,
ayanamsa: "kp",
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.declaredWindow?.toolInput.ayanamsa, "kp");
});
test("pre-reserve plan guard sees resolved server mode and blocks billing on failure", async () => {
const order: string[] = [];
await assert.rejects(prepareConsultationRoute({
userId: "user-1",
mode: "general_no_birth_time",
loadProfile: async () => ({
...profile,
reported_birth_time: "14:49:00",
birth_time_source: "family_exact",
birth_time_status: "reported",
}),
beforeReserve({ consultationMode, serverChart }) {
order.push("plan");
assert.equal(consultationMode, "unverified_birth_time");
assert.equal(serverChart?.toolInput.minute, 49);
throw new Error("plan rejected");
},
reserve: async () => {
order.push("reserve");
return "reserved";
},
}), /plan rejected/);
assert.deepEqual(order, ["plan"]);
});
test("verified route uses only server active time", async () => {
const prepared = await prepareConsultationRoute({
userId: "user-1",
mode: "verified_chart",
loadProfile: async () => ({ ...profile, birth_time_status: "confirmed" }),
reserve: async () => "reserved",
});
assert.equal(prepared.serverChart?.toolInput.hour, 5);
assert.equal(prepared.serverChart?.toolInput.minute, 18);
assert.equal(prepared.serverChart?.truth.selectedTimeKind, "active");
});
test("user-accepted rectification time is the server-owned chart time", async () => {
const prepared = await prepareConsultationRoute({
userId: "user-1",
mode: "verified_chart",
loadProfile: async () => ({ ...profile, birth_time_status: "accepted" }),
reserve: async () => "reserved",
});
assert.equal(prepared.serverChart?.toolInput.hour, 5);
assert.equal(prepared.serverChart?.toolInput.minute, 18);
assert.equal(prepared.serverChart?.truth.birthTimeStatus, "accepted");
assert.equal(prepared.serverChart?.truth.selectedTimeKind, "active");
});
test("global normalized places use their exact coordinates and historical offset", async () => {
const prepared = await prepareConsultationRoute({
userId: "user-global",
mode: "unverified_birth_time",
loadProfile: async () => ({
...profile,
country_code: "TW",
province_code: null,
city_code: null,
district_code: null,
birth_place_label: "台湾 · 台北市",
birth_place_type: "locality",
birth_place_provider: "geonames",
birth_place_provider_id: "1668341",
timezone_id: "Asia/Taipei",
timezone_source: "iana_historical",
latitude: 25.033,
longitude: 121.5654,
timezone_offset: 9,
}),
reserve: async () => "reserved",
});
assert.deepEqual(prepared.serverChart?.toolInput, {
year: 1997,
month: 8,
day: 8,
hour: 5,
minute: 30,
city: "台湾 · 台北市",
lat: 25.033,
lon: 121.5654,
tz: 9,
ayanamsa: "raman",
declared_accuracy: "15min",
time_source: "family_vague",
});
assert.equal(prepared.serverChart?.truth.placeId, "1668341");
assert.equal(prepared.serverChart?.truth.timezoneId, "Asia/Taipei");
});
test("legacy China place codes no longer pin exact coordinates to an administrative center", async () => {
const prepared = await prepareConsultationRoute({
userId: "user-precise-cn",
mode: "unverified_birth_time",
loadProfile: async () => ({ ...profile, latitude: 36.5, timezone_offset: 9 }),
reserve: async () => "reserved",
});
assert.equal(prepared.serverChart?.toolInput.lat, 36.5);
assert.equal(prepared.serverChart?.toolInput.tz, 9);
});
test("incomplete, inconsistent, or mode-mismatched profile fails before billing", async () => {
for (const [expectedCode, invalid] of [
["profile_incomplete", { ...profile, birth_date: null }],
["profile_inconsistent", { ...profile, latitude: 91 }],
["profile_inconsistent", { ...profile, timezone_offset: 15 }],
["mode_changed", { ...profile, birth_time_status: "confirmed" }],
] as const) {
let reserveCalls = 0;
await assert.rejects(
prepareConsultationRoute({
userId: "user-1",
mode: "unverified_birth_time",
loadProfile: async () => invalid,
reserve: async () => {
reserveCalls += 1;
return "reserved";
},
}),
(error: unknown) => error instanceof ConsultationProfileTruthError
&& error.code === expectedCode,
);
assert.equal(reserveCalls, 0);
}
});
test("profile storage failure is stable and never reaches billing", async () => {
let reserveCalls = 0;
await assert.rejects(
prepareConsultationRoute({
userId: "user-1",
mode: "verified_chart",
loadProfile: async () => { throw new Error("raw database detail"); },
reserve: async () => {
reserveCalls += 1;
return "reserved";
},
}),
(error: unknown) => error instanceof ConsultationProfileTruthError
&& error.code === "profile_unavailable"
&& !error.message.includes("raw database detail"),
);
assert.equal(reserveCalls, 0);
});
test("verified global chart resolves a missing historical offset using the final active time before billing", async () => {
const order: string[] = [];
const prepared = await prepareConsultationRoute({
userId: "user-global",
mode: "verified_chart",
loadProfile: async () => ({
...profile,
birth_time_status: "confirmed",
birth_place_label: "San Francisco, California, United States",
country_code: "US",
province_code: null,
city_code: null,
district_code: null,
latitude: 37.7879363,
longitude: -122.4075201,
timezone_id: "America/Los_Angeles",
timezone_offset: null,
}),
async resolveTimezoneOffset(value, selectedTime) {
order.push("timezone");
assert.equal(selectedTime, "05:18");
return { ...(value as Record<string, unknown>), timezone_offset: -8 };
},
async reserve() {
order.push("reserve");
return "reserved";
},
});
assert.deepEqual(order, ["timezone", "reserve"]);
assert.equal(prepared.serverChart?.toolInput.tz, -8);
assert.equal(prepared.serverChart?.toolInput.hour, 5);
assert.equal(prepared.serverChart?.toolInput.minute, 18);
});
test("historical timezone failure remains pre-billing", async () => {
let reserveCalls = 0;
await assert.rejects(prepareConsultationRoute({
userId: "user-global",
mode: "verified_chart",
loadProfile: async () => ({
...profile,
birth_time_status: "confirmed",
timezone_id: "America/Los_Angeles",
timezone_offset: null,
}),
resolveTimezoneOffset: async () => { throw new Error("timezone unavailable"); },
reserve: async () => {
reserveCalls += 1;
return "reserved";
},
}), (error: unknown) => error instanceof ConsultationProfileTruthError
&& error.code === "profile_unavailable");
assert.equal(reserveCalls, 0);
});
test("stale general mode is upgraded from persisted exact-minute profile truth", async () => {
const prepared = await prepareConsultationRoute({
userId: "user-1",
mode: "general_no_birth_time",
loadProfile: async () => ({
...profile,
reported_birth_time: "14:49:00",
birth_time_source: "family_exact",
birth_time_status: "reported",
}),
reserve: async () => "reserved",
});
assert.equal(prepared.consultationMode, "unverified_birth_time");
assert.equal(prepared.serverChart?.toolInput.hour, 14);
assert.equal(prepared.serverChart?.toolInput.minute, 49);
assert.equal(prepared.serverChart?.truth.selectedTimeKind, "reported");
assert.equal(prepared.reservation, "reserved");
});
test("stale general mode upgrades period-only profiles to a declared birth window", async () => {
const prepared = await prepareConsultationRoute({
userId: "user-1",
mode: "general_no_birth_time",
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(prepared.consultationMode, "declared_birth_window");
assert.equal(prepared.serverChart, null);
assert.equal(prepared.declaredWindow?.toolInput.rangeStart, "18:00");
assert.equal(prepared.declaredWindow?.toolInput.rangeEnd, "22:59");
assert.equal(prepared.declaredWindow?.toolInput.ayanamsa, "raman");
assert.equal("hour" in (prepared.declaredWindow?.toolInput ?? {}), false);
assert.equal("minute" in (prepared.declaredWindow?.toolInput ?? {}), false);
assert.deepEqual(prepared.generalDailyReference, {
latitude: profile.latitude,
longitude: profile.longitude,
timezoneOffset: profile.timezone_offset,
placeLabel: "已保存地点",
});
assert.equal(prepared.reservation, "reserved");
});
test("a custom declared window consults those clocks instead of the leftover period bucket", async () => {
const prepared = await prepareConsultationRoute({
userId: "user-1",
mode: "general_no_birth_time",
loadProfile: async () => ({
...profile,
reported_birth_time: null,
active_birth_time: null,
birth_time_source: "period_only",
birth_time_period: "afternoon",
declared_window_start: "14:30",
declared_window_end: "15:00",
birth_time_status: "reported",
}),
reserve: async () => "reserved",
});
assert.equal(prepared.consultationMode, "declared_birth_window");
assert.equal(prepared.declaredWindow?.toolInput.rangeStart, "14:30");
assert.equal(prepared.declaredWindow?.toolInput.rangeEnd, "15:00");
});
test("consult route constructs workflow input from the route service rather than client chart fields", () => {
const route = readFileSync(new URL("../src/app/api/consult/route.ts", import.meta.url), "utf8");
const select = "name,birth_date,reported_birth_time,active_birth_time,birth_time_source,birth_time_period,declared_window_start,declared_window_end,birth_time_status,country_code,province_code,city_code,district_code,latitude,longitude,timezone_offset";
assert.match(route, new RegExp(select));
assert.match(route, /prepareConsultationRoute/);
assert.match(route, /loadCandidateRange/);
assert.match(route, /timezone_id,timezone_source,ayanamsa/);
assert.match(route, /\.\.\.prepared\.serverChart\.toolInput/);
const toolInput = route.slice(route.indexOf("const toolInput = consultationInputSchema.parse"));
assert.doesNotMatch(toolInput.slice(0, toolInput.indexOf("const workflowContext")), /\.\.\.parsed\.data/);
});
test("consult route rejects retired rectification handoff payloads", () => {
const route = readFileSync(new URL("../src/app/api/consult/route.ts", import.meta.url), "utf8");
assert.doesNotMatch(route, /rectificationHandoff/);
assert.doesNotMatch(route, /parsed\.data\.candidateRange/);
});
test("accepted rectification time attaches the adopted range and confirmed does not", async () => {
const accepted = await prepareConsultationRoute({
userId: "user-1",
mode: "verified_chart",
loadProfile: async () => ({ ...profile, birth_time_status: "accepted" }),
loadCandidateRange: async () => ({ startTime: "05:00", endTime: "05:26" }),
reserve: async () => "reserved",
});
assert.equal(accepted.serverChart?.toolInput.birth_time_accuracy, "provisional");
assert.deepEqual(accepted.serverChart?.toolInput.candidate_range, {
start_time: "05:00",
end_time: "05:26",
});
assert.equal(accepted.serverChart?.truth.birthTimeStatus, "accepted");
const confirmed = await prepareConsultationRoute({
userId: "user-1",
mode: "verified_chart",
loadProfile: async () => ({ ...profile, birth_time_status: "confirmed" }),
loadCandidateRange: async () => ({ startTime: "05:00", endTime: "05:26" }),
reserve: async () => "reserved",
});
assert.equal("birth_time_accuracy" in (confirmed.serverChart?.toolInput ?? {}), false);
assert.equal("candidate_range" in (confirmed.serverChart?.toolInput ?? {}), false);
assert.equal(confirmed.serverChart?.truth.birthTimeStatus, "confirmed");
});