broken_source:
"""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 adds + dels:
            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)

source:
"""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 sorted(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)

prompt:
The reversed hunk shows new lines before old lines inside each change.

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.

split: open-access


broken_source:
"""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 False:
            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)

meaning: Fixture-count band, not measured model difficulty

deps: stdlib

source:
"""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:
            pass
        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)

prompt:
After reordering, the missing-newline marker follows the wrong line or starts a block.

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.

split: open-access


broken_source:
"""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 @@' % (fmt(c, cn), fmt(a, an))]
    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)

source:
"""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.strip())]
    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)

prompt:
Reversed hunks lose the section heading shown after the @@ markers.

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.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(ann, ops, commit, ignore_ws):
    res = []
    i = 0
    k = 0
    while k < len(ops):
        tag = ops[k][0]
        if tag == ' ':
            res.append(ann[i])
            i += 1
            k += 1
            continue
        dels = []
        while k < len(ops) and ops[k][0] == '-':
            dels.append((ann[i], ops[k][1]))
            k += 1
        adds = []
        while k < len(ops) and ops[k][0] == '+':
            adds.append(ops[k][1])
            k += 1
        for idx, text in enumerate(adds):
            if ignore_ws and idx < len(dels) and ''.join(dels[idx][1].split()) == ''.join(text.split()):
                res.append(dels[idx][0])
            else:
                res.append(commit)
    return res
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
    1: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N1', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    2: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N2', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    3: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N3', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    4: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N4', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    5: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N5', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
}[N]
for label, args, expected in cases:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(ann, ops, commit, ignore_ws):
    res = []
    i = 0
    k = 0
    while k < len(ops):
        tag = ops[k][0]
        if tag == ' ':
            res.append(ann[i])
            i += 1
            k += 1
            continue
        dels = []
        while k < len(ops) and ops[k][0] == '-':
            dels.append((ann[i], ops[k][1]))
            k += 1
        i += 1 if dels else 0
        adds = []
        while k < len(ops) and ops[k][0] == '+':
            adds.append(ops[k][1])
            k += 1
        for idx, text in enumerate(adds):
            if ignore_ws and idx < len(dels) and ''.join(dels[idx][1].split()) == ''.join(text.split()):
                res.append(dels[idx][0])
            else:
                res.append(commit)
    return res
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
    1: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N1', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    2: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N2', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    3: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N3', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    4: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N4', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    5: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N5', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
}[N]
for label, args, expected in cases:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Lines after a deletion are credited to the commits of the deleted lines.

Given the old file's per-line commit annotations and an edit script, produce annotations for the new file: context lines keep their old annotation, added lines get the new commit. With ignore_ws, within a run of removed lines followed by added lines, the i-th added line keeps the i-th removed line's annotation when both are equal after deleting all whitespace.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(ann, ops, commit, ignore_ws):
    res = []
    i = 0
    k = 0
    while k < len(ops):
        tag = ops[k][0]
        if tag == ' ':
            res.append(ann[i])
            i += 1
            k += 1
            continue
        dels = []
        while k < len(ops) and ops[k][0] == '-':
            dels.append((ann[i], ops[k][1]))
            i += 1
            k += 1
        adds = []
        while k < len(ops) and ops[k][0] == '+':
            adds.append(ops[k][1])
            k += 1
        for idx, text in enumerate(adds):
            if idx < len(dels) and ''.join(dels[idx][1].split()) == ''.join(text.split()):
                res.append(dels[idx][0])
            else:
                res.append(commit)
    return res
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
    1: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N1', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    2: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N2', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    3: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N3', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    4: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N4', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    5: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N5', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
}[N]
for label, args, expected in cases:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(ann, ops, commit, ignore_ws):
    res = []
    i = 0
    k = 0
    while k < len(ops):
        tag = ops[k][0]
        if tag == ' ':
            res.append(ann[i])
            i += 1
            k += 1
            continue
        dels = []
        while k < len(ops) and ops[k][0] == '-':
            dels.append((ann[i], ops[k][1]))
            i += 1
            k += 1
        adds = []
        while k < len(ops) and ops[k][0] == '+':
            adds.append(ops[k][1])
            k += 1
        for idx, text in enumerate(adds):
            if ignore_ws and idx < len(dels) and dels[idx][1].strip() == text.strip():
                res.append(dels[idx][0])
            else:
                res.append(commit)
    return res
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
    1: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N1', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    2: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N2', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    3: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N3', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    4: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N4', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    5: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N5', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
}[N]
for label, args, expected in cases:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Plain blame hides reformatting commits.

