Files
Jyotisha/frontend/tests/personal-report-density-retry.test.ts
T
jesse-uxandGrok (agent loop) 1f9947a0d7 删除三个无调用方接口和约 3000 行前端死代码
关掉未登录就会触发约 20 秒计算的入口,并记下 BUG-1342。普通导出的逐字节锁保留。自测 tsc 0 错,lint 0 error / 123 warning,改到的前端测试 fail=0,两份 Python 测试通过,test:db 失败 13 条与 Windows 已知清单一致。

Co-Authored-By: Grok (agent loop)
2026-10-14 08:39:32 +08:00

144 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { projectOrdinaryReportMarkdown } from "../src/lib/report-public-projection";
import { spawnSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import test from "node:test";
import { cleanReaderAppendixMarkdown } from "../src/lib/reader-appendix-language";
import { createPersonalReportSectionService } from "../src/lib/personal-report-section-service-core";
import { LONGFORM_SNAPSHOT_SECTION_ID } from "../src/lib/personal-report-longform-snapshot";
const golden = JSON.parse(readFileSync(new URL("./fixtures/report-density-fictional-reader.json", import.meta.url), "utf8"));
test("density full engine reader cleanup removes embedded product contracts without losing rows or numeric fields", () => {
assert.equal(golden.fixtureProvenance.fictional, true);
const raw = golden.markdown as string;
// 原值 01cc1e03c5adca2833e014156e1162fff12e5cb336e4484c5871859cd878acd7
// 新值 f3aeb8f4b09ba0a78af4ab5e7aee4db32d7499b8e6b1488f2925b35fd91750b9
// 原因:原 sha 锁的是投影截断后的泄漏输出(半句与孤立标记仍在)。整行删除 PL9 内部词后正文更短。
// 原值 f3aeb8f4b09ba0a78af4ab5e7aee4db32d7499b8e6b1488f2925b35fd91750b9
// 新值 3d16948c52d97adbdcfee45441336f8cd1ae242e3c0c99f766cb8aa0bc964067
// 原因:BUG-1026 修复单 D3 保留内部表之前的标题;逐行对照仅新增标题和空行。
assert.equal(createHash("sha256").update(projectOrdinaryReportMarkdown(raw)).digest("hex"), "3d16948c52d97adbdcfee45441336f8cd1ae242e3c0c99f766cb8aa0bc964067");
assert.match(raw, /pl9_personal_long_report\.v2/);
const clean = cleanReaderAppendixMarkdown(raw);
assert.doesNotMatch(clean, /pl9/i);
assert.equal(clean.split("\n").length, raw.split("\n").length);
assert.equal(clean.split("\n").filter(line => line.startsWith("|")).length, raw.split("\n").filter(line => line.startsWith("|")).length);
for (const field of ["sign_cn", "degree_in_sign", "nakshatra_lord"]) {
assert.equal(clean.split(field).length, raw.split(field).length);
}
// 原值: releaseRawReportAppendix 的正文不含 pl9
// 新值: 删掉这条。上面 cleanReaderAppendixMarkdown 仍断言净化正文不含 pl9,行数与数值列不变
// 原因: 原始附录出口已删除;净化合同留在 cleanReaderAppendixMarkdown
});
test("density snapshot never enters writer recovery or chapter progress lists", async () => {
const row = { user_id: "123e4567-e89b-12d3-a456-426614174001", request_id: "123e4567-e89b-12d3-a456-426614174002", section_id: LONGFORM_SNAPSHOT_SECTION_ID, status: "ready", payload: { kind: "longform_calculation_snapshot", version: 1 } };
const client = { from() { return { select() { return this; }, eq() { return this; }, order: async () => ({ data: [row], error: null }) }; } };
const service = createPersonalReportSectionService(client as never);
assert.deepEqual(await service.list(row.user_id, row.request_id), []);
const listSource = readFileSync(new URL("../src/app/api/reports/route.ts", import.meta.url), "utf8");
assert.match(listSource, /row\.section_id === LONGFORM_SNAPSHOT_SECTION_ID\) continue/);
});
for (const mode of ["snapshot-only", "appendix-only", "final-ready", "legacy", "corrupt", "mismatch", "pending-with-markdown", "late-pending", "late-ready", "parallel-ready"]) {
test(`density durable retry golden: ${mode}`, () => {
const script = `
import assert from "node:assert/strict";
import { mock } from "node:test";
import { readFileSync } from "node:fs";
mock.module("server-only", { defaultExport: {} });
const { generatePersonalReportLongform } = await import("./src/lib/personal-report-longform-generate.ts");
const { readLongformSnapshot } = await import("./src/lib/personal-report-longform-snapshot.ts");
const { projectOrdinaryReportMarkdown } = await import("./src/lib/report-public-projection.ts");
const packet = JSON.parse(readFileSync("tests/fixtures/report-density-fictional-engine.json", "utf8"));
const golden = JSON.parse(readFileSync("tests/fixtures/report-density-fictional-reader.json", "utf8"));
const mode = ${JSON.stringify(mode)};
const rows = new Map(); let calls = 0; let interrupt = mode === "snapshot-only";
let releaseWrite, reachedWrite;
const writeGate = new Promise(resolve => { releaseWrite = resolve; });
const reached = new Promise(resolve => { reachedWrite = resolve; });
let delayed = false;
const admin = { async rpc(name, args) {
if (!delayed && ((mode === "late-pending" && name === "ensure_personal_report_section") || ((mode === "late-ready" || mode === "parallel-ready") && name === "complete_personal_report_section"))) {
delayed = true; reachedWrite(); await writeGate;
}
const table = "personal_report_sections"; const current = rows.get(table);
if (name === "ensure_personal_report_section" && !current) rows.set(table, { user_id: args.p_user_id, request_id: args.p_request_id, section_id: args.p_section_id, status: "pending", payload: null });
if (name === "complete_personal_report_section" && current?.status === "pending") rows.set(table, { ...current, status: "ready", payload: structuredClone(args.p_payload) });
return { data: [], error: null };
}, from(table) { return {
select() { return this; }, eq() { return this; },
async maybeSingle() { return { data: structuredClone(rows.get(table) ?? null), error: null }; },
async upsert(row) {
if (table === "personal_report_longform_appendices" && interrupt) { interrupt = false; return { error: { message: "simulated crash" } }; }
rows.set(table, structuredClone(row)); return { error: null };
}
}; }};
const report = { id: "123e4567-e89b-12d3-a456-426614174000", userId: "123e4567-e89b-12d3-a456-426614174001", requestId: "123e4567-e89b-12d3-a456-426614174002", reportType: "personal_full", presentationMode: "default", depth: "standard", requestedThemes: ["career"], skillName: "jyotish-vedic-astrology", skillVersion: "6.9.14", skillSourceCommit: null, skillSnapshotSha256: "ab".repeat(32) };
const deps = { report, admin, profile: { birth_date: "2000-01-01", reported_birth_time: "12:00", birth_time_status: "reported", latitude: 0, longitude: 0, timezone_offset: 0, ayanamsa: "lahiri" }, candidateRange: null, displayName: "虚构测试", birthTimeStatus: "reported", now: () => new Date("2026-09-22T12:00:00Z"), fetchImpl: async () => { calls++; return Response.json({ format: "markdown", markdown: golden.markdown, fact_table_packet: packet, reader_dasha_applicability: golden.reader_dasha_applicability }); } };
if (mode === "legacy") rows.set("personal_report_longform_appendices", { report_id: report.id, user_id: report.userId, request_id: report.requestId, status: "ready", markdown: golden.markdown });
if (mode === "late-pending" || (mode === "late-ready" || mode === "parallel-ready")) {
const controller = new AbortController();
const stale = generatePersonalReportLongform({ ...deps, signal: controller.signal, fetchImpl: async () => {
calls++; return Response.json({ format: "markdown", markdown: golden.markdown + "\\nSTALE", fact_table_packet: packet, reader_dasha_applicability: golden.reader_dasha_applicability });
} });
const staleResult = stale.then(value => ({ value }), error => ({ error }));
await reached;
if (mode !== "parallel-ready") controller.abort();
const winner = await generatePersonalReportLongform(deps);
assert.equal(winner.document.factTables.length, 8); assert.equal(winner.document.charts.length, 16);
const committed = structuredClone(rows.get("personal_report_sections"));
releaseWrite(); const loser = await staleResult;
if (mode === "parallel-ready") {
assert.ok(loser.value); assert.deepEqual(loser.value.document, winner.document);
}
assert.deepEqual(rows.get("personal_report_sections"), committed);
assert.equal(rows.get("personal_report_longform_appendices").markdown, golden.markdown);
} else if (mode === "snapshot-only") await assert.rejects(generatePersonalReportLongform(deps), /appendix_persist_failed/);
else {
const first = await generatePersonalReportLongform(deps);
assert.equal(first.document.charts.length, mode === "legacy" ? 1 : 16);
if (mode !== "legacy") assert.equal(first.document.factTables.length, 8);
// appendix-only deliberately discards the result before final report persistence.
if (mode === "final-ready") report.reportDocument = structuredClone(first.document);
}
const snapshotRow = rows.get("personal_report_sections");
if (mode === "corrupt") snapshotRow.payload.charts = [];
if (mode === "mismatch") snapshotRow.payload.requestId = report.userId;
if (mode === "pending-with-markdown") { snapshotRow.status = "pending"; snapshotRow.payload = null; }
if (["corrupt", "mismatch", "pending-with-markdown"].includes(mode)) {
await assert.rejects(generatePersonalReportLongform(deps), /longform_snapshot_invalid/);
assert.equal(calls, 1);
} else {
const retry = await generatePersonalReportLongform(deps);
assert.equal(calls, mode === "legacy" ? 0 : (mode === "late-ready" || mode === "parallel-ready") ? 2 : 1);
assert.equal(retry.document.factTables?.length ?? 0, mode === "legacy" ? 0 : 8);
assert.equal(retry.document.charts.length, mode === "legacy" ? 1 : 16);
const storedMarkdown = rows.get("personal_report_longform_appendices").markdown;
assert.equal(storedMarkdown, golden.markdown);
assert.equal(projectOrdinaryReportMarkdown(storedMarkdown), projectOrdinaryReportMarkdown(golden.markdown));
const persisted = await readLongformSnapshot(admin, { reportId: report.id, userId: report.userId, requestId: report.requestId });
// 原值: releaseRawReportAppendix 的正文不含 pl9,且 legacy 补「缺少…适用性证据」、其余含 Tribhagi-40;final-ready 再打原始附录接口
// 新值: 直接核对快照。legacy 没有计算快照;其余快照的适用性原文与正文和已保存的一致
// 原因: 原始附录出口已删除。快照是否写上、正文是否原样留下,这两条不放宽
if (mode === "legacy") {
assert.equal(persisted, null);
} else {
assert.equal(persisted && persisted.status, "ready");
if (persisted && persisted.status === "ready") {
assert.equal(persisted.snapshot.readerDashaApplicability, golden.reader_dasha_applicability);
assert.equal(persisted.snapshot.markdown, storedMarkdown);
}
}
}
`;
const result = spawnSync(process.execPath, ["--experimental-test-module-mocks", "--import", "tsx", "--input-type=module", "--eval", script], {
cwd: fileURLToPath(new URL("../", import.meta.url)), encoding: "utf8", timeout: 120_000,
});
assert.equal(result.status, 0, result.stderr + result.stdout);
});
}