Files
msd-core/.changeset/build-hooks-atomic-write.md
Tom Boucher c4f11db5e9 fix(build-hooks): atomic rename to prevent race with concurrent install reads
scripts/build-hooks.js used fs.copyFileSync (truncate-then-write, non-atomic).
Under --test-concurrency=4, multiple builder invocations raced; a parallel
install.js subprocess could readFileSync between truncate and write and
observe an empty file, then write that emptiness into the install target.
Surfaced as the release-blocking bug-2136-sh-hook-version part 4 failure on
main even though the same SHA passed every install-smoke matrix entry.

Fix: stage outputs to hooks/.dist-staging/ then fs.renameSync into hooks/dist/.
POSIX rename(2) is atomic, so concurrent readers always observe a complete
file. The existing bug-2136 part 4 test locks the post-fix invariant.

Failing run: https://github.com/gsd-build/get-shit-done/actions/runs/25472202941/job/74738276687

Closes #3214

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 23:34:29 -04:00

1.3 KiB

type
type
Fixed

Atomic writes in scripts/build-hooks.js to fix flaky release CI — nine test files invoke build-hooks.js from their before() hooks, and scripts/run-tests.cjs runs test files with --test-concurrency=4, so multiple builders raced to rewrite the same files in hooks/dist/. fs.copyFileSync(src, dest) truncates dest then writes it; a parallel bin/install.js subprocess (spawned by another install test) could fs.readFileSync between the truncate and the write and observe an empty file. install.js then wrote that empty content into the install target, so installed .sh hooks lacked their # gsd-hook-version: header. This surfaced as the release-blocking failure in tests/bug-2136-sh-hook-version.test.cjs part 4 even though the same SHA passed on every other Node-22/Node-24 install-smoke matrix run. build-hooks.js now stages each output to a sibling hooks/.dist-staging/ directory (same filesystem as hooks/dist/) and uses fs.renameSync to swap into place — POSIX rename(2) is atomic, so concurrent readers always observe a complete file. The existing tests/bug-2136-sh-hook-version.test.cjs part 4 already locks the post-fix invariant. (Failing run: https://github.com/gsd-build/get-shit-done/actions/runs/25472202941/job/74738276687)