FA-75391 / Text diff and three-way merge / Open access
Unified hunk builder: empty ranges start at the next line · case 01
Headers for pure insertions or deletions point one line too far, so patch tools apply them in the wrong place.
ROOT CAUSE
An empty range uses the 1-based next line instead of the line before.
VERIFIED REPAIR
For a count of 0 the start is the line before the (empty) range, 0 at the beginning of a file.
Unsuccessful approach: Special-casing position 0 still prints 1 for insertions into an empty file.
Case contract
Given a full edit script ([tag, line], tags " ", "-", "+") and a context width C, group changes whose separating equal lines number at most 2C, extend each group by up to C lines on both sides, and emit a header "@@ -a,b +c,d @@" followed by the hunk lines. A range start is the 1-based first line, or the line before when the count is 0; a count of 1 is omitted.
Why this case matters
Unified diff output depends on hunk grouping, context trimming and the header conventions for empty and single-line ranges.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(ops, context):
changes = [i for i, op in enumerate(ops) if op[0] != ' ']
if not changes:
return []
groups = []
start = end = changes[0]
for i in changes[1:]:
if i - end - 1 <= 2 * context:
end = i
else:
groups.append((start, end))
start = end = i
groups.append((start, end))
old_no, new_no = [], []
o = w = 0
for tag, _ in ops:
old_no.append(o)
new_no.append(w)
if tag != '+':
o += 1
if tag != '-':
w += 1
def rng(start0, count):
first = start0 + 1
return str(first) if count == 1 else '%d,%d' % (first, count)
out = []
for s, e in groups:
lo = max(0, s - context)
hi = min(len(ops) - 1, e + context)
body = ops[lo:hi + 1]
ol = sum(1 for t, _ in body if t != '+')
nl = sum(1 for t, _ in body if t != '-')
out.append('@@ -%s +%s @@' % (rng(old_no[lo], ol), rng(new_no[lo], nl)))
out.extend(t + x for t, x in body)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
1: [('single change in the middle', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['-', 'old'], ['+', 'new'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7']], 2], ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5']), ('change at the very start', [[['-', 'first'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4']], 3], ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2']), ('pure insertion into an empty file', [[['+', 'x0']], 3], ['@@ -0,0 +1 @@', '+x0']), ('pure deletion of every line', [[['-', 'gone']], 1], ['@@ -1 +0,0 @@', '-gone']), ('two changes separated by exactly twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 1], ['@@ -1,4 +1,4 @@', '-a', ' c0', ' c1', '+b', ' c0']), ('two changes separated by more than twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 1], ['@@ -1,2 +1 @@', '-a', ' c0', '@@ -4,2 +3,3 @@', ' c2', '+b', ' c0']), ('insertion after existing lines', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'tail']], 2], ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail']), ('single-line ranges', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['-', 'x'], ['+', 'y'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 0], ['@@ -4 +4 @@', '-x', '+y']), ('no changes', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3']], 3], []), ('deletion and insertion in separate hunks', [[[' ', 'a'], ['-', 'b'], [' ', 'c'], ['+', 'd'], [' ', 'e']], 0], ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d']), ('deletion near the start with wide context', [[[' ', 'c0'], ['-', 'd1'], ['-', 'd2'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5']], 3], ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'])],
2: [('single change in the middle', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['-', 'old'], ['+', 'new'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7']], 2], ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5']), ('change at the very start', [[['-', 'first'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4']], 3], ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2']), ('pure insertion into an empty file', [[['+', 'x0'], ['+', 'x1']], 3], ['@@ -0,0 +1,2 @@', '+x0', '+x1']), ('pure deletion of every line', [[['-', 'gone']], 1], ['@@ -1 +0,0 @@', '-gone']), ('two changes separated by exactly twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 2], ['@@ -1,7 +1,7 @@', '-a', ' c0', ' c1', ' c2', ' c3', '+b', ' c0', ' c1']), ('two changes separated by more than twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 2], ['@@ -1,3 +1,2 @@', '-a', ' c0', ' c1', '@@ -5,4 +4,5 @@', ' c3', ' c4', '+b', ' c0', ' c1']), ('insertion after existing lines', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'tail']], 2], ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail']), ('single-line ranges', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['-', 'x'], ['+', 'y'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 0], ['@@ -4 +4 @@', '-x', '+y']), ('no changes', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3']], 3], []), ('deletion and insertion in separate hunks', [[[' ', 'a'], ['-', 'b'], [' ', 'c'], ['+', 'd'], [' ', 'e']], 0], ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d']), ('deletion near the start with wide context', [[[' ', 'c0'], ['-', 'd1'], ['-', 'd2'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5']], 3], ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'])],
3: [('single change in the middle', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['-', 'old'], ['+', 'new'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7']], 2], ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5']), ('change at the very start', [[['-', 'first'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4']], 3], ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2']), ('pure insertion into an empty file', [[['+', 'x0'], ['+', 'x1'], ['+', 'x2']], 3], ['@@ -0,0 +1,3 @@', '+x0', '+x1', '+x2']), ('pure deletion of every line', [[['-', 'gone']], 1], ['@@ -1 +0,0 @@', '-gone']), ('two changes separated by exactly twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 3], ['@@ -1,10 +1,10 @@', '-a', ' c0', ' c1', ' c2', ' c3', ' c4', ' c5', '+b', ' c0', ' c1', ' c2']), ('two changes separated by more than twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 3], ['@@ -1,4 +1,3 @@', '-a', ' c0', ' c1', ' c2', '@@ -6,6 +5,7 @@', ' c4', ' c5', ' c6', '+b', ' c0', ' c1', ' c2']), ('insertion after existing lines', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'tail']], 2], ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail']), ('single-line ranges', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['-', 'x'], ['+', 'y'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 0], ['@@ -4 +4 @@', '-x', '+y']), ('no changes', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3']], 3], []), ('deletion and insertion in separate hunks', [[[' ', 'a'], ['-', 'b'], [' ', 'c'], ['+', 'd'], [' ', 'e']], 0], ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d']), ('deletion near the start with wide context', [[[' ', 'c0'], ['-', 'd1'], ['-', 'd2'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5']], 3], ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'])],
4: [('single change in the middle', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['-', 'old'], ['+', 'new'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7']], 2], ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5']), ('change at the very start', [[['-', 'first'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4']], 3], ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2']), ('pure insertion into an empty file', [[['+', 'x0'], ['+', 'x1'], ['+', 'x2'], ['+', 'x3']], 3], ['@@ -0,0 +1,4 @@', '+x0', '+x1', '+x2', '+x3']), ('pure deletion of every line', [[['-', 'gone']], 1], ['@@ -1 +0,0 @@', '-gone']), ('two changes separated by exactly twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 4], ['@@ -1,12 +1,12 @@', '-a', ' c0', ' c1', ' c2', ' c3', ' c4', ' c5', ' c6', ' c7', '+b', ' c0', ' c1', ' c2']), ('two changes separated by more than twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7'], [' ', 'c8'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 4], ['@@ -1,5 +1,4 @@', '-a', ' c0', ' c1', ' c2', ' c3', '@@ -7,7 +6,8 @@', ' c5', ' c6', ' c7', ' c8', '+b', ' c0', ' c1', ' c2']), ('insertion after existing lines', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'tail']], 2], ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail']), ('single-line ranges', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['-', 'x'], ['+', 'y'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 0], ['@@ -4 +4 @@', '-x', '+y']), ('no changes', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3']], 3], []), ('deletion and insertion in separate hunks', [[[' ', 'a'], ['-', 'b'], [' ', 'c'], ['+', 'd'], [' ', 'e']], 0], ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d']), ('deletion near the start with wide context', [[[' ', 'c0'], ['-', 'd1'], ['-', 'd2'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5']], 3], ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'])],
5: [('single change in the middle', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['-', 'old'], ['+', 'new'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7']], 2], ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5']), ('change at the very start', [[['-', 'first'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4']], 3], ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2']), ('pure insertion into an empty file', [[['+', 'x0'], ['+', 'x1'], ['+', 'x2'], ['+', 'x3'], ['+', 'x4']], 3], ['@@ -0,0 +1,5 @@', '+x0', '+x1', '+x2', '+x3', '+x4']), ('pure deletion of every line', [[['-', 'gone']], 1], ['@@ -1 +0,0 @@', '-gone']), ('two changes separated by exactly twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7'], [' ', 'c8'], [' ', 'c9'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 5], ['@@ -1,14 +1,14 @@', '-a', ' c0', ' c1', ' c2', ' c3', ' c4', ' c5', ' c6', ' c7', ' c8', ' c9', '+b', ' c0', ' c1', ' c2']), ('two changes separated by more than twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7'], [' ', 'c8'], [' ', 'c9'], [' ', 'c10'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 5], ['@@ -1,6 +1,5 @@', '-a', ' c0', ' c1', ' c2', ' c3', ' c4', '@@ -8,8 +7,9 @@', ' c6', ' c7', ' c8', ' c9', ' c10', '+b', ' c0', ' c1', ' c2']), ('insertion after existing lines', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'tail']], 2], ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail']), ('single-line ranges', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['-', 'x'], ['+', 'y'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 0], ['@@ -4 +4 @@', '-x', '+y']), ('no changes', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3']], 3], []), ('deletion and insertion in separate hunks', [[[' ', 'a'], ['-', 'b'], [' ', 'c'], ['+', 'd'], [' ', 'e']], 0], ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d']), ('deletion near the start with wide context', [[[' ', 'c0'], ['-', 'd1'], ['-', 'd2'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5']], 3], ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'])],
}[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 |
|---|---|---|---|
| single change in the middle | ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5'] | ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5'] | Passed |
| change at the very start | ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2'] | ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2'] | Passed |
| pure insertion into an empty file | ['@@ -1,0 +1 @@', '+x0'] | ['@@ -0,0 +1 @@', '+x0'] | Failed |
| pure deletion of every line | ['@@ -1 +1,0 @@', '-gone'] | ['@@ -1 +0,0 @@', '-gone'] | Failed |
| two changes separated by exactly twice the context | ['@@ -1,4 +1,4 @@', '-a', ' c0', ' c1', '+b', ' c0'] | ['@@ -1,4 +1,4 @@', '-a', ' c0', ' c1', '+b', ' c0'] | Passed |
| two changes separated by more than twice the context | ['@@ -1,2 +1 @@', '-a', ' c0', '@@ -4,2 +3,3 @@', ' c2', '+b', ' c0'] | ['@@ -1,2 +1 @@', '-a', ' c0', '@@ -4,2 +3,3 @@', ' c2', '+b', ' c0'] | Passed |
| insertion after existing lines | ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail'] | ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail'] | Passed |
| single-line ranges | ['@@ -4 +4 @@', '-x', '+y'] | ['@@ -4 +4 @@', '-x', '+y'] | Passed |
| no changes | [] | [] | Passed |
| deletion and insertion in separate hunks | ['@@ -2 +2,0 @@', '-b', '@@ -4,0 +3 @@', '+d'] | ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d'] | Failed |
| deletion near the start with wide context | ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'] | ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'] | Passed |
SHA-256 / d4e1b1eada3500520f1852466a31ebe3914737b7a8913d4343a0ae2e25d6786a
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(ops, context):
changes = [i for i, op in enumerate(ops) if op[0] != ' ']
if not changes:
return []
groups = []
start = end = changes[0]
for i in changes[1:]:
if i - end - 1 <= 2 * context:
end = i
else:
groups.append((start, end))
start = end = i
groups.append((start, end))
old_no, new_no = [], []
o = w = 0
for tag, _ in ops:
old_no.append(o)
new_no.append(w)
if tag != '+':
o += 1
if tag != '-':
w += 1
def rng(start0, count):
first = start0 if count == 0 and start0 > 0 else start0 + 1
return str(first) if count == 1 else '%d,%d' % (first, count)
out = []
for s, e in groups:
lo = max(0, s - context)
hi = min(len(ops) - 1, e + context)
body = ops[lo:hi + 1]
ol = sum(1 for t, _ in body if t != '+')
nl = sum(1 for t, _ in body if t != '-')
out.append('@@ -%s +%s @@' % (rng(old_no[lo], ol), rng(new_no[lo], nl)))
out.extend(t + x for t, x in body)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
1: [('single change in the middle', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['-', 'old'], ['+', 'new'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7']], 2], ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5']), ('change at the very start', [[['-', 'first'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4']], 3], ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2']), ('pure insertion into an empty file', [[['+', 'x0']], 3], ['@@ -0,0 +1 @@', '+x0']), ('pure deletion of every line', [[['-', 'gone']], 1], ['@@ -1 +0,0 @@', '-gone']), ('two changes separated by exactly twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 1], ['@@ -1,4 +1,4 @@', '-a', ' c0', ' c1', '+b', ' c0']), ('two changes separated by more than twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 1], ['@@ -1,2 +1 @@', '-a', ' c0', '@@ -4,2 +3,3 @@', ' c2', '+b', ' c0']), ('insertion after existing lines', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'tail']], 2], ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail']), ('single-line ranges', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['-', 'x'], ['+', 'y'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 0], ['@@ -4 +4 @@', '-x', '+y']), ('no changes', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3']], 3], []), ('deletion and insertion in separate hunks', [[[' ', 'a'], ['-', 'b'], [' ', 'c'], ['+', 'd'], [' ', 'e']], 0], ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d']), ('deletion near the start with wide context', [[[' ', 'c0'], ['-', 'd1'], ['-', 'd2'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5']], 3], ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'])],
2: [('single change in the middle', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['-', 'old'], ['+', 'new'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7']], 2], ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5']), ('change at the very start', [[['-', 'first'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4']], 3], ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2']), ('pure insertion into an empty file', [[['+', 'x0'], ['+', 'x1']], 3], ['@@ -0,0 +1,2 @@', '+x0', '+x1']), ('pure deletion of every line', [[['-', 'gone']], 1], ['@@ -1 +0,0 @@', '-gone']), ('two changes separated by exactly twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 2], ['@@ -1,7 +1,7 @@', '-a', ' c0', ' c1', ' c2', ' c3', '+b', ' c0', ' c1']), ('two changes separated by more than twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 2], ['@@ -1,3 +1,2 @@', '-a', ' c0', ' c1', '@@ -5,4 +4,5 @@', ' c3', ' c4', '+b', ' c0', ' c1']), ('insertion after existing lines', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'tail']], 2], ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail']), ('single-line ranges', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['-', 'x'], ['+', 'y'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 0], ['@@ -4 +4 @@', '-x', '+y']), ('no changes', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3']], 3], []), ('deletion and insertion in separate hunks', [[[' ', 'a'], ['-', 'b'], [' ', 'c'], ['+', 'd'], [' ', 'e']], 0], ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d']), ('deletion near the start with wide context', [[[' ', 'c0'], ['-', 'd1'], ['-', 'd2'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5']], 3], ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'])],
3: [('single change in the middle', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['-', 'old'], ['+', 'new'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7']], 2], ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5']), ('change at the very start', [[['-', 'first'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4']], 3], ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2']), ('pure insertion into an empty file', [[['+', 'x0'], ['+', 'x1'], ['+', 'x2']], 3], ['@@ -0,0 +1,3 @@', '+x0', '+x1', '+x2']), ('pure deletion of every line', [[['-', 'gone']], 1], ['@@ -1 +0,0 @@', '-gone']), ('two changes separated by exactly twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 3], ['@@ -1,10 +1,10 @@', '-a', ' c0', ' c1', ' c2', ' c3', ' c4', ' c5', '+b', ' c0', ' c1', ' c2']), ('two changes separated by more than twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 3], ['@@ -1,4 +1,3 @@', '-a', ' c0', ' c1', ' c2', '@@ -6,6 +5,7 @@', ' c4', ' c5', ' c6', '+b', ' c0', ' c1', ' c2']), ('insertion after existing lines', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'tail']], 2], ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail']), ('single-line ranges', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['-', 'x'], ['+', 'y'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 0], ['@@ -4 +4 @@', '-x', '+y']), ('no changes', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3']], 3], []), ('deletion and insertion in separate hunks', [[[' ', 'a'], ['-', 'b'], [' ', 'c'], ['+', 'd'], [' ', 'e']], 0], ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d']), ('deletion near the start with wide context', [[[' ', 'c0'], ['-', 'd1'], ['-', 'd2'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5']], 3], ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'])],
4: [('single change in the middle', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['-', 'old'], ['+', 'new'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7']], 2], ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5']), ('change at the very start', [[['-', 'first'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4']], 3], ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2']), ('pure insertion into an empty file', [[['+', 'x0'], ['+', 'x1'], ['+', 'x2'], ['+', 'x3']], 3], ['@@ -0,0 +1,4 @@', '+x0', '+x1', '+x2', '+x3']), ('pure deletion of every line', [[['-', 'gone']], 1], ['@@ -1 +0,0 @@', '-gone']), ('two changes separated by exactly twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 4], ['@@ -1,12 +1,12 @@', '-a', ' c0', ' c1', ' c2', ' c3', ' c4', ' c5', ' c6', ' c7', '+b', ' c0', ' c1', ' c2']), ('two changes separated by more than twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7'], [' ', 'c8'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 4], ['@@ -1,5 +1,4 @@', '-a', ' c0', ' c1', ' c2', ' c3', '@@ -7,7 +6,8 @@', ' c5', ' c6', ' c7', ' c8', '+b', ' c0', ' c1', ' c2']), ('insertion after existing lines', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'tail']], 2], ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail']), ('single-line ranges', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['-', 'x'], ['+', 'y'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 0], ['@@ -4 +4 @@', '-x', '+y']), ('no changes', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3']], 3], []), ('deletion and insertion in separate hunks', [[[' ', 'a'], ['-', 'b'], [' ', 'c'], ['+', 'd'], [' ', 'e']], 0], ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d']), ('deletion near the start with wide context', [[[' ', 'c0'], ['-', 'd1'], ['-', 'd2'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5']], 3], ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'])],
5: [('single change in the middle', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['-', 'old'], ['+', 'new'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7']], 2], ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5']), ('change at the very start', [[['-', 'first'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4']], 3], ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2']), ('pure insertion into an empty file', [[['+', 'x0'], ['+', 'x1'], ['+', 'x2'], ['+', 'x3'], ['+', 'x4']], 3], ['@@ -0,0 +1,5 @@', '+x0', '+x1', '+x2', '+x3', '+x4']), ('pure deletion of every line', [[['-', 'gone']], 1], ['@@ -1 +0,0 @@', '-gone']), ('two changes separated by exactly twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7'], [' ', 'c8'], [' ', 'c9'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 5], ['@@ -1,14 +1,14 @@', '-a', ' c0', ' c1', ' c2', ' c3', ' c4', ' c5', ' c6', ' c7', ' c8', ' c9', '+b', ' c0', ' c1', ' c2']), ('two changes separated by more than twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7'], [' ', 'c8'], [' ', 'c9'], [' ', 'c10'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 5], ['@@ -1,6 +1,5 @@', '-a', ' c0', ' c1', ' c2', ' c3', ' c4', '@@ -8,8 +7,9 @@', ' c6', ' c7', ' c8', ' c9', ' c10', '+b', ' c0', ' c1', ' c2']), ('insertion after existing lines', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'tail']], 2], ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail']), ('single-line ranges', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['-', 'x'], ['+', 'y'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 0], ['@@ -4 +4 @@', '-x', '+y']), ('no changes', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3']], 3], []), ('deletion and insertion in separate hunks', [[[' ', 'a'], ['-', 'b'], [' ', 'c'], ['+', 'd'], [' ', 'e']], 0], ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d']), ('deletion near the start with wide context', [[[' ', 'c0'], ['-', 'd1'], ['-', 'd2'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5']], 3], ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'])],
}[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 |
|---|---|---|---|
| single change in the middle | ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5'] | ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5'] | Passed |
| change at the very start | ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2'] | ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2'] | Passed |
| pure insertion into an empty file | ['@@ -1,0 +1 @@', '+x0'] | ['@@ -0,0 +1 @@', '+x0'] | Failed |
| pure deletion of every line | ['@@ -1 +1,0 @@', '-gone'] | ['@@ -1 +0,0 @@', '-gone'] | Failed |
| two changes separated by exactly twice the context | ['@@ -1,4 +1,4 @@', '-a', ' c0', ' c1', '+b', ' c0'] | ['@@ -1,4 +1,4 @@', '-a', ' c0', ' c1', '+b', ' c0'] | Passed |
| two changes separated by more than twice the context | ['@@ -1,2 +1 @@', '-a', ' c0', '@@ -4,2 +3,3 @@', ' c2', '+b', ' c0'] | ['@@ -1,2 +1 @@', '-a', ' c0', '@@ -4,2 +3,3 @@', ' c2', '+b', ' c0'] | Passed |
| insertion after existing lines | ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail'] | ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail'] | Passed |
| single-line ranges | ['@@ -4 +4 @@', '-x', '+y'] | ['@@ -4 +4 @@', '-x', '+y'] | Passed |
| no changes | [] | [] | Passed |
| deletion and insertion in separate hunks | ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d'] | ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d'] | Passed |
| deletion near the start with wide context | ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'] | ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'] | Passed |
SHA-256 / 90b46133ec1417936aa84ba6efe531aebd24774e94ab02b36db99ecaf9854dba
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(ops, context):
changes = [i for i, op in enumerate(ops) if op[0] != ' ']
if not changes:
return []
groups = []
start = end = changes[0]
for i in changes[1:]:
if i - end - 1 <= 2 * context:
end = i
else:
groups.append((start, end))
start = end = i
groups.append((start, end))
old_no, new_no = [], []
o = w = 0
for tag, _ in ops:
old_no.append(o)
new_no.append(w)
if tag != '+':
o += 1
if tag != '-':
w += 1
def rng(start0, count):
first = start0 + 1 if count > 0 else start0
return str(first) if count == 1 else '%d,%d' % (first, count)
out = []
for s, e in groups:
lo = max(0, s - context)
hi = min(len(ops) - 1, e + context)
body = ops[lo:hi + 1]
ol = sum(1 for t, _ in body if t != '+')
nl = sum(1 for t, _ in body if t != '-')
out.append('@@ -%s +%s @@' % (rng(old_no[lo], ol), rng(new_no[lo], nl)))
out.extend(t + x for t, x in body)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
1: [('single change in the middle', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['-', 'old'], ['+', 'new'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7']], 2], ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5']), ('change at the very start', [[['-', 'first'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4']], 3], ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2']), ('pure insertion into an empty file', [[['+', 'x0']], 3], ['@@ -0,0 +1 @@', '+x0']), ('pure deletion of every line', [[['-', 'gone']], 1], ['@@ -1 +0,0 @@', '-gone']), ('two changes separated by exactly twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 1], ['@@ -1,4 +1,4 @@', '-a', ' c0', ' c1', '+b', ' c0']), ('two changes separated by more than twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 1], ['@@ -1,2 +1 @@', '-a', ' c0', '@@ -4,2 +3,3 @@', ' c2', '+b', ' c0']), ('insertion after existing lines', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'tail']], 2], ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail']), ('single-line ranges', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['-', 'x'], ['+', 'y'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 0], ['@@ -4 +4 @@', '-x', '+y']), ('no changes', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3']], 3], []), ('deletion and insertion in separate hunks', [[[' ', 'a'], ['-', 'b'], [' ', 'c'], ['+', 'd'], [' ', 'e']], 0], ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d']), ('deletion near the start with wide context', [[[' ', 'c0'], ['-', 'd1'], ['-', 'd2'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5']], 3], ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'])],
2: [('single change in the middle', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['-', 'old'], ['+', 'new'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7']], 2], ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5']), ('change at the very start', [[['-', 'first'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4']], 3], ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2']), ('pure insertion into an empty file', [[['+', 'x0'], ['+', 'x1']], 3], ['@@ -0,0 +1,2 @@', '+x0', '+x1']), ('pure deletion of every line', [[['-', 'gone']], 1], ['@@ -1 +0,0 @@', '-gone']), ('two changes separated by exactly twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 2], ['@@ -1,7 +1,7 @@', '-a', ' c0', ' c1', ' c2', ' c3', '+b', ' c0', ' c1']), ('two changes separated by more than twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 2], ['@@ -1,3 +1,2 @@', '-a', ' c0', ' c1', '@@ -5,4 +4,5 @@', ' c3', ' c4', '+b', ' c0', ' c1']), ('insertion after existing lines', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'tail']], 2], ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail']), ('single-line ranges', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['-', 'x'], ['+', 'y'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 0], ['@@ -4 +4 @@', '-x', '+y']), ('no changes', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3']], 3], []), ('deletion and insertion in separate hunks', [[[' ', 'a'], ['-', 'b'], [' ', 'c'], ['+', 'd'], [' ', 'e']], 0], ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d']), ('deletion near the start with wide context', [[[' ', 'c0'], ['-', 'd1'], ['-', 'd2'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5']], 3], ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'])],
3: [('single change in the middle', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['-', 'old'], ['+', 'new'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7']], 2], ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5']), ('change at the very start', [[['-', 'first'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4']], 3], ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2']), ('pure insertion into an empty file', [[['+', 'x0'], ['+', 'x1'], ['+', 'x2']], 3], ['@@ -0,0 +1,3 @@', '+x0', '+x1', '+x2']), ('pure deletion of every line', [[['-', 'gone']], 1], ['@@ -1 +0,0 @@', '-gone']), ('two changes separated by exactly twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 3], ['@@ -1,10 +1,10 @@', '-a', ' c0', ' c1', ' c2', ' c3', ' c4', ' c5', '+b', ' c0', ' c1', ' c2']), ('two changes separated by more than twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 3], ['@@ -1,4 +1,3 @@', '-a', ' c0', ' c1', ' c2', '@@ -6,6 +5,7 @@', ' c4', ' c5', ' c6', '+b', ' c0', ' c1', ' c2']), ('insertion after existing lines', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'tail']], 2], ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail']), ('single-line ranges', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['-', 'x'], ['+', 'y'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 0], ['@@ -4 +4 @@', '-x', '+y']), ('no changes', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3']], 3], []), ('deletion and insertion in separate hunks', [[[' ', 'a'], ['-', 'b'], [' ', 'c'], ['+', 'd'], [' ', 'e']], 0], ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d']), ('deletion near the start with wide context', [[[' ', 'c0'], ['-', 'd1'], ['-', 'd2'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5']], 3], ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'])],
4: [('single change in the middle', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['-', 'old'], ['+', 'new'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7']], 2], ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5']), ('change at the very start', [[['-', 'first'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4']], 3], ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2']), ('pure insertion into an empty file', [[['+', 'x0'], ['+', 'x1'], ['+', 'x2'], ['+', 'x3']], 3], ['@@ -0,0 +1,4 @@', '+x0', '+x1', '+x2', '+x3']), ('pure deletion of every line', [[['-', 'gone']], 1], ['@@ -1 +0,0 @@', '-gone']), ('two changes separated by exactly twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 4], ['@@ -1,12 +1,12 @@', '-a', ' c0', ' c1', ' c2', ' c3', ' c4', ' c5', ' c6', ' c7', '+b', ' c0', ' c1', ' c2']), ('two changes separated by more than twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7'], [' ', 'c8'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 4], ['@@ -1,5 +1,4 @@', '-a', ' c0', ' c1', ' c2', ' c3', '@@ -7,7 +6,8 @@', ' c5', ' c6', ' c7', ' c8', '+b', ' c0', ' c1', ' c2']), ('insertion after existing lines', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'tail']], 2], ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail']), ('single-line ranges', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['-', 'x'], ['+', 'y'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 0], ['@@ -4 +4 @@', '-x', '+y']), ('no changes', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3']], 3], []), ('deletion and insertion in separate hunks', [[[' ', 'a'], ['-', 'b'], [' ', 'c'], ['+', 'd'], [' ', 'e']], 0], ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d']), ('deletion near the start with wide context', [[[' ', 'c0'], ['-', 'd1'], ['-', 'd2'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5']], 3], ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'])],
5: [('single change in the middle', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], ['-', 'old'], ['+', 'new'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7']], 2], ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5']), ('change at the very start', [[['-', 'first'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4']], 3], ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2']), ('pure insertion into an empty file', [[['+', 'x0'], ['+', 'x1'], ['+', 'x2'], ['+', 'x3'], ['+', 'x4']], 3], ['@@ -0,0 +1,5 @@', '+x0', '+x1', '+x2', '+x3', '+x4']), ('pure deletion of every line', [[['-', 'gone']], 1], ['@@ -1 +0,0 @@', '-gone']), ('two changes separated by exactly twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7'], [' ', 'c8'], [' ', 'c9'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 5], ['@@ -1,14 +1,14 @@', '-a', ' c0', ' c1', ' c2', ' c3', ' c4', ' c5', ' c6', ' c7', ' c8', ' c9', '+b', ' c0', ' c1', ' c2']), ('two changes separated by more than twice the context', [[['-', 'a'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5'], [' ', 'c6'], [' ', 'c7'], [' ', 'c8'], [' ', 'c9'], [' ', 'c10'], ['+', 'b'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 5], ['@@ -1,6 +1,5 @@', '-a', ' c0', ' c1', ' c2', ' c3', ' c4', '@@ -8,8 +7,9 @@', ' c6', ' c7', ' c8', ' c9', ' c10', '+b', ' c0', ' c1', ' c2']), ('insertion after existing lines', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], ['+', 'tail']], 2], ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail']), ('single-line ranges', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], ['-', 'x'], ['+', 'y'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2']], 0], ['@@ -4 +4 @@', '-x', '+y']), ('no changes', [[[' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3']], 3], []), ('deletion and insertion in separate hunks', [[[' ', 'a'], ['-', 'b'], [' ', 'c'], ['+', 'd'], [' ', 'e']], 0], ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d']), ('deletion near the start with wide context', [[[' ', 'c0'], ['-', 'd1'], ['-', 'd2'], [' ', 'c0'], [' ', 'c1'], [' ', 'c2'], [' ', 'c3'], [' ', 'c4'], [' ', 'c5']], 3], ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'])],
}[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 |
|---|---|---|---|
| single change in the middle | ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5'] | ['@@ -3,5 +3,5 @@', ' c2', ' c3', '-old', '+new', ' c4', ' c5'] | Passed |
| change at the very start | ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2'] | ['@@ -1,4 +1,3 @@', '-first', ' c0', ' c1', ' c2'] | Passed |
| pure insertion into an empty file | ['@@ -0,0 +1 @@', '+x0'] | ['@@ -0,0 +1 @@', '+x0'] | Passed |
| pure deletion of every line | ['@@ -1 +0,0 @@', '-gone'] | ['@@ -1 +0,0 @@', '-gone'] | Passed |
| two changes separated by exactly twice the context | ['@@ -1,4 +1,4 @@', '-a', ' c0', ' c1', '+b', ' c0'] | ['@@ -1,4 +1,4 @@', '-a', ' c0', ' c1', '+b', ' c0'] | Passed |
| two changes separated by more than twice the context | ['@@ -1,2 +1 @@', '-a', ' c0', '@@ -4,2 +3,3 @@', ' c2', '+b', ' c0'] | ['@@ -1,2 +1 @@', '-a', ' c0', '@@ -4,2 +3,3 @@', ' c2', '+b', ' c0'] | Passed |
| insertion after existing lines | ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail'] | ['@@ -4,2 +4,3 @@', ' c3', ' c4', '+tail'] | Passed |
| single-line ranges | ['@@ -4 +4 @@', '-x', '+y'] | ['@@ -4 +4 @@', '-x', '+y'] | Passed |
| no changes | [] | [] | Passed |
| deletion and insertion in separate hunks | ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d'] | ['@@ -2 +1,0 @@', '-b', '@@ -3,0 +3 @@', '+d'] | Passed |
| deletion near the start with wide context | ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'] | ['@@ -1,6 +1,4 @@', ' c0', '-d1', '-d2', ' c0', ' c1', ' c2'] | Passed |
SHA-256 / b5f1348407f6694091c078ea031a065d5743fe8fd44b61e3b6df6bc0ac17aba8
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:06.010343+00:00.
Case digest / 47b01f114cf478622a4745181baa0ba17b9f490200daac2309fc71e7dcb0da24