import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import test from "node:test"; import { computeRequestFingerprint } from "../src/lib/personal-report-generation.ts"; import { safeParseServerReportDocument } from "../src/lib/personal-report-contract.server-core.ts"; import { resolveReportCreate, resolveReportDelete, resolveReportRead, type ReportCreateCoreDeps, type ReportServicePort, } from "../src/lib/personal-report-route-core.ts"; import type { CreateGeneratingInput, CreateGeneratingResult, PersonalReportRecord, } from "../src/lib/personal-report-service-core.ts"; import type { ReportAgentPort, PersonalReportAgentOutput } from "../src/mastra/personal-report.ts"; const createRoute = readFileSync( new URL("../src/app/api/reports/route.ts", import.meta.url), "utf8", ); const itemRoute = readFileSync( new URL("../src/app/api/reports/[reportId]/route.ts", import.meta.url), "utf8", ); const generationSource = readFileSync( new URL("../src/lib/personal-report-generation.ts", import.meta.url), "utf8", ); const codesSource = readFileSync( new URL("../src/lib/personal-report-codes.ts", import.meta.url), "utf8", ); const coreSource = readFileSync( new URL("../src/lib/personal-report-route-core.ts", import.meta.url), "utf8", ); // --------------------------------------------------------------------------- // Fixtures // --------------------------------------------------------------------------- const UUID_A = "11111111-1111-4111-8111-111111111111"; const UUID_B = "22222222-2222-4222-8222-222222222222"; const REPORT_ID = "33333333-3333-4333-8333-333333333333"; const SESSION_ID = "44444444-4444-4444-8444-444444444444"; function chartPayload() { const planets = ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn", "Rahu", "Ketu"] .map((name, index) => ({ id: name, sign: ["Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo", "Libra", "Scorpio", "Sagittarius"][index], degree: 12.5 + index * 10, house: index + 1, retrograde: index === 6, })); const houses = Array.from({ length: 12 }, (_, index) => ({ number: index + 1, sign: ["Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo", "Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces"][index], })); return { success: true, chart: { ascendant: { sign: "Leo", degree: 12.5 }, planets, houses, dasha: { mahadashas: [{ lord: "Moon", start: "2019-01-01", end: "2029-01-01" }] }, modules: { varga_full: { d9: { houses } }, narayana_dasha: { periods: [] } }, }, consumer_context: { route: "general", core_status: "ready", available_layers: ["D1", "Vimshottari"], missing_route_layers: [], hard_blockers: [], answer_policy: { can_answer_precise_timing: true, deterministic_claims_forbidden_for: [] }, }, machine_evidence_packet: { conflicts: [], sections: [{ name: "Functional Benefic/Malefic", status: "verified", note: "" }], }, }; } function agentOutput(): PersonalReportAgentOutput { return { executiveSummary: { headline: "综合盘面以事业发展为主线", summary: "事业结构稳定,财富与婚恋需结合分盘审慎解读。", priorities: ["先聚焦职业方向"], }, thematicNarrative: [ { id: "career", title: "事业", narrative: "事业层面以十宫与 D10 结构为主,方向性判断稳定。", actions: ["在稳定领域深耕"], caveats: [], claimStatus: "single_system_inference", evidenceRefs: ["ev-audit-2"], }, ], }; } const fakeAgent: ReportAgentPort = { modelId: "test-model", async generate() { return agentOutput(); }, }; const SKILL_SNAPSHOT = { sha256: "a".repeat(64), sourceCommit: "b".repeat(40) }; function profileFixture(overrides: Record = {}) { return { name: "测试用户", birth_date: "1997-08-08", active_birth_time: "05:30:00", birth_time_status: "confirmed", latitude: 39.9, longitude: 116.4, timezone_offset: 8, birth_place_label: "北京", ...overrides, }; } class MemoryPersistence implements ReportServicePort { rows = new Map(); constructor(seed: PersonalReportRecord[] = []) { for (const row of seed) this.rows.set(row.id, row); } record(input: CreateGeneratingInput, id: string, status: "generating" | "failed"): PersonalReportRecord { return { id, userId: input.userId, sessionId: input.sessionId ?? null, chartProfileId: input.chartProfileId ?? null, requestId: input.requestId, requestFingerprint: input.requestFingerprint, reportType: input.reportType, status, schemaVersion: "report_document.v1", presentationMode: input.presentationMode, requestedThemes: input.requestedThemes ?? [], reportDocument: null, calculationHash: null, evidenceHash: null, skillSourceCommit: input.skillSourceCommit ?? null, skillSnapshotSha256: input.skillSnapshotSha256, failureCode: status === "failed" ? "calculation_unavailable" : null, createdAt: "2026-08-06T00:00:00.000Z", updatedAt: "2026-08-06T00:00:00.000Z", completedAt: null, }; } async getByUserAndRequestId(userId: string, requestId: string) { for (const row of this.rows.values()) { if (row.userId === userId && row.requestId === requestId) return row; } return null; } async createGenerating(input: CreateGeneratingInput): Promise { const existing = await this.getByUserAndRequestId(input.userId, input.requestId); if (existing) { if (existing.requestFingerprint === input.requestFingerprint) { return { kind: "replayed", record: existing }; } return { kind: "request_conflict", record: existing }; } const inFlight = [...this.rows.values()].find( (row) => row.userId === input.userId && row.status === "generating", ); if (inFlight) return { kind: "generation_in_progress", record: inFlight }; const row = this.record(input, REPORT_ID, "generating"); this.rows.set(row.id, row); return { kind: "created", record: row }; } async completeReady(userId: string, reportId: string, document: unknown) { const row = this.rows.get(reportId); assert.ok(row && row.userId === userId && row.status === "generating"); const readyRow: PersonalReportRecord = { ...row, status: "ready", reportDocument: document as PersonalReportRecord["reportDocument"], completedAt: "2026-08-06T00:01:00.000Z", }; this.rows.set(reportId, readyRow); return readyRow; } async markFailed(userId: string, reportId: string, failureCode: string) { const row = this.rows.get(reportId); assert.ok(row && row.userId === userId); const failedRow: PersonalReportRecord = { ...row, status: "failed", failureCode: failureCode as PersonalReportRecord["failureCode"], completedAt: "2026-08-06T00:01:00.000Z", }; this.rows.set(reportId, failedRow); return failedRow; } async getOwnedById(userId: string, reportId: string) { const row = this.rows.get(reportId); return row && row.userId === userId ? row : null; } async deleteOwned(userId: string, reportId: string) { const row = this.rows.get(reportId); if (!row || row.userId !== userId) return false; this.rows.delete(reportId); return true; } } function baseDeps(overrides: Partial = {}): ReportCreateCoreDeps { const persistence = new MemoryPersistence(); return { requestUrl: "https://jyotisha.chat/api/reports", origin: "https://jyotisha.chat", allowedOrigins: [], userId: UUID_A, rawBody: { requestId: UUID_B, reportType: "personal_full", presentationMode: "default", themes: ["career", "marriage", "wealth", "timing"], }, profile: profileFixture(), checkSessionOwned: async () => true, checkChartProfileOwned: async () => true, featureEnabled: true, dailyLimit: 5, counts: { countGenerating: async () => 0, countCreatedToday: async () => 0, }, persistence, model: { id: "test-model" }, runWorkflow: async () => chartPayload(), createAgent: () => fakeAgent, skillSnapshot: SKILL_SNAPSHOT, now: () => new Date("2026-08-06T00:00:00.000Z"), ...overrides, }; } // --------------------------------------------------------------------------- // Executable route core behavior (no network, no model) // --------------------------------------------------------------------------- test("core create: 401 when not logged in", async () => { const response = await resolveReportCreate(baseDeps({ userId: null })); assert.equal(response.status, 401); }); test("core create: 403 on cross-origin", async () => { const response = await resolveReportCreate(baseDeps({ origin: "https://evil.example" })); assert.equal(response.status, 403); assert.equal(response.body.code, "report_resource_forbidden"); }); test("core create: 400 on invalid payload", async () => { const response = await resolveReportCreate(baseDeps({ rawBody: { requestId: "not-a-uuid" } })); assert.equal(response.status, 400); assert.equal(response.body.code, "invalid_request"); }); test("core create: 422 profile_incomplete without a profile", async () => { const response = await resolveReportCreate(baseDeps({ profile: null })); assert.equal(response.status, 422); assert.equal(response.body.code, "profile_incomplete"); }); test("core create: 422 birth_time_not_usable for reported status", async () => { const response = await resolveReportCreate(baseDeps({ profile: profileFixture({ birth_time_status: "reported", active_birth_time: "05:30:00" }), })); assert.equal(response.status, 422); assert.equal(response.body.code, "birth_time_not_usable"); }); test("core create: 422 birth_time_not_usable for incomplete profile fields", async () => { const response = await resolveReportCreate(baseDeps({ profile: profileFixture({ latitude: null, longitude: null }), })); assert.equal(response.status, 422); assert.equal(response.body.code, "birth_time_not_usable"); }); test("core create: 403 when the session or chart profile is not owned", async () => { const response = await resolveReportCreate(baseDeps({ rawBody: { requestId: UUID_B, reportType: "personal_full", presentationMode: "default", themes: ["career"], sessionId: SESSION_ID, }, checkSessionOwned: async () => false, })); assert.equal(response.status, 403); assert.equal(response.body.code, "report_resource_forbidden"); }); test("core create: 403 when the feature is disabled", async () => { const response = await resolveReportCreate(baseDeps({ featureEnabled: false })); assert.equal(response.status, 403); assert.equal(response.body.code, "report_export_disabled"); }); test("core create: 409 request conflict for a different payload under the same requestId", async () => { const fingerprintA = computeRequestFingerprint({ reportType: "personal_full", presentationMode: "default", themes: ["career", "marriage", "wealth", "timing"], sessionId: null, chartProfileId: null, }); const fingerprintB = computeRequestFingerprint({ reportType: "personal_full", presentationMode: "default", themes: ["career"], sessionId: null, chartProfileId: null, }); assert.notEqual(fingerprintA, fingerprintB); const seeded = new MemoryPersistence([{ id: REPORT_ID, userId: UUID_A, sessionId: null, chartProfileId: null, requestId: UUID_B, requestFingerprint: fingerprintA, reportType: "personal_full", status: "ready", schemaVersion: "report_document.v1", presentationMode: "default", requestedThemes: ["career", "marriage", "wealth", "timing"], reportDocument: { ok: true } as unknown as PersonalReportRecord["reportDocument"], calculationHash: "c".repeat(64), evidenceHash: "d".repeat(64), skillSourceCommit: null, skillSnapshotSha256: "a".repeat(64), failureCode: null, createdAt: "2026-08-06T00:00:00.000Z", updatedAt: "2026-08-06T00:00:00.000Z", completedAt: "2026-08-06T00:00:00.000Z", }]); const response = await resolveReportCreate(baseDeps({ rawBody: { requestId: UUID_B, reportType: "personal_full", presentationMode: "default", themes: ["career"] }, persistence: seeded, })); assert.equal(response.status, 409); assert.equal(response.body.code, "report_request_conflict"); }); test("core create: 200 replay for a ready row with the same fingerprint", async () => { const fingerprint = computeRequestFingerprint({ reportType: "personal_full", presentationMode: "default", themes: ["career", "marriage", "wealth", "timing"], sessionId: null, chartProfileId: null, }); const seeded = new MemoryPersistence([{ id: REPORT_ID, userId: UUID_A, sessionId: null, chartProfileId: null, requestId: UUID_B, requestFingerprint: fingerprint, reportType: "personal_full", status: "ready", schemaVersion: "report_document.v1", presentationMode: "default", requestedThemes: ["career", "marriage", "wealth", "timing"], reportDocument: { ok: true } as unknown as PersonalReportRecord["reportDocument"], calculationHash: "c".repeat(64), evidenceHash: "d".repeat(64), skillSourceCommit: null, skillSnapshotSha256: "a".repeat(64), failureCode: null, createdAt: "2026-08-06T00:00:00.000Z", updatedAt: "2026-08-06T00:00:00.000Z", completedAt: "2026-08-06T00:00:00.000Z", }]); const response = await resolveReportCreate(baseDeps({ persistence: seeded })); assert.equal(response.status, 200); assert.deepEqual(response.body.reportDocument, { ok: true }); }); test("core create: 409 when a generation is already in progress", async () => { const generating = new MemoryPersistence(); generating.rows.set("55555555-5555-4555-8555-555555555555", { id: "55555555-5555-4555-8555-555555555555", userId: UUID_A, sessionId: null, chartProfileId: null, requestId: "66666666-6666-4666-8666-666666666666", requestFingerprint: "e".repeat(64), reportType: "personal_full", status: "generating", schemaVersion: "report_document.v1", presentationMode: "default", requestedThemes: [], reportDocument: null, calculationHash: null, evidenceHash: null, skillSourceCommit: null, skillSnapshotSha256: "a".repeat(64), failureCode: null, createdAt: "2026-08-06T00:00:00.000Z", updatedAt: "2026-08-06T00:00:00.000Z", completedAt: null, }); const response = await resolveReportCreate(baseDeps({ persistence: generating })); assert.equal(response.status, 409); assert.equal(response.body.code, "report_generation_in_progress"); }); test("core create: 429 at the daily limit", async () => { const response = await resolveReportCreate(baseDeps({ counts: { countGenerating: async () => 0, countCreatedToday: async () => 5 }, })); assert.equal(response.status, 429); assert.equal(response.body.code, "report_rate_limited"); }); test("core create: 502 model_unavailable when no model is configured", async () => { const persistence = new MemoryPersistence(); const response = await resolveReportCreate(baseDeps({ model: null, persistence, })); assert.equal(response.status, 502); assert.equal(response.body.code, "model_unavailable"); const row = persistence.rows.get(REPORT_ID); assert.equal(row?.status, "failed"); assert.equal(row?.failureCode, "model_unavailable"); }); test("core create: 502 calculation_unavailable when the workflow throws", async () => { const persistence = new MemoryPersistence(); const response = await resolveReportCreate(baseDeps({ persistence, runWorkflow: async () => { throw new Error("engine down"); }, })); assert.equal(response.status, 502); assert.equal(response.body.code, "calculation_unavailable"); assert.equal(persistence.rows.get(REPORT_ID)?.status, "failed"); }); test("core create: 502 when the workflow returns no usable chart", async () => { const response = await resolveReportCreate(baseDeps({ runWorkflow: async () => ({ success: false }), })); assert.equal(response.status, 502); assert.equal(response.body.code, "calculation_unavailable"); }); test("core create: 422 when the real evidence cannot support a report (fail closed)", async () => { const persistence = new MemoryPersistence(); const workflow = chartPayload() as Record; const chart = workflow.chart as Record; chart.houses = (chart.houses as unknown[]).slice(0, 6); const response = await resolveReportCreate(baseDeps({ persistence, runWorkflow: async () => workflow, })); assert.equal(response.status, 422); assert.equal(response.body.code, "calculation_unavailable"); assert.equal(persistence.rows.get(REPORT_ID)?.status, "failed"); }); test("core create: 201 ready with a document on the happy path", async () => { const persistence = new MemoryPersistence(); const response = await resolveReportCreate(baseDeps({ persistence })); assert.equal(response.status, 201); assert.ok(response.body.reportDocument); const row = persistence.rows.get(REPORT_ID); assert.equal(row?.status, "ready"); assert.ok(row?.reportDocument); }); test("core create: 422 report_guard_rejected when the agent output violates the guard", async () => { const persistence = new MemoryPersistence(); const violatingAgent: ReportAgentPort = { modelId: "test-model", async generate(): Promise { return { executiveSummary: { headline: "综合盘面", summary: "结构稳定。", priorities: [], }, thematicNarrative: [{ id: "career", title: "事业", narrative: "你必定会胜诉。", actions: [], caveats: [], claimStatus: "single_system_inference", evidenceRefs: ["ev-audit-2"], }], }; }, }; const response = await resolveReportCreate(baseDeps({ persistence, createAgent: () => violatingAgent, })); assert.equal(response.status, 422); assert.equal(response.body.code, "report_guard_rejected"); assert.equal(persistence.rows.get(REPORT_ID)?.status, "failed"); }); test("core read: 401 without user, 404 for non-owned or missing reports", async () => { const persistence = new MemoryPersistence(); const readyRow = await createReadyRow(persistence); const unauthenticated = await resolveReportRead({ requestUrl: "https://jyotisha.chat/api/reports/x", origin: null, allowedOrigins: [], userId: null, reportId: REPORT_ID, persistence, validateReadyDocument: acceptAnyDocument, }); assert.equal(unauthenticated.status, 401); const otherUser = await resolveReportRead({ requestUrl: "https://jyotisha.chat/api/reports/x", origin: null, allowedOrigins: [], userId: UUID_B, reportId: REPORT_ID, persistence, validateReadyDocument: acceptAnyDocument, }); assert.equal(otherUser.status, 404); const missing = await resolveReportRead({ requestUrl: "https://jyotisha.chat/api/reports/x", origin: null, allowedOrigins: [], userId: UUID_A, reportId: "99999999-9999-4999-8999-999999999999", persistence, validateReadyDocument: acceptAnyDocument, }); assert.equal(missing.status, 404); assert.equal(missing.body.code, "report_not_found"); assert.equal(readyRow, true); }); test("core read: ready returns the document, generating returns status only", async () => { const persistence = new MemoryPersistence(); const row = await createReadyRow(persistence); const ready = await resolveReportRead({ requestUrl: "https://jyotisha.chat/api/reports/x", origin: null, allowedOrigins: [], userId: UUID_A, reportId: REPORT_ID, persistence, validateReadyDocument: acceptAnyDocument, }); assert.equal(ready.status, 200); assert.ok(ready.body.reportDocument); assert.equal(row, true); const generatingPersistence = new MemoryPersistence(); generatingPersistence.rows.set(REPORT_ID, { ...seedRecord(), status: "generating", reportDocument: null, completedAt: null, }); const generating = await resolveReportRead({ requestUrl: "https://jyotisha.chat/api/reports/x", origin: null, allowedOrigins: [], userId: UUID_A, reportId: REPORT_ID, persistence: generatingPersistence, validateReadyDocument: acceptAnyDocument, }); assert.equal(generating.status, 200); assert.equal("reportDocument" in generating.body, false); assert.equal((generating.body.report as { status: string }).status, "generating"); }); test("core read: rejects a polluted stored ready document via canonical re-validation", async () => { const persistence = new MemoryPersistence(); persistence.rows.set(REPORT_ID, { ...seedRecord(), reportDocument: { hacked: true } as unknown as PersonalReportRecord["reportDocument"], }); const response = await resolveReportRead({ requestUrl: "https://jyotisha.chat/api/reports/x", origin: null, allowedOrigins: [], userId: UUID_A, reportId: REPORT_ID, persistence, validateReadyDocument: (document) => { const parsed = safeParseServerReportDocument(document); return parsed.ok ? { ok: true, document: parsed.document } : { ok: false }; }, }); assert.equal(response.status, 422); assert.equal(response.body.code, "report_schema_invalid"); assert.equal("reportDocument" in response.body, false); assert.equal((response.body.report as { status: string }).status, "ready"); }); test("core read: returns a legitimate ready document after canonical re-validation", async () => { const persistence = new MemoryPersistence(); await createReadyRow(persistence); const response = await resolveReportRead({ requestUrl: "https://jyotisha.chat/api/reports/x", origin: null, allowedOrigins: [], userId: UUID_A, reportId: REPORT_ID, persistence, validateReadyDocument: (document) => { const parsed = safeParseServerReportDocument(document); return parsed.ok ? { ok: true, document: parsed.document } : { ok: false }; }, }); assert.equal(response.status, 200); assert.ok(response.body.reportDocument); }); test("core delete: owner-only, 200 ok for the owner and 404 otherwise", async () => { const persistence = new MemoryPersistence(); await createReadyRow(persistence); const otherUser = await resolveReportDelete({ requestUrl: "https://jyotisha.chat/api/reports/x", origin: null, allowedOrigins: [], userId: UUID_B, reportId: REPORT_ID, persistence, }); assert.equal(otherUser.status, 404); const owner = await resolveReportDelete({ requestUrl: "https://jyotisha.chat/api/reports/x", origin: null, allowedOrigins: [], userId: UUID_A, reportId: REPORT_ID, persistence, }); assert.equal(owner.status, 200); assert.deepEqual(owner.body, { ok: true }); assert.equal(persistence.rows.has(REPORT_ID), false); }); function acceptAnyDocument(document: unknown): { ok: true; document: unknown } | { ok: false } { return { ok: true, document }; } async function createReadyRow(persistence: MemoryPersistence): Promise { const fingerprint = computeRequestFingerprint({ reportType: "personal_full", presentationMode: "default", themes: ["career", "marriage", "wealth", "timing"], sessionId: null, chartProfileId: null, }); const response = await resolveReportCreate(baseDeps({ persistence })); if (response.status !== 201) return false; const row = persistence.rows.get(REPORT_ID); assert.equal(row?.requestFingerprint, fingerprint); return true; } function seedRecord(): PersonalReportRecord { return { id: REPORT_ID, userId: UUID_A, sessionId: null, chartProfileId: null, requestId: UUID_B, requestFingerprint: "f".repeat(64), reportType: "personal_full", status: "ready", schemaVersion: "report_document.v1", presentationMode: "default", requestedThemes: ["career", "marriage", "wealth", "timing"], reportDocument: { ok: true } as unknown as PersonalReportRecord["reportDocument"], calculationHash: "c".repeat(64), evidenceHash: "d".repeat(64), skillSourceCommit: null, skillSnapshotSha256: "a".repeat(64), failureCode: null, createdAt: "2026-08-06T00:00:00.000Z", updatedAt: "2026-08-06T00:00:00.000Z", completedAt: "2026-08-06T00:00:00.000Z", }; } // --------------------------------------------------------------------------- // Source-level production wiring checks // --------------------------------------------------------------------------- test("POST route uses dual clients: authenticated reads + admin persistence", () => { assert.match(createRoute, /createServerSupabaseClient\(\)/); assert.match(createRoute, /\.from\("profiles"\)/); assert.match(createRoute, /createAdminSupabaseClient\(\)/); assert.match(createRoute, /createSupabasePersonalReportService\(admin\)/); assert.match(createRoute, /createPersonalReportDataClient\(admin\)/); assert.doesNotMatch(createRoute, /resolveReportPersistencePort|resolveReportContractPort/); assert.doesNotMatch(createRoute, /ReportPersistenceUnavailableError|ReportContractUnavailableError/); assert.doesNotMatch(createRoute, /not wired yet|尚未就绪/); }); test("GET/DELETE use the authenticated client (least privilege) and the core handlers", () => { assert.match(itemRoute, /createServerSupabaseClient\(\)/); assert.match(itemRoute, /createSupabasePersonalReportService\(supabase\)/); assert.match(itemRoute, /resolveReportRead/); assert.match(itemRoute, /resolveReportDelete/); assert.doesNotMatch(itemRoute, /createAdminSupabaseClient/); }); test("route core enforces same-origin and never leaks raw exception text", () => { assert.match(coreSource, /checkSameOrigin/); assert.match(coreSource, /REPORT_STABLE_CODES\.resourceForbidden/); assert.doesNotMatch(createRoute, /error\.message\)/); assert.doesNotMatch(itemRoute, /error\.message\)/); assert.doesNotMatch(createRoute, /\.stack/); assert.doesNotMatch(itemRoute, /\.stack/); }); test("POST route reads the daily limit from env and resolves a real skill snapshot", () => { assert.match(createRoute, /readPersonalReportDailyLimit\(process\.env\)/); assert.match(createRoute, /resolveSkillSnapshot\(\)/); assert.doesNotMatch(createRoute, /每日.*上限.*\d|PERSONAL_REPORT_DAILY_LIMIT.*\?\?\s*["']\d/); }); test("GET route re-validates stored ready documents through the canonical server parse", () => { assert.match(itemRoute, /safeParseServerReportDocument\(document\)/); assert.match(itemRoute, /validateReadyDocument/); assert.match(coreSource, /validateReadyDocument/); assert.match(coreSource, /canonical server parse/); assert.match(coreSource, /REPORT_STABLE_CODES\.schemaInvalid/); assert.doesNotMatch(coreSource, /client.*validation|validate.*client/i); }); test("POST route never generates HTML/PDF/base64 or local paths", () => { assert.doesNotMatch(createRoute, /window\.print|html2canvas|jsPDF|base64|\.pdf/); assert.doesNotMatch(createRoute, /sendFile|createWriteStream|\/opt\/|\/var\/|\/Users\//); }); test("stable error codes live in the dependency-free codes module", () => { for (const code of [ "profile_incomplete", "birth_time_not_usable", "report_generation_in_progress", "report_rate_limited", "calculation_unavailable", "model_unavailable", "report_schema_invalid", "report_guard_rejected", "report_not_found", "report_request_conflict", ]) { assert.ok(codesSource.includes(`"${code}"`), `missing stable code ${code}`); } // The codes module must stay free of heavy imports so route handlers that // only need codes never trace the generation/skill-snapshot logic. assert.doesNotMatch(codesSource, /node:fs|node:path|node:crypto|readdirSync|readFileSync/); assert.doesNotMatch(createRoute, /dangerouslySetInnerHTML/); }); test("GET route imports codes from the pure module, never the generation module", () => { assert.match(itemRoute, /personal-report-codes/); assert.doesNotMatch(itemRoute, /personal-report-generation/); assert.doesNotMatch(itemRoute, /resolveSkillSnapshot|buildReportEvidencePacket|canonicalSerialize/); assert.match(generationSource, /personal-report-codes/); }); test("generation pipeline re-validates with the canonical server parse after the guard", () => { assert.match(generationSource, /safeParseServerReportDocument\(guarded\.document\)/); assert.match(generationSource, /assembleReportDocument/); }); test("evidence hash is the canonical appendix hash, never a model self-report", () => { assert.match(generationSource, /computeEvidenceHash\(parsed\.document\.evidenceAppendix\)/); assert.match(generationSource, /computeEvidenceHash\(appendix\)/); }); test("skill snapshot resolution fails closed without a real source", () => { assert.match(generationSource, /SkillSnapshotUnavailableError/); assert.match(generationSource, /source-manifest\.json/); assert.doesNotMatch(generationSource, /skill_snapshot_unavailable.*digest/); }); test("generation module has no filesystem/path scanning (static manifest import only)", () => { assert.doesNotMatch(generationSource, /node:fs|node:path|readdirSync|readFileSync/); assert.doesNotMatch(generationSource, /\bskillDirectory\b|\brepoRoot\b|turbopackIgnore/); assert.match(generationSource, /source-manifest\.json/); });