FA-75731 / Text diff and three-way merge / Open access
Blame propagation: removed lines do not advance the old-line cursor · case 01
Lines after a deletion are credited to the commits of the deleted lines.
ROOT CAUSE
The loop over removed lines never moves the cursor into the old annotations.
VERIFIED REPAIR
Advance the old-line cursor once for every removed line.
Unsuccessful approach: Advancing once per run still misattributes lines after a multi-line deletion.
Case contract
Given the old file's per-line commit annotations and an edit script, produce annotations for the new file: context lines keep their old annotation, added lines get the new commit. With ignore_ws, within a run of removed lines followed by added lines, the i-th added line keeps the i-th removed line's annotation when both are equal after deleting all whitespace.
Why this case matters
Blame and annotate views follow each line through history; whitespace-insensitive blame should not credit reformatting commits.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(ann, ops, commit, ignore_ws):
res = []
i = 0
k = 0
while k < len(ops):
tag = ops[k][0]
if tag == ' ':
res.append(ann[i])
i += 1
k += 1
continue
dels = []
while k < len(ops) and ops[k][0] == '-':
dels.append((ann[i], ops[k][1]))
k += 1
adds = []
while k < len(ops) and ops[k][0] == '+':
adds.append(ops[k][1])
k += 1
for idx, text in enumerate(adds):
if ignore_ws and idx < len(dels) and ''.join(dels[idx][1].split()) == ''.join(text.split()):
res.append(dels[idx][0])
else:
res.append(commit)
return res
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
1: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y = 2'], [' ', 'k']], 'N1', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
2: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y = 2'], [' ', 'k']], 'N2', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
3: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y = 2'], [' ', 'k']], 'N3', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
4: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y = 2'], [' ', 'k']], 'N4', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
5: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y = 2'], [' ', 'k']], 'N5', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
}[N]
for label, args, expected in cases:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| context keeps attribution | ['c1', 'c2'] | ['c1', 'c3'] | Failed |
| insertion attributed to the new commit | ['c1', 'N', 'c2'] | ['c1', 'N', 'c2'] | Passed |
| removed lines advance the old cursor | ['c1', 'c2'] | ['c3', 'c4'] | Failed |
| whitespace-only change keeps blame when ignoring whitespace | ['c1', 'c1'] | ['c1', 'c2'] | Failed |
| whitespace-only change is new without the flag | ['N', 'c1'] | ['N', 'c2'] | Failed |
| second pair compared positionally | ['c1', 'c1', 'c1'] | ['c1', 'c2', 'c3'] | Failed |
| extra additions are new | ['c1', 'N', 'c1'] | ['c1', 'N', 'c2'] | Failed |
| real change within a whitespace block | ['c1', 'N', 'c1'] | ['c1', 'N', 'c3'] | Failed |
SHA-256 / 22535da568a606ee63f1a462b8f95384a82716351ae3a17b83d31c2e395aaf42
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(ann, ops, commit, ignore_ws):
res = []
i = 0
k = 0
while k < len(ops):
tag = ops[k][0]
if tag == ' ':
res.append(ann[i])
i += 1
k += 1
continue
dels = []
while k < len(ops) and ops[k][0] == '-':
dels.append((ann[i], ops[k][1]))
k += 1
i += 1 if dels else 0
adds = []
while k < len(ops) and ops[k][0] == '+':
adds.append(ops[k][1])
k += 1
for idx, text in enumerate(adds):
if ignore_ws and idx < len(dels) and ''.join(dels[idx][1].split()) == ''.join(text.split()):
res.append(dels[idx][0])
else:
res.append(commit)
return res
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
1: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y = 2'], [' ', 'k']], 'N1', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
2: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y = 2'], [' ', 'k']], 'N2', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
3: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y = 2'], [' ', 'k']], 'N3', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
4: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y = 2'], [' ', 'k']], 'N4', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
5: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y = 2'], [' ', 'k']], 'N5', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
}[N]
for label, args, expected in cases:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| context keeps attribution | ['c1', 'c3'] | ['c1', 'c3'] | Passed |
| insertion attributed to the new commit | ['c1', 'N', 'c2'] | ['c1', 'N', 'c2'] | Passed |
| removed lines advance the old cursor | ['c2', 'c3'] | ['c3', 'c4'] | Failed |
| whitespace-only change keeps blame when ignoring whitespace | ['c1', 'c2'] | ['c1', 'c2'] | Passed |
| whitespace-only change is new without the flag | ['N', 'c2'] | ['N', 'c2'] | Passed |
| second pair compared positionally | ['c1', 'c1', 'c2'] | ['c1', 'c2', 'c3'] | Failed |
| extra additions are new | ['c1', 'N', 'c2'] | ['c1', 'N', 'c2'] | Passed |
| real change within a whitespace block | ['c1', 'N', 'c2'] | ['c1', 'N', 'c3'] | Failed |
SHA-256 / c256a52c2aa3c256267b8e5072c9365a0526d01174326e5aaa9ccad461eacb04
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(ann, ops, commit, ignore_ws):
res = []
i = 0
k = 0
while k < len(ops):
tag = ops[k][0]
if tag == ' ':
res.append(ann[i])
i += 1
k += 1
continue
dels = []
while k < len(ops) and ops[k][0] == '-':
dels.append((ann[i], ops[k][1]))
i += 1
k += 1
adds = []
while k < len(ops) and ops[k][0] == '+':
adds.append(ops[k][1])
k += 1
for idx, text in enumerate(adds):
if ignore_ws and idx < len(dels) and ''.join(dels[idx][1].split()) == ''.join(text.split()):
res.append(dels[idx][0])
else:
res.append(commit)
return res
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
1: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y = 2'], [' ', 'k']], 'N1', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
2: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y = 2'], [' ', 'k']], 'N2', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
3: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y = 2'], [' ', 'k']], 'N3', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
4: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y = 2'], [' ', 'k']], 'N4', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
5: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y = 2'], [' ', 'k']], 'N5', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
}[N]
for label, args, expected in cases:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| context keeps attribution | ['c1', 'c3'] | ['c1', 'c3'] | Passed |
| insertion attributed to the new commit | ['c1', 'N', 'c2'] | ['c1', 'N', 'c2'] | Passed |
| removed lines advance the old cursor | ['c3', 'c4'] | ['c3', 'c4'] | Passed |
| whitespace-only change keeps blame when ignoring whitespace | ['c1', 'c2'] | ['c1', 'c2'] | Passed |
| whitespace-only change is new without the flag | ['N', 'c2'] | ['N', 'c2'] | Passed |
| second pair compared positionally | ['c1', 'c2', 'c3'] | ['c1', 'c2', 'c3'] | Passed |
| extra additions are new | ['c1', 'N', 'c2'] | ['c1', 'N', 'c2'] | Passed |
| real change within a whitespace block | ['c1', 'N', 'c3'] | ['c1', 'N', 'c3'] | Passed |
SHA-256 / d4528568653c52e70162c7d70fe2e90bde1762740af533d308824a624b901b3f
Verification & scope
A deterministic, bounded teaching model of one diff, patch or merge rule with stipulated conventions; it is not a production diff or version-control implementation and makes no claim of conformance to any specific tool. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:49:09.623432+00:00.
Case digest / 4dec42f76f176159d02c4b63abb9a914091465fc76a552660e3e09777a7bde15