os worktree tests pass env to spawns, share one git seed, and run in parallel (#634b) #708

Closed
opened 2026-09-24 21:14:44 +00:00 by jared · 2 comments
Owner

Problem

Global ENV mutation in plugins/os worktree test helpers blocks parallel test runs, and each test forks its own git init sequence instead of sharing one seed.

Observed

  • plugins/os/tests/support/worktree_finish_test_case.rb:27-33 with_path_prepended mutates ENV['PATH'] (5 callers).
  • plugins/os/tests/support/worktree_finish_test_case.rb:35-42 seed_repo runs five system('git', ...) calls per test.
  • plugins/os/lib/worktree/binary_locator.rb:8 ENV.fetch('PATH', ''); plugins/os/lib/worktree/usage_sweep.rb uses it; plugins/os/lib/worktree/finish_command.rb also spawns a rubocop-server stop; none take an env hash.
  • Suite command from .sdlc/project.yaml: ruby plugins/os/tests/all.rb.
  • Precedent: plugins/os-sdlc/tests/test_helper.rb:166-168 parallelize_me! plus a SerializedChdir monitor (ADR-0205); plugins/os-sdlc/tests/support/repo_seeder.rb is the mirror target.

Reproduce

grep -rn "ENV\['PATH'\] =" plugins/os/tests
grep -c "system('git', 'init'" plugins/os/tests/support/worktree_finish_test_case.rb
ruby plugins/os/tests/all.rb

Approach

Required work:

  1. Worktree::CLI.start(argv, env: ENV) threads env to FinishCommand, UsageSweep, BinaryLocator (search_path from env["PATH"]) and every system/Open3 call in the finish path passes the env hash — check: grep -rn "ENV" plugins/os/lib/worktree empty
  2. tests call Worktree::CLI.start(argv, env: {"PATH" => "#{fakebin}:#{ENV['PATH']}"}) and with_path_prepended is deleted — check: grep -rn "ENV\['PATH'\] =" plugins/os/tests empty
  3. plugins/os/tests/support/repo_seeder.rb mirroring the os-sdlc one (seed once per suite, FileUtils.cp_r per test) replaces seed_repo's git calls — check: grep -c "system('git', 'init'" plugins/os/tests/support/worktree_finish_test_case.rb is 0
  4. Dir.chdir in tests replaced by cwd injection or a SerializedChdir monitor — check: grep -rn "Dir.chdir" plugins/os/tests only inside the monitor helper
  5. parallelize_me! in plugins/os/tests/all.rb, suite green 3 consecutive runs — check: for i in 1 2 3; do ruby plugins/os/tests/all.rb || exit 1; done

Rejected: tests-only change (lib system/Open3 calls take no env hash today; the fix must thread env through lib, not just rewrite test helpers).

VERDICT: CREATE

Acceptance criteria

  1. Given a caller invokes Worktree::CLI.start with an env: keyword, when the finish path spawns git, rubocop, or os-sdlc-runner, then each spawn receives the supplied env hash instead of inheriting global ENV.
  2. Given the os test suite, when it is grepped for ENV['PATH'] = or a system('git', 'init' call inside worktree_finish_test_case.rb, then no matches remain.
  3. Given plugins/os/tests/all.rb declares parallelize_me!, when the suite is run three consecutive times, then all three runs pass with no flakes.

Owner sketch

module Worktree
  class CLI < Thor
    def self.start(given_args = ARGV, config = {}, env: ENV)
      # thread env into FinishCommand/UsageSweep/BinaryLocator construction
    end
  end

  class BinaryLocator
    def initialize(env: ENV)
      @search_path = env.fetch('PATH', '')
    end
  end
end

Non-goals

  • plugins/os-backlog CLI/lib env threading (tracked as #634a).
  • The ADR-0205 amendment extending affected-components to os and os-backlog (owed once both children ship; parent #634 tracks it).

Origin

Trigger: split of #634.
Improvised this session: no.
Chain ending at DESIGN ADR-0205.
Root candidate "#634 (split 2026-09-24, session 082c3e8b)".
Where: plugins/os.
Session: 082c3e8b-5598-4c69-9ea6-b717e9c8afb2.
Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/082c3e8b-5598-4c69-9ea6-b717e9c8afb2.jsonl.

## Problem Global ENV mutation in `plugins/os` worktree test helpers blocks parallel test runs, and each test forks its own git init sequence instead of sharing one seed. ## Observed - `plugins/os/tests/support/worktree_finish_test_case.rb:27-33` `with_path_prepended` mutates `ENV['PATH']` (5 callers). - `plugins/os/tests/support/worktree_finish_test_case.rb:35-42` `seed_repo` runs five `system('git', ...)` calls per test. - `plugins/os/lib/worktree/binary_locator.rb:8` `ENV.fetch('PATH', '')`; `plugins/os/lib/worktree/usage_sweep.rb` uses it; `plugins/os/lib/worktree/finish_command.rb` also spawns a rubocop-server stop; none take an env hash. - Suite command from `.sdlc/project.yaml`: `ruby plugins/os/tests/all.rb`. - Precedent: `plugins/os-sdlc/tests/test_helper.rb:166-168` `parallelize_me!` plus a `SerializedChdir` monitor (ADR-0205); `plugins/os-sdlc/tests/support/repo_seeder.rb` is the mirror target. ## Reproduce grep -rn "ENV\['PATH'\] =" plugins/os/tests grep -c "system('git', 'init'" plugins/os/tests/support/worktree_finish_test_case.rb ruby plugins/os/tests/all.rb ## Approach Required work: 1. `Worktree::CLI.start(argv, env: ENV)` threads env to `FinishCommand`, `UsageSweep`, `BinaryLocator` (`search_path` from `env["PATH"]`) and every `system`/`Open3` call in the finish path passes the env hash — check: `grep -rn "ENV" plugins/os/lib/worktree` empty 2. tests call `Worktree::CLI.start(argv, env: {"PATH" => "#{fakebin}:#{ENV['PATH']}"})` and `with_path_prepended` is deleted — check: `grep -rn "ENV\['PATH'\] =" plugins/os/tests` empty 3. `plugins/os/tests/support/repo_seeder.rb` mirroring the os-sdlc one (seed once per suite, `FileUtils.cp_r` per test) replaces `seed_repo`'s git calls — check: `grep -c "system('git', 'init'" plugins/os/tests/support/worktree_finish_test_case.rb` is 0 4. `Dir.chdir` in tests replaced by cwd injection or a `SerializedChdir` monitor — check: `grep -rn "Dir.chdir" plugins/os/tests` only inside the monitor helper 5. `parallelize_me!` in `plugins/os/tests/all.rb`, suite green 3 consecutive runs — check: `for i in 1 2 3; do ruby plugins/os/tests/all.rb || exit 1; done` Rejected: tests-only change (lib `system`/`Open3` calls take no env hash today; the fix must thread env through lib, not just rewrite test helpers). VERDICT: CREATE ## Acceptance criteria 1. Given a caller invokes `Worktree::CLI.start` with an `env:` keyword, when the finish path spawns `git`, `rubocop`, or `os-sdlc-runner`, then each spawn receives the supplied env hash instead of inheriting global `ENV`. 2. Given the os test suite, when it is grepped for `ENV['PATH'] =` or a `system('git', 'init'` call inside `worktree_finish_test_case.rb`, then no matches remain. 3. Given `plugins/os/tests/all.rb` declares `parallelize_me!`, when the suite is run three consecutive times, then all three runs pass with no flakes. ## Owner sketch ```ruby module Worktree class CLI < Thor def self.start(given_args = ARGV, config = {}, env: ENV) # thread env into FinishCommand/UsageSweep/BinaryLocator construction end end class BinaryLocator def initialize(env: ENV) @search_path = env.fetch('PATH', '') end end end ``` ## Non-goals - `plugins/os-backlog` CLI/lib env threading (tracked as #634a). - The ADR-0205 amendment extending affected-components to os and os-backlog (owed once both children ship; parent #634 tracks it). ## Origin Trigger: split of #634. Improvised this session: no. Chain ending at DESIGN ADR-0205. Root candidate "#634 (split 2026-09-24, session 082c3e8b)". Where: plugins/os. Session: 082c3e8b-5598-4c69-9ea6-b717e9c8afb2. Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/082c3e8b-5598-4c69-9ea6-b717e9c8afb2.jsonl.
Author
Owner

Work started in session 082c3e8b on branch ticket-708 via /os-sdlc:implement.

Work started in session 082c3e8b on branch ticket-708 via /os-sdlc:implement.
Author
Owner

Resolution

Done: Worktree::CLI.start(argv, config, env:) stores env thread-locally and passes it to FinishCommand, which threads it to RepoRoot, ConflictScan, Removal, UsageSweep, BinaryLocator and every system/Open3 call on the finish path; backtick shell-outs became Open3 calls with an env hash. Tests: with_path_prepended deleted, RepoSeeder seeds one template repo per suite and copies it per test, SerializedChdir wraps Dir.chdir in a Monitor, ThreadRoutedIO makes capture_io thread-safe, plugins/os/tests/all.rb enables parallelize_me!.

Evidence: Pipeline implementation 37, 15 dispatches, implementation_complete. Suite green 3 consecutive runs (25 runs, 0 failures). Checks: the only ENV read left in plugins/os/lib/worktree is the CLI's default fallback; no PATH assignment in tests; zero init calls in worktree_finish_test_case.rb. Remaining rubocop offenses are Style/Documentation only, matching existing plugin practice under the repo's no-comment rule. Commit on branch ticket-708.

Follow-ups: ADR-0205 amendment extending affected-components to os and os-backlog: done next by this session (VERDICT: CREATE).

## Resolution **Done:** Worktree::CLI.start(argv, config, env:) stores env thread-locally and passes it to FinishCommand, which threads it to RepoRoot, ConflictScan, Removal, UsageSweep, BinaryLocator and every system/Open3 call on the finish path; backtick shell-outs became Open3 calls with an env hash. Tests: with_path_prepended deleted, RepoSeeder seeds one template repo per suite and copies it per test, SerializedChdir wraps Dir.chdir in a Monitor, ThreadRoutedIO makes capture_io thread-safe, plugins/os/tests/all.rb enables parallelize_me!. **Evidence:** Pipeline implementation 37, 15 dispatches, implementation_complete. Suite green 3 consecutive runs (25 runs, 0 failures). Checks: the only ENV read left in plugins/os/lib/worktree is the CLI's default fallback; no PATH assignment in tests; zero init calls in worktree_finish_test_case.rb. Remaining rubocop offenses are Style/Documentation only, matching existing plugin practice under the repo's no-comment rule. Commit on branch ticket-708. **Follow-ups:** ADR-0205 amendment extending affected-components to os and os-backlog: done next by this session (VERDICT: CREATE).
jared closed this issue 2026-09-25 06:26:06 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#708
No description provided.