Git::Repo#changed_paths mixes repo-relative and cwd-relative paths; nested targets get doubled paths in lint and diff-test #615

Closed
opened 2026-09-18 14:19:07 +00:00 by jared · 2 comments
Owner

Git::Repo#changed_paths mixes repo-relative and cwd-relative paths; nested targets get doubled paths in lint and diff-test [capture]

Context

This came up during the #612 pipeline run, on target plugins/os-backlog.
The lint gate failed on every programmer and repair attempt.

Observed

git diff --name-only prints paths relative to the repository top level.
git ls-files --others --exclude-standard prints paths relative to the current working directory.
Adapter::Git::Repo#changed_paths concatenates both lists without normalizing the base.
For a target that is a subdirectory of the repo, this mixes two different path bases in one list.
On the #612 run, the rubocop command built from this list doubled the target prefix.

rubocop --server --format json plugins/os-backlog/lib/backlog/template_validator.rb
No such file or directory: /.../plugins/os-backlog/plugins/os-backlog/lib/backlog/template_validator.rb (exit 2)

This happened on all 8 programmer gate attempts and 3 repair rounds. The bound exhausted and the ticket was hand-finished.
A second effect: tracked changed test files arrive repo-relative, so they never match project.test.include?, which expects the tests/ prefix.
The diff-test gate silently drops these files. Only the untracked new test file ran, shown as "4 runs".
One diff-test attempt in implementation 1 showed the same doubled path with require_relative.
os-sdlc's own runs, with target plugins/os-sdlc, are exposed to the same mismatch.

Reproduce

cd plugins/os-backlog && git diff --name-only -- lib/backlog/template_validator.rb

Compare the output path base against:

cd plugins/os-backlog && git ls-files --others --exclude-standard

The first is repo-relative; the second is cwd-relative.

Expected

def test_changed_paths_are_relative_to_one_base
  # arrange: a repo with a nested target directory and a tracked, modified file inside it
  # act: call Adapter::Git::Repo#changed_paths from the nested target's cwd
  # assert: the returned path matches the same base as an untracked file in the same list
end

Origin

  • Trigger: lint gate exit 2 on every round of the #612 implementation, target plugins/os-backlog
  • Improvised this session: hand-finished the ticket after bound exhaustion; no code fix applied
  • Chain: lint gate exit 2 on every round ← rubocop given a repo-relative path from a target-relative cwd ← changed_paths mixes two path bases ← DESIGN (plugins/os-sdlc/lib/os_sdlc/adapter/git/repo.rb, changed_paths)
  • Root candidate: this ticket
  • Where: plugins/os-sdlc/lib/os_sdlc/adapter/git/repo.rb
  • Session: edb23374-6b44-4410-b666-a485a1923501
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/edb23374-6b44-4410-b666-a485a1923501.jsonl

Slice

Fix Adapter::Git::Repo#changed_paths so both source lists share one path base, relative to the caller's cwd.

Acceptance criteria

  • changed_paths returns paths relative to the same base for both tracked and untracked files.
  • A tracked, modified file inside a nested target directory (for example a plugin under plugins/) resolves to a path the lint gate can pass to rubocop without doubling the target prefix.
  • A tracked, modified test file inside a nested target is included by the diff-test gate's test selection.

Non-goals

This ticket does not change test_path defaults. See the companion ticket on Project::Test.

Owner sketch

class Adapter::Git::Repo
  def changed_paths
end

Cases

  1. Given a tracked modified file under a nested target, when changed_paths runs from the target directory, then the path is target-relative.
  2. Given a tracked modified test file under a nested target, when the diff-test gate selects tests, then the file is included.
  3. Given a tracked modified lib file under a nested target, when the lint gate builds its rubocop command, then rubocop inspects exactly that file (inspected_file_count 1).

Skeptic verdict

VERDICT: CREATE
REASON: Root-cause design bug in Adapter::Git::Repo#changed_paths (mixed repo-relative/cwd-relative path bases), reproduced and observed across a full bound-exhausted #612 pipeline run with a clean Origin chain ending in DESIGN, not improvisation.

