FAILURE MAP
← Case archive

FA-75386 / Text diff and three-way merge / Open access

Unified hunk builder: hunks whose contexts touch are split · case 01

Two nearby changes produce two hunks that repeat the same context lines.

Verified by executionVariant 1 · 11 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

Changes are grouped only when the gap is at most one context width.

VERIFIED REPAIR

Group changes when the equal lines between them number at most twice the context width.

Unsuccessful approach: A strict comparison still splits changes separated by exactly twice the context.

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 <= 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 fixtureActualExpectedOutcome
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,2 +1 @@', '-a', ' c0', '@@ -3,2 +2,3 @@', ' c1', '+b', ' c0']['@@ -1,4 +1,4 @@', '-a', ' c0', ' c1', '+b', ' c0']Failed
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 / 51c36dcff43019bbb6658650f59bd2fed5b36ecf92fd361718138fa98642da9f

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 + 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 fixtureActualExpectedOutcome
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,2 +1 @@', '-a', ' c0', '@@ -3,2 +2,3 @@', ' c1', '+b', ' c0']['@@ -1,4 +1,4 @@', '-a', ' c0', ' c1', '+b', ' c0']Failed
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 +3,0 @@', '-x', '@@ -4,0 +4 @@', '+y']['@@ -4 +4 @@', '-x', '+y']Failed
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 / 921f9ee1c92c55aa222ea02264cc23a59593c784c609e6b2f06687e56fea16c6

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 fixtureActualExpectedOutcome
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:05.973430+00:00.

Case digest / 11f0e5c6f3c08b04c71348ea9ab22d2744644f04b06170359d746f577317ce89