Skip to content

test-perf: diagnose and cut the wall clock of the local test and gate corpus, especially on Windows Git Bash #3716

Description

@kyle-sexton

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-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.
  • scripts/run-plugin-tests.sh keeps --jobs 1 as 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.
  • 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.

Related

Proposed work

  1. 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.
  2. 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.
  3. 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).
  4. Make parallelism safe on Windows: fix the suites in tool-honesty and jira conformance suites fail under run-plugin-tests --jobs 4, pass serially #3694 that fail under --jobs, then measure whether --jobs 2 or --jobs 4 pays on a healthy host and set the default accordingly.
  5. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions