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
Running the local test suites and the pre-PR gate scripts takes long enough on a Windows Git Bash host that a single phase close-out spends most of its wall clock waiting on them, and several individual scripts exceed the Claude Code Bash tool's two-minute default timeout on their own. The repository already documents the cause in scripts/affected-tests.sh: "The full corpus is tens of minutes of wall clock on a Windows box (Git Bash pays ~140ms per process spawn, and these suites are spawn-bound), which is long enough that nobody runs it locally and regressions reach CI." This issue asks for a measured program to troubleshoot, diagnose, and optimize test and gate performance so the corpus is as fast as it can be, with Windows as the primary target.
Observed (2026-09-04, Windows 11, Git Bash, worktree on the feat/handoff-prompt-qol branch)
Corpus size: 354 *.test.sh suites plus 42 Python test files under plugins/.
scripts/check-purged-em-dashes.sh exceeded the 120-second tool default on its first run (killed, exit 143) while scanning 105 files; it passed on a rerun under a 10-minute timeout.
scripts/check-changed-skills.sh origin/main exceeds 120 seconds for six touched skills and has to be backgrounded.
scripts/affected-tests.sh --run on a 56-file diff takes several minutes per run; two runs were needed this session.
plugins/session-flow/scripts/save_point.test.sh: 52 pytest cases take 10 to 14 seconds; plugins/session-flow/skills/retro/scripts/parse-transcript.test.sh: 38 cases take 2.6 to 5.4 seconds. Both are dominated by interpreter startup and per-case subprocess spawns, not by the assertions.
Side observation while diagnosing: with a merge in progress in the worktree, affected-tests.sh resolves its diff base to the fork point rather than the merge target, so files changed only on origin/main are reported as unmapped and the run exits 1 before executing any suite. Worth a guard or a clearer message.
Instrument first. Add a timing mode to scripts/run-plugin-tests.sh and scripts/affected-tests.sh that records per-suite wall clock and a process-spawn count (a DEBUG trap or bash -x line count is enough on Git Bash where strace is unavailable), and commit a ranked baseline table so every later change is measured against it.
Diagnose the top offenders by mechanism: command substitutions inside per-item loops, grep/sed/jq/git invoked once per file or per line, find walks repeated per suite, mktemp -d per case, cygpath and uname per call, npx cold starts, and one pytest interpreter start per wrapper.
Optimize by the same pattern lib/hook-utils.sh already used (perf(hook-utils): build the telemetry envelope and read file_path with builtins #3678): builtins over spawns, one batched git call over many, one jq parse reused, one find walk hoisted, and one pytest invocation for co-located Python suites (with -p no:cacheprovider so no .pytest_cache is left for markdownlint to trip over).
Guard the result: a per-suite wall-clock budget lane (warn, then fail above a documented ceiling) so a regression is caught locally, and a documented fast local loop (the smallest command that covers a typical diff).
Acceptance
A committed baseline table of per-suite wall clock on Windows and on the Linux CI runner.
No single gate script in scripts/ exceeds 60 seconds on a healthy Windows host.
scripts/affected-tests.sh --run for a typical 50-file diff completes in under 2 minutes on Windows.
The full scripts/run-plugin-tests.sh corpus completes in under 10 minutes on Windows, with the number recorded.
Each optimization is behavior-preserving and shown so by the existing suites passing unchanged.
Summary
Running the local test suites and the pre-PR gate scripts takes long enough on a Windows Git Bash host that a single phase close-out spends most of its wall clock waiting on them, and several individual scripts exceed the Claude Code Bash tool's two-minute default timeout on their own. The repository already documents the cause in
scripts/affected-tests.sh: "The full corpus is tens of minutes of wall clock on a Windows box (Git Bash pays ~140ms per process spawn, and these suites are spawn-bound), which is long enough that nobody runs it locally and regressions reach CI." This issue asks for a measured program to troubleshoot, diagnose, and optimize test and gate performance so the corpus is as fast as it can be, with Windows as the primary target.Observed (2026-09-04, Windows 11, Git Bash, worktree on the
feat/handoff-prompt-qolbranch)*.test.shsuites plus 42 Python test files underplugins/.scripts/check-purged-em-dashes.shexceeded the 120-second tool default on its first run (killed, exit 143) while scanning 105 files; it passed on a rerun under a 10-minute timeout.scripts/check-changed-skills.sh origin/mainexceeds 120 seconds for six touched skills and has to be backgrounded.scripts/affected-tests.sh --runon a 56-file diff takes several minutes per run; two runs were needed this session.plugins/session-flow/scripts/save_point.test.sh: 52 pytest cases take 10 to 14 seconds;plugins/session-flow/skills/retro/scripts/parse-transcript.test.sh: 38 cases take 2.6 to 5.4 seconds. Both are dominated by interpreter startup and per-case subprocess spawns, not by the assertions.scripts/run-plugin-tests.shkeeps--jobs 1as the default on Windows because a parallel run measured sublinear (the box saturates on process creation), and tool-honesty and jira conformance suites fail under run-plugin-tests --jobs 4, pass serially #3694 shows two suites fail under--jobs 4.affected-tests.shresolves its diff base to the fork point rather than the merge target, so files changed only onorigin/mainare reported as unmapped and the run exits 1 before executing any suite. Worth a guard or a clearer message.Related
--jobs 4): the CI-side and parallelism-side halves of the same problem.Proposed work
scripts/run-plugin-tests.shandscripts/affected-tests.shthat records per-suite wall clock and a process-spawn count (aDEBUGtrap orbash -xline count is enough on Git Bash wherestraceis unavailable), and commit a ranked baseline table so every later change is measured against it.grep/sed/jq/gitinvoked once per file or per line,findwalks repeated per suite,mktemp -dper case,cygpathandunameper call,npxcold starts, and one pytest interpreter start per wrapper.lib/hook-utils.shalready used (perf(hook-utils): build the telemetry envelope and read file_path with builtins #3678): builtins over spawns, one batchedgitcall over many, onejqparse reused, onefindwalk hoisted, and one pytest invocation for co-located Python suites (with-p no:cacheproviderso no.pytest_cacheis left for markdownlint to trip over).--jobs, then measure whether--jobs 2or--jobs 4pays on a healthy host and set the default accordingly.Acceptance
scripts/exceeds 60 seconds on a healthy Windows host.scripts/affected-tests.sh --runfor a typical 50-file diff completes in under 2 minutes on Windows.scripts/run-plugin-tests.shcorpus completes in under 10 minutes on Windows, with the number recorded.