Given the old file's per-line commit annotations and an edit script, produce annotations for the new file: context lines keep their old annotation, added lines get the new commit. With ignore_ws, within a run of removed lines followed by added lines, the i-th added line keeps the i-th removed line's annotation when both are equal after deleting all whitespace.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(ann, ops, commit, ignore_ws):
    res = []
    i = 0
    k = 0
    while k < len(ops):
        tag = ops[k][0]
        if tag == ' ':
            res.append(ann[i])
            i += 1
            k += 1
            continue
        dels = []
        while k < len(ops) and ops[k][0] == '-':
            dels.append((ann[i], ops[k][1]))
            i += 1
            k += 1
        adds = []
        while k < len(ops) and ops[k][0] == '+':
            adds.append(ops[k][1])
            k += 1
        for idx, text in enumerate(adds):
            if ignore_ws and idx < len(dels) and ''.join(dels[0][1].split()) == ''.join(text.split()):
                res.append(dels[0][0])
            else:
                res.append(commit)
    return res
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
    1: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N1', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    2: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N2', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    3: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N3', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    4: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N4', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    5: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N5', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
}[N]
for label, args, expected in cases:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(ann, ops, commit, ignore_ws):
    res = []
    i = 0
    k = 0
    while k < len(ops):
        tag = ops[k][0]
        if tag == ' ':
            res.append(ann[i])
            i += 1
            k += 1
            continue
        dels = []
        while k < len(ops) and ops[k][0] == '-':
            dels.append((ann[i], ops[k][1]))
            i += 1
            k += 1
        adds = []
        while k < len(ops) and ops[k][0] == '+':
            adds.append(ops[k][1])
            k += 1
        for idx, text in enumerate(adds):
            same = [d for d in dels if ''.join(d[1].split()) == ''.join(text.split())]
            if ignore_ws and same:
                res.append(same[0][0])
            else:
                res.append(commit)
    return res
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
    1: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N1', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    2: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N2', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    3: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N3', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    4: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N4', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
    5: [('context keeps attribution', [['c1', 'c2', 'c3'], [[' ', 'a'], ['-', 'b'], [' ', 'c']], 'N', False], ['c1', 'c3']), ('insertion attributed to the new commit', [['c1', 'c2'], [[' ', 'a'], ['+', 'x'], [' ', 'b']], 'N', False], ['c1', 'N', 'c2']), ('removed lines advance the old cursor', [['c1', 'c2', 'c3', 'c4'], [['-', 'a'], ['-', 'b'], [' ', 'c'], [' ', 'd']], 'N', True], ['c3', 'c4']), ('whitespace-only change keeps blame when ignoring whitespace', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', True], ['c1', 'c2']), ('whitespace-only change is new without the flag', [['c1', 'c2'], [['-', 'f(a,b)'], ['+', 'f(a, b)'], [' ', 'z']], 'N', False], ['N', 'c2']), ('second pair compared positionally', [['c1', 'c2', 'c3'], [['-', 'x = 1'], ['-', 'y = 2'], ['+', 'x=1'], ['+', 'y =  2'], [' ', 'k']], 'N5', True], ['c1', 'c2', 'c3']), ('extra additions are new', [['c1', 'c2'], [['-', 'p'], ['+', 'p '], ['+', 'p'], [' ', 'q']], 'N', True], ['c1', 'N', 'c2']), ('real change within a whitespace block', [['c1', 'c2', 'c3'], [['-', 'u'], ['-', 'v'], ['+', 'u'], ['+', 'w'], [' ', 't']], 'N', True], ['c1', 'N', 'c3'])],
}[N]
for label, args, expected in cases:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
The second and later reformatted lines are credited to the reformatting commit, and duplicates inherit the wrong commit.

Given the old file's per-line commit annotations and an edit script, produce annotations for the new file: context lines keep their old annotation, added lines get the new commit. With ignore_ws, within a run of removed lines followed by added lines, the i-th added line keeps the i-th removed line's annotation when both are equal after deleting all whitespace.

split: open-access