write-build-stamp.mjs rewrites `builtAt` on every build, and build.mjs runs it
before compilation, so the desktop build rewrote a file its own receipt hashed
as a prepared input. Two concurrent `hermes desktop` builds therefore made
recordProduct() fail with "Build inputs changed during compilation" on a change
the build itself caused, and the caller turned that into SystemExit(1).
Hash the stamp's provenance identity instead of its raw bytes. builtAt is the
only field that moves between two stamps (the tree documents it as
"differs on every rebuild"), and it is a build clock, not provenance: the baked
output changes when commit/payload/tag change, never when time passes. A
non-JSON stamp still falls back to the whole-file hash, so content keeps
deciding freshness and only the clock is ignored.
Unlike b3618bda35, the stamp cannot simply leave the hash set:
bundleElectronMain bakes its bytes into electron-main.mjs, and
bundle-swap.test.ts pins "same commit rebuilt (builtAt moved)" as a real swap,
so freezing the clock would break a committed test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>