You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
rtk diff produces cascading false positives on insertions/deletions #1869
rtk diff file1 file2 produces cascading false positives when lines are inserted or deleted. It uses a naive index-based line comparison that shifts all subsequent line indices, causing unchanged lines to be reported as removed and added.
This is distinct from #781 (similarity threshold causing "Files are identical"), which PRs #792 and #1144 address.
Version
rtk 0.39.0
Minimal reproduction
# Create a 20-line file
seq 1 20 > a.txt
# Insert one line in the middle
cp a.txt b.txt
sed -i '5i\INSERTED' b.txt
# Compare
rtk diff a.txt b.txt
So roughly 1,112× more tokens than diff output for the same change. When the rtk diff result gets fed back into the model context (e.g. in an agent loop), it's essentially sending both files in full rather than a diff.
The cascade is still generated — it is then thrown away by the never-worse guard, which
notices the cascading render is bigger than the raw input and substitutes a dump of both
files. So the symptom mutated from "wrong diff" into "no diff at all", which is what @EvolveAegis measured above as 1,112× the tokens of diff. Same root cause, and their
numbers stand.
The defect is in compute_diff, not in any renderer
compute_diff walks both files by index and compares line i against line i. One
inserted line shifts every subsequent index, so every later line is reported as changed.
Nothing downstream can recover the alignment, so this survives any change to how the
result is printed. Reproduced against the raw comparison, the 3-line case from the
description gives:
rtk: 1,2c1,2 / < a / < b / --- / > b / > c then 3d2 / < c
GNU: 1d0 / < a
and the 20-line case emits 36 lines where diff emits 2.
How to test it
The trap is that a wrong-but-well-formed diff still applies. I generated 900 random file
pairs (0–12 lines each side, half derived from the first by 1–3 edits, some with an empty
side) and checked the emitted patches: 885 non-empty patches, all 885 apply with patch
and reproduce the second file byte-for-byte. Validity is not the problem. Only 289 of
885 match GNU's edit script; the rest are correct but not minimal, averaging ~40% more
bytes across the corpus.
So the acceptance criterion has to be minimality, not applicability:
for a random pair (a, b):
assert rtk_edit_script(a, b) == `diff a b`
A property test over generated pairs is the cheap version — the generator matters more than
the count, since it needs to produce insertions and deletions in the middle of a file,
not just at the ends. Two regression cases worth pinning directly, both from this issue:
seq 1 20 vs the same with one line inserted at position 5 → must be exactly 4a5 / > INSERTED
Activity
fix(cmds/git/diff): preserve POSIX/git contract for programmatic cons…
pszymkowiak commentedon May 27, 2026
🔍 Automated Triage
bughighSummary
rtk diff uses naive index-based line comparison causing cascading false positives on insertions/deletions; PR #1981 is in progress.
📁 Relevant files
cmds/git/diffTriaged automatically by wshm · This is an automated analysis, not a human review.
fix(cmds/git/diff): preserve POSIX/git contract for programmatic cons…
EvolveAegis commentedon Aug 1, 2026
I ran into this with a larger file and measured the token impact, in case it helps with prioritization.
With a 1,000-line file and one line inserted at the top:
So roughly 1,112× more tokens than
diffoutput for the same change. When thertk diffresult gets fed back into the model context (e.g. in an agent loop), it's essentially sending both files in full rather than a diff.The repro is just:
Tested with rtk 0.43.0. Looks like #2668 should address this — happy to run the same test against the PR branch if that would help.
fix(diff): replace naive index-based comparison with LCS algorithm
KuSh commentedon Aug 31, 2026
Confirming this is still live, and explaining why it currently looks unreproducible — the
needs-reproductionlabel is misleading rather than wrong.Why the repro in the description no longer shows the cascade
On
developtoday, the repro prints neither the cascade nor a sane diff:The cascade is still generated — it is then thrown away by the never-worse guard, which
notices the cascading render is bigger than the raw input and substitutes a dump of both
files. So the symptom mutated from "wrong diff" into "no diff at all", which is what
@EvolveAegis measured above as 1,112× the tokens of
diff. Same root cause, and theirnumbers stand.
The defect is in
compute_diff, not in any renderercompute_diffwalks both files by index and compares line i against line i. Oneinserted line shifts every subsequent index, so every later line is reported as changed.
Nothing downstream can recover the alignment, so this survives any change to how the
result is printed. Reproduced against the raw comparison, the 3-line case from the
description gives:
and the 20-line case emits 36 lines where
diffemits 2.How to test it
The trap is that a wrong-but-well-formed diff still applies. I generated 900 random file
pairs (0–12 lines each side, half derived from the first by 1–3 edits, some with an empty
side) and checked the emitted patches: 885 non-empty patches, all 885 apply with
patchand reproduce the second file byte-for-byte. Validity is not the problem. Only 289 of
885 match GNU's edit script; the rest are correct but not minimal, averaging ~40% more
bytes across the corpus.
So the acceptance criterion has to be minimality, not applicability:
A property test over generated pairs is the cheap version — the generator matters more than
the count, since it needs to produce insertions and deletions in the middle of a file,
not just at the ends. Two regression cases worth pinning directly, both from this issue:
seq 1 20vs the same with one line inserted at position 5 → must be exactly4a5/> INSERTEDa\nb\ncvsb\nc→ must be exactly1d0/< aNeither passes today.