# Git::Repo#changed_paths mixes repo-relative and cwd-relative paths; nested targets get doubled paths in lint and diff-test [capture] ## Context This came up during the #612 pipeline run, on target `plugins/os-backlog`. The lint gate failed on every programmer and repair attempt. ## Observed `git diff --name-only` prints paths relative to the repository top level. `git ls-files --others --exclude-standard` prints paths relative to the current working directory. `Adapter::Git::Repo#changed_paths` concatenates both lists without normalizing the base. For a target that is a subdirectory of the repo, this mixes two different path bases in one list. On the #612 run, the rubocop command built from this list doubled the target prefix. ``` rubocop --server --format json plugins/os-backlog/lib/backlog/template_validator.rb ``` ``` No such file or directory: /.../plugins/os-backlog/plugins/os-backlog/lib/backlog/template_validator.rb (exit 2) ``` This happened on all 8 programmer gate attempts and 3 repair rounds. The bound exhausted and the ticket was hand-finished. A second effect: tracked changed test files arrive repo-relative, so they never match `project.test.include?`, which expects the `tests/` prefix. The diff-test gate silently drops these files. Only the untracked new test file ran, shown as "4 runs". One diff-test attempt in implementation 1 showed the same doubled path with `require_relative`. os-sdlc's own runs, with target `plugins/os-sdlc`, are exposed to the same mismatch. ## Reproduce ``` cd plugins/os-backlog && git diff --name-only -- lib/backlog/template_validator.rb ``` Compare the output path base against: ``` cd plugins/os-backlog && git ls-files --others --exclude-standard ``` The first is repo-relative; the second is cwd-relative. ## Expected ```ruby def test_changed_paths_are_relative_to_one_base # arrange: a repo with a nested target directory and a tracked, modified file inside it # act: call Adapter::Git::Repo#changed_paths from the nested target's cwd # assert: the returned path matches the same base as an untracked file in the same list end ``` ## Origin - Trigger: lint gate exit 2 on every round of the #612 implementation, target plugins/os-backlog - Improvised this session: hand-finished the ticket after bound exhaustion; no code fix applied - Chain: lint gate exit 2 on every round ← rubocop given a repo-relative path from a target-relative cwd ← changed_paths mixes two path bases ← DESIGN (plugins/os-sdlc/lib/os_sdlc/adapter/git/repo.rb, changed_paths) - Root candidate: this ticket - Where: plugins/os-sdlc/lib/os_sdlc/adapter/git/repo.rb - Session: edb23374-6b44-4410-b666-a485a1923501 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/edb23374-6b44-4410-b666-a485a1923501.jsonl ## Slice Fix `Adapter::Git::Repo#changed_paths` so both source lists share one path base, relative to the caller's cwd. ## Acceptance criteria - `changed_paths` returns paths relative to the same base for both tracked and untracked files. - A tracked, modified file inside a nested target directory (for example a plugin under `plugins/`) resolves to a path the lint gate can pass to rubocop without doubling the target prefix. - A tracked, modified test file inside a nested target is included by the diff-test gate's test selection. ## Non-goals This ticket does not change `test_path` defaults. See the companion ticket on `Project::Test`. ## Owner sketch ```ruby class Adapter::Git::Repo def changed_paths end ``` ## Cases 1. Given a tracked modified file under a nested target, when changed_paths runs from the target directory, then the path is target-relative. 2. Given a tracked modified test file under a nested target, when the diff-test gate selects tests, then the file is included. 3. Given a tracked modified lib file under a nested target, when the lint gate builds its rubocop command, then rubocop inspects exactly that file (inspected_file_count 1). ## Skeptic verdict VERDICT: CREATE REASON: Root-cause design bug in Adapter::Git::Repo#changed_paths (mixed repo-relative/cwd-relative path bases), reproduced and observed across a full bound-exhausted #612 pipeline run with a clean Origin chain ending in DESIGN, not improvisation.
Author
Owner

Work started on branch ticket-615 in a worktree.

Work started on branch ticket-615 in a worktree.
Author
Owner

Resolution

Done: Git::Repo#changed_paths passes --relative to git diff --name-only so tracked and untracked paths share the cwd base for nested targets.

Evidence: Merged to main from branch ticket-615 (commit 3f4e34bf). os-sdlc suite 1346 runs, 0 failures. rubocop clean. New test test_changed_paths_shares_one_path_base_for_a_nested_target was red on the doubled path, green after. The #611 pipeline run on target plugins/os-sdlc is the live check.

Follow-ups: none

## Resolution **Done:** Git::Repo#changed_paths passes --relative to git diff --name-only so tracked and untracked paths share the cwd base for nested targets. **Evidence:** Merged to main from branch ticket-615 (commit 3f4e34bf). os-sdlc suite 1346 runs, 0 failures. rubocop clean. New test test_changed_paths_shares_one_path_base_for_a_nested_target was red on the doubled path, green after. The #611 pipeline run on target plugins/os-sdlc is the live check. **Follow-ups:** none
jared closed this issue 2026-09-18 14:27:11 +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#615
No description provided.