Stop os-backlog tests from rewriting the main checkout .cc-os/config from a linked worktree #1759

Open
opened 2026-11-13 20:32:10 +00:00 by jared · 0 comments
Owner

Problem

os-backlog project configure writes the .cc-os/config of the primary checkout when the working directory is in a linked git worktree that has no .cc-os/config. The os-backlog tests run project configure repo:docs/issues. Thus a test run in such a worktree can replace the tracker of the real repository, and then every os-backlog ticket command in the repository fails.

Observed

At about 15:21 EST on 2026-11-13 a process rewrote /home/jared/dev/cc-os/.cc-os/config to tracker=repo:docs/issues.
Only os-backlog tests and os-sdlc tests use the value repo:docs/issues. The directory docs/issues does not exist.
Every os-backlog ticket command in the repository failed until an agent ran os-backlog project configure forgejo:jared/cc-os (file mtime 15:24:13).
Git ignores the file (.gitignore:26), so git has no history of it.

Mechanism, read in the source:

  • plugins/os-backlog/lib/backlog/config_locator.rb:13-15 locate_for_write uses find_owning_root when the start directory has no .cc-os/config.
  • plugins/os-backlog/lib/backlog/config_locator.rb:24-30 find_owning_root returns the primary checkout root when the start directory is in a linked worktree (OsGit::RepoRoot.primary_root, plugins/os-git/lib/os_git/repo_root.rb:13-17 and :49-55).
  • plugins/os-backlog/lib/backlog/cli/session.rb:16 gives Dir.pwd as the start directory.
  • plugins/os-backlog/lib/backlog/config/write_command.rb:14-16 writes the file.

Candidate writer (strong evidence, not proven):

  • The tests that run project configure repo:docs/issues are plugins/os-backlog/test/cli_config_write_command_test.rb:47 and plugins/os-backlog/test/cli_config_write_origin_remote_test.rb:49. They are safe only while in_dir (plugins/os-backlog/test/support/temporary_chdir.rb) moves the process into a temporary directory first.
  • The worktree /home/jared/dev/cc-os/.claude/worktrees/os-backlog-test-speed has no .cc-os/config. Most other worktrees have a symlink to the .cc-os of the main checkout.
  • A parallel session edited that worktree at the time of the defect. test/support/temporary_chdir.rb has mtime 15:18:31. test/cli_config_write_command_test.rb, test/cli_config_write_origin_remote_test.rb, test/support/cli_sandbox.rb, test/support/in_process_cli_run.rb, lib/backlog/cli/session.rb, and lib/backlog/cli/project_commands.rb have mtime 15:23:52. That work removes in_dir from those tests and replaces Dir.pwd in Session with an injected cwd.
  • Most likely event: between 15:18 and 15:24 a test run in that worktree used a half-edited state. The test did not change the directory, and the production code read Dir.pwd. project configure repo:docs/issues then ran with the working directory in the worktree, and the write went to the main checkout.
  • Not proven: the edit at 15:23:52 replaced the intermediate file state, and no log shows the test run.
  • Not the writer: the takedown run of #1748 (docs/takedown/1748-20261113-150953 in the worktree ticket-1742). It ran only os-sdlc ConceptCycle tests in a scratch repository below ~/.cache/cc-os/takedown-runs/. That repository is not a linked worktree.

Reproduce

Not run, because it rewrites the real file. Expected to reproduce:

cd /home/jared/dev/cc-os/.claude/worktrees/os-backlog-test-speed/plugins/os-backlog && /home/jared/.claude/plugins/os-backlog/bin/os-backlog project configure repo:docs/issues

Acceptance criteria

  1. Given a linked worktree that has no .cc-os/config, when the full os-backlog suite and the os-sdlc tests that use repo:docs/issues run from that worktree, then /home/jared/dev/cc-os/.cc-os/config is byte-identical before and after the run.
  2. Given a test or a pipeline step that runs project configure, when its write target is outside its temporary directory, then it fails with an error and writes nothing.
  3. Given project configure in a linked worktree that has no .cc-os/config, when it runs, then it obeys a recorded decision about a write to the primary checkout.

Origin

  • Trigger: os-backlog ticket commands failed in /home/jared/dev/cc-os after about 15:21 EST on 2026-11-13; the file contained tracker=repo:docs/issues.
  • Improvised this session: an agent restored the value with os-backlog project configure forgejo:jared/cc-os.
  • Chain: ticket commands fail ← .cc-os/config holds the test value repo:docs/issues (file content, observed) ← project configure repo:docs/issues ran with a working directory in a linked worktree without .cc-os/config (inferred from file mtimes in the worktree os-backlog-test-speed) ← locate_for_write sends the write to the primary checkout (plugins/os-backlog/lib/backlog/config_locator.rb:13-30) ← DESIGN (plugins/os-backlog/lib/backlog/config_locator.rb).
  • Root candidate: none found; searched .cc-os/config, locate_for_write, ConfigLocator, primary_root, worktree config, repo:docs/issues, project configure, Dir.pwd, os-backlog-test-speed, injected cwd
  • Where: plugins/os-backlog/lib/backlog/config_locator.rb (Backlog::ConfigLocator#locate_for_write); plugins/os-backlog/test/cli_config_write_command_test.rb
  • Session: 2bb44e9c-522c-4c97-8449-bd46bed898e0
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-ticket-1233/2bb44e9c-522c-4c97-8449-bd46bed898e0.jsonl

VERDICT: CREATE (ticket-skeptic, 2026-11-13): a test run from a linked worktree can overwrite the git-ignored .cc-os/config of the real repository; the nearest open ticket #1674 covers a different fault.

## Problem `os-backlog project configure` writes the `.cc-os/config` of the primary checkout when the working directory is in a linked git worktree that has no `.cc-os/config`. The os-backlog tests run `project configure repo:docs/issues`. Thus a test run in such a worktree can replace the tracker of the real repository, and then every os-backlog ticket command in the repository fails. ## Observed At about 15:21 EST on 2026-11-13 a process rewrote `/home/jared/dev/cc-os/.cc-os/config` to `tracker=repo:docs/issues`. Only os-backlog tests and os-sdlc tests use the value `repo:docs/issues`. The directory `docs/issues` does not exist. Every os-backlog ticket command in the repository failed until an agent ran `os-backlog project configure forgejo:jared/cc-os` (file mtime 15:24:13). Git ignores the file (`.gitignore:26`), so git has no history of it. Mechanism, read in the source: - `plugins/os-backlog/lib/backlog/config_locator.rb:13-15` `locate_for_write` uses `find_owning_root` when the start directory has no `.cc-os/config`. - `plugins/os-backlog/lib/backlog/config_locator.rb:24-30` `find_owning_root` returns the primary checkout root when the start directory is in a linked worktree (`OsGit::RepoRoot.primary_root`, `plugins/os-git/lib/os_git/repo_root.rb:13-17` and `:49-55`). - `plugins/os-backlog/lib/backlog/cli/session.rb:16` gives `Dir.pwd` as the start directory. - `plugins/os-backlog/lib/backlog/config/write_command.rb:14-16` writes the file. Candidate writer (strong evidence, not proven): - The tests that run `project configure repo:docs/issues` are `plugins/os-backlog/test/cli_config_write_command_test.rb:47` and `plugins/os-backlog/test/cli_config_write_origin_remote_test.rb:49`. They are safe only while `in_dir` (`plugins/os-backlog/test/support/temporary_chdir.rb`) moves the process into a temporary directory first. - The worktree `/home/jared/dev/cc-os/.claude/worktrees/os-backlog-test-speed` has no `.cc-os/config`. Most other worktrees have a symlink to the `.cc-os` of the main checkout. - A parallel session edited that worktree at the time of the defect. `test/support/temporary_chdir.rb` has mtime 15:18:31. `test/cli_config_write_command_test.rb`, `test/cli_config_write_origin_remote_test.rb`, `test/support/cli_sandbox.rb`, `test/support/in_process_cli_run.rb`, `lib/backlog/cli/session.rb`, and `lib/backlog/cli/project_commands.rb` have mtime 15:23:52. That work removes `in_dir` from those tests and replaces `Dir.pwd` in `Session` with an injected `cwd`. - Most likely event: between 15:18 and 15:24 a test run in that worktree used a half-edited state. The test did not change the directory, and the production code read `Dir.pwd`. `project configure repo:docs/issues` then ran with the working directory in the worktree, and the write went to the main checkout. - Not proven: the edit at 15:23:52 replaced the intermediate file state, and no log shows the test run. - Not the writer: the takedown run of #1748 (`docs/takedown/1748-20261113-150953` in the worktree `ticket-1742`). It ran only os-sdlc ConceptCycle tests in a scratch repository below `~/.cache/cc-os/takedown-runs/`. That repository is not a linked worktree. ## Reproduce Not run, because it rewrites the real file. Expected to reproduce: ``` cd /home/jared/dev/cc-os/.claude/worktrees/os-backlog-test-speed/plugins/os-backlog && /home/jared/.claude/plugins/os-backlog/bin/os-backlog project configure repo:docs/issues ``` ## Acceptance criteria 1. Given a linked worktree that has no `.cc-os/config`, when the full os-backlog suite and the os-sdlc tests that use `repo:docs/issues` run from that worktree, then `/home/jared/dev/cc-os/.cc-os/config` is byte-identical before and after the run. 2. Given a test or a pipeline step that runs `project configure`, when its write target is outside its temporary directory, then it fails with an error and writes nothing. 3. Given `project configure` in a linked worktree that has no `.cc-os/config`, when it runs, then it obeys a recorded decision about a write to the primary checkout. ## Origin - Trigger: os-backlog ticket commands failed in `/home/jared/dev/cc-os` after about 15:21 EST on 2026-11-13; the file contained `tracker=repo:docs/issues`. - Improvised this session: an agent restored the value with `os-backlog project configure forgejo:jared/cc-os`. - Chain: ticket commands fail ← `.cc-os/config` holds the test value `repo:docs/issues` (file content, observed) ← `project configure repo:docs/issues` ran with a working directory in a linked worktree without `.cc-os/config` (inferred from file mtimes in the worktree `os-backlog-test-speed`) ← `locate_for_write` sends the write to the primary checkout (`plugins/os-backlog/lib/backlog/config_locator.rb:13-30`) ← DESIGN (`plugins/os-backlog/lib/backlog/config_locator.rb`). - Root candidate: none found; searched .cc-os/config, locate_for_write, ConfigLocator, primary_root, worktree config, repo:docs/issues, project configure, Dir.pwd, os-backlog-test-speed, injected cwd - Where: `plugins/os-backlog/lib/backlog/config_locator.rb` (`Backlog::ConfigLocator#locate_for_write`); `plugins/os-backlog/test/cli_config_write_command_test.rb` - Session: 2bb44e9c-522c-4c97-8449-bd46bed898e0 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-ticket-1233/2bb44e9c-522c-4c97-8449-bd46bed898e0.jsonl VERDICT: CREATE (ticket-skeptic, 2026-11-13): a test run from a linked worktree can overwrite the git-ignored `.cc-os/config` of the real repository; the nearest open ticket #1674 covers a different fault.
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#1759
No description provided.