/** * Render gate. Refuses to let a stale, missing, or unreviewed asset reach the * composition. * * Run before `demo:render`. Remotion also rejects a bad capture at render time * via requireCapture(), but failing here gives a readable list instead of one * React error, and it catches drift the composition cannot see — a file whose * bytes changed after it was approved. */ import { createHash } from 'node:crypto'; import { readFile, readdir } from 'node:fs/promises'; import { join } from 'node:path'; type Capture = { id: string; file: string; width: number; height: number; contentHash: string; audienceVerdict: string; auditStatus: string; }; const CAPTURE_ROOT = 'demo/public'; async function main(): Promise { const manifest = JSON.parse(await readFile('demo/capture-manifest.json', 'utf8')) as { buildRevision: string; captures: Capture[]; }; const scenes = await readFile('demo/src/scenes.ts', 'utf8'); const problems: string[] = []; for (const capture of manifest.captures) { if (capture.auditStatus !== 'pass') { problems.push(`${capture.id}: auditStatus is '${capture.auditStatus}', expected 'pass'`); } if (capture.audienceVerdict !== 'perfect') { problems.push( `${capture.id}: audienceVerdict is '${capture.audienceVerdict}'. Only 'perfect' promotes — ` + `fix the screen at its owning layer or cut the beat honestly.`, ); } let bytes: Buffer; try { bytes = await readFile(join(CAPTURE_ROOT, capture.file)); } catch { problems.push(`${capture.id}: file missing at ${join(CAPTURE_ROOT, capture.file)}`); continue; } const actual = `sha256:${createHash('sha256').update(bytes).digest('hex')}`; if (actual !== capture.contentHash) { problems.push( `${capture.id}: content hash changed since approval — the file was re-captured without ` + `being re-audited. Re-inspect it, then update the manifest.`, ); } } // Every promoted capture should be used, and every referenced capture promoted. const referenced = [...scenes.matchAll(/captureId: '([^']+)'/g)].map((m) => m[1]); const promoted = manifest.captures.map((c) => c.id); for (const id of referenced) { if (!promoted.includes(id)) { problems.push(`scene references '${id}', which is not a promoted capture`); } } const orphans = promoted.filter((id) => !referenced.includes(id)); // Nothing may sit in the promoted directory without a manifest row. const onDisk = (await readdir(join(CAPTURE_ROOT, 'captures'))).filter((f) => f.endsWith('.png')); for (const file of onDisk) { if (!promoted.includes(file.replace(/\.png$/, ''))) { problems.push(`${file} is in demo/public/captures but has no manifest row`); } } process.stdout.write( `preflight: ${manifest.captures.length} captures, revision ${manifest.buildRevision}\n`, ); if (orphans.length > 0) { // Not fatal: a capture can be a standalone artefact. Reported so it is a // decision rather than an accident. process.stdout.write(` note: promoted but unused by any scene: ${orphans.join(', ')}\n`); } // The title card must not contradict the manifest. It hardcoded the image tag // and check count until 2026-08-30 and drifted two image rolls behind, so the // rendered walkthrough described a deployment that was no longer running. // scenes.ts now derives both; this asserts the derivation is actually in place, // because a future edit could paste a literal back in. const verifiedTag = manifest.verifiedImage.split('@')[0]?.split(':').pop() ?? manifest.verifiedImage; // Strip comments before scanning: this file's own explanation of the rule cites // the stale literal as an example, and matching that would fail forever. const scenesCode = scenes .replace(/\/\*[\s\S]*?\*\//g, '') .split('\n') .filter((line) => !line.trim().startsWith('//') && !line.trim().startsWith('*')) .join('\n'); if (!scenesCode.includes('DEPLOYMENT_FOOTER')) { problems.push( 'scenes.ts no longer uses DEPLOYMENT_FOOTER — the title card has been hardcoded again ' + 'and will drift from the verified image on the next roll', ); } if (/image m12-[a-z0-9-]+ ·/.test(scenesCode)) { problems.push( `scenes.ts contains a hardcoded image tag; it must derive from manifest.verifiedImage ` + `(currently ${verifiedTag})`, ); } if (problems.length > 0) { process.stderr.write(`\npreflight FAILED:\n${problems.map((p) => ` ✗ ${p}`).join('\n')}\n`); process.exit(1); } process.stdout.write(' all captures present, hash-stable, and audited perfect\n'); } await main();