fix: respect Python indentation significance in Apply diff pipeline#12597
Open
rodboev wants to merge 1 commit into
Open
fix: respect Python indentation significance in Apply diff pipeline#12597rodboev wants to merge 1 commit into
rodboev wants to merge 1 commit into
Conversation
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.
Fixes #12455
Summary
"Apply" silently fails on Python files because the diff pipeline treats indentation differences as cosmetic. For Python, indentation is syntax, so changes to nesting depth or tabs-vs-spaces are real structural edits that get discarded.
Root cause
core/diff/util.ts:matchLine()has apermissiveAboutIndentationpath that returns the old line's content when two lines differ only in leading whitespace. This is correct for C++ and JS where indentation is cosmetic, but wrong for Python where indentation defines block structure. When an LLM produces Python code with different indentation, the diff sees every line as "same" and produces a no-op edit. The buffer stays unchanged despite the highlight appearing briefly.Additionally,
core/edit/lazy/deterministic.ts:shouldRejectDiff()has a 30% removal threshold that Python indentation diffs routinely exceed (every re-indented line counts as a removal + addition), forcing a fallback to the non-instant path where the indentation permissiveness then discards the changes entirely.Changes
core/diff/util.ts: addfilenameparameter tomatchLine(), skippermissiveAboutIndentationfor.pyfilescore/diff/streamDiff.ts: threadfilenamethrough tomatchLine()core/edit/lazy/streamLazyApply.ts: passfilenamethrough tostreamDiff()core/edit/streamDiffLines.ts: passoptions.fileUrithrough tostreamDiff()so the LLM-assisted edit path also respects Python indentationcore/edit/lazy/deterministic-python.vitest.ts: new test verifyingstreamDiffpreserves Python indentation changesPrior work
PR #11289 (merged 2026-03-24) fixed indentation corruption in the search-and-replace fallback path by adding
adjustReplacementIndentation(). That fix covers thesearchAndReplacecode path wheretrimmedMatch/whitespaceIgnoredMatchstrategies apply. This PR addresses a different code path:deterministicApplyLazyEdit→shouldRejectDiff→ non-instant fallback, wherematchLine()'spermissiveAboutIndentationdiscards Python indentation changes before the search-and-replace path is ever reached.What this doesn't change
The 30% removal threshold is untouched. Indentation permissiveness for non-Python files is unchanged. The
VerticalDiffHandlerUI layer and the search-and-replace path (including the #11289 fix) are not modified.Checklist
Screen recording or screenshot
N/A — the fix is in the diff pipeline, not the UI.
Tests
cd core && npx vitest run edit/lazy/deterministic-python.vitest.ts— new test verifyingstreamDiffpreserves Python indentation changescd core && npx vitest run diff/streamDiff.vitest.ts— existingfastapi-tabs-vs-spacestest still passes, confirming no regressionSummary by cubic
Fixes silent no-ops when applying edits to Python files by treating indentation changes as real diffs. Threads the filename through the diff pipeline and disables indentation permissiveness for
.py, leaving other languages unchanged.core/diff/util.ts: addfilenametomatchLine()and skip indentation permissiveness for.py.core/diff/streamDiff.ts,core/edit/lazy/streamLazyApply.ts,core/edit/streamDiffLines.ts: passfilename/fileUrithrough to ensure Python indentation is respected in all paths.core/edit/lazy/deterministic-python.vitest.tsto verify Python indentation diffs; existing JS indentation test still passes.Written for commit cc579d9. Summary will update on new commits.