/** * Deterministic generation-stamp resolution for Brainy's build-time code * generators. * * Two builds of the same source tree must produce byte-identical output. * A wall-clock stamp (`new Date()`) breaks that guarantee, so every * generator that writes a "Generated:" header or a `generatedAt` field * into its output must resolve the stamp through this module instead. * * Resolution order: * 1. The newest git commit timestamp among the generator's input files * (the generator script itself always counts as an input). * 2. If git metadata is unavailable (for example, building from a * published npm tarball with no `.git` directory), the stamp already * recorded in the previously generated output file. * 3. If neither is available, the fixed epoch string * `1970-01-01T00:00:00.000Z`. * * Every fallback logs a line to stderr — deterministic degradation is * loud, never a silent divergence. */ import { execFileSync } from 'child_process' import * as fs from 'fs' const EPOCH_STAMP = '1970-01-01T00:00:00.000Z' const STAMP_PATTERN = /\*\s*Generated:\s*(\S+)/ /** * Resolve the deterministic stamp for a generator run. * * @param inputPaths Absolute paths to every file whose content determines * the generator's output, including the generator script itself. * @param previousOutputPath Absolute path to the previously generated * file, used for the existing-stamp fallback when git is unavailable. * @returns An ISO-8601 timestamp string that is deterministic for a given * source tree. */ export function resolveDeterministicStamp( inputPaths: string[], previousOutputPath: string ): string { const gitStamp = newestGitCommitTimestamp(inputPaths) if (gitStamp) { return gitStamp } const existingStamp = readExistingStamp(previousOutputPath) if (existingStamp) { process.stderr.write( `[deterministic-stamp] no git commit history found for generator inputs; ` + `reusing existing stamp from ${previousOutputPath}: ${existingStamp}\n` ) return existingStamp } process.stderr.write( `[deterministic-stamp] no git commit history and no previous output at ` + `${previousOutputPath}; falling back to fixed epoch stamp ${EPOCH_STAMP}\n` ) return EPOCH_STAMP } /** * Find the newest git commit timestamp among the given input paths. * Returns null if git is unavailable, the tree is not a git repository, * or none of the inputs have any commit history yet. */ function newestGitCommitTimestamp(inputPaths: string[]): string | null { let newest: string | null = null for (const inputPath of inputPaths) { if (!fs.existsSync(inputPath)) { continue } let out: string try { out = execFileSync( 'git', ['log', '-1', '--format=%cI', '--', inputPath], { stdio: ['ignore', 'pipe', 'ignore'] } ) .toString() .trim() } catch { // git missing, not a repository, or no permissions — handled by the // caller's fallback chain. continue } if (!out) { // Path exists but has no commit history yet (e.g. newly created, // uncommitted file). continue } if (!newest || new Date(out).getTime() > new Date(newest).getTime()) { newest = out } } return newest } /** * Parse the `* Generated: ` header out of a previously * generated file, if one exists. */ function readExistingStamp(outputPath: string): string | null { if (!fs.existsSync(outputPath)) { return null } const content = fs.readFileSync(outputPath, 'utf-8') const match = content.match(STAMP_PATTERN) return match ? match[1] : null }