#!/usr/bin/env node import { createHash } from "node:crypto"; import { spawnSync } from "node:child_process"; import { mkdir, readFile, writeFile } from "node:fs/promises"; import { arch, platform } from "node:os"; import { basename, dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; const generatorPath = fileURLToPath(import.meta.url); const root = join(dirname(generatorPath), ".."); const rendererPath = join(root, "src", "lib", "audio", "editor.ts"); const fixtureDir = join(root, "public", "fixtures", "audio", "v1"); const publicGeneratorSnapshot = join( fixtureDir, "generate-audio-flagship-evidence.mjs.txt" ); const publicManifest = join(fixtureDir, "evidence.json"); const sourceManifest = join( root, "src", "lib", "flagships", "audio-evidence.generated.json" ); const researchDir = join(root, "public", "research"); const publicFindingsCsv = join(researchDir, "audio-v1-findings.csv"); const publicDurationChart = join(researchDir, "audio-v1-duration.svg"); const publicFrequencyChart = join(researchDir, "audio-v1-frequency.svg"); const publicSignalChart = join(researchDir, "audio-v1-signal-checks.svg"); const sampleRate = 44_100; function commandResult(binary, args) { return spawnSync(binary, args, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], }); } function resolveBinary(environmentValue, name, fallbacks) { const candidates = [ environmentValue, name, ...fallbacks, ].filter(Boolean); for (const candidate of candidates) { const result = commandResult(candidate, ["-version"]); if (result.status === 0) return candidate; } throw new Error( `Unable to find ${name}. Set FILEMORF_EVIDENCE_${name.toUpperCase()} to an executable path.` ); } const ffmpeg = resolveBinary(process.env.FILEMORF_EVIDENCE_FFMPEG, "ffmpeg", [ "/opt/homebrew/bin/ffmpeg", "/usr/local/bin/ffmpeg", "/usr/bin/ffmpeg", ]); const ffprobe = resolveBinary( process.env.FILEMORF_EVIDENCE_FFPROBE, "ffprobe", [ "/opt/homebrew/bin/ffprobe", "/usr/local/bin/ffprobe", "/usr/bin/ffprobe", ] ); function run(binary, args) { const result = commandResult(binary, args); if (result.status !== 0) { throw new Error( `${basename(binary)} failed (${result.status}): ${result.stderr || result.stdout}` ); } return result.stdout.trim(); } function pcmWav(durationSec, sampleFn) { const frames = Math.round(durationSec * sampleRate); const channels = 2; const bytesPerSample = 2; const dataBytes = frames * channels * bytesPerSample; const buffer = Buffer.alloc(44 + dataBytes); buffer.write("RIFF", 0); buffer.writeUInt32LE(36 + dataBytes, 4); buffer.write("WAVE", 8); buffer.write("fmt ", 12); buffer.writeUInt32LE(16, 16); buffer.writeUInt16LE(1, 20); buffer.writeUInt16LE(channels, 22); buffer.writeUInt32LE(sampleRate, 24); buffer.writeUInt32LE(sampleRate * channels * bytesPerSample, 28); buffer.writeUInt16LE(channels * bytesPerSample, 32); buffer.writeUInt16LE(bytesPerSample * 8, 34); buffer.write("data", 36); buffer.writeUInt32LE(dataBytes, 40); for (let frame = 0; frame < frames; frame += 1) { const time = frame / sampleRate; const value = Math.max(-1, Math.min(1, sampleFn(time, frame))); const integer = Math.round(value * 32_767); const offset = 44 + frame * channels * bytesPerSample; buffer.writeInt16LE(integer, offset); buffer.writeInt16LE(integer, offset + bytesPerSample); } return buffer; } function envelope(time, duration, attack = 0.015, release = 0.025) { return Math.min(1, time / attack, (duration - time) / release); } function tone(frequency, duration, amplitude = 0.35) { return pcmWav( duration, (time) => Math.sin(2 * Math.PI * frequency * time) * amplitude * Math.max(0, envelope(time, duration)) ); } function speedFixture() { const duration = 2.4; return pcmWav(duration, (time) => { const base = Math.sin(2 * Math.PI * 523.25 * time) * 0.24; const beatPhase = time % 0.6; const tick = beatPhase < 0.025 ? Math.sin(2 * Math.PI * 1_400 * beatPhase) * (1 - beatPhase / 0.025) * 0.45 : 0; return (base + tick) * Math.max(0, envelope(time, duration)); }); } function slowedFixture() { const duration = 2; return pcmWav(duration, (time) => { const toneValue = (Math.sin(2 * Math.PI * 330 * time) + 0.3 * Math.sin(2 * Math.PI * 660 * time)) * 0.2; const pulsePhase = time % 0.5; const pulse = pulsePhase < 0.012 ? Math.sin(2 * Math.PI * 1_000 * pulsePhase) * (1 - pulsePhase / 0.012) * 0.6 : 0; return (toneValue + pulse) * Math.max(0, envelope(time, duration)); }); } function voiceLikeFixture() { const duration = 2.2; return pcmWav(duration, (time) => { const syllable = 0.25 + 0.75 * Math.max(0, Math.sin(2 * Math.PI * 2.2 * time)); const voice = Math.sin(2 * Math.PI * 180 * time) + 0.42 * Math.sin(2 * Math.PI * 360 * time) + 0.18 * Math.sin(2 * Math.PI * 540 * time); return voice * syllable * 0.16 * Math.max(0, envelope(time, duration)); }); } async function sha256(path) { return createHash("sha256").update(await readFile(path)).digest("hex"); } function probe(path) { const parsed = JSON.parse( run(ffprobe, [ "-v", "error", "-select_streams", "a:0", "-show_entries", "stream=sample_rate,channels,duration:format=duration,size", "-of", "json", path, ]) ); const stream = parsed.streams?.[0] ?? {}; return { bytes: Number(parsed.format?.size ?? 0), durationSec: Number( Number(parsed.format?.duration ?? stream.duration).toFixed(4) ), sampleRate: Number(stream.sample_rate), channels: Number(stream.channels), }; } async function describe(path) { return { href: `/fixtures/audio/v1/${basename(path)}`, sha256: await sha256(path), ...probe(path), mime: "audio/wav", }; } async function decodePcm16Wav(path) { const buffer = await readFile(path); if (buffer.toString("ascii", 0, 4) !== "RIFF") { throw new Error(`${path} is not a RIFF file`); } let offset = 12; let format; let data; while (offset + 8 <= buffer.length) { const id = buffer.toString("ascii", offset, offset + 4); const size = buffer.readUInt32LE(offset + 4); const payload = offset + 8; if (id === "fmt ") { format = { encoding: buffer.readUInt16LE(payload), channels: buffer.readUInt16LE(payload + 2), sampleRate: buffer.readUInt32LE(payload + 4), bitsPerSample: buffer.readUInt16LE(payload + 14), }; } if (id === "data") { data = { payload, size }; break; } offset = payload + size + (size % 2); } if ( !format || !data || format.encoding !== 1 || format.bitsPerSample !== 16 ) { throw new Error(`${path} is not supported 16-bit PCM WAV`); } const bytesPerFrame = format.channels * 2; const samples = []; for ( let frameOffset = data.payload; frameOffset < data.payload + data.size; frameOffset += bytesPerFrame ) { let mixed = 0; for (let channel = 0; channel < format.channels; channel += 1) { mixed += buffer.readInt16LE(frameOffset + channel * 2) / 32_768; } samples.push(mixed / format.channels); } return { ...format, samples }; } function sliceSamples(decoded, startSec, endSec) { return decoded.samples.slice( Math.max(0, Math.floor(startSec * decoded.sampleRate)), Math.min(decoded.samples.length, Math.ceil(endSec * decoded.sampleRate)) ); } function rms(decoded, startSec, endSec) { const samples = sliceSamples(decoded, startSec, endSec); if (samples.length === 0) throw new Error("Cannot measure an empty window"); return Math.sqrt( samples.reduce((total, sample) => total + sample * sample, 0) / samples.length ); } function dominantFrequency( decoded, startSec, endSec, minimumHz, maximumHz ) { const samples = sliceSamples(decoded, startSec, endSec); let bestFrequency = minimumHz; let bestPower = -Infinity; for ( let frequency = minimumHz; frequency <= maximumHz; frequency += 0.1 ) { let real = 0; let imaginary = 0; for (let index = 0; index < samples.length; index += 1) { const phase = (2 * Math.PI * frequency * index) / decoded.sampleRate; real += samples[index] * Math.cos(phase); imaginary -= samples[index] * Math.sin(phase); } const power = real * real + imaginary * imaginary; if (power > bestPower) { bestPower = power; bestFrequency = frequency; } } return bestFrequency; } function alignedDifferenceRms(source, output, sourceStartSec) { const start = Math.round(sourceStartSec * source.sampleRate); if ( source.sampleRate !== output.sampleRate || start + output.samples.length > source.samples.length ) { throw new Error("Cannot compare unaligned PCM windows"); } let total = 0; for (let index = 0; index < output.samples.length; index += 1) { const difference = output.samples[index] - source.samples[start + index]; total += difference * difference; } return Math.sqrt(total / output.samples.length); } function rounded(value, digits = 6) { return Number(value.toFixed(digits)); } function relativePath(value) { return value.startsWith(root) ? value.slice(root.length + 1) : value; } function assertion(id, comparator, expected, actual, unit, tolerance) { return { id, comparator, expected, actual: rounded(actual), ...(tolerance === undefined ? {} : { tolerance }), unit, }; } function assertionPasses(value) { if ( !Number.isFinite(value.actual) || !Number.isFinite(value.expected) ) { return false; } if (value.comparator === "within") { return ( Number.isFinite(value.tolerance) && Math.abs(value.actual - value.expected) <= value.tolerance ); } if (value.comparator === "gte") return value.actual >= value.expected; if (value.comparator === "lte") return value.actual <= value.expected; return false; } function csvCell(value) { if (value === undefined || value === null) return ""; const text = String(value); return /[",\n\r]/.test(text) ? `"${text.replaceAll('"', '""')}"` : text; } function findingCategory(value) { if (value.unit === "s") return "duration"; if (value.unit === "Hz") return "frequency"; return "signal"; } function buildFindingsCsv(records, baseCommit, generatedAt) { const header = [ "corpus_version", "tool", "scope", "category", "metric", "comparator", "expected", "actual", "tolerance", "unit", "source_manifest", "source_commit", "generated_at", ]; const rows = []; const sourceManifestHref = "/fixtures/audio/v1/evidence.json"; for (const [tool, record] of Object.entries(records)) { rows.push([ "audio-v1", tool, record.scope, "duration", "input-duration", "observed", "", rounded( record.inputs.reduce((total, file) => total + file.durationSec, 0), 4 ), "", "s", sourceManifestHref, baseCommit, generatedAt, ]); const durationAssertions = record.assertions.filter( (value) => value.unit === "s" ); if (durationAssertions.length > 1) { throw new Error(`${tool} has more than one duration assertion`); } const durationAssertion = durationAssertions[0]; rows.push([ "audio-v1", tool, record.scope, "duration", durationAssertion?.id ?? "output-duration-observed", durationAssertion?.comparator ?? "observed", durationAssertion?.expected ?? "", record.output.durationSec, durationAssertion?.tolerance ?? "", "s", sourceManifestHref, baseCommit, generatedAt, ]); for (const value of record.assertions.filter((entry) => entry.unit !== "s")) { rows.push([ "audio-v1", tool, record.scope, findingCategory(value), value.id, value.comparator, value.expected, value.actual, value.tolerance ?? "", value.unit, sourceManifestHref, baseCommit, generatedAt, ]); } } return `${[header, ...rows] .map((row) => row.map(csvCell).join(",")) .join("\n")}\n`; } function svgEscape(value) { return String(value) .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'"); } function chartShell({ title, description, body, generatedAt }) { return ` ${svgEscape(title)} ${svgEscape(description)} ${svgEscape(title)} ${svgEscape(description)} ${body} audio-v1 · generated ${svgEscape(generatedAt)} `; } function buildDurationChart(records, generatedAt) { const rows = [ { label: "Audio Joiner", input: records["audio-joiner"].inputs.reduce( (total, file) => total + file.durationSec, 0 ), output: records["audio-joiner"].output.durationSec, }, { label: "Speed Changer", input: records["audio-speed-changer"].inputs[0].durationSec, output: records["audio-speed-changer"].output.durationSec, }, { label: "Slowed and Reverb", input: records["slowed-and-reverb"].inputs[0].durationSec, output: records["slowed-and-reverb"].output.durationSec, }, { label: "Voice Recorder edit", input: records["voice-recorder"].inputs[0].durationSec, output: records["voice-recorder"].output.durationSec, }, ]; const max = Math.max(...rows.flatMap((row) => [row.input, row.output])); const plotX = 340; const plotWidth = 720; const rowHeight = 112; const body = rows .map((row, index) => { const y = 184 + index * rowHeight; const inputWidth = (row.input / max) * plotWidth; const outputWidth = (row.output / max) * plotWidth; return ` ${svgEscape(row.label)} ${row.input.toFixed(4)} s input ${row.output.toFixed(4)} s output `; }) .join("\n"); return chartShell({ title: "Audio v1 duration outcomes", description: "Measured input and output durations for deterministic synthetic reference fixtures.", body, generatedAt, }); } function assertionById(record, id) { const matches = record.assertions.filter((entry) => entry.id === id); if (matches.length !== 1) { throw new Error( `Expected exactly one evidence assertion named ${id}; found ${matches.length}` ); } return matches[0]; } function buildFrequencyChart(records, generatedAt) { const rows = [ { label: "Join segment 1", value: assertionById( records["audio-joiner"], "first-segment-frequency" ), }, { label: "Join segment 2", value: assertionById( records["audio-joiner"], "second-segment-frequency" ), }, { label: "Pitch preserved at 0.75x", value: assertionById( records["audio-speed-changer"], "preserved-frequency" ), }, { label: "Tape-style pitch at 0.8x", value: assertionById(records["slowed-and-reverb"], "tape-frequency"), }, ]; const max = 700; const plotX = 340; const plotWidth = 720; const rowHeight = 112; const body = rows .map(({ label, value }, index) => { const y = 184 + index * rowHeight; const expectedWidth = (value.expected / max) * plotWidth; const actualWidth = (value.actual / max) * plotWidth; return ` ${svgEscape(label)} ${value.expected} Hz target ${value.actual} Hz measured `; }) .join("\n"); return chartShell({ title: "Audio v1 frequency checks", description: "Measured dominant frequencies compared with the declared reference targets.", body, generatedAt, }); } function buildSignalChart(records, generatedAt) { const rows = [ { label: "Join boundary RMS", value: assertionById(records["audio-joiner"], "join-boundary-rms"), rule: "at or below", }, { label: "Echo tail RMS", value: assertionById(records["slowed-and-reverb"], "echo-tail-rms"), rule: "at or above", }, { label: "Trim alignment RMS", value: assertionById( records["voice-recorder"], "source-alignment-rms" ), rule: "at or below", }, ]; const body = rows .map(({ label, value, rule }, index) => { const y = 182 + index * 142; const ratio = value.expected === 0 ? 0 : Math.min(3.5, value.actual / value.expected); const width = ratio * 190; const thresholdX = 340 + 190; return ` ${svgEscape(label)} ${value.actual} FS measured · ${svgEscape(rule)} ${value.expected} FS PASS `; }) .join("\n"); return chartShell({ title: "Audio v1 signal acceptance checks", description: "Full-scale RMS measurements shown against their declared acceptance thresholds.", body, generatedAt, }); } async function describePublication(id, kind, path, mime) { const content = await readFile(path); return { id, kind, href: `/research/${basename(path)}`, mime, bytes: content.byteLength, sha256: createHash("sha256").update(content).digest("hex"), }; } async function main() { const baseCommit = run("git", ["rev-parse", "HEAD"]); const generatedPaths = [ "public/fixtures/audio/v1/evidence.json", "public/fixtures/audio/v1/generate-audio-flagship-evidence.mjs.txt", "public/fixtures/audio/v1/join-a-440hz.wav", "public/fixtures/audio/v1/join-b-660hz.wav", "public/fixtures/audio/v1/joined-reference.wav", "public/fixtures/audio/v1/slowed-080-hall-reference.wav", "public/fixtures/audio/v1/slowed-impulse-330hz.wav", "public/fixtures/audio/v1/speed-075-keep-pitch-reference.wav", "public/fixtures/audio/v1/speed-metronome-523hz.wav", "public/fixtures/audio/v1/synthetic-voice-like-source.wav", "public/fixtures/audio/v1/voice-edit-trim-reference.wav", "public/research/audio-v1-findings.csv", "public/research/audio-v1-duration.svg", "public/research/audio-v1-frequency.svg", "public/research/audio-v1-signal-checks.svg", "src/lib/flagships/audio-evidence.generated.json", ]; const workingTree = run("git", [ "status", "--porcelain=v1", "--untracked-files=all", "--", ".", ...generatedPaths.map((path) => `:(exclude)${path}`), ]).length > 0; if (workingTree) { throw new Error( "Evidence generation requires a clean source commit. Commit source changes first." ); } await mkdir(fixtureDir, { recursive: true }); await mkdir(dirname(sourceManifest), { recursive: true }); await mkdir(researchDir, { recursive: true }); await writeFile(publicGeneratorSnapshot, await readFile(generatorPath)); const inputPaths = { joinA: join(fixtureDir, "join-a-440hz.wav"), joinB: join(fixtureDir, "join-b-660hz.wav"), speed: join(fixtureDir, "speed-metronome-523hz.wav"), slowed: join(fixtureDir, "slowed-impulse-330hz.wav"), recorder: join(fixtureDir, "synthetic-voice-like-source.wav"), }; await writeFile(inputPaths.joinA, tone(440, 1, 0.34)); await writeFile(inputPaths.joinB, tone(660, 1.25, 0.3)); await writeFile(inputPaths.speed, speedFixture()); await writeFile(inputPaths.slowed, slowedFixture()); await writeFile(inputPaths.recorder, voiceLikeFixture()); const outputPaths = { joiner: join(fixtureDir, "joined-reference.wav"), speed: join(fixtureDir, "speed-075-keep-pitch-reference.wav"), slowed: join(fixtureDir, "slowed-080-hall-reference.wav"), recorder: join(fixtureDir, "voice-edit-trim-reference.wav"), }; const common = ["-y", "-hide_banner", "-loglevel", "error"]; const commands = { joiner: [ ...common, "-i", inputPaths.joinA, "-i", inputPaths.joinB, "-filter_complex", "[0:a]atrim=start=0:end=1.000,asetpts=PTS-STARTPTS,aresample=44100,aformat=sample_fmts=fltp:channel_layouts=stereo,afade=t=out:st=0.9940:d=0.006[c0];[1:a]atrim=start=0:end=1.250,asetpts=PTS-STARTPTS,aresample=44100,aformat=sample_fmts=fltp:channel_layouts=stereo,afade=t=in:st=0:d=0.006[c1];[c0][c1]concat=n=2:v=0:a=1[out]", "-map", "[out]", "-vn", "-c:a", "pcm_s16le", "-map_metadata", "-1", "-bitexact", outputPaths.joiner, ], speed: [ ...common, "-i", inputPaths.speed, "-filter:a", "atempo=0.7500", "-vn", "-c:a", "pcm_s16le", "-map_metadata", "-1", "-bitexact", outputPaths.speed, ], slowed: [ ...common, "-i", inputPaths.slowed, "-filter:a", "aecho=0.8:0.9:300|450:0.4|0.25,aresample=44100,asetrate=35280,aresample=44100", "-vn", "-c:a", "pcm_s16le", "-map_metadata", "-1", "-bitexact", outputPaths.slowed, ], recorder: [ ...common, "-i", inputPaths.recorder, "-filter:a", "atrim=start=0.200:end=2.000,asetpts=PTS-STARTPTS,aresample=44100,aformat=sample_fmts=fltp:channel_layouts=stereo", "-vn", "-c:a", "pcm_s16le", "-map_metadata", "-1", "-bitexact", outputPaths.recorder, ], }; for (const args of Object.values(commands)) run(ffmpeg, args); const joinerPcm = await decodePcm16Wav(outputPaths.joiner); const speedPcm = await decodePcm16Wav(outputPaths.speed); const slowedPcm = await decodePcm16Wav(outputPaths.slowed); const recorderInputPcm = await decodePcm16Wav(inputPaths.recorder); const recorderOutputPcm = await decodePcm16Wav(outputPaths.recorder); const records = { "audio-joiner": { scope: "ffmpeg-cli-reference", inputs: [ await describe(inputPaths.joinA), await describe(inputPaths.joinB), ], output: await describe(outputPaths.joiner), operation: "Two synthetic tones, ordered 440 Hz then 660 Hz, normalized to 44.1 kHz stereo, with 6 ms internal microfades.", demonstrates: [ "ordered concatenation", "6 ms boundary attenuation", "44.1 kHz stereo PCM output", ], doesNotDemonstrate: [ "browser performance", "cross-device equivalence", ], assertions: [ assertion("output-duration", "within", 2.25, probe(outputPaths.joiner).durationSec, "s", 0.02), assertion("first-segment-frequency", "within", 440, dominantFrequency(joinerPcm, 0.2, 0.8, 430, 450), "Hz", 1), assertion("second-segment-frequency", "within", 660, dominantFrequency(joinerPcm, 1.3, 2, 650, 670), "Hz", 1), assertion("join-boundary-rms", "lte", 0.01, rms(joinerPcm, 0.998, 1.002), "FS"), ], command: commands.joiner.map(relativePath), }, "audio-speed-changer": { scope: "ffmpeg-cli-reference", inputs: [await describe(inputPaths.speed)], output: await describe(outputPaths.speed), operation: "0.75× tempo with pitch-preserving FFmpeg atempo.", demonstrates: [ "0.75× duration change", "523.25 Hz reference-tone preservation", ], doesNotDemonstrate: [ "browser performance", "artifact-free output for arbitrary sources", ], assertions: [ assertion("output-duration", "within", 3.2, probe(outputPaths.speed).durationSec, "s", 0.04), assertion("preserved-frequency", "within", 523.25, dominantFrequency(speedPcm, 1, 1.5, 510, 535), "Hz", 1), ], command: commands.speed.map(relativePath), }, "slowed-and-reverb": { scope: "ffmpeg-cli-reference", inputs: [await describe(inputPaths.slowed)], output: await describe(outputPaths.slowed), operation: "FFmpeg hall aecho followed by the 0.8× tape-style resampling chain.", demonstrates: [ "0.8× tape-style pitch shift", "measurable echo tail after the dry slowed source", ], doesNotDemonstrate: [ "measured room convolution", "browser performance", ], assertions: [ assertion("tape-frequency", "within", 264, dominantFrequency(slowedPcm, 0.05, 0.45, 250, 278), "Hz", 1), assertion("echo-tail-rms", "gte", 0.01, rms(slowedPcm, 2.7, 3), "FS"), ], command: commands.slowed.map(relativePath), }, "voice-recorder": { scope: "ffmpeg-cli-edit-reference", inputs: [await describe(inputPaths.recorder)], output: await describe(outputPaths.recorder), operation: "Synthetic voice-like signal with 0.2 s trimmed from each edge and PCM WAV output.", demonstrates: [ "deterministic timeline trim", "sample-aligned PCM WAV output", ], doesNotDemonstrate: [ "microphone permission", "MediaRecorder capture", "browser performance", ], assertions: [ assertion("trimmed-duration", "within", 1.8, probe(outputPaths.recorder).durationSec, "s", 0.02), assertion("source-alignment-rms", "lte", 0.000001, alignedDifferenceRms(recorderInputPcm, recorderOutputPcm, 0.2), "FS"), ], command: commands.recorder.map(relativePath), }, }; const ffmpegVersion = run(ffmpeg, ["-version"]).split("\n")[0]; const ffprobeVersion = run(ffprobe, ["-version"]).split("\n")[0]; const failedAssertions = Object.entries(records).flatMap( ([tool, record]) => record.assertions .filter((value) => !assertionPasses(value)) .map((value) => `${tool}:${value.id}`) ); if (failedAssertions.length > 0) { throw new Error( `Evidence assertions failed: ${failedAssertions.join(", ")}` ); } const requestedTimestamp = process.env.FILEMORF_EVIDENCE_GENERATED_AT || new Date().toISOString(); if (Number.isNaN(Date.parse(requestedTimestamp))) { throw new Error("FILEMORF_EVIDENCE_GENERATED_AT must be an ISO timestamp"); } await writeFile( publicFindingsCsv, buildFindingsCsv(records, baseCommit, new Date(requestedTimestamp).toISOString()) ); await writeFile( publicDurationChart, buildDurationChart(records, new Date(requestedTimestamp).toISOString()) ); await writeFile( publicFrequencyChart, buildFrequencyChart(records, new Date(requestedTimestamp).toISOString()) ); await writeFile( publicSignalChart, buildSignalChart(records, new Date(requestedTimestamp).toISOString()) ); const evidence = { schema: "filemorf-audio-flagship-evidence/3", generatedAt: new Date(requestedTimestamp).toISOString(), corpusVersion: "audio-v1", rights: { license: "CC0-1.0", provenance: "Deterministic PCM signals generated from mathematical functions. No customer or third-party audio.", }, source: { repository: "https://github.com/jddelia/file-convert", baseCommit, workingTree: false, generatorPath: "scripts/generate-audio-flagship-evidence.mjs", publicGeneratorHref: "/fixtures/audio/v1/generate-audio-flagship-evidence.mjs.txt", generatorSha256: await sha256(generatorPath), rendererPath: "src/lib/audio/editor.ts", rendererSha256: await sha256(rendererPath), }, environment: { runner: `${platform()} ${arch()}`, node: process.version, referenceRuntime: "FFmpeg CLI", engine: ffmpegVersion, probeEngine: ffprobeVersion, browserRuntime: "@ffmpeg/ffmpeg 0.12.15 with @ffmpeg/core 0.12.10", browserEvidenceStatus: "separate-release-gate", }, review: { automatedContract: "passed-at-generation", technical: "pending-independent-human-review", nativeLanguage: "pending-human-review", }, publications: [ await describePublication( "audio-v1-findings", "aggregate", publicFindingsCsv, "text/csv" ), await describePublication( "audio-v1-duration", "chart", publicDurationChart, "image/svg+xml" ), await describePublication( "audio-v1-frequency", "chart", publicFrequencyChart, "image/svg+xml" ), await describePublication( "audio-v1-signal-checks", "chart", publicSignalChart, "image/svg+xml" ), ], records, }; const text = `${JSON.stringify(evidence, null, 2)}\n`; await writeFile(publicManifest, text); await writeFile(sourceManifest, text); process.stdout.write( `Generated ${Object.keys(records).length} evidence records in ${fixtureDir}\n` ); } await main();