You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
bug(hooks): gsd-validate-commit.sh 112KB padded-command row exceeds time bound on macOS CI (bash 3.2), reds next #5473
Tests on next is red after merging green PR #5468 (run 38894835669, job conformance test (macos-latest, 24)). tests/hooks-opt-in.test.cjs:1815 ("the suffix window still sees an option after a 112KB command") failed: the hooks/gsd-validate-commit.sh invocation was killed at the 10000 ms bound. #5468 touches no hook code. This recurs every few PRs.
Measured duration_ms of that row on the macOS conformance job (two hook invocations per row):
run
padded row
"112KB conforming" row
38893639881
5006
337
38879172769
5925
404
38879074054
5525
461
38894835669 (red)
10414 (killed)
416
The padded row costs ~12x a same-size unpadded row on the same runner. Passing runs already use 50-60% of the bound. scripts/run-tests.cjs runs 4 test files concurrently on macOS.
What did you expect?
The hook validates a 112KB command in bounded time that does not depend on runner load.
Steps to reproduce
Run the Tests workflow's macOS conformance job; the row fails intermittently.
Error output / logs
with trailing option: hook was killed at the 10000ms bound — the quadratic suffix scan is back (unfixed cost on this row is ~30s) (expected 'SIGKILL' notStrictEqual actual 'SIGKILL').
How often does this happen?
Intermittently, every few PRs.
Impact
Blocks the required Required tests gate on next.
Plan
Which hook phase is superlinear on whitespace-padded input under bash 3.2 is not yet identified. First step: a macOS-only CI diagnostic that times each phase of the hook on the padded input. Then a linear fix and a non-wall-clock regression test.
Reopening: #5476 merged the diagnostic only (its Fixes #5473 was required by the issue-link gate). The row still fails intermittently; nothing in the hook or the test was changed.
What the merged diagnostic measured on macos-latest, bash 3.2.57 (run 38954101023):
padded 112KB
unpadded 112KB body
ratio
idle
199 ms median
196 ms
1.0x
4 processes forking node
359 ms
403 ms
0.9x
So the hook is NOT superlinear on whitespace-padded input under bash 3.2, and it is ~10-25x cheaper in isolation than the 2.5-5 s per invocation the conformance job shows for this row. The extra time appears only inside the real conformance tier.
Next: measure inside the real macOS conformance job (same hook, same contention): the inherited test-runner environment vs a minimal one, and the test's own detached-process-group spawn, then a traced run under the tier's conditions.
Root cause found (measured inside the macOS conformance job, #5480, run 38969807931, job 117205238703; macos-latest, /bin/bash 3.2.57, 3 cpus, load average ~18).
Row: padded + trailing --cleanup=verbatim (114750 bytes), same hook, one change at a time (2 runs each, ms):
environment
median
inherited (what the real row passes; LC_ALL=en_US.UTF-8)
6344 (spawnSync) / 5841 (async + detached, as the real row)
minimal env (PATH, HOME)
596
LC_ALL=C
547
LC_ALL=en_US.UTF-8
5603
without NODE_*
5158
without GSD_* / RUN_TESTS_*
6128
The unpadded 112KB body row is ~0.4 s in every column. So: not the interpreter (the PATH bash IS /bin/bash 3.2.57), not the node/GSD environment, not the spawn mode. It is the locale: in a UTF-8 locale bash 3.2's pattern matching on a 112KB value is ~10x slower.
The traced run under the same environment (4817 ms over 98 commands) puts 3.5 s of it in one place: hooks/gsd-validate-commit.sh 574-589, the RESOLVE=0 fallback (this row is RESOLVE=0 because of the trailing --cleanup=verbatim):
SUBJECT="${MSG%%$'\n'*}" # 112KB MSG, longest-suffix match of `\n*`
The earlier standalone diagnostic (#5476) never reached this line: its padded rows exited 0 (the classifier took the fail-open path), where the real row exits 2.
Fix: do the first-line extraction in the C locale (byte matching), which the LC_ALL=C cell shows brings the whole row to ~0.55 s.
Activity
test(#5473): pin timestamped-xtrace per-line cost attribution
ci(#5473): time each phase of gsd-validate-commit.sh on the padded 11…
ci(#5473): address isolated review of the phase-timing diagnostic
ci(#5473): keep the xtrace helper out of the shipped scripts/lib and …
ci(#5473): assign PS4 via BASH_ENV (bash 5 ignores an exported PS4's …
ci(#5473): keep perl locale warnings out of the xtrace stream
ci(#5473): install the xtrace PS4 from a sourcing prologue, not a sta…
ci(#5473): the stream-terminating newline is not part of the last tra…
ci(#5473): address the standards and spec review passes
ci(#5473): fix the CodeQL alerts on the diagnostic
ci(#5473): give the traced hook copy the directory layout the hook's …
test(#5473): split the real-bash tests into a .platform sibling and l…
test(#5473): the base file header describes only what it still tests
ci(#5473): time each phase of gsd-validate-commit.sh on the padded 11…
trek-e commentedon Oct 16, 2026
Reopening: #5476 merged the diagnostic only (its
Fixes #5473was required by the issue-link gate). The row still fails intermittently; nothing in the hook or the test was changed.What the merged diagnostic measured on
macos-latest, bash 3.2.57 (run 38954101023):So the hook is NOT superlinear on whitespace-padded input under bash 3.2, and it is ~10-25x cheaper in isolation than the 2.5-5 s per invocation the conformance job shows for this row. The extra time appears only inside the real conformance tier.
Next: measure inside the real macOS conformance job (same hook, same contention): the inherited test-runner environment vs a minimal one, and the test's own detached-process-group spawn, then a traced run under the tier's conditions.
ci(#5473): keep environment data out of the in-tier report and make t…
ci(#5473): time the 112KB validate-commit rows inside the real macOS …
trek-e commentedon Oct 16, 2026
Root cause found (measured inside the macOS conformance job, #5480, run 38969807931, job 117205238703;
macos-latest, /bin/bash 3.2.57, 3 cpus, load average ~18).Row: padded + trailing
--cleanup=verbatim(114750 bytes), same hook, one change at a time (2 runs each, ms):LC_ALL=en_US.UTF-8)LC_ALL=CLC_ALL=en_US.UTF-8NODE_*GSD_*/RUN_TESTS_*The unpadded 112KB body row is ~0.4 s in every column. So: not the interpreter (the PATH
bashIS /bin/bash 3.2.57), not the node/GSD environment, not the spawn mode. It is the locale: in a UTF-8 locale bash 3.2's pattern matching on a 112KB value is ~10x slower.The traced run under the same environment (4817 ms over 98 commands) puts 3.5 s of it in one place:
hooks/gsd-validate-commit.sh574-589, theRESOLVE=0fallback (this row isRESOLVE=0because of the trailing--cleanup=verbatim):The earlier standalone diagnostic (#5476) never reached this line: its padded rows exited 0 (the classifier took the fail-open path), where the real row exits 2.
Fix: do the first-line extraction in the C locale (byte matching), which the
LC_ALL=Ccell shows brings the whole row to ~0.55 s.docs(#5473): changeset for the first-line extraction fix
docs(#5473): backfill the PR number in the changeset
fix(#5473): extract the commit subject byte-wise so a 112KB message i…