Batch 17 of 17 — the terminal batch — in the ad hoc timeout literal
migration (epic #4445). Replaces every bare numeric timeout/timeoutMs
object-literal property in tests/cjs-command-router-adapter.test.cjs,
tests/dispatcher.test.cjs, tests/run-tests-temp-root.test.cjs, and
tests/shell-command-projection-dispatch.test.cjs with a named constant,
per eslint-rules/no-adhoc-timeout-literal.cjs. No src/bin file touched,
no numeric value changed anywhere.
Eslint ground truth (9 sites) matches the issue's own stated count
exactly for the first time in this epic — no drift to disclose.
Reuses PROBE_TIMEOUT_MS (1 site) and QUICK_SPAWN_TIMEOUT_MS (1 site).
Adds four file-local constants for shapes with no existing match:
RUN_TESTS_ISOLATED_PROBE_TIMEOUT_MS and RUN_TESTS_HARNESS_SPAWN_TIMEOUT_MS
(run-tests-temp-root.test.cjs, distinguishing a `node -e` isolated
function call from a real end-to-end spawn of the test runner itself,
despite each coinciding numerically with an unrelated existing
constant), and EXEC_TOOL_OPTION_PASSTHROUGH_TIMEOUT_MS and
DISPATCH_FORCED_TIMEOUT_MS (shell-command-projection-dispatch.test.cjs
— a mocked-spawnSync pass-through fixture and a deliberately-forced
real timeout, neither a real subprocess bound in the usual sense).
Terminal-batch cleanup: deletes
eslint-rules/no-adhoc-timeout-literal.allowlist.json entirely, drops
its require and the allowlist option from eslint.config.mjs's
local/no-adhoc-timeout-literal registration (now a bare 'error',
mirroring local/no-unbounded-spawn's own already-terminal
configuration in the same file), and updates TESTING-STANDARDS.md's
enforcement note to match — a stale pointer to the deleted file caught
by review, fixed inline. A full-repo eslint run with no cache confirms
zero violations anywhere in the tree under the now allowlist-free rule.
Co-authored-by: sim <sim@local>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
* fix(#4220): terminate the temp-sweep ancestor walk with a fixed-point check
scripts/run-tests.cjs's sweepProtectSet block walked each selected test
file's ancestor directories, stopping on `cur !== runTempRoot &&
cur.length > 1` — a POSIX-only sentinel. path.posix.dirname('/') === '/'
(length 1) correctly stops, but path.win32.dirname('C:\\') === 'C:\\'
(length 3) never satisfies the length check, so the walk spun forever on
Windows whenever a selected file lived outside runTempRoot (the common
case). This has hung every Windows CI shard since #4207.
Extract the walk into a pure, exported computeSweepProtectSet(selected,
runTempRoot, dirnameImpl) helper and replace the length sentinel with a
fixed-point check (stop when dirnameImpl(cur) === cur), which terminates
correctly on POSIX, Windows drive roots, and UNC roots alike with no
platform branch.
* fix(#4220): repoint TEMP/TMP alongside TMPDIR in run-tests-temp-root test child env
Node's os.tmpdir() on Windows never reads TMPDIR, only TEMP/TMP. The
test's runNode child-process env override only set TMPDIR, so on a
real Windows runner nested inside a run-tests invocation the child
inherited the outer process's already-repointed TEMP/TMP and its
mkdtempSync(os.tmpdir()) landed under the outer run's temp root
instead of the test's intended `outer` directory. This was masked on
gsd-test's benches and locally because Windows CI always died in the
#4220 infinite loop before reaching this test.
* fix(#4220): stop the ancestor walk from protecting the filesystem root itself
computeSweepProtectSet added `cur` to the protect set before checking
whether dirname(cur) === cur, so on the terminating iteration it
protected the filesystem root (posix `/`, and analogously a win32
drive root) instead of stopping before adding it. Caught by the
existing posix-parity regression assertion
(`!protectSet.has('/')`) on the linux-node24 gsd-test bench. Reorder
to compute the parent and check the fixed point before adding.
* fix(#4220): backfill changeset pr number to 4245
---------
Co-authored-by: sim <sim@local>
* test(#4020): the runner must bound and sweep a run-scoped temp root
* fix(#4020): bound the run's temp footprint with a swept run-scoped root
* test(#4020): isolate the env-mutating rows in child processes
* fix(#4020): gate root removal on ownership so nested runners spare the outer root
* test(#4020): pass the probe file via --files, the runner's explicit-file flag
* test(#4020): resolve the probe by basename, as --files matching requires
* test(#4020): assert root survival, not content survival, in the nested-row
* chore(#4020): changeset for the run-scoped temp root
* chore(#4020): backfill changeset pr number
* fix(#4020): the sweep spares ancestors of the runner's own selected files
* fix(#4020): TMPDIR precedence — an operator redirect beats inherited TEMP/TMP
* fix(#4020): only the root's owner sweeps — a nested runner spares live sibling fixtures
---------
Co-authored-by: sim <sim@local>