Skip to content

fix(toolpath-convo): strip leading slash in unified_diff headers#43

Merged
eliothedeman merged 1 commit into
mainfrom
eliot/issue-36-diff-header-slash
Apr 22, 2026
Merged

fix(toolpath-convo): strip leading slash in unified_diff headers#43
eliothedeman merged 1 commit into
mainfrom
eliot/issue-36-diff-header-slash

Conversation

@eliothedeman
Copy link
Copy Markdown
Collaborator

Closes #36

Summary

unified_diff(path, ...) previously emitted --- a//abs/file.rs / +++ b//abs/file.rs whenever path already started with / (common for Claude's tool_use.input.file_path, which carries absolute paths like /Users/.../src/login.rs). Git-style a/ and b/ prefixes already denote the repo root, so the doubled slash breaks patch(1) and any other tool that parses the header.

The fix trims a single leading / before splicing into the header. The toolpath-claude test that asserted on the broken form ("--- a//src/login.rs") has been updated to match — it had been canonicalising the bug.

Changes

  • crates/toolpath-convo/src/derive.rs::unified_diff — strip leading / via trim_start_matches('/'); doc comment updated to explain the rationale.
  • crates/toolpath-convo/src/derive.rs — add test_unified_diff_strips_leading_slash_on_absolute_path and test_unified_diff_preserves_relative_path regression tests.
  • crates/toolpath-claude/src/derive.rs::test_derive_path_edit_tool_emits_unified_diff — assert the correct headers and explicitly reject any a// substring.

Risk

Low. The frontend diff renderer (toolpath-desktop) splits on lines and does not parse the header, so no UI breakage. External consumers piping .path.json diffs into patch(1) benefit directly. No public API change; no version bump.

Test plan

  • cargo test -p toolpath-convo -p toolpath-claude
  • cargo clippy -p toolpath-convo -p toolpath-claude -- -D warnings

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 22, 2026

🔍 Preview deployed: https://fb9414f9.toolpath.pages.dev

Copy link
Copy Markdown
Collaborator Author

@eliothedeman eliothedeman left a comment

Choose a reason for hiding this comment

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

Summary

Targeted, correct fix for #36. unified_diff now strips the leading / so absolute paths stop emitting --- a//abs/path.rs. Both --- and +++ headers use the trimmed display, and the misleading Claude test is corrected rather than deleted.

Notes

  • crates/toolpath-convo/src/derive.rs:381trim_start_matches('/') strips all leading slashes, not just one. The issue only spec'd stripping a single /, but this is the safer choice (nonstandard //foo inputs also normalize) and test_unified_diff_strips_leading_slash_on_absolute_path enforces the !contains("a//") invariant. Worth noting in case anyone expects Path::new-style "preserve // root" semantics, but I'd keep it as-is.
  • Edge cases behave reasonably: empty string and bare / both produce --- a/\n+++ b/\n — same as before for the empty case, strictly better for /. Relative paths pass through untouched (covered by test_unified_diff_preserves_relative_path).
  • crates/toolpath-claude/src/derive.rs:1619 — good that the updated test asserts both headers plus the negative !raw.contains("a//"); that's what keeps the canonicalised-bug from reappearing.
  • Scope is clean: no version bump (correct — public signature and semantics for the common relative-path case are unchanged), no CHANGELOG entry (consistent with the file's version-scoped pattern), no refactoring drift.
  • Risk: a downstream consumer that specifically parses a//abs/... would break, but that already means they worked around our bug. The PR body's patch(1) framing is right — this makes output correct per git conventions.

Verdict

LGTM (commenting rather than approving — GitHub blocks self-approval). Matches the issue spec, has regression coverage on both sides of the crate boundary, and the doc comment on unified_diff now explains why the trim happens so a future reader won't undo it.

`unified_diff(path, ...)` previously emitted `--- a//abs/file.rs` /
`+++ b//abs/file.rs` when `path` already started with `/` (common for
Claude's `tool_use.input.file_path`, which carries absolute paths).
Git-style `a/` and `b/` prefixes already denote the repo root, so the
doubled slash breaks `patch(1)` and any other tool that parses the
header.

Trim a single leading `/` before splicing into the header. Add a
regression test in `toolpath-convo::derive::tests` and update the
`toolpath-claude::derive::test_derive_path_edit_tool_emits_unified_diff`
assertion, which had been canonicalising the broken output.

The frontend diff renderer splits on lines and does not parse the
header, so no UI breakage. Internal-only; no API change.

Closes #36
@eliothedeman eliothedeman force-pushed the eliot/issue-36-diff-header-slash branch from 7ae44f8 to 783aa51 Compare April 22, 2026 20:59
@eliothedeman eliothedeman merged commit 1cad908 into main Apr 22, 2026
2 checks passed
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.

toolpath-convo: unified_diff emits double-slash in headers for absolute paths

1 participant