* fix(3803): replace wall-clock polls with Atomics.wait barrier (mirrorsc22e869b) Three execFileSync('sleep', ...) wall-clock deadline spins in graphify-auto-update tests replaced with Atomics.wait-based atomicSleep helper. This is the same pattern established inc22e869b(PR #3790) for locking-bugs:180. - cleanupHookRepo: 50 ms Atomics.wait steps instead of spawning a POSIX sleep process per iteration while waiting for .rebuild.lock to clear. - "completes to status=ok" poll: 100 ms Atomics.wait steps instead of execFileSync('sleep', ['0.1']) while waiting for the detached rebuild process to write the final status file. - "completes to status=failed" poll: same fix. The ceiling deadlines (4 s / 15 s) remain as timeout guards — they are not the synchronization primitive. The CPU-yielding wait is now Atomics.wait so no external process is spawned per iteration. All 36 tests in the suite pass (node --test tests/graphify-auto-update.test.cjs). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(3803): replace wall-clock deadline polls with behavior-anchored iteration counts The previous commit (752a5684) replaced execFileSync('sleep') with Atomics.wait but kept the `Date.now() + 15000` wall-clock deadline pattern in the two assertion-path polls. That is still the timing-flake antipattern described in #3803: the loop bound is an absolute time, not a function of the mock's known behavior. This commit removes both `const deadline = Date.now() + 15000` / `while (Date.now() < deadline)` loops and replaces them with iteration-count bounds derived from the mock's declared sleepMs: waitBudget = sleepMs + 2000 (2 s covers two bash spawn overheads: hook script + detached rebuild subprocess) maxIter = ceil(waitBudget / 100) (100 ms poll step) The 2 s buffer absorbs process spawn + filesystem write latency without anchoring to an absolute wall-clock value. If the budget is exhausted the assertion below fires with a clear diagnostic instead of a silent time-dependent pass. Same antipattern fixed by PR #3793 (bug-1974-context-exhaustion-record). Verified: 3 consecutive local runs, 0 failures each (~80-100 s/run). Anti-pattern sweep results (Date.now() + N in tests/): - tests/locking-bugs-1909-1916-1925-1927.test.cjs:291,448 — coordination BARRIER backstops (wait for both subprocesses to reach gate), not completion polls; different pattern, out of scope for this PR. - tests/graphify-auto-update.test.cjs:286 — cleanupHookRepo backstop (not an assertion path); acceptable. - tests/bug-2962-windows-sdk-shim.test.cjs:132 — Date.now() + 20 (20 ms relative offset used in a deadline expiry calculation, not a spin loop). - tests/core.test.cjs:2006 — timeAgo(new Date(Date.now() + 5000)) (a value assertion for the timeAgo utility, not a polling loop). No additional assertion-path wall-clock polls found. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
26 KiB
26 KiB