import { readFile, writeFile } from 'node:fs/promises'; import path from 'node:path'; import { AUDIT_ARTIFACTS_DIR, buildAuditPayload, createSqlClient, summarizeIssues, writeAuditArtifact } from './pdf-audit-utils.ts'; async function readReport(fileName: string): Promise { const filePath = path.resolve(AUDIT_ARTIFACTS_DIR, fileName); try { const raw = await readFile(filePath, 'utf8'); return JSON.parse(raw) as T; } catch { return null; } } async function main() { const sql = createSqlClient(); try { const payload = await buildAuditPayload(sql); const templateVersionReport = await readReport>( 'template-version-report.json' ); const placeholderReport = await readReport>( 'placeholder-integrity-report.json' ); const payloadReport = await readReport>('payload-parity-report.json'); const snapshotReport = await readReport>('signature-audit-report.json'); const statuses = [ String(templateVersionReport?.overallStatus ?? 'WARNING'), String(placeholderReport?.overallStatus ?? 'WARNING'), String(payloadReport?.overallStatus ?? 'WARNING'), String(snapshotReport?.overallStatus ?? 'WARNING') ] as Array<'PASS' | 'WARNING' | 'FAIL'>; const overallStatus = summarizeIssues(statuses); const topicRuntimeReport = { audit: 'topic-runtime', overallStatus: Object.keys(payload.topicInputs).length > 0 ? 'PASS' : 'FAIL', quotationCode: payload.quotationCode, topicCount: payload.quotationMetrics.topicCount, topicInputKeys: Object.keys(payload.topicInputs) .filter((key) => key.startsWith('topic_')) .sort(), itemTopicInputKeys: Object.keys(payload.topicInputs) .filter((key) => key.startsWith('item_topic_')) .sort(), duplicateKeys: Object.keys(payload.topicInputs).filter( (key, index, array) => array.indexOf(key) !== index ), emptySections: Object.entries(payload.topicInputs) .filter(([, value]) => !Array.isArray(value) || value.length === 0) .map(([key]) => key) }; await writeAuditArtifact('topic-runtime-report.json', topicRuntimeReport); const summary = { generatedAt: new Date().toISOString(), overallStatus, quotationCode: payload.quotationCode, artifacts: { templateVersionReport: 'template-version-report.json', placeholderIntegrityReport: 'placeholder-integrity-report.json', payloadParityReport: 'payload-parity-report.json', topicRuntimeReport: 'topic-runtime-report.json', signatureAuditReport: 'signature-audit-report.json' }, statuses: { templateVersion: templateVersionReport?.overallStatus ?? 'WARNING', placeholderIntegrity: placeholderReport?.overallStatus ?? 'WARNING', payloadParity: payloadReport?.overallStatus ?? 'WARNING', topicRuntime: topicRuntimeReport.overallStatus, approvedSnapshotParity: snapshotReport?.overallStatus ?? 'WARNING' } }; const artifactPath = await writeAuditArtifact('summary.json', summary); const markdown = [ '# PDF Integrity Summary', '', `- Generated At: ${summary.generatedAt}`, `- Overall Status: ${summary.overallStatus}`, `- Quotation Code: ${summary.quotationCode}`, '', '## Statuses', '', `- Template Version Integrity: ${summary.statuses.templateVersion}`, `- Placeholder Integrity: ${summary.statuses.placeholderIntegrity}`, `- Payload Parity: ${summary.statuses.payloadParity}`, `- Topic Runtime: ${summary.statuses.topicRuntime}`, `- Approved Snapshot Parity: ${summary.statuses.approvedSnapshotParity}`, '', '## Artifact Files', '', `- ${summary.artifacts.templateVersionReport}`, `- ${summary.artifacts.placeholderIntegrityReport}`, `- ${summary.artifacts.payloadParityReport}`, `- ${summary.artifacts.topicRuntimeReport}`, `- ${summary.artifacts.signatureAuditReport}` ].join('\n'); const markdownPath = path.resolve(AUDIT_ARTIFACTS_DIR, 'summary.md'); await writeFile(markdownPath, `${markdown}\n`, 'utf8'); console.log(JSON.stringify({ ...summary, artifactPath, markdownPath }, null, 2)); } finally { await sql.end({ timeout: 5 }); } } main().catch((error) => { console.error(`[generate-pdf-integrity-report] ${error.message}`); process.exit(1); });