os-backlog tests inject env instead of mutating ENV; Backlog::CLI threads env to ProjectIndex and Wakeup::State (#634a) #707

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

Problem

Global ENV mutation in plugins/os-backlog test helpers blocks parallel test runs. Backlog::CLI does not thread an env: keyword down to ProjectIndex/Wakeup::State, so tests mutate ENV["CC_OS_HOME"] and interpolate PATH into a backtick string instead of passing an env hash.

Observed

  • plugins/os-backlog/tests/support/cli_test_helpers.rb:19-20 ENV["CC_OS_HOME"] = home in with_isolated_project_index (5 callers).
  • plugins/os-backlog/tests/support/labels_cli_helpers.rb:49-50 builds path = fakebin ? "#{fakebin}:#{ENV['PATH']}" : ENV["PATH"] then runs a backtick PATH=#{path} ruby #{BIN} #{args} 2>&1 (3 callers).
  • plugins/os-backlog/lib/backlog/project_index.rb:9 def self.default_path(env: ENV); plugins/os-backlog/lib/backlog/wakeup/state.rb:8 same pattern; plugins/os-backlog/lib/backlog/cli.rb:20-26 Backlog::CLI.start(given_args = ARGV, config = {}) threads no env to either.
  • Suite command from .sdlc/project.yaml: ruby plugins/os-backlog/tests/all.rb.
  • Precedent: plugins/os-sdlc/tests/test_helper.rb:166-168 parallelize_me! plus a SerializedChdir monitor (ADR-0205).

Reproduce

grep -rn 'ENV\[.*\] *=' plugins/os-backlog/tests
grep -n 'PATH=#' plugins/os-backlog/tests/support/labels_cli_helpers.rb
ruby plugins/os-backlog/tests/all.rb

Approach

Required work:

  1. Backlog::CLI.start accepts env: (default ENV) and passes it to every ProjectIndex/Wakeup::State construction reached from CLI commands — check: grep -rn "default_path$\|default_path)" plugins/os-backlog/lib shows env passed
  2. cli_test_helpers passes env: {"CC_OS_HOME" => home} to Backlog::CLI.start, no ENV write — check: grep -rn 'ENV\[.*\] *=' plugins/os-backlog/tests empty
  3. labels_cli_helpers spawns via Open3.capture2e({"PATH" => path}, "ruby", BIN, *args, chdir: dir) — check: grep -n 'PATH=#' plugins/os-backlog/tests empty
  4. tests stop using Dir.chdir or wrap it in a SerializedChdir monitor copied from os-sdlc — check: grep -rn "Dir.chdir" plugins/os-backlog/tests only inside the monitor helper
  5. parallelize_me! in plugins/os-backlog/tests/test_helper.rb, suite green 3 consecutive runs — check: for i in 1 2 3; do ruby plugins/os-backlog/tests/all.rb || exit 1; done

Rejected: tests-only change (the in-process CLI reads ENV; the fix must thread env through lib, not just rewrite test helpers).

VERDICT: CREATE

Acceptance criteria

  1. Given a caller invokes Backlog::CLI.start with an env: keyword, when that call reaches ProjectIndex or Wakeup::State, then those objects receive the supplied env hash instead of reading global ENV.
  2. Given the os-backlog test suite, when it is grepped for ENV[...] = or a backtick-interpolated PATH=, then no matches remain.
  3. Given plugins/os-backlog/tests/test_helper.rb declares parallelize_me!, when the suite is run three consecutive times, then all three runs pass with no flakes.

Owner sketch

module Backlog
  class CLI < Thor
    def self.start(given_args = ARGV, config = {}, env: ENV)
      # thread env into Thor invocation context, read by commands below
    end
  end

  class ProjectIndex
    def self.default_path(env: ENV)
      # unchanged signature, now actually reached with a passed-in env
    end
  end
end

Non-goals

  • plugins/os worktree/finish env threading (tracked as #634b).
  • 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-backlog.
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-backlog` test helpers blocks parallel test runs. `Backlog::CLI` does not thread an `env:` keyword down to `ProjectIndex`/`Wakeup::State`, so tests mutate `ENV["CC_OS_HOME"]` and interpolate `PATH` into a backtick string instead of passing an env hash. ## Observed - `plugins/os-backlog/tests/support/cli_test_helpers.rb:19-20` `ENV["CC_OS_HOME"] = home` in `with_isolated_project_index` (5 callers). - `plugins/os-backlog/tests/support/labels_cli_helpers.rb:49-50` builds `path = fakebin ? "#{fakebin}:#{ENV['PATH']}" : ENV["PATH"]` then runs a backtick `PATH=#{path} ruby #{BIN} #{args} 2>&1` (3 callers). - `plugins/os-backlog/lib/backlog/project_index.rb:9` `def self.default_path(env: ENV)`; `plugins/os-backlog/lib/backlog/wakeup/state.rb:8` same pattern; `plugins/os-backlog/lib/backlog/cli.rb:20-26` `Backlog::CLI.start(given_args = ARGV, config = {})` threads no env to either. - Suite command from `.sdlc/project.yaml`: `ruby plugins/os-backlog/tests/all.rb`. - Precedent: `plugins/os-sdlc/tests/test_helper.rb:166-168` `parallelize_me!` plus a `SerializedChdir` monitor (ADR-0205). ## Reproduce grep -rn 'ENV\[.*\] *=' plugins/os-backlog/tests grep -n 'PATH=#' plugins/os-backlog/tests/support/labels_cli_helpers.rb ruby plugins/os-backlog/tests/all.rb ## Approach Required work: 1. `Backlog::CLI.start` accepts `env:` (default `ENV`) and passes it to every `ProjectIndex`/`Wakeup::State` construction reached from CLI commands — check: `grep -rn "default_path$\|default_path)" plugins/os-backlog/lib` shows env passed 2. `cli_test_helpers` passes `env: {"CC_OS_HOME" => home}` to `Backlog::CLI.start`, no `ENV` write — check: `grep -rn 'ENV\[.*\] *=' plugins/os-backlog/tests` empty 3. `labels_cli_helpers` spawns via `Open3.capture2e({"PATH" => path}, "ruby", BIN, *args, chdir: dir)` — check: `grep -n 'PATH=#' plugins/os-backlog/tests` empty 4. tests stop using `Dir.chdir` or wrap it in a `SerializedChdir` monitor copied from os-sdlc — check: `grep -rn "Dir.chdir" plugins/os-backlog/tests` only inside the monitor helper 5. `parallelize_me!` in `plugins/os-backlog/tests/test_helper.rb`, suite green 3 consecutive runs — check: `for i in 1 2 3; do ruby plugins/os-backlog/tests/all.rb || exit 1; done` Rejected: tests-only change (the in-process CLI reads ENV; the fix must thread env through lib, not just rewrite test helpers). VERDICT: CREATE ## Acceptance criteria 1. Given a caller invokes `Backlog::CLI.start` with an `env:` keyword, when that call reaches `ProjectIndex` or `Wakeup::State`, then those objects receive the supplied env hash instead of reading global `ENV`. 2. Given the os-backlog test suite, when it is grepped for `ENV[...] =` or a backtick-interpolated `PATH=`, then no matches remain. 3. Given `plugins/os-backlog/tests/test_helper.rb` declares `parallelize_me!`, when the suite is run three consecutive times, then all three runs pass with no flakes. ## Owner sketch ```ruby module Backlog class CLI < Thor def self.start(given_args = ARGV, config = {}, env: ENV) # thread env into Thor invocation context, read by commands below end end class ProjectIndex def self.default_path(env: ENV) # unchanged signature, now actually reached with a passed-in env end end end ``` ## Non-goals - `plugins/os` worktree/finish env threading (tracked as #634b). - 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-backlog. 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-707 via /os-sdlc:implement.

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

Resolution

Done: Backlog::CLI.start(argv, config, env:) stores env thread-locally (CliEnvContext) and threads it to ConfigWriteCommand and ProjectsCommand, which build ProjectIndex from ProjectIndex.default_path(env:). Test helpers no longer write ENV: with_isolated_project_index yields a home dir the test passes as env; labels_cli_helpers spawns via Open3.capture2e with a PATH hash; Dir.chdir is serialized by a Monitor (SerializedChdir); tests/test_helper.rb enables parallelize_me!.

Evidence: Pipeline implementation 36, 15 dispatches, implementation_complete. Suite green 3 consecutive runs (249 runs, 0 failures). Checks: no ENV assignment in plugins/os-backlog/tests, no PATH interpolation. rubocop clean on 10 changed files. CLI command bodies moved to Backlog::CliCommandHelpers to satisfy the class-length cop. Commit on branch ticket-707.

Follow-ups: ADR-0205 amendment extending affected-components to os and os-backlog is owed after #708 ships (owner: this session, VERDICT: CREATE).

## Resolution **Done:** Backlog::CLI.start(argv, config, env:) stores env thread-locally (CliEnvContext) and threads it to ConfigWriteCommand and ProjectsCommand, which build ProjectIndex from ProjectIndex.default_path(env:). Test helpers no longer write ENV: with_isolated_project_index yields a home dir the test passes as env; labels_cli_helpers spawns via Open3.capture2e with a PATH hash; Dir.chdir is serialized by a Monitor (SerializedChdir); tests/test_helper.rb enables parallelize_me!. **Evidence:** Pipeline implementation 36, 15 dispatches, implementation_complete. Suite green 3 consecutive runs (249 runs, 0 failures). Checks: no ENV assignment in plugins/os-backlog/tests, no PATH interpolation. rubocop clean on 10 changed files. CLI command bodies moved to Backlog::CliCommandHelpers to satisfy the class-length cop. Commit on branch ticket-707. **Follow-ups:** ADR-0205 amendment extending affected-components to os and os-backlog is owed after #708 ships (owner: this session, VERDICT: CREATE).
jared closed this issue 2026-09-24 22:21:10 +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#707
No description provided.