Files
Jyotisha/frontend/tests/personal-report-worker.test.ts
T
jesse-uxGrok (agent loop)Cursor
123295135a
Independent Staging Quality Gate / validate (push) Successful in 16m50s
Independent Staging Quality Gate / publish (push) Successful in 10m2s
fix(synastry): restore report paging and finish the third review gaps
The list query had been split into four reads, so older pages no longer followed one cursor. A7 was read from the wrong module, and the shell asked for the product switch on every mount.

Co-Authored-By: Grok (agent loop)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-19 15:53:06 +08:00

913 lines
33 KiB
TypeScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
import {
PersonalReportJobServiceError,
type PersonalReportJobRecord,
type RecoverExpiredPersonalReportJobsResult,
} from "../src/lib/personal-report-job-service-core.ts";
import type { GeneratePersonalReportResult } from "../src/lib/personal-report-generation.ts";
import type {
PersonalReportFailureCode,
PersonalReportRecord,
} from "../src/lib/personal-report-service-core.ts";
import {
PersonalReportWorkerError,
createPersonalReportWorker,
} from "../src/lib/personal-report-worker-core.ts";
import { loadReportWorkerProfile, reportWorkerUsesCandidateRange } from "../src/lib/personal-report-worker-subject.ts";
import type { ReportBillingPort } from "../src/lib/personal-report-billing.ts";
import { writeSynastryLanguage } from "../src/lib/synastry-full-generate.ts";
const USER_ID = "11111111-1111-4111-8111-111111111111";
const REQUEST_ID = "22222222-2222-4222-8222-222222222222";
const REPORT_ID = "33333333-3333-4333-8333-333333333333";
const JOB_ID = "44444444-4444-4444-8444-444444444444";
const LEASE_A = "55555555-5555-4555-8555-555555555555";
const FINGERPRINT = "a".repeat(64);
const NOW = new Date("2026-08-14T12:00:00.000Z");
type ReadyDocument = Extract<GeneratePersonalReportResult, { status: "ready" }>["document"];
const READY_DOCUMENT = { schemaVersion: "report_document.v2", reportId: REPORT_ID } as ReadyDocument;
function reportRecord(overrides: Partial<PersonalReportRecord> = {}): PersonalReportRecord {
return {
id: REPORT_ID,
userId: USER_ID,
sessionId: null,
chartProfileId: null,
requestId: REQUEST_ID,
requestFingerprint: FINGERPRINT,
reportType: "personal_full",
status: "generating",
schemaVersion: "report_document.v2",
presentationMode: "default",
depth: "standard",
requestedThemes: ["career"],
reportDocument: null,
calculationHash: null,
evidenceHash: null,
skillName: "jyotish-personal-report",
skillVersion: "1.0.0",
skillSourceCommit: null,
skillSnapshotSha256: "b".repeat(64),
failureCode: null,
createdAt: "2026-08-14T11:59:00.000Z",
updatedAt: "2026-08-14T11:59:00.000Z",
completedAt: null,
...overrides,
};
}
function jobRecord(overrides: Partial<PersonalReportJobRecord> = {}): PersonalReportJobRecord {
return {
id: JOB_ID,
userId: USER_ID,
requestId: REQUEST_ID,
requestFingerprint: FINGERPRINT,
status: "queued",
attemptCount: 0,
maxAttempts: 3,
leaseToken: null,
leaseOwner: null,
leaseAcquiredAt: null,
leaseExpiresAt: null,
heartbeatAt: null,
nextAttemptAt: null,
progressPhase: "queued",
progressPercent: 0,
lastErrorCode: null,
lastErrorAt: null,
startedAt: null,
finishedAt: null,
createdAt: "2026-08-14T11:59:00.000Z",
updatedAt: "2026-08-14T11:59:00.000Z",
...overrides,
};
}
function createHarness(input: Readonly<{
job?: PersonalReportJobRecord;
report?: PersonalReportRecord | null;
loadProfile?: (userId: string, subjectId: string) => Promise<unknown>;
generate?: (context: {
profile: unknown;
report: PersonalReportRecord;
onProgress?: (progress: Readonly<{ phase: string; completed: number; total: number }>) => Promise<void> | void;
}) => Promise<GeneratePersonalReportResult>;
loseLeaseBeforeCompletion?: boolean;
markReadyError?: PersonalReportJobServiceError;
billing?: ReportBillingPort;
}>) {
let job = input.job ?? jobRecord();
let report = input.report === undefined ? reportRecord() : input.report;
let leaseSerial = 0;
const events: string[] = [];
let generateCount = 0;
let completeCount = 0;
let reportFailureCount = 0;
let billingCompleteCount = 0;
const billingReleaseReasons: string[] = [];
function requireLease(jobId: string, leaseToken: string): PersonalReportJobRecord {
assert.equal(jobId, job.id);
assert.equal(job.status, "running");
assert.equal(leaseToken, job.leaseToken);
return job;
}
const jobs = {
async recoverExpiredLeases(): Promise<RecoverExpiredPersonalReportJobsResult> {
events.push("recover");
if (job.status !== "running" || !job.leaseExpiresAt || Date.parse(job.leaseExpiresAt) > NOW.getTime()) {
return { retryingCount: 0, failedCount: 0 };
}
if (report?.status === "ready") {
job = {
...job,
status: "ready",
leaseToken: null,
leaseOwner: null,
leaseExpiresAt: null,
progressPhase: "ready",
progressPercent: 100,
};
return { retryingCount: 0, failedCount: 0 };
}
if (job.attemptCount < job.maxAttempts) {
job = {
...job,
status: "retrying",
leaseToken: null,
leaseOwner: null,
leaseExpiresAt: null,
progressPhase: "retry_wait",
lastErrorCode: "lease_expired",
};
return { retryingCount: 1, failedCount: 0 };
}
if (report?.status === "generating") {
reportFailureCount += 1;
report = reportRecord({
...report,
status: "failed",
failureCode: "calculation_unavailable",
});
}
job = {
...job,
status: "failed",
leaseToken: null,
leaseOwner: null,
leaseExpiresAt: null,
progressPhase: "failed",
lastErrorCode: "lease_expired_attempts_exhausted",
};
return { retryingCount: 0, failedCount: 1 };
},
async claimLease({ workerId }: { workerId: string; leaseSeconds?: number; jobId?: string | null }) {
events.push("claim");
if (job.status !== "queued" && job.status !== "retrying") return null;
leaseSerial += 1;
job = {
...job,
status: "running",
attemptCount: job.attemptCount + 1,
leaseToken: LEASE_A.replace(/.$/, String(leaseSerial)),
leaseOwner: workerId,
leaseAcquiredAt: NOW.toISOString(),
leaseExpiresAt: new Date(NOW.getTime() + 120_000).toISOString(),
};
return job;
},
async heartbeatLease({ jobId, leaseToken }: { jobId: string; leaseToken: string; leaseSeconds?: number }) {
requireLease(jobId, leaseToken);
events.push("heartbeat");
return job;
},
async updateProgress({ jobId, leaseToken, phase, percent }: {
jobId: string;
leaseToken: string;
phase: string;
percent: number;
}) {
requireLease(jobId, leaseToken);
events.push(`progress:${phase}:${percent}`);
job = { ...job, progressPhase: phase, progressPercent: percent };
return job;
},
async markReady({ jobId, leaseToken }: { jobId: string; leaseToken: string }) {
requireLease(jobId, leaseToken);
events.push("job:ready");
if (input.markReadyError) throw input.markReadyError;
job = {
...job,
status: "ready",
leaseToken: null,
leaseOwner: null,
leaseExpiresAt: null,
progressPhase: "ready",
progressPercent: 100,
};
return job;
},
async completeReportReady({ jobId, leaseToken, report: reportInput, document }: {
jobId: string;
leaseToken: string;
report: PersonalReportRecord;
document: unknown;
}) {
if (input.loseLeaseBeforeCompletion) {
job = { ...job, leaseToken: LEASE_A };
throw new PersonalReportJobServiceError("lease_lost");
}
requireLease(jobId, leaseToken);
events.push("report+job:ready");
assert.equal(reportInput, report);
assert.equal(document, READY_DOCUMENT);
assert.ok(report);
completeCount += 1;
report = reportRecord({
...report,
status: "ready",
reportDocument: document as PersonalReportRecord["reportDocument"],
completedAt: NOW.toISOString(),
});
job = {
...job,
status: "ready",
leaseToken: null,
leaseOwner: null,
leaseExpiresAt: null,
progressPhase: "ready",
progressPercent: 100,
};
return job;
},
async completeReportFailed({ jobId, leaseToken, errorCode, report: reportInput, failureCode }: {
jobId: string;
leaseToken: string;
errorCode: string;
report: PersonalReportRecord;
failureCode: PersonalReportFailureCode;
}) {
if (input.loseLeaseBeforeCompletion) {
job = { ...job, leaseToken: LEASE_A };
throw new PersonalReportJobServiceError("lease_lost");
}
requireLease(jobId, leaseToken);
events.push(`report+job:failed:${failureCode}:${errorCode}`);
assert.equal(reportInput, report);
assert.ok(report);
reportFailureCount += 1;
report = reportRecord({ ...report, status: "failed", failureCode });
job = {
...job,
status: "failed",
leaseToken: null,
leaseOwner: null,
leaseExpiresAt: null,
progressPhase: "failed",
lastErrorCode: errorCode,
};
return job;
},
async markFailed({ jobId, leaseToken, errorCode }: {
jobId: string;
leaseToken: string;
errorCode: string;
}) {
requireLease(jobId, leaseToken);
events.push(`job:failed:${errorCode}`);
job = {
...job,
status: "failed",
leaseToken: null,
leaseOwner: null,
leaseExpiresAt: null,
progressPhase: "failed",
lastErrorCode: errorCode,
};
return job;
},
async scheduleRetry({ jobId, leaseToken, errorCode, nextAttemptAt }: {
jobId: string;
leaseToken: string;
errorCode: string;
nextAttemptAt?: Date;
}) {
requireLease(jobId, leaseToken);
events.push(`job:retry:${errorCode}`);
if (job.attemptCount >= job.maxAttempts) {
return { kind: "exhausted" as const, job };
}
job = {
...job,
status: "retrying",
leaseToken: null,
leaseOwner: null,
leaseExpiresAt: null,
nextAttemptAt: nextAttemptAt?.toISOString() ?? NOW.toISOString(),
lastErrorCode: errorCode,
progressPhase: "retry_wait",
};
return { kind: "scheduled" as const, job };
},
};
const reports = {
async getByUserAndRequestId(userId: string, requestId: string) {
events.push("report:get");
assert.equal(userId, USER_ID);
assert.equal(requestId, REQUEST_ID);
return report;
},
};
const worker = createPersonalReportWorker({
workerId: "test-worker",
jobs,
reports,
loadProfile: async (userId, subjectId) => {
events.push("profile:get");
assert.equal(userId, USER_ID);
return input.loadProfile ? input.loadProfile(userId, subjectId) : { birth_time_status: "confirmed" };
},
generate: async (context) => {
events.push("generate");
generateCount += 1;
return input.generate?.(context) ?? { status: "ready", document: READY_DOCUMENT, evidenceHash: "c".repeat(64) };
},
billing: input.billing
? {
reserve: input.billing.reserve,
complete: async (completeInput: Parameters<ReportBillingPort["complete"]>[0]) => {
billingCompleteCount += 1;
return input.billing!.complete(completeInput);
},
release: async (releaseInput: Parameters<ReportBillingPort["release"]>[0]) => {
billingReleaseReasons.push(releaseInput.reason);
return input.billing!.release(releaseInput);
},
}
: undefined,
now: () => NOW,
retryDelayMs: () => 1_000,
heartbeatIntervalMs: 60_000,
});
return {
worker,
events,
get job() { return job; },
get report() { return report; },
get generateCount() { return generateCount; },
get completeCount() { return completeCount; },
get reportFailureCount() { return reportFailureCount; },
get billingCompleteCount() { return billingCompleteCount; },
billingReleaseReasons,
};
}
const OTHER_ID = "66666666-6666-4666-8666-666666666666";
const typedOther = {
id: OTHER_ID, user_id: USER_ID, role: "other", name: "虚构乙",
birth_date: "1988-03-04", reported_birth_time: "07:40:00",
birth_time_source: "hospital_record", birth_time_status: "reported",
birth_place_label: "虚构港", latitude: 22.3, longitude: 114.1,
timezone_offset: 8, timezone_id: "Asia/Shanghai", ayanamsa: "raman",
};
function subjectClient(row: unknown) {
return { from(table: string) {
assert.equal(table, "chart_profiles", "another person's worker must never read profiles");
return { select() {
const query = {
eq(column: string, value: string) {
assert.equal(value, column === "id" ? OTHER_ID : column === "user_id" ? USER_ID : "other");
return query;
},
async maybeSingle() { return { data: row, error: null }; },
};
return query;
} };
} };
}
test("queued report worker passes only persisted other birth data to the fake engine", async () => {
const harness = createHarness({
report: reportRecord({ chartProfileId: OTHER_ID }),
loadProfile: (userId, subjectId) => loadReportWorkerProfile(subjectClient(typedOther), userId, subjectId),
generate: async ({ report, profile }) => {
const row = profile as Record<string, unknown>;
assert.equal(row.birth_date, typedOther.birth_date);
assert.equal(row.reported_birth_time, typedOther.reported_birth_time);
assert.equal(row.latitude, typedOther.latitude);
assert.equal(row.ayanamsa, "raman");
assert.equal(reportWorkerUsesCandidateRange(report, row), false);
assert.equal(row.rectification_case_id, undefined);
return { status: "ready", document: READY_DOCUMENT, evidenceHash: "c".repeat(64) };
},
});
assert.equal((await harness.worker.tick()).outcome, "ready");
assert.equal(harness.generateCount, 1);
assert.equal(harness.report?.chartProfileId, OTHER_ID);
});
test("deleted or foreign report subject fails terminally and releases reservation without owner fallback", async () => {
for (const row of [null, { ...typedOther, user_id: "foreign-owner" }]) {
const harness = createHarness({
report: reportRecord({ chartProfileId: OTHER_ID }),
loadProfile: (userId, subjectId) => loadReportWorkerProfile(subjectClient(row), userId, subjectId),
billing: { reserve: async () => { throw new Error("already reserved by enqueue"); }, complete: async () => true, release: async () => true },
});
assert.equal((await harness.worker.tick()).outcome, "failed");
assert.equal(harness.generateCount, 0);
assert.deepEqual(harness.billingReleaseReasons, ["profile_incomplete"]);
}
});
test("tick recovers first, heartbeats, persists the report, then closes the leased job", async () => {
const harness = createHarness({});
const result = await harness.worker.tick();
assert.equal(result.outcome, "ready");
assert.equal(harness.job.status, "ready");
assert.equal(harness.report?.status, "ready");
assert.equal(harness.completeCount, 1);
assert.equal(harness.events.filter((event) => event === "report+job:ready").length, 1);
assert.ok(harness.events.indexOf("recover") < harness.events.indexOf("claim"));
assert.ok(harness.events.includes("heartbeat"));
assert.equal(harness.events.includes("report:ready"), false);
assert.equal(harness.events.includes("job:ready"), false);
assert.deepEqual(
harness.events.filter((event) => event.startsWith("progress:")),
[
"progress:loading_context:10",
"progress:generating_report:30",
"progress:persisting_report:90",
],
);
});
test("section progress heartbeats the lease before recording percent", async () => {
const harness = createHarness({
generate: async (context) => {
await context.onProgress?.({ phase: "section:theme-career", completed: 1, total: 4 });
return { status: "ready", document: READY_DOCUMENT, evidenceHash: "c".repeat(64) };
},
});
const result = await harness.worker.tick();
assert.equal(result.outcome, "ready");
const generateAt = harness.events.indexOf("generate");
const progressAt = harness.events.indexOf("progress:section:theme-career:43");
assert.ok(generateAt >= 0);
assert.ok(progressAt > generateAt);
assert.ok(harness.events.slice(generateAt + 1, progressAt).includes("heartbeat"));
});
test("a restarted process reclaims an expired lease and does not create a second report or job", async () => {
const harness = createHarness({
job: jobRecord({
status: "running",
attemptCount: 1,
leaseToken: LEASE_A,
leaseOwner: "dead-process",
leaseExpiresAt: "2026-08-14T11:59:59.000Z",
}),
});
const first = await harness.worker.tick();
const second = await harness.worker.tick();
assert.equal(first.recovery.retryingCount, 1);
assert.equal(first.outcome, "ready");
assert.equal(second.outcome, "idle");
assert.equal(harness.job.attemptCount, 2);
assert.equal(harness.generateCount, 1);
assert.equal(harness.completeCount, 1);
assert.equal(harness.events.filter((event) => event === "report:get").length, 1);
});
test("restart after a historical split commit reconciles an expired final-attempt job to ready", async () => {
const harness = createHarness({
job: jobRecord({
status: "running",
attemptCount: 3,
maxAttempts: 3,
leaseToken: LEASE_A,
leaseOwner: "dead-after-report-commit",
leaseExpiresAt: "2026-08-14T11:59:59.000Z",
}),
report: reportRecord({
status: "ready",
reportDocument: READY_DOCUMENT as PersonalReportRecord["reportDocument"],
completedAt: "2026-08-14T11:59:58.000Z",
}),
});
const result = await harness.worker.tick();
assert.equal(result.outcome, "idle");
assert.equal(harness.job.status, "ready");
assert.equal(harness.generateCount, 0);
assert.equal(harness.completeCount, 0);
assert.deepEqual(harness.events, ["recover", "claim"]);
});
test("expired final-attempt recovery atomically fails a still-generating report and job", async () => {
const harness = createHarness({
job: jobRecord({
status: "running",
attemptCount: 3,
maxAttempts: 3,
leaseToken: LEASE_A,
leaseOwner: "expired-worker",
leaseExpiresAt: "2026-08-14T11:59:59.000Z",
}),
});
const result = await harness.worker.tick();
assert.equal(result.outcome, "idle");
assert.equal(result.recovery.failedCount, 1);
assert.equal(harness.report?.status, "failed");
assert.equal(harness.report?.failureCode, "calculation_unavailable");
assert.equal(harness.job.status, "failed");
assert.equal(harness.job.lastErrorCode, "lease_expired_attempts_exhausted");
assert.equal(harness.reportFailureCount, 1);
assert.deepEqual(harness.events, ["recover", "claim"]);
});
test("ready reconciliation storage failure never downgrades the job to failed", async () => {
const harness = createHarness({
job: jobRecord({ maxAttempts: 1 }),
report: reportRecord({
status: "ready",
reportDocument: READY_DOCUMENT as PersonalReportRecord["reportDocument"],
completedAt: "2026-08-14T11:59:58.000Z",
}),
markReadyError: new PersonalReportJobServiceError("storage_failed"),
});
const result = await harness.worker.tick();
assert.equal(result.outcome, "reconcile_deferred");
assert.equal(harness.report?.status, "ready");
assert.equal(harness.job.status, "running");
assert.equal(harness.job.attemptCount, 1);
assert.equal(harness.reportFailureCount, 0);
assert.equal(harness.events.includes("job:failed:report_generation_failed"), false);
assert.equal(harness.events.some((event) => event.startsWith("report+job:failed:")), false);
});
test("a worker that loses its lease cannot atomically commit either terminal state", async () => {
const harness = createHarness({ loseLeaseBeforeCompletion: true });
const result = await harness.worker.tick();
assert.equal(result.outcome, "lease_lost");
assert.equal(harness.completeCount, 0);
assert.equal(harness.report?.status, "generating");
assert.equal(harness.job.status, "running");
assert.equal(harness.events.includes("report+job:ready"), false);
});
test("a worker that loses its lease cannot atomically fail either terminal state", async () => {
const harness = createHarness({
loseLeaseBeforeCompletion: true,
generate: async () => ({
status: "failed",
failureCode: "report_schema_invalid",
innerReason: "agent_output_invalid",
}),
});
const result = await harness.worker.tick();
assert.equal(result.outcome, "lease_lost");
assert.equal(harness.reportFailureCount, 0);
assert.equal(harness.report?.status, "generating");
assert.equal(harness.job.status, "running");
assert.equal(harness.events.some((event) => event.startsWith("report+job:failed:")), false);
});
test("invalid writer output atomically fails the report and lease-bound job", async () => {
const harness = createHarness({
generate: async () => ({
status: "failed",
failureCode: "report_schema_invalid",
innerReason: "agent_output_invalid",
}),
});
const result = await harness.worker.tick();
assert.equal(result.outcome, "failed");
assert.equal(harness.report?.status, "failed");
assert.equal(harness.report?.failureCode, "report_schema_invalid");
assert.equal(harness.job.status, "failed");
assert.equal(harness.job.lastErrorCode, "report_schema_invalid");
assert.equal(harness.reportFailureCount, 1);
assert.equal(
harness.events.filter((event) =>
event === "report+job:failed:report_schema_invalid:report_schema_invalid").length,
1,
);
assert.equal(harness.events.some((event) => event.startsWith("job:retry:")), false);
});
test("retryable failures use the bounded job retry budget and fail the report on exhaustion", async () => {
const harness = createHarness({
job: jobRecord({ maxAttempts: 2 }),
generate: async () => {
throw new PersonalReportWorkerError("calculation_unavailable", true);
},
});
const first = await harness.worker.tick();
const second = await harness.worker.tick();
assert.equal(first.outcome, "retry_scheduled");
assert.equal(second.outcome, "failed");
assert.equal(harness.job.attemptCount, 2);
assert.equal(harness.job.status, "failed");
assert.equal(harness.report?.status, "failed");
assert.equal(harness.report?.failureCode, "calculation_unavailable");
assert.equal(harness.reportFailureCount, 1);
});
test("successful durable generation completes the reserved report usage", async () => {
const billing: ReportBillingPort = {
async reserve() { throw new Error("not used"); },
async complete(input) {
assert.equal(input.userId, USER_ID);
assert.equal(input.requestId, REQUEST_ID);
assert.deepEqual(input.usage, {
actualModelId: "model-a",
modelConfigVersion: 7,
inputTokens: 120,
outputTokens: 45,
durationMs: 0,
});
return true;
},
async release() { throw new Error("release must not run"); },
};
const harness = createHarness({
billing,
generate: async () => ({
status: "ready",
document: READY_DOCUMENT,
evidenceHash: "c".repeat(64),
usage: { inputTokens: 120, outputTokens: 45, actualModelId: "model-a", modelConfigVersion: 7 },
}),
});
const result = await harness.worker.tick();
assert.equal(result.outcome, "ready");
assert.equal(harness.billingCompleteCount, 1);
assert.deepEqual(harness.billingReleaseReasons, []);
});
test("terminal durable generation failure releases the reserved report usage", async () => {
const billing: ReportBillingPort = {
async reserve() { throw new Error("not used"); },
async complete() { throw new Error("complete must not run"); },
async release(input) {
assert.equal(input.userId, USER_ID);
assert.equal(input.requestId, REQUEST_ID);
return true;
},
};
const harness = createHarness({
billing,
generate: async () => ({
status: "failed",
failureCode: "report_schema_invalid",
innerReason: "agent_output_invalid",
}),
});
const result = await harness.worker.tick();
assert.equal(result.outcome, "failed");
assert.deepEqual(harness.billingReleaseReasons, ["report_schema_invalid"]);
assert.equal(harness.billingCompleteCount, 0);
});
test("a synastry report rejected by the reader gate releases the reservation", async () => {
const billing: ReportBillingPort = {
async reserve() { throw new Error("not used"); },
async complete() { throw new Error("complete must not run"); },
async release(input) {
assert.equal(input.userId, USER_ID);
assert.equal(input.requestId, REQUEST_ID);
return true;
},
};
let gates = 0;
const harness = createHarness({
billing,
report: reportRecord({ reportType: "synastry_full" }),
generate: async () => {
try {
await writeSynastryLanguage({
language: "zh",
names: { a: "甲", b: "乙" },
dossier: {},
segments: [
{ id: "s1", start: "2026-01", end: "2027-01", basis: "甲。" },
{ id: "s2", start: "2027-01", end: "2028-01", basis: "甲。" },
{ id: "s3", start: "2028-01", end: "2029-01", basis: "甲。" },
],
signal: new AbortController().signal,
timeoutMs: 1000,
write: async ({ sectionId }) => {
if (sectionId === "timeline") {
return { body: { segments: [{ id: "s1", phase: "靠近", text: "先把节奏说清楚。" }, { id: "s2", phase: "磨合", text: "把分歧说完。" }, { id: "s3", phase: "协作", text: "一起写下来。" }] }, inputTokens: 1, outputTokens: 1 };
}
if (sectionId === "practices") return { body: { items: [{ text: "每周谈一次。", evidence: "证据甲" }] }, inputTokens: 1, outputTokens: 1 };
return { body: { text: "这段关系先把话说清楚。", reasons: [{ plain: "节奏不同。", basis: "证据甲", evidence: "证据甲", label: "盘面" }] }, inputTokens: 1, outputTokens: 1 };
},
gate: async () => {
gates += 1;
return { ok: false, failures: [{ section: "climate", code: "too_short" }] };
},
});
} catch (error) {
assert.equal(gates, 2);
assert.equal(error instanceof Error ? error.message : "", "synastry_gate_rejected");
throw new PersonalReportWorkerError("report_guard_rejected", false);
}
throw new Error("the second gate should have rejected the report");
},
});
const result = await harness.worker.tick();
assert.equal(gates, 2);
assert.equal(result.outcome, "failed");
assert.equal(harness.report?.status, "failed");
assert.equal(harness.job.status, "failed");
assert.deepEqual(harness.billingReleaseReasons, ["report_guard_rejected"]);
assert.equal(harness.billingCompleteCount, 0);
});
test("retryable durable generation failure does not release before retry exhaustion", async () => {
const billing: ReportBillingPort = {
async reserve() { throw new Error("not used"); },
async complete() { throw new Error("complete must not run"); },
async release() { return true; },
};
const harness = createHarness({
billing,
job: jobRecord({ maxAttempts: 2 }),
generate: async () => {
throw new PersonalReportWorkerError("calculation_unavailable", true);
},
});
const first = await harness.worker.tick();
assert.equal(first.outcome, "retry_scheduled");
assert.deepEqual(harness.billingReleaseReasons, []);
});
test("zero-token settlement is forwarded after a ready cover document", async () => {
const billing: ReportBillingPort = {
async reserve() { throw new Error("not used"); },
async complete(input) {
assert.equal(input.usage.inputTokens, 0);
assert.equal(input.usage.outputTokens, 0);
assert.equal(input.usage.actualModelId, "model-a");
return true;
},
async release() { throw new Error("release must not run"); },
};
const harness = createHarness({
billing,
generate: async () => ({
status: "ready",
document: READY_DOCUMENT,
evidenceHash: "c".repeat(64),
usage: { inputTokens: 0, outputTokens: 0, actualModelId: "model-a", modelConfigVersion: 7 },
}),
});
const result = await harness.worker.tick();
assert.equal(result.outcome, "ready");
assert.equal(harness.billingCompleteCount, 1);
});
test("zero-token longform settlement completes reserved usage and does not release", async () => {
const billing: ReportBillingPort = {
async reserve() { throw new Error("not used"); },
async complete(input) {
assert.equal(input.usage.actualModelId, "catalog-default");
assert.equal(input.usage.inputTokens, 0);
assert.equal(input.usage.outputTokens, 0);
return true;
},
async release() { throw new Error("release must not run"); },
};
const harness = createHarness({
billing,
generate: async () => ({
status: "ready",
document: READY_DOCUMENT,
evidenceHash: "c".repeat(64),
usage: { inputTokens: 0, outputTokens: 0, actualModelId: "catalog-default", modelConfigVersion: 1 },
}),
});
const result = await harness.worker.tick();
assert.equal(result.outcome, "ready");
assert.equal(harness.billingCompleteCount, 1);
assert.deepEqual(harness.billingReleaseReasons, []);
});
test("billing refuses the unknown model id before the report is marked ready", async () => {
const billing: ReportBillingPort = {
async reserve() { throw new Error("not used"); },
async complete() { throw new Error("complete must not run"); },
async release() { return true; },
};
const harness = createHarness({
billing,
job: jobRecord({ maxAttempts: 2 }),
generate: async () => ({
status: "ready",
document: READY_DOCUMENT,
evidenceHash: "c".repeat(64),
usage: { inputTokens: 0, outputTokens: 0, actualModelId: "unknown" },
}),
});
const result = await harness.worker.tick();
assert.equal(result.outcome, "retry_scheduled");
assert.equal(harness.report?.status, "generating");
assert.equal(harness.billingCompleteCount, 0);
});
test("instrumentation retains the Skill guard and starts a singleton Node worker loop", () => {
const instrumentation = readFileSync(new URL("../src/instrumentation.ts", import.meta.url), "utf8");
const productionAdapter = readFileSync(new URL("../src/lib/personal-report-worker.ts", import.meta.url), "utf8");
assert.match(instrumentation, /verifyAllActiveSkillPackages\(\)/);
assert.match(instrumentation, /resolveLiveJyotishSkill\(\)/);
assert.match(instrumentation, /startPersonalReportWorker\(\)/);
assert.ok(
instrumentation.indexOf("verifyAllActiveSkillPackages()")
< instrumentation.indexOf("resolveLiveJyotishSkill()"),
);
assert.ok(
instrumentation.indexOf("resolveLiveJyotishSkill()")
< instrumentation.indexOf("startPersonalReportWorker()"),
);
assert.match(productionAdapter, /jyotishaPersonalReportWorker/);
assert.match(productionAdapter, /if \(state\.jyotishaPersonalReportWorker\) return/);
assert.match(productionAdapter, /loadReportCandidateRange/);
assert.match(productionAdapter, /generatePersonalReportLongform/);
assert.match(productionAdapter, /PERSONAL_REPORT_WRITER_ENABLED/);
assert.match(productionAdapter, /inputTokens: 0/);
assert.doesNotMatch(productionAdapter, /actualModelId: "unknown"/);
assert.doesNotMatch(productionAdapter, /from\("agentic_rectification_cases"\)/);
assert.doesNotMatch(productionAdapter, /from\("birth_time_rectification_cases"\)/);
assert.doesNotMatch(productionAdapter, /after\s*\(/);
});
test("self worker preserves linked case metadata with real column projection and no second birth authority", async () => {
const caseId = "77777777-7777-4777-8777-777777777777";
const columns: string[] = [];
const self = { ...typedOther, rectification_case_id: caseId };
const client = { from(table: string) {
assert.equal(table, "profiles");
return { select(select: string) {
columns.push(select);
return { eq(column: string, value: string) {
assert.equal(column, "id"); assert.equal(value, USER_ID);
return { async maybeSingle() { return { error: null, data: Object.fromEntries(
select.split(",").map(key => [key, self[key as keyof typeof self]]),
) }; } };
} };
} };
} };
const harness = createHarness({
loadProfile: (userId, subjectId) => loadReportWorkerProfile(client, userId, subjectId),
generate: async ({ report, profile }) => {
const row = profile as Record<string, unknown>;
assert.equal(row.rectification_case_id, caseId);
assert.equal(row.birth_date, typedOther.birth_date);
assert.equal(reportWorkerUsesCandidateRange(report, row), true);
return { status: "ready", document: READY_DOCUMENT, evidenceHash: "c".repeat(64) };
},
});
assert.equal((await harness.worker.tick()).outcome, "ready");
assert.equal(columns.length, 2);
assert.equal(columns[1], "rectification_case_id");
});