FAILURE MAP
← Case archive

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

Patch application with offset search: a rejected hunk still shifts later hunks · case 01

After one hunk fails, the following hunks are searched at displaced positions.

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

ROOT CAUSE

The size change of a rejected hunk is added to the shift even though nothing was applied.

VERIFIED REPAIR

Leave the shift untouched when a hunk is rejected.

Unsuccessful approach: Resetting the shift to zero discards the offsets of hunks that did apply.

Case contract

Hunks [old_start, old_lines, new_lines] are applied in order. The expected index is old_start-1 plus the accumulated shift. The search tries distance 0, then 1, 2, ... up to max_offset, at each distance the earlier position before the later one; the first position where old_lines match replaces them with new_lines. After an applied hunk the shift grows by (found-expected) + len(new)-len(old); a hunk that does not match is rejected and changes nothing. Return lines, 1-based applied positions and rejected hunk indices.

Why this case matters

Patch tools tolerate drift by searching near the expected line and carrying the discovered offset to later hunks.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(target, hunks, max_offset):
    lines = list(target)
    delta = 0
    applied, rejected = [], []
    for h_i, (old_start, old, new) in enumerate(hunks):
        expect = old_start - 1 + delta
        found = None
        for dist in range(0, max_offset + 1):
            for pos in ((expect - dist, expect + dist) if dist else (expect,)):
                if 0 <= pos and pos + len(old) <= len(lines) and lines[pos:pos + len(old)] == old:
                    found = pos
                    break
            if found is not None:
                break
        if found is None:
            rejected.append(h_i)
            delta += len(new) - len(old)
            continue
        lines[found:found + len(old)] = new
        applied.append(found + 1)
        delta += (found - expect) + len(new) - len(old)
    return {'lines': lines, 'applied': applied, 'rejected': rejected}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
    1: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 2], {'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 0], {'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 1], {'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [3, 11], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L81']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
    2: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 3], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 1], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 2], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [4, 12], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L82']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L82', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
    3: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [6], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 2], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 3], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L83']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L83', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
    4: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 5], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [7], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 3], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [6, 14], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L84']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L84', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
    5: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 6], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [8], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 5], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [7, 15], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L85']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L85', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
}[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
clean apply at the expected line{'applied': [3], 'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}{'applied': [3], 'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}Passed
offset because lines were added above{'applied': [4], 'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}{'applied': [4], 'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}Passed
offset beyond the limit is rejected{'applied': [], 'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]}{'applied': [], 'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]}Passed
second hunk follows the first hunk's offset{'applied': [3, 11], 'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'rejected': []}{'applied': [3, 11], 'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'rejected': []}Passed
equal distances prefer the earlier match{'applied': [2], 'lines': ['a', 'K', 'b', 'k', 'c'], 'rejected': []}{'applied': [2], 'lines': ['a', 'K', 'b', 'k', 'c'], 'rejected': []}Passed
rejected hunk does not shift later hunks{'applied': [], 'lines': ['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0, 1]}{'applied': [5], 'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]}Failed
rejected hunk keeps earlier shifts{'applied': [1, 7], 'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [1]}{'applied': [1, 7], 'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [1]}Passed
carried offset keeps a far hunk in range{'applied': [5, 13], 'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}{'applied': [5, 13], 'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}Passed
two hunks with size changes{'applied': [1, 5, 11], 'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'rejected': []}{'applied': [1, 5, 11], 'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'rejected': []}Passed
only a later occurrence matches{'applied': [2], 'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'rejected': [0]}{'applied': [2], 'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'rejected': [0]}Passed
match exactly at the offset limit{'applied': [4], 'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}{'applied': [4], 'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}Passed

SHA-256 / 81c303a2c7ec59afe6510a80b6bcb5ee4aa210257b2a04b47dbbce136072508b

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(target, hunks, max_offset):
    lines = list(target)
    delta = 0
    applied, rejected = [], []
    for h_i, (old_start, old, new) in enumerate(hunks):
        expect = old_start - 1 + delta
        found = None
        for dist in range(0, max_offset + 1):
            for pos in ((expect - dist, expect + dist) if dist else (expect,)):
                if 0 <= pos and pos + len(old) <= len(lines) and lines[pos:pos + len(old)] == old:
                    found = pos
                    break
            if found is not None:
                break
        if found is None:
            rejected.append(h_i)
            delta = 0
            continue
        lines[found:found + len(old)] = new
        applied.append(found + 1)
        delta += (found - expect) + len(new) - len(old)
    return {'lines': lines, 'applied': applied, 'rejected': rejected}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
    1: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 2], {'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 0], {'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 1], {'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [3, 11], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L81']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
    2: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 3], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 1], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 2], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [4, 12], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L82']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L82', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
    3: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [6], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 2], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 3], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L83']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L83', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
    4: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 5], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [7], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 3], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [6, 14], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L84']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L84', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
    5: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 6], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [8], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 5], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [7, 15], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L85']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L85', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
}[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
clean apply at the expected line{'applied': [3], 'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}{'applied': [3], 'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}Passed
offset because lines were added above{'applied': [4], 'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}{'applied': [4], 'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}Passed
offset beyond the limit is rejected{'applied': [], 'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]}{'applied': [], 'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]}Passed
second hunk follows the first hunk's offset{'applied': [3, 11], 'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'rejected': []}{'applied': [3, 11], 'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'rejected': []}Passed
equal distances prefer the earlier match{'applied': [2], 'lines': ['a', 'K', 'b', 'k', 'c'], 'rejected': []}{'applied': [2], 'lines': ['a', 'K', 'b', 'k', 'c'], 'rejected': []}Passed
rejected hunk does not shift later hunks{'applied': [5], 'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]}{'applied': [5], 'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]}Passed
rejected hunk keeps earlier shifts{'applied': [1], 'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [1, 2]}{'applied': [1, 7], 'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [1]}Failed
carried offset keeps a far hunk in range{'applied': [5, 13], 'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}{'applied': [5, 13], 'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}Passed
two hunks with size changes{'applied': [1, 5, 11], 'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'rejected': []}{'applied': [1, 5, 11], 'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'rejected': []}Passed
only a later occurrence matches{'applied': [2], 'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'rejected': [0]}{'applied': [2], 'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'rejected': [0]}Passed
match exactly at the offset limit{'applied': [4], 'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}{'applied': [4], 'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}Passed

