Skip to content

fix(pipeline): keep diff paths that contain spaces - #679

Merged
piekstra merged 2 commits into
mainfrom
fix/diff-paths-with-spaces
Oct 21, 2026
Merged

piekstra merged 2 commits into
mainfrom
fix/diff-paths-with-spaces

Conversation

@piekstra

Copy link
Copy Markdown
Member

Summary

Fixes #678.

Git quotes a path in a diff --git a/<path> b/<path> header for special characters, not for spaces. parseDiffGitPaths split the header at the first space, so data/2024-06-08 - a.json became old path data/2024-06-08 and new path -. The +++ b/<path> line corrected the new path of added and modified files, but a deleted file has +++ /dev/null and kept -. Two such deletions produced two manifest rows with the path -, and selection failed with pipeline: index selection manifest: duplicate canonical path "-" in file manifest.

The same split gave wrong paths in other shapes:

  • An added file kept a truncated old path, which the dossier listed as its old_path.
  • Empty added or deleted files, binary added or deleted files, and mode-only changes have no ---/+++ lines, so both paths were fragments.
  • C-quoted rename from/rename to lines (paths with non-ASCII bytes or control characters) kept their quotes and octal escapes.

Changes

  • parseDiffGitPaths reads an unquoted header whose two halves name the same file by splitting at its middle space. A rename's halves differ, so it keeps the existing token parsing and takes its paths from the rename from/rename to lines.
  • rename from/rename to paths are decoded with the unquoting the ---/+++ lines already used.

Validation

  • TestParseUnifiedDiffUnquotedPathsWithSpaces covers deleted, added, empty, binary, mode-only, pure-rename and content-changing-rename files with spaces, in git's output shape (a tab after a spaced ---/+++ path). On main every non-rename case fails.
  • TestParseUnifiedDiffQuotedRenamePaths covers a C-quoted rename. On main the paths keep their quotes and escapes.
  • TestSelectionOnlyAcceptsDeletedPathsWithSpaces deletes two spaced files in a git fixture repository and runs selection on the real git diff output. On main it fails with the error from the issue.
  • go test -race ./... and golangci-lint run with the Makefile's keyring_nopassage tag: pass.

Model: Claude Opus 5.5 (context unknown, xhigh effort) in Claude Code.

Git leaves a path with spaces unquoted in the "diff --git a/<path> b/<path>"
header, and the parser split that header at the first space. Added and
modified files recovered their new path from the "+++ b/<path>" line, but a
deleted file ("+++ /dev/null") kept the fragment after the last space. Deleting
"data/2024-06-08 - a.json" and "data/2024-06-08 - b.json" gave both files the
path "-", and selection stopped on a duplicate canonical path in the file
manifest. Files with no "---"/"+++" lines (empty, binary and mode-only changes)
kept both fragments, and an added file kept a truncated old path.

Read an unquoted header whose two halves name the same file by splitting at its
middle space. Renames keep the token parsing and take their paths from the
"rename from" and "rename to" lines, which are now decoded when git C-quotes
them.

Fixes #678.

@monit-reviewer monit-reviewer left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated PR Review

Reviewed commit: fd258ed08d60
Profile: claude-monit-reviewer - Posting as: monit-reviewer

Summary

Reviewer Findings
go:implementation-tests 0
harness-engineering:repo-health 0
security:code-auditor 0

Reviewer Coverage

Complete coverage details are retained in the local coverage.json artifact.

  • go:implementation-tests — complete (broad); scope: 3 files; examples: internal/pipeline/diff.go, internal/pipeline/diff_test.go, internal/pipeline/pipeline_test.go; body-inspected: 3 files; examples: internal/pipeline/diff.go, internal/pipeline/diff_test.go, internal/pipeline/pipeline_test.go; skipped: none; constraints: Reviewed the diff only; tests were not executed.
  • harness-engineering:repo-health — complete (constrained); scope: 3 files; examples: internal/pipeline/diff.go, internal/pipeline/diff_test.go, internal/pipeline/pipeline_test.go; body-inspected: 3 files; examples: internal/pipeline/diff.go, internal/pipeline/diff_test.go, internal/pipeline/pipeline_test.go; skipped: none; constraints: Static review of the diff only; tests were not run.
  • security:code-auditor — complete (broad); scope: 1 file; examples: internal/pipeline/diff.go; body-inspected: 1 file; examples: internal/pipeline/diff.go; skipped: none; constraints: Reviewed the diff of internal/pipeline/diff.go only; did not trace downstream consumers of manifest paths beyond the diff.

0 PR discussion threads considered. 0 summarized; 0 resolved.


Completed in 1m 15s | ~$1.31 (est.) | claude-sonnet-5-5 | cr 0.10.342
Field Value
Model claude-sonnet-5-5
Reviewers go:implementation-tests, harness-engineering:repo-health, security:code-auditor
Engine claude_cli · claude-sonnet-5-5
Reviewed by cr · monit-reviewer
Duration 1m 15s wall · 1m 39s compute
Cost ~$1.31 (est.)
Pricing basis baseline-2026-10-02/pricing
Tokens 34 in / 4.9k out

Per-workstream usage

  • orchestrator-selection — claude-sonnet-5-5
    • In: 6
    • Out: 1.2k
    • Cache read: 59.7k
    • Cache create: 51.7k
    • Cost: ~$0.23 (est.)
    • Duration: 19s
  • go:implementation-tests — claude-sonnet-5-5
    • In: 6
    • Out: 1.3k
    • Cache read: 61.7k
    • Cache create: 55.7k
    • Cost: ~$0.25 (est.)
    • Duration: 22s
  • harness-engineering:repo-health — claude-sonnet-5-5
    • In: 10
    • Out: 1.2k
    • Cache read: 165.4k
    • Cache create: 56.9k
    • Cost: ~$0.27 (est.)
    • Duration: 22s
  • security:code-auditor — claude-sonnet-5-5
    • In: 6
    • Out: 827
    • Cache read: 61.9k
    • Cache create: 52.0k
    • Cost: ~$0.23 (est.)
    • Duration: 20s
  • orchestrator-rollup — claude-sonnet-5-5
    • In: 6
    • Out: 450
    • Cache read: 134.0k
    • Cache create: 74.4k
    • Cost: ~$0.33 (est.)
    • Duration: 14s

@piekstra
piekstra marked this pull request as ready for review October 21, 2026 15:13
@piekstra
piekstra merged commit aafccea into main Oct 21, 2026
11 of 12 checks passed
@piekstra
piekstra deleted the fix/diff-paths-with-spaces branch October 21, 2026 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Review fails with a duplicate canonical path when a pull request deletes files with spaces in their names

2 participants