feat(report): add dense personal report appendix

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
jesse-ux
2026-09-23 10:42:17 +08:00
co-authored by Claude Code
parent a7f82dc2a6
commit bbd96d3b6b
44 changed files with 48833 additions and 50 deletions
@@ -2,6 +2,11 @@ import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import test from "node:test";
import { startPostgresFixture } from "./helpers/postgres-fixture.ts";
import { readFileSync } from "node:fs";
import { assembleReportFactTables } from "../src/lib/report-fact-tables";
import { assembleLongformCharts } from "../src/lib/personal-report-generation";
import { hashLongformMarkdown } from "../src/lib/personal-report-longform-appendix";
import { LONGFORM_SNAPSHOT_SECTION_ID, validateLongformSnapshot } from "../src/lib/personal-report-longform-snapshot";
const runnerPath = new URL("../scripts/db-migrate.mjs", import.meta.url).pathname;
const USER_A = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
@@ -150,6 +155,26 @@ test("personal report sections enforce owner-read RLS and service-owned durable
),
"SET\n0",
);
const packet = JSON.parse(readFileSync(new URL("./fixtures/report-density-fictional-engine.json", import.meta.url), "utf8"));
const reader = JSON.parse(readFileSync(new URL("./fixtures/report-density-fictional-reader.json", import.meta.url), "utf8"));
const identity = { reportId: REPORT_ID, userId: USER_A, requestId: REQUEST_ID };
const snapshot = validateLongformSnapshot({
...identity, kind: "longform_calculation_snapshot", version: 1,
markdown: reader.markdown, contentSha256: hashLongformMarkdown(reader.markdown),
factTables: assembleReportFactTables(packet), charts: assembleLongformCharts(packet, "ev-cover-longform"),
readerDashaApplicability: reader.reader_dasha_applicability,
}, identity);
const encoded = JSON.stringify(snapshot).replaceAll("'", "''");
fixture.psqlAs("service_runtime", "service-runtime-test-password", serviceSql(`
select status from public.ensure_personal_report_section('${USER_A}', '${REQUEST_ID}', '${LONGFORM_SNAPSHOT_SECTION_ID}', 2);
select status from public.complete_personal_report_section('${USER_A}', '${REQUEST_ID}', '${LONGFORM_SNAPSHOT_SECTION_ID}', '${encoded}'::jsonb);
-- Late ensure and conflicting completion must preserve the first committed snapshot.
select status from public.ensure_personal_report_section('${USER_A}', '${REQUEST_ID}', '${LONGFORM_SNAPSHOT_SECTION_ID}', 2);
select status from public.complete_personal_report_section('${USER_A}', '${REQUEST_ID}', '${LONGFORM_SNAPSHOT_SECTION_ID}', '{"kind":"stale-worker"}'::jsonb);
`));
const durable = JSON.parse(fixture.psql(`select payload from public.personal_report_sections where user_id = '${USER_A}' and request_id = '${REQUEST_ID}' and section_id = '${LONGFORM_SNAPSHOT_SECTION_ID}'`));
assert.deepEqual(validateLongformSnapshot(durable, identity), snapshot);
assert.equal(fixture.psqlAs("app_runtime", "app-runtime-test-password", selectAsAuthenticated(USER_B, `select count(*) from public.personal_report_sections where section_id = '${LONGFORM_SNAPSHOT_SECTION_ID}'`)), `SET\n${USER_B}\n0`);
} finally {
fixture.stop();
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+2 -1
View File
@@ -1443,6 +1443,7 @@ test("failed report reads aggregate existing section error codes without importi
assert.match(itemRoute, /listSections/);
assert.match(itemRoute, /createPersonalReportSectionService\(supabase as never\)/);
assert.match(createRoute, /from\("personal_report_sections"\)/);
assert.match(createRoute, /select\("request_id, status, last_error_code"\)/);
assert.match(createRoute, /select\("request_id, section_id, status, last_error_code"\)/);
assert.match(createRoute, /row\.section_id === LONGFORM_SNAPSHOT_SECTION_ID\) continue/);
assert.doesNotMatch(itemRoute, /personal-report-generation/);
});
@@ -0,0 +1,142 @@
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 { releaseRawReportAppendix } from "../src/lib/personal-report-raw-appendix";
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;
// Captured by running baeec66f8's actual projector on this complete fictional engine Markdown.
assert.equal(createHash("sha256").update(projectOrdinaryReportMarkdown(raw)).digest("hex"), "01cc1e03c5adca2833e014156e1162fff12e5cb336e4484c5871859cd878acd7");
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);
}
assert.doesNotMatch(releaseRawReportAppendix(raw, golden.reader_dasha_applicability).markdown, /pl9/i);
});
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 { releaseRawReportAppendix } = await import("./src/lib/personal-report-raw-appendix.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 });
const raw = releaseRawReportAppendix(storedMarkdown, persisted?.snapshot?.readerDashaApplicability).markdown;
assert.doesNotMatch(raw, /pl9/i);
assert.match(raw, mode === "legacy" ? /缺少本次计算的结构化适用性证据/ : /Tribhagi-40/);
if (mode === "final-ready") {
mock.module("@/lib/personal-report-entitlement", { namedExports: { checkSameOrigin: () => ({ ok: true }), resolveAllowedReportOrigins: () => [] } });
mock.module("@/lib/personal-report-service", { namedExports: { createSupabasePersonalReportService: () => ({ getOwnedById: async () => ({ ...report, status: "ready" }) }) } });
mock.module("@/lib/supabase/config", { namedExports: { isSupabaseConfigurationError: () => false } });
mock.module("@/lib/supabase/server", { namedExports: { createServerSupabaseClient: async () => ({ ...admin, auth: { getUser: async () => ({ data: { user: { id: report.userId } }, error: null }) } }) } });
const { POST } = await import("./src/app/api/reports/[reportId]/raw-appendix/route.ts");
const response = await POST(new Request("https://staging.jyotisha.chat/api/reports/" + report.id + "/raw-appendix", { method: "POST" }), { params: Promise.resolve({ reportId: report.id }) });
assert.equal(response.status, 200);
const body = await response.json();
assert.equal(body.markdown, raw);
assert.doesNotMatch(body.markdown, /pl9|pyjhora|jhora|cmd_[a-z0-9_]+|build_professional_report_reference_packet/i);
assert.equal(calls, 1);
}
}
`;
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);
});
}
@@ -111,6 +111,7 @@ function makeBundle(input: Readonly<{
const blocked = input.blocked ?? [];
const statuses = new Map<string, EvidenceRefStatus>();
statuses.set("ev-tech-d1", "verified");
for (const chart of input.charts ?? []) statuses.set(`ev-tech-${chart.id.toLowerCase()}`, "verified");
for (const theme of input.themes) {
for (const ref of theme.refs) statuses.set(ref, "verified");
}
@@ -0,0 +1,112 @@
import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import test from "node:test";
import { releaseRawReportAppendix, MISSING_DASHA_APPLICABILITY } from "../src/lib/personal-report-raw-appendix.ts";
import { projectOrdinaryReportMarkdown } from "../src/lib/report-public-projection.ts";
import { cleanReaderAppendixMarkdown } from "../src/lib/reader-appendix-language.ts";
// Vocabulary/security cases, not fabricated engine contract fixtures.
test("raw appendix retains status rows and raw columns without changing ordinary projection", () => {
const source = "# 数据\n\n| sign_cn | degree_in_sign | nakshatra_lord |\n| --- | --- | --- |\n| Aries | 12.5 | parameter_sensitive |\n";
const before = projectOrdinaryReportMarkdown(source);
const result = releaseRawReportAppendix(source);
assert.equal(result.documentKind, "raw_appendix");
assert.equal(result.markdown, source.replace("parameter_sensitive", "参数敏感") + MISSING_DASHA_APPLICABILITY);
assert.equal(result.markdown.split("\n").filter((line) => line.startsWith("|")).length, 3);
assert.equal(projectOrdinaryReportMarkdown(source), before);
assert.doesNotMatch(before, /parameter_sensitive|参数敏感|12\.5/);
});
test("raw appendix cleans old cache vocabulary but leaves English prose intact", () => {
for (const [value, label] of Object.entries({
parameter_sensitive: "参数敏感", pyjhora_behavior_only: "仅单一外部参照,未做多引擎核对",
not_multiengine_parity: "仅单一外部参照,未做多引擎核对", unresolved_external_tuple_boundary: "外部边界未对齐",
partial_verified: "部分核验", raw_appendix_only: "仅原始附录可见", missing_in_local: "本地暂无",
})) assert.equal(cleanReaderAppendixMarkdown(value), label);
for (const value of ["PL9 第 83-88 页", "PL9 第 40 / 48 页", "PL9 page 99-100", "PL9.pdf"]) {
assert.equal(cleanReaderAppendixMarkdown(value), "外部参照资料");
}
assert.equal(cleanReaderAppendixMarkdown("PyJHora JHora cmd_full_reading"), "外部参照引擎 外部参照引擎 本地计算");
const prose = "The available result was computed and executed, not blocked.";
assert.equal(cleanReaderAppendixMarkdown(prose), prose);
assert.equal(cleanReaderAppendixMarkdown("| blocked | `executed` | available | computed |"), "| 暂不可用 | `已执行` | 可用 | 已计算 |");
});
test("raw appendix keeps established HTML URL secret and chart-fence safety boundaries", () => {
const fence = '```jyotish-chart\n{"version":1,"id":"D1","title":"本命","layout":"north","ascendant":{"sign":"Aries","degree":1},"planets":[]}\n```\n';
const raw = '<script>alert(1)</script>\n<iframe src="https://evil.example"></iframe>\n[bad](javascript:alert(1))\nhttp://127.0.0.1:5200/internal\nsk-testsecretvalue\n' + fence;
const result = releaseRawReportAppendix(raw).markdown;
assert.doesNotMatch(result, /script|iframe|javascript:|127\.0\.0\.1|sk-testsecretvalue/);
assert.ok(result.includes(fence));
assert.equal(releaseRawReportAppendix(result).markdown, result);
});
function routeCase(mode: string) {
const script = `
import { mock } from "node:test";
const mode = ${JSON.stringify(mode)};
const id = "123e4567-e89b-12d3-a456-426614174000";
const filters = [];
let reads = 0;
mock.module("@/lib/personal-report-entitlement", { namedExports: {
checkSameOrigin: () => ({ ok: mode !== "cross-origin" }), resolveAllowedReportOrigins: () => [],
}});
mock.module("@/lib/personal-report-service", { namedExports: {
createSupabasePersonalReportService: () => ({ getOwnedById: async (userId, reportId) => {
if (userId !== "owner" || reportId !== id) throw new Error("identity mismatch");
return mode === "foreign" ? null : { status: mode === "generating" ? "generating" : "ready", requestId: "request" };
}}),
}});
mock.module("@/lib/supabase/config", { namedExports: { isSupabaseConfigurationError: () => false }});
mock.module("@/lib/supabase/server", { namedExports: {
createServerSupabaseClient: async () => ({
auth: { getUser: async () => ({ data: { user: mode === "anonymous" ? null : { id: "owner" } }, error: null }) },
from: (table) => table === "personal_report_sections" ? {
select() { return this; }, eq() { return this; }, async maybeSingle() { return { data: null, error: null }; }
} : ({
select() { return this; }, eq(key, value) { filters.push([key,value]); return this; },
async maybeSingle() { reads++; return { error: null, data: mode === "missing" ? null : {
report_id: mode === "wrong-report" ? "other" : id,
user_id: mode === "wrong-owner" ? "other" : "owner",
request_id: mode === "wrong-request" ? "other" : "request",
status: mode === "pending" ? "pending" : "ready", markdown: "| degree_in_sign | parameter_sensitive |",
}}; },
}),
}),
}});
globalThis.fetch = () => { throw new Error("must not recalculate"); };
const { POST } = await import("./src/app/api/reports/[reportId]/raw-appendix/route.ts");
const response = await POST(new Request("https://staging.jyotisha.chat/api/reports/" + id + "/raw-appendix", { method: "POST" }),
{ params: Promise.resolve({ reportId: mode === "invalid-id" ? "invalid" : id }) });
console.log(JSON.stringify({ status: response.status, body: await response.json(), cache: response.headers.get("cache-control"), filters, reads }));
`;
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",
});
assert.equal(result.status, 0, result.stderr || result.stdout);
return JSON.parse(result.stdout.trim());
}
for (const [mode, status] of Object.entries({ anonymous: 401, "cross-origin": 403, foreign: 404, "invalid-id": 404, generating: 409, missing: 410, pending: 410, "wrong-report": 410, "wrong-owner": 410, "wrong-request": 410, ready: 200 })) {
test(`raw appendix route guards ${mode}`, () => {
const result = routeCase(mode);
assert.equal(result.status, status);
assert.equal(result.cache, "private, no-store");
if (status < 410 && status !== 200) assert.equal(result.reads, 0);
if (status === 200) {
assert.deepEqual(result.filters, [["report_id", "123e4567-e89b-12d3-a456-426614174000"], ["user_id", "owner"], ["request_id", "request"]]);
assert.deepEqual(result.body, { documentKind: "raw_appendix", format: "markdown", markdown: "| degree_in_sign | 参数敏感 |" + MISSING_DASHA_APPLICABILITY });
} else assert.equal(result.body.markdown, undefined);
});
}
test("raw appendix UI is independent of ordinary export and accepts no birth payload", () => {
const ui = readFileSync(new URL("../src/components/personal-report/raw-appendix-download.tsx", import.meta.url), "utf8");
assert.match(ui, /下载原始附录/);
assert.match(ui, /\/raw-appendix/);
assert.doesNotMatch(ui, /正在加载|Spinner|body:|birth|projectOrdinaryReportMarkdown/);
const ordinary = readFileSync(new URL("../src/lib/personal-report-longform-download.ts", import.meta.url), "utf8");
assert.doesNotMatch(ordinary, /raw-appendix/);
});
+70
View File
@@ -0,0 +1,70 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
import { assembleReportFactTables } from "../src/lib/report-fact-tables";
import { reportFactTablesSchema } from "../src/lib/report-fact-table-schema";
import { assembleLongformCharts } from "../src/lib/personal-report-generation";
import { buildLongformCoverDocument } from "../src/lib/personal-report-longform-cover";
import { CHART_IDS, reportDocumentV2Schema } from "../src/lib/personal-report-contract";
import { projectOrdinaryReportMarkdown } from "../src/lib/report-public-projection";
const packet = JSON.parse(readFileSync(new URL("./fixtures/report-density-fictional-engine.json", import.meta.url), "utf8"));
const resolve = (path: string) => path.replace(/\[(\d+)\]/g, ".$1").split(".").reduce((value, key) => value?.[key], packet);
test("density golden: sixteen real charts have complete houses and nine occupants", () => {
const charts = assembleLongformCharts(packet, "ev-cover-longform");
assert.deepEqual(charts.map(chart => chart.id), [...CHART_IDS]);
assert.equal(reportDocumentV2Schema.shape.charts.safeParse(charts).success, true);
const document = buildLongformCoverDocument({
report: { id: "123e4567-e89b-12d3-a456-426614174000", reportType: "personal_full", presentationMode: "default", depth: "standard", requestedThemes: ["career"], skillName: "jyotish-vedic-astrology", skillVersion: "6.9.14", skillSourceCommit: null, skillSnapshotSha256: "ab".repeat(32) },
subject: { displayName: "虚构测试", birthTimeStatus: "reported", birthPlaceLabel: "虚构地点" },
markdown: "# 个人报告\n\n## 摘要\n\n原始计算供核对。", charts, factTables: assembleReportFactTables(packet),
});
assert.equal(document.factTables?.length, 8);
assert.equal(document.charts.length, 16);
for (const chart of charts) {
assert.equal(chart.houses.length, 12);
assert.equal(chart.houses.flatMap(h => h.occupants).length, 9);
assert.equal(chart.claimStatus, "parameter_sensitive");
}
});
test("density applicability remains outside ordinary narrative projection", () => {
const prose = "# 个人报告\n\n这是普通正文。\n";
const appendix = "\n## 辅助时间轴适用性(参数敏感)\n\n| 大运族 | 是否适用 / 原因 | 使用边界 |\n| --- | --- | --- |\n| Yogini | 已返回周期 | 第二时间轴,仅供交叉核对,不单独生成应期 |\n";
assert.equal(projectOrdinaryReportMarkdown(prose + appendix), projectOrdinaryReportMarkdown(prose + "\n## 核对(参数敏感)\n"));
assert.doesNotMatch(projectOrdinaryReportMarkdown(prose + appendix), /Yogini|第二时间轴/);
});
test("density golden: eight server groups contain only unchanged engine leaves", () => {
assert.equal(packet.fixtureProvenance.fictional, true);
const tables = assembleReportFactTables(packet);
assert.equal(tables.length, 8);
for (const table of tables) {
assert.ok(table.rows.length > 0, table.id);
for (const row of table.rows) assert.deepEqual(row.cells[1], resolve(row.sourcePath), row.sourcePath);
}
assert.equal(tables.find(t => t.id === "shadbala")?.rows.length, 42);
assert.equal(tables.find(t => t.id === "ashtakavarga")?.rows.length, 108);
assert.ok(tables.find(t => t.id === "annual")?.rows.some(row => row.sourcePath.includes("advanced_systems.sahams")));
});
test("density golden: Sade Sati reports missing cycle dates without inventing them", () => {
const table = assembleReportFactTables(packet).find(t => t.id === "sade_sati")!;
assert.match(table.note, /尚无三轮起止日期/);
assert.equal(table.rows.length, 6);
assert.equal(table.claimStatus, "parameter_sensitive");
assert.ok(table.rows.every(row => !/start|end|date/.test(row.sourcePath)));
});
test("density facts preserve declared limitations and reject malformed provenance", () => {
const altered = structuredClone(packet);
altered.worksheets.advanced_systems.yogas_doshas.sade_sati.claimStatus = "user_history_verification_required";
assert.equal(assembleReportFactTables(altered).find(t => t.id === "sade_sati")?.claimStatus, "user_history_verification_required");
const tables = assembleReportFactTables(packet);
tables[0].rows[0].sourcePath = tables[0].sourcePath + "_wrong.lord";
assert.equal(reportFactTablesSchema.safeParse(tables).success, false);
assert.deepEqual(assembleReportFactTables(undefined), []);
});