SHA-256 / 6819e0bc78ade04cc6139914803fcc74692ccb2a2e9b85137585e66d5a88e1fe

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(target, hunks, max_offset):
    lines = list(target)
    delta = 0
    applied, rejected = [], []
    for h_i, (old_start, old, new) in enumerate(hunks):
        expect = old_start - 1 + delta
        found = None
        for dist in range(0, max_offset + 1):
            for pos in ((expect - dist, expect + dist) if dist else (expect,)):
                if 0 <= pos and pos + len(old) <= len(lines) and lines[pos:pos + len(old)] == old:
                    found = pos
                    break
            if found is not None:
                break
        if found is None:
            rejected.append(h_i)
            continue
        lines[found:found + len(old)] = new
        applied.append(found + 1)
        delta += (found - expect) + len(new) - len(old)
    return {'lines': lines, 'applied': applied, 'rejected': rejected}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
    1: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 2], {'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 0], {'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 1], {'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [3, 11], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L81']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
    2: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 3], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 1], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 2], {'lines': ['pre0', 'pre1', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [4, 12], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L82']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L82', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
    3: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [6], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 2], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 3], {'lines': ['pre0', 'pre1', 'pre2', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L83']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L83', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
    4: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 5], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [7], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 3], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [6, 14], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L84']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L84', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
    5: [('clean apply at the expected line', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X', 'l4']]], 3], {'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [3], 'rejected': []}), ('offset because lines were added above', [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 6], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [8], 'rejected': []}), ('offset beyond the limit is rejected', [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[3, ['l3', 'l4'], ['l3', 'X']]], 4], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [], 'rejected': [0]}), ("second hunk follows the first hunk's offset", [['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['l2', 'A', 'B']], [8, ['l8', 'l9'], ['Z']]], 5], {'lines': ['pre0', 'pre1', 'pre2', 'pre3', 'pre4', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'applied': [7, 15], 'rejected': []}), ('equal distances prefer the earlier match', [['a', 'k', 'b', 'k', 'c'], [[3, ['k'], ['K']]], 1], {'lines': ['a', 'K', 'b', 'k', 'c'], 'applied': [2], 'rejected': []}), ('rejected hunk does not shift later hunks', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['nope'], ['x', 'y', 'z']], [5, ['l5'], ['F', 'l5']]], 1], {'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [5], 'rejected': [0]}), ('rejected hunk keeps earlier shifts', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['l1', 'a', 'b']], [3, ['nope'], ['x']], [5, ['l5'], ['F']]], 1], {'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [1, 7], 'rejected': [1]}), ('carried offset keeps a far hunk in range', [['pre', 'pre', 'pre', 'l1', 'l2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[2, ['l2'], ['L2']], [8, ['l8'], ['L85']]], 3], {'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L85', 'l9', 'l10', 'l11', 'l12'], 'applied': [5, 13], 'rejected': []}), ('two hunks with size changes', [['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1', 'l2'], ['l1']], [6, ['l6'], ['l6', 'm', 'm2']], [10, ['l10'], ['T']]], 0], {'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'applied': [1, 5, 11], 'rejected': []}), ('only a later occurrence matches', [['q', 'r', 's', 'x', 'y', 'x', 'y'], [[4, ['x', 'z'], ['w']], [1, ['r'], ['R']]], 2], {'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'applied': [2], 'rejected': [0]}), ('match exactly at the offset limit', [['p', 'p', 'z', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], [[1, ['l1'], ['L1']]], 3], {'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'applied': [4], 'rejected': []})],
}[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
clean apply at the expected line{'applied': [3], 'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}{'applied': [3], 'lines': ['l1', 'l2', 'l3', 'X', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}Passed
offset because lines were added above{'applied': [4], 'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}{'applied': [4], 'lines': ['pre0', 'l1', 'l2', 'l3', 'X', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}Passed
offset beyond the limit is rejected{'applied': [], 'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]}{'applied': [], 'lines': ['pre0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]}Passed
second hunk follows the first hunk's offset{'applied': [3, 11], 'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'rejected': []}{'applied': [3, 11], 'lines': ['pre0', 'l1', 'l2', 'A', 'B', 'l3', 'l4', 'l5', 'l6', 'l7', 'Z', 'l10', 'l11', 'l12'], 'rejected': []}Passed
equal distances prefer the earlier match{'applied': [2], 'lines': ['a', 'K', 'b', 'k', 'c'], 'rejected': []}{'applied': [2], 'lines': ['a', 'K', 'b', 'k', 'c'], 'rejected': []}Passed
rejected hunk does not shift later hunks{'applied': [5], 'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]}{'applied': [5], 'lines': ['l1', 'l2', 'l3', 'l4', 'F', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [0]}Passed
rejected hunk keeps earlier shifts{'applied': [1, 7], 'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [1]}{'applied': [1, 7], 'lines': ['l1', 'a', 'b', 'l2', 'l3', 'l4', 'F', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': [1]}Passed
carried offset keeps a far hunk in range{'applied': [5, 13], 'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}{'applied': [5, 13], 'lines': ['pre', 'pre', 'pre', 'l1', 'L2', 'l3', 'l4', 'l5', 'ins1', 'ins2', 'l6', 'l7', 'L81', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}Passed
two hunks with size changes{'applied': [1, 5, 11], 'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'rejected': []}{'applied': [1, 5, 11], 'lines': ['l1', 'l3', 'l4', 'l5', 'l6', 'm', 'm2', 'l7', 'l8', 'l9', 'T', 'l11', 'l12'], 'rejected': []}Passed
only a later occurrence matches{'applied': [2], 'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'rejected': [0]}{'applied': [2], 'lines': ['q', 'R', 's', 'x', 'y', 'x', 'y'], 'rejected': [0]}Passed
match exactly at the offset limit{'applied': [4], 'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}{'applied': [4], 'lines': ['p', 'p', 'z', 'L1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', 'l9', 'l10', 'l11', 'l12'], 'rejected': []}Passed

SHA-256 / 19a69c28fe03b86f3981723c9ff25c540adb7a3127eb82393dced86942209357

Verification & scope

A deterministic, bounded teaching model of one diff, patch or merge rule with stipulated conventions; it is not a production diff or version-control implementation and makes no claim of conformance to any specific tool. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:49:06.458891+00:00.

Case digest / 5f57f7339292846effd50e40a22ff88fca878384c7e14e744598404cc6f3a006