FA-75706 / Text diff and three-way merge / Open access
Patch reversal: an omitted count becomes an explicit zero · case 01
Reversing a single-line hunk produces a header claiming an empty range.
ROOT CAUSE
The formatter substitutes 0 for an omitted count, which by convention means 1.
VERIFIED REPAIR
Keep an omitted count omitted.
Unsuccessful approach: Writing an explicit ",1" is equivalent in meaning but no longer preserves the header form.
Case contract
Reverse one unified hunk: swap the old and new ranges in the header, keeping each range's count omitted if it was omitted and keeping any trailing header text; swap "-" and "+" on body lines; within each run of changed lines emit the (new) removed lines before the (new) added lines; a "\" marker line stays attached to the line it follows.
Why this case matters
Reverting a change applies the reversed patch, which must still be a valid, conventionally ordered hunk.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import re
N = 1
observations = []
def solve(lines):
m = re.match(r'@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$', lines[0])
a, an, c, cn, tail = m.groups()
def fmt(s, cnt):
return s + ',' + (cnt or '0')
out = ['@@ -%s +%s @@%s' % (fmt(c, cn), fmt(a, an), tail)]
units = []
for ln in lines[1:]:
if ln.startswith('\\') and units:
units[-1].append(ln)
else:
units.append([ln])
dels, adds = [], []
def flush():
for u in dels + adds:
out.extend(u)
dels.clear()
adds.clear()
for u in units:
tag = u[0][:1]
if tag == '+':
dels.append(['-' + u[0][1:]] + u[1:])
elif tag == '-':
adds.append(['+' + u[0][1:]] + u[1:])
else:
flush()
out.extend(u)
flush()
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
1: [('replacement block', [['@@ -3,2 +3,2 @@ def f():', ' a', '-b', '+B', ' c']], ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c']), ('omitted counts stay omitted', [['@@ -5 +5 @@', '-x', '+y']], ['@@ -5 +5 @@', '-y', '+x']), ('explicit zero count', [['@@ -0,0 +1,1 @@', '+n0']], ['@@ -1,1 +0,0 @@', '-n0']), ('no-newline marker follows its line', [['@@ -1,2 +1,2 @@', ' k', '-old', '\\ No newline at end of file', '+new', '\\ No newline at end of file']], ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file']), ('several blocks', [['@@ -1,6 +1,5 @@', '-a', ' b', '+c', '+d', ' e', '-f', '-g', '+h', ' i']], ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i']), ('insertion only', [['@@ -2,1 +2,3 @@', ' p', '+q', '+r']], ['@@ -2,3 +2,1 @@', ' p', '-q', '-r']), ('marker after the new side only', [['@@ -4,1 +4,1 @@', '-z', '+z2', '\\ No newline at end of file']], ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z']), ('header without trailing text', [['@@ -7,3 +7,3 @@', ' u', '-v', ' w', '+x0']], ['@@ -7,3 +7,3 @@', ' u', '+v', ' w', '-x0'])],
2: [('replacement block', [['@@ -3,2 +3,2 @@ def f():', ' a', '-b', '+B', ' c']], ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c']), ('omitted counts stay omitted', [['@@ -5 +5 @@', '-x', '+y']], ['@@ -5 +5 @@', '-y', '+x']), ('explicit zero count', [['@@ -0,0 +1,2 @@', '+n0', '+n1']], ['@@ -1,2 +0,0 @@', '-n0', '-n1']), ('no-newline marker follows its line', [['@@ -1,2 +1,2 @@', ' k', '-old', '\\ No newline at end of file', '+new', '\\ No newline at end of file']], ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file']), ('several blocks', [['@@ -1,6 +1,5 @@', '-a', ' b', '+c', '+d', ' e', '-f', '-g', '+h', ' i']], ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i']), ('insertion only', [['@@ -2,1 +2,3 @@', ' p', '+q', '+r']], ['@@ -2,3 +2,1 @@', ' p', '-q', '-r']), ('marker after the new side only', [['@@ -4,1 +4,1 @@', '-z', '+z2', '\\ No newline at end of file']], ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z']), ('header without trailing text', [['@@ -7,3 +7,4 @@', ' u', '-v', ' w', '+x0', '+x1']], ['@@ -7,4 +7,3 @@', ' u', '+v', ' w', '-x0', '-x1'])],
3: [('replacement block', [['@@ -3,2 +3,2 @@ def f():', ' a', '-b', '+B', ' c']], ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c']), ('omitted counts stay omitted', [['@@ -5 +5 @@', '-x', '+y']], ['@@ -5 +5 @@', '-y', '+x']), ('explicit zero count', [['@@ -0,0 +1,3 @@', '+n0', '+n1', '+n2']], ['@@ -1,3 +0,0 @@', '-n0', '-n1', '-n2']), ('no-newline marker follows its line', [['@@ -1,2 +1,2 @@', ' k', '-old', '\\ No newline at end of file', '+new', '\\ No newline at end of file']], ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file']), ('several blocks', [['@@ -1,6 +1,5 @@', '-a', ' b', '+c', '+d', ' e', '-f', '-g', '+h', ' i']], ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i']), ('insertion only', [['@@ -2,1 +2,3 @@', ' p', '+q', '+r']], ['@@ -2,3 +2,1 @@', ' p', '-q', '-r']), ('marker after the new side only', [['@@ -4,1 +4,1 @@', '-z', '+z2', '\\ No newline at end of file']], ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z']), ('header without trailing text', [['@@ -7,3 +7,5 @@', ' u', '-v', ' w', '+x0', '+x1', '+x2']], ['@@ -7,5 +7,3 @@', ' u', '+v', ' w', '-x0', '-x1', '-x2'])],
4: [('replacement block', [['@@ -3,2 +3,2 @@ def f():', ' a', '-b', '+B', ' c']], ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c']), ('omitted counts stay omitted', [['@@ -5 +5 @@', '-x', '+y']], ['@@ -5 +5 @@', '-y', '+x']), ('explicit zero count', [['@@ -0,0 +1,4 @@', '+n0', '+n1', '+n2', '+n3']], ['@@ -1,4 +0,0 @@', '-n0', '-n1', '-n2', '-n3']), ('no-newline marker follows its line', [['@@ -1,2 +1,2 @@', ' k', '-old', '\\ No newline at end of file', '+new', '\\ No newline at end of file']], ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file']), ('several blocks', [['@@ -1,6 +1,5 @@', '-a', ' b', '+c', '+d', ' e', '-f', '-g', '+h', ' i']], ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i']), ('insertion only', [['@@ -2,1 +2,3 @@', ' p', '+q', '+r']], ['@@ -2,3 +2,1 @@', ' p', '-q', '-r']), ('marker after the new side only', [['@@ -4,1 +4,1 @@', '-z', '+z2', '\\ No newline at end of file']], ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z']), ('header without trailing text', [['@@ -7,3 +7,6 @@', ' u', '-v', ' w', '+x0', '+x1', '+x2', '+x3']], ['@@ -7,6 +7,3 @@', ' u', '+v', ' w', '-x0', '-x1', '-x2', '-x3'])],
5: [('replacement block', [['@@ -3,2 +3,2 @@ def f():', ' a', '-b', '+B', ' c']], ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c']), ('omitted counts stay omitted', [['@@ -5 +5 @@', '-x', '+y']], ['@@ -5 +5 @@', '-y', '+x']), ('explicit zero count', [['@@ -0,0 +1,5 @@', '+n0', '+n1', '+n2', '+n3', '+n4']], ['@@ -1,5 +0,0 @@', '-n0', '-n1', '-n2', '-n3', '-n4']), ('no-newline marker follows its line', [['@@ -1,2 +1,2 @@', ' k', '-old', '\\ No newline at end of file', '+new', '\\ No newline at end of file']], ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file']), ('several blocks', [['@@ -1,6 +1,5 @@', '-a', ' b', '+c', '+d', ' e', '-f', '-g', '+h', ' i']], ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i']), ('insertion only', [['@@ -2,1 +2,3 @@', ' p', '+q', '+r']], ['@@ -2,3 +2,1 @@', ' p', '-q', '-r']), ('marker after the new side only', [['@@ -4,1 +4,1 @@', '-z', '+z2', '\\ No newline at end of file']], ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z']), ('header without trailing text', [['@@ -7,3 +7,7 @@', ' u', '-v', ' w', '+x0', '+x1', '+x2', '+x3', '+x4']], ['@@ -7,7 +7,3 @@', ' u', '+v', ' w', '-x0', '-x1', '-x2', '-x3', '-x4'])],
}[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 |
|---|---|---|---|
| replacement block | ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c'] | ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c'] | Passed |
| omitted counts stay omitted | ['@@ -5,0 +5,0 @@', '-y', '+x'] | ['@@ -5 +5 @@', '-y', '+x'] | Failed |
| explicit zero count | ['@@ -1,1 +0,0 @@', '-n0'] | ['@@ -1,1 +0,0 @@', '-n0'] | Passed |
| no-newline marker follows its line | ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file'] | ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file'] | Passed |
| several blocks | ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i'] | ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i'] | Passed |
| insertion only | ['@@ -2,3 +2,1 @@', ' p', '-q', '-r'] | ['@@ -2,3 +2,1 @@', ' p', '-q', '-r'] | Passed |
| marker after the new side only | ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z'] | ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z'] | Passed |
| header without trailing text | ['@@ -7,3 +7,3 @@', ' u', '+v', ' w', '-x0'] | ['@@ -7,3 +7,3 @@', ' u', '+v', ' w', '-x0'] | Passed |
SHA-256 / 698f0abc232abbeba54229c490993b0eb1c46e6e9ef11ce3ea3582fe371e4ca1
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import re
N = 1
observations = []
def solve(lines):
m = re.match(r'@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$', lines[0])
a, an, c, cn, tail = m.groups()
def fmt(s, cnt):
return s + ',' + (cnt or '1')
out = ['@@ -%s +%s @@%s' % (fmt(c, cn), fmt(a, an), tail)]
units = []
for ln in lines[1:]:
if ln.startswith('\\') and units:
units[-1].append(ln)
else:
units.append([ln])
dels, adds = [], []
def flush():
for u in dels + adds:
out.extend(u)
dels.clear()
adds.clear()
for u in units:
tag = u[0][:1]
if tag == '+':
dels.append(['-' + u[0][1:]] + u[1:])
elif tag == '-':
adds.append(['+' + u[0][1:]] + u[1:])
else:
flush()
out.extend(u)
flush()
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
1: [('replacement block', [['@@ -3,2 +3,2 @@ def f():', ' a', '-b', '+B', ' c']], ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c']), ('omitted counts stay omitted', [['@@ -5 +5 @@', '-x', '+y']], ['@@ -5 +5 @@', '-y', '+x']), ('explicit zero count', [['@@ -0,0 +1,1 @@', '+n0']], ['@@ -1,1 +0,0 @@', '-n0']), ('no-newline marker follows its line', [['@@ -1,2 +1,2 @@', ' k', '-old', '\\ No newline at end of file', '+new', '\\ No newline at end of file']], ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file']), ('several blocks', [['@@ -1,6 +1,5 @@', '-a', ' b', '+c', '+d', ' e', '-f', '-g', '+h', ' i']], ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i']), ('insertion only', [['@@ -2,1 +2,3 @@', ' p', '+q', '+r']], ['@@ -2,3 +2,1 @@', ' p', '-q', '-r']), ('marker after the new side only', [['@@ -4,1 +4,1 @@', '-z', '+z2', '\\ No newline at end of file']], ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z']), ('header without trailing text', [['@@ -7,3 +7,3 @@', ' u', '-v', ' w', '+x0']], ['@@ -7,3 +7,3 @@', ' u', '+v', ' w', '-x0'])],
2: [('replacement block', [['@@ -3,2 +3,2 @@ def f():', ' a', '-b', '+B', ' c']], ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c']), ('omitted counts stay omitted', [['@@ -5 +5 @@', '-x', '+y']], ['@@ -5 +5 @@', '-y', '+x']), ('explicit zero count', [['@@ -0,0 +1,2 @@', '+n0', '+n1']], ['@@ -1,2 +0,0 @@', '-n0', '-n1']), ('no-newline marker follows its line', [['@@ -1,2 +1,2 @@', ' k', '-old', '\\ No newline at end of file', '+new', '\\ No newline at end of file']], ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file']), ('several blocks', [['@@ -1,6 +1,5 @@', '-a', ' b', '+c', '+d', ' e', '-f', '-g', '+h', ' i']], ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i']), ('insertion only', [['@@ -2,1 +2,3 @@', ' p', '+q', '+r']], ['@@ -2,3 +2,1 @@', ' p', '-q', '-r']), ('marker after the new side only', [['@@ -4,1 +4,1 @@', '-z', '+z2', '\\ No newline at end of file']], ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z']), ('header without trailing text', [['@@ -7,3 +7,4 @@', ' u', '-v', ' w', '+x0', '+x1']], ['@@ -7,4 +7,3 @@', ' u', '+v', ' w', '-x0', '-x1'])],
3: [('replacement block', [['@@ -3,2 +3,2 @@ def f():', ' a', '-b', '+B', ' c']], ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c']), ('omitted counts stay omitted', [['@@ -5 +5 @@', '-x', '+y']], ['@@ -5 +5 @@', '-y', '+x']), ('explicit zero count', [['@@ -0,0 +1,3 @@', '+n0', '+n1', '+n2']], ['@@ -1,3 +0,0 @@', '-n0', '-n1', '-n2']), ('no-newline marker follows its line', [['@@ -1,2 +1,2 @@', ' k', '-old', '\\ No newline at end of file', '+new', '\\ No newline at end of file']], ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file']), ('several blocks', [['@@ -1,6 +1,5 @@', '-a', ' b', '+c', '+d', ' e', '-f', '-g', '+h', ' i']], ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i']), ('insertion only', [['@@ -2,1 +2,3 @@', ' p', '+q', '+r']], ['@@ -2,3 +2,1 @@', ' p', '-q', '-r']), ('marker after the new side only', [['@@ -4,1 +4,1 @@', '-z', '+z2', '\\ No newline at end of file']], ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z']), ('header without trailing text', [['@@ -7,3 +7,5 @@', ' u', '-v', ' w', '+x0', '+x1', '+x2']], ['@@ -7,5 +7,3 @@', ' u', '+v', ' w', '-x0', '-x1', '-x2'])],
4: [('replacement block', [['@@ -3,2 +3,2 @@ def f():', ' a', '-b', '+B', ' c']], ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c']), ('omitted counts stay omitted', [['@@ -5 +5 @@', '-x', '+y']], ['@@ -5 +5 @@', '-y', '+x']), ('explicit zero count', [['@@ -0,0 +1,4 @@', '+n0', '+n1', '+n2', '+n3']], ['@@ -1,4 +0,0 @@', '-n0', '-n1', '-n2', '-n3']), ('no-newline marker follows its line', [['@@ -1,2 +1,2 @@', ' k', '-old', '\\ No newline at end of file', '+new', '\\ No newline at end of file']], ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file']), ('several blocks', [['@@ -1,6 +1,5 @@', '-a', ' b', '+c', '+d', ' e', '-f', '-g', '+h', ' i']], ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i']), ('insertion only', [['@@ -2,1 +2,3 @@', ' p', '+q', '+r']], ['@@ -2,3 +2,1 @@', ' p', '-q', '-r']), ('marker after the new side only', [['@@ -4,1 +4,1 @@', '-z', '+z2', '\\ No newline at end of file']], ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z']), ('header without trailing text', [['@@ -7,3 +7,6 @@', ' u', '-v', ' w', '+x0', '+x1', '+x2', '+x3']], ['@@ -7,6 +7,3 @@', ' u', '+v', ' w', '-x0', '-x1', '-x2', '-x3'])],
5: [('replacement block', [['@@ -3,2 +3,2 @@ def f():', ' a', '-b', '+B', ' c']], ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c']), ('omitted counts stay omitted', [['@@ -5 +5 @@', '-x', '+y']], ['@@ -5 +5 @@', '-y', '+x']), ('explicit zero count', [['@@ -0,0 +1,5 @@', '+n0', '+n1', '+n2', '+n3', '+n4']], ['@@ -1,5 +0,0 @@', '-n0', '-n1', '-n2', '-n3', '-n4']), ('no-newline marker follows its line', [['@@ -1,2 +1,2 @@', ' k', '-old', '\\ No newline at end of file', '+new', '\\ No newline at end of file']], ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file']), ('several blocks', [['@@ -1,6 +1,5 @@', '-a', ' b', '+c', '+d', ' e', '-f', '-g', '+h', ' i']], ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i']), ('insertion only', [['@@ -2,1 +2,3 @@', ' p', '+q', '+r']], ['@@ -2,3 +2,1 @@', ' p', '-q', '-r']), ('marker after the new side only', [['@@ -4,1 +4,1 @@', '-z', '+z2', '\\ No newline at end of file']], ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z']), ('header without trailing text', [['@@ -7,3 +7,7 @@', ' u', '-v', ' w', '+x0', '+x1', '+x2', '+x3', '+x4']], ['@@ -7,7 +7,3 @@', ' u', '+v', ' w', '-x0', '-x1', '-x2', '-x3', '-x4'])],
}[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 |
|---|---|---|---|
| replacement block | ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c'] | ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c'] | Passed |
| omitted counts stay omitted | ['@@ -5,1 +5,1 @@', '-y', '+x'] | ['@@ -5 +5 @@', '-y', '+x'] | Failed |
| explicit zero count | ['@@ -1,1 +0,0 @@', '-n0'] | ['@@ -1,1 +0,0 @@', '-n0'] | Passed |
| no-newline marker follows its line | ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file'] | ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file'] | Passed |
| several blocks | ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i'] | ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i'] | Passed |
| insertion only | ['@@ -2,3 +2,1 @@', ' p', '-q', '-r'] | ['@@ -2,3 +2,1 @@', ' p', '-q', '-r'] | Passed |
| marker after the new side only | ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z'] | ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z'] | Passed |
| header without trailing text | ['@@ -7,3 +7,3 @@', ' u', '+v', ' w', '-x0'] | ['@@ -7,3 +7,3 @@', ' u', '+v', ' w', '-x0'] | Passed |
SHA-256 / 81e159b3cc650643f7e4a35ee934098048b658a96314364955729e8bf14ee9b5
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import re
N = 1
observations = []
def solve(lines):
m = re.match(r'@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$', lines[0])
a, an, c, cn, tail = m.groups()
def fmt(s, cnt):
return s if cnt is None else s + ',' + cnt
out = ['@@ -%s +%s @@%s' % (fmt(c, cn), fmt(a, an), tail)]
units = []
for ln in lines[1:]:
if ln.startswith('\\') and units:
units[-1].append(ln)
else:
units.append([ln])
dels, adds = [], []
def flush():
for u in dels + adds:
out.extend(u)
dels.clear()
adds.clear()
for u in units:
tag = u[0][:1]
if tag == '+':
dels.append(['-' + u[0][1:]] + u[1:])
elif tag == '-':
adds.append(['+' + u[0][1:]] + u[1:])
else:
flush()
out.extend(u)
flush()
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
1: [('replacement block', [['@@ -3,2 +3,2 @@ def f():', ' a', '-b', '+B', ' c']], ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c']), ('omitted counts stay omitted', [['@@ -5 +5 @@', '-x', '+y']], ['@@ -5 +5 @@', '-y', '+x']), ('explicit zero count', [['@@ -0,0 +1,1 @@', '+n0']], ['@@ -1,1 +0,0 @@', '-n0']), ('no-newline marker follows its line', [['@@ -1,2 +1,2 @@', ' k', '-old', '\\ No newline at end of file', '+new', '\\ No newline at end of file']], ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file']), ('several blocks', [['@@ -1,6 +1,5 @@', '-a', ' b', '+c', '+d', ' e', '-f', '-g', '+h', ' i']], ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i']), ('insertion only', [['@@ -2,1 +2,3 @@', ' p', '+q', '+r']], ['@@ -2,3 +2,1 @@', ' p', '-q', '-r']), ('marker after the new side only', [['@@ -4,1 +4,1 @@', '-z', '+z2', '\\ No newline at end of file']], ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z']), ('header without trailing text', [['@@ -7,3 +7,3 @@', ' u', '-v', ' w', '+x0']], ['@@ -7,3 +7,3 @@', ' u', '+v', ' w', '-x0'])],
2: [('replacement block', [['@@ -3,2 +3,2 @@ def f():', ' a', '-b', '+B', ' c']], ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c']), ('omitted counts stay omitted', [['@@ -5 +5 @@', '-x', '+y']], ['@@ -5 +5 @@', '-y', '+x']), ('explicit zero count', [['@@ -0,0 +1,2 @@', '+n0', '+n1']], ['@@ -1,2 +0,0 @@', '-n0', '-n1']), ('no-newline marker follows its line', [['@@ -1,2 +1,2 @@', ' k', '-old', '\\ No newline at end of file', '+new', '\\ No newline at end of file']], ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file']), ('several blocks', [['@@ -1,6 +1,5 @@', '-a', ' b', '+c', '+d', ' e', '-f', '-g', '+h', ' i']], ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i']), ('insertion only', [['@@ -2,1 +2,3 @@', ' p', '+q', '+r']], ['@@ -2,3 +2,1 @@', ' p', '-q', '-r']), ('marker after the new side only', [['@@ -4,1 +4,1 @@', '-z', '+z2', '\\ No newline at end of file']], ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z']), ('header without trailing text', [['@@ -7,3 +7,4 @@', ' u', '-v', ' w', '+x0', '+x1']], ['@@ -7,4 +7,3 @@', ' u', '+v', ' w', '-x0', '-x1'])],
3: [('replacement block', [['@@ -3,2 +3,2 @@ def f():', ' a', '-b', '+B', ' c']], ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c']), ('omitted counts stay omitted', [['@@ -5 +5 @@', '-x', '+y']], ['@@ -5 +5 @@', '-y', '+x']), ('explicit zero count', [['@@ -0,0 +1,3 @@', '+n0', '+n1', '+n2']], ['@@ -1,3 +0,0 @@', '-n0', '-n1', '-n2']), ('no-newline marker follows its line', [['@@ -1,2 +1,2 @@', ' k', '-old', '\\ No newline at end of file', '+new', '\\ No newline at end of file']], ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file']), ('several blocks', [['@@ -1,6 +1,5 @@', '-a', ' b', '+c', '+d', ' e', '-f', '-g', '+h', ' i']], ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i']), ('insertion only', [['@@ -2,1 +2,3 @@', ' p', '+q', '+r']], ['@@ -2,3 +2,1 @@', ' p', '-q', '-r']), ('marker after the new side only', [['@@ -4,1 +4,1 @@', '-z', '+z2', '\\ No newline at end of file']], ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z']), ('header without trailing text', [['@@ -7,3 +7,5 @@', ' u', '-v', ' w', '+x0', '+x1', '+x2']], ['@@ -7,5 +7,3 @@', ' u', '+v', ' w', '-x0', '-x1', '-x2'])],
4: [('replacement block', [['@@ -3,2 +3,2 @@ def f():', ' a', '-b', '+B', ' c']], ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c']), ('omitted counts stay omitted', [['@@ -5 +5 @@', '-x', '+y']], ['@@ -5 +5 @@', '-y', '+x']), ('explicit zero count', [['@@ -0,0 +1,4 @@', '+n0', '+n1', '+n2', '+n3']], ['@@ -1,4 +0,0 @@', '-n0', '-n1', '-n2', '-n3']), ('no-newline marker follows its line', [['@@ -1,2 +1,2 @@', ' k', '-old', '\\ No newline at end of file', '+new', '\\ No newline at end of file']], ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file']), ('several blocks', [['@@ -1,6 +1,5 @@', '-a', ' b', '+c', '+d', ' e', '-f', '-g', '+h', ' i']], ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i']), ('insertion only', [['@@ -2,1 +2,3 @@', ' p', '+q', '+r']], ['@@ -2,3 +2,1 @@', ' p', '-q', '-r']), ('marker after the new side only', [['@@ -4,1 +4,1 @@', '-z', '+z2', '\\ No newline at end of file']], ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z']), ('header without trailing text', [['@@ -7,3 +7,6 @@', ' u', '-v', ' w', '+x0', '+x1', '+x2', '+x3']], ['@@ -7,6 +7,3 @@', ' u', '+v', ' w', '-x0', '-x1', '-x2', '-x3'])],
5: [('replacement block', [['@@ -3,2 +3,2 @@ def f():', ' a', '-b', '+B', ' c']], ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c']), ('omitted counts stay omitted', [['@@ -5 +5 @@', '-x', '+y']], ['@@ -5 +5 @@', '-y', '+x']), ('explicit zero count', [['@@ -0,0 +1,5 @@', '+n0', '+n1', '+n2', '+n3', '+n4']], ['@@ -1,5 +0,0 @@', '-n0', '-n1', '-n2', '-n3', '-n4']), ('no-newline marker follows its line', [['@@ -1,2 +1,2 @@', ' k', '-old', '\\ No newline at end of file', '+new', '\\ No newline at end of file']], ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file']), ('several blocks', [['@@ -1,6 +1,5 @@', '-a', ' b', '+c', '+d', ' e', '-f', '-g', '+h', ' i']], ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i']), ('insertion only', [['@@ -2,1 +2,3 @@', ' p', '+q', '+r']], ['@@ -2,3 +2,1 @@', ' p', '-q', '-r']), ('marker after the new side only', [['@@ -4,1 +4,1 @@', '-z', '+z2', '\\ No newline at end of file']], ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z']), ('header without trailing text', [['@@ -7,3 +7,7 @@', ' u', '-v', ' w', '+x0', '+x1', '+x2', '+x3', '+x4']], ['@@ -7,7 +7,3 @@', ' u', '+v', ' w', '-x0', '-x1', '-x2', '-x3', '-x4'])],
}[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 |
|---|---|---|---|
| replacement block | ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c'] | ['@@ -3,2 +3,2 @@ def f():', ' a', '-B', '+b', ' c'] | Passed |
| omitted counts stay omitted | ['@@ -5 +5 @@', '-y', '+x'] | ['@@ -5 +5 @@', '-y', '+x'] | Passed |
| explicit zero count | ['@@ -1,1 +0,0 @@', '-n0'] | ['@@ -1,1 +0,0 @@', '-n0'] | Passed |
| no-newline marker follows its line | ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file'] | ['@@ -1,2 +1,2 @@', ' k', '-new', '\\ No newline at end of file', '+old', '\\ No newline at end of file'] | Passed |
| several blocks | ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i'] | ['@@ -1,5 +1,6 @@', '+a', ' b', '-c', '-d', ' e', '-h', '+f', '+g', ' i'] | Passed |
| insertion only | ['@@ -2,3 +2,1 @@', ' p', '-q', '-r'] | ['@@ -2,3 +2,1 @@', ' p', '-q', '-r'] | Passed |
| marker after the new side only | ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z'] | ['@@ -4,1 +4,1 @@', '-z2', '\\ No newline at end of file', '+z'] | Passed |
| header without trailing text | ['@@ -7,3 +7,3 @@', ' u', '+v', ' w', '-x0'] | ['@@ -7,3 +7,3 @@', ' u', '+v', ' w', '-x0'] | Passed |
SHA-256 / 60005a6c39c3bb955d488ae11ca4bc7ac154f68e83ecf2270785580f27d1e4a7
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.482394+00:00.
Case digest / cf220c40becf1677aee213423811dc3621f30e8c4913111bcdddfe4a53f02bff