Repository navigation
fix(work): read copy headers in the attempt diff canvas - #289
Merged
Lucas1479 merged 2 commits intoNov 4, 2026
Merged
Conversation
With diff.renames=copies, git diff reports a new file copied from a changed file with "copy from" / "copy to" extended headers. The parser handled the equivalent rename headers but ignored these, so a copy was shown as "modified". An exact copy has no ---/+++ lines; when its source and target paths contain spaces the diff --git header cannot be split, so the canvas showed a phantom entry plus the real path again as a hunk-less entry from changed_files. Read the copy headers like the rename headers: the entry gets status "copied", oldPath from "copy from", and path/newPath from "copy to". The status is displayed as text by the canvas; no consumer branches on its value. Tests cover exact and edited copies in the parser and a committed copy in an attempt finalized with diff.renames=copies; both fail without the fix. Fixes Code-Amadeus#286
# Conflicts: # tests/test_work_artifact_registry.py
Lucas1479
approved these changes
Nov 4, 2026
Lucas1479
left a comment
Member
There was a problem hiding this comment.
Thank you for the focused copy-header fix and regression coverage. I verified that copied entries use the existing free-text status field and render without a new consumer contract. The branch is now updated with #290; both sides of the test conflict were preserved and their test bodies were checked unchanged. All 65 relevant Windows tests, Ruff and diff checks pass on this head. Existing C-quoted path decoding is a separate non-blocking follow-up; no duplicate rename-only restriction is needed. Merge will wait for hosted CI on the updated head.
5 of 7 tasks
Lucas1479
added a commit
that referenced
this pull request
Nov 4, 2026
## What and why Fixes #285. With `diff.suppressBlankEmpty=true`, Git emits blank context as empty patch lines. The parser previously discarded these lines, omitting context and shifting later line numbers. The parser now accepts empty lines while the hunk still expects content. Host patch assembly also removes only one final LF from each patch segment, rather than stripping every trailing LF. This preserves blank context at the end of committed and working-tree patches, including when both are combined. Empty separators outside completed hunks remain ignored. Owning layers: `server/unified_diff.py` and `collect_git_delta` in `server/work_artifact_registry.py`. The output schema, configuration, permissions and attribution rules are unchanged. ## Change class - [x] Routine bug fix and regression coverage - [ ] Product-semantic or public-contract change - [ ] Isolated experiment ## Evidence - The original parser and real-repository regressions fail on unmodified main and pass with the parser fix. - Six additional end-to-end cases cover one/two trailing blank context lines in working-only, committed-only and combined patches. All six fail before the assembly fix and pass afterward. - `python -X utf8 -m pytest tests/test_local_git_provider_diff.py tests/test_work_artifact_registry.py tests/test_unified_diff_canvas.py tests/test_work_export_integration.py -q`: **73 passed** on the final combined tree, including #289 and #290. After updating to merged main, head `2f0c9488dd0938820d0f4331daeafe4cee1f1dc5` was verified byte-for-byte identical to that tested tree. - Test-file conflicts with #289/#290 were resolved by retaining both sides' test functions and manual runner calls. Existing test bodies were checked unchanged. - Ruff on the affected files and `git diff --check`: passed. - Local validation used Windows, Python 3.12.10 and Git 2.56.0. Linux/macOS and broader application validation rely on hosted CI; no local Electron journey or live provider call was performed. ## Final check - [x] One coherent blank-context preservation fix - [x] No new dependency, schema, fallback or public configuration - [x] No secrets, personal data or restricted assets - [x] CPU/model-less baseline retained --------- Co-authored-by: Lucas1479 <sli776@aucklanduni.ac.nz>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
With
diff.renames=copies,git diffreports a new file copied from a changed file withcopy from/copy toextended headers.parse_unified_diffhandled the equivalent rename headers but ignored these (details in #286):modified.---/+++lines. When its source and target paths contain spaces, thediff --githeader cannot be split, so the canvas showed a phantom entry (src.txtwitholdPathmy), plus the real path again as a hunk-less entry fromchanged_files.The copy headers are now read like the rename headers: status
copied,oldPathfromcopy from, andpath/newPathfromcopy to. The canvas displays the status as text, and no consumer branches on its value.Fixes #286
Linked Issue for product-semantic or public-contract changes: none (routine fix)
Change class
Owning layer:
server/unified_diff.py, the parser that turnsgit diffoutput into the provider-neutral diff canvas shape.User-visible effect, or
none: for users withdiff.renames=copies, copied files appear once in the attempt diff canvas ascopiedwith their real paths.Compatibility or migration impact, or
none: none.copiedis a new value of the existing free-textstatusfield; the output shape is unchanged.Evidence
Commands and manual journeys run:
python -m pytest -q tests/test_local_git_provider_diff.py tests/test_work_artifact_registry.py tests/test_unified_diff_canvas.py tests/test_work_export_integration.py: 63 passed (Linux, Python 3.12,uv sync --locked --extra dev, Git 2.43).The new tests
test_parse_unified_diff_reads_copy_headers(exact and edited copies) andtest_attempt_diff_lists_committed_copies_once_with_copy_detection(committed copy in an attempt finalized withdiff.renames=copies) fail onmainand pass with this change.python tests/test_unified_diff_canvas.pyandpython tests/test_work_artifact_registry.py: passed.ruff check server tests/test_unified_diff_canvas.py tests/test_work_artifact_registry.pyandgit diff --check: passed.pytest tests -k "diff or canvas or artifact": 183 passed, 18 skipped. The 6 failures aretest_auip_artifact_style.py::test_real_entry_css_delivery_and_advisory_boundaries, which fails the same way on unmodifiedmainin this environment.Parsed real
git -c diff.renames=copies diff HEADoutput (Git 2.54) with an exact copymy src.txt->my dup.txt. Before:src.txt,my src.txt,my dup.txt(allmodified). After:my dup.txt(copied frommy src.txt) andmy src.txt.Relevant Python tests pass
CPU/model-less baseline remains supported
Electron
npm run buildpasses when Electron code changedDependency audit passes when dependencies changed
Before/after screenshots are attached for visible UI changes
Documentation/examples are updated for changed settings or contracts
Final check