FAILURE MAP
← Case archive

FA-75171 / CRDT convergence / Open access

Visible index translation: delete targets the character before the cursor index · case 01

Deleting index zero removes the last character; other deletes remove the preceding character.

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

ROOT CAUSE

The delete maps index i to visible element i-1, the insert anchor rule.

VERIFIED REPAIR

A delete at visible index i targets the visible element at i.

Unsuccessful approach: Clamping the shifted index fixes index zero but still deletes the preceding character elsewhere.

Case contract

A sequence CRDT holds [id, char, deleted]. Local edits use visible indices: ["insert", i, ch] (0 <= i <= visible length) references the visible element at i-1 (None at 0), is placed immediately after it, and gets id "L<k>" from a counter advanced only by accepted inserts; ["delete", i] (0 <= i < visible length) tombstones the visible element at i. Out-of-range edits yield ["reject", i]. Return the emitted ops and visible text.

Why this case matters

Editors translate cursor positions into identifier-based CRDT operations; tombstones make that translation error-prone.

1 / The failure

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

N = 1
observations = []
def solve(elements, edits):
    seq = [list(e) for e in elements]
    out = []
    k = 0
    for ed in edits:
        vis = [i for i, e in enumerate(seq) if not e[2]]
        idx = ed[1]
        if ed[0] == 'insert':
            if idx < 0 or idx > len(vis):
                out.append(['reject', idx])
                continue
            if idx == 0:
                after, pos = None, 0
            else:
                p = vis[idx - 1]
                after, pos = seq[p][0], p + 1
            k += 1
            nid = 'L%d' % k
            seq.insert(pos, [nid, ed[2], False])
            out.append(['ins', nid, after])
        else:
            if idx < 0 or idx >= len(vis):
                out.append(['reject', idx])
                continue
            p = vis[idx - 1]
            seq[p][2] = True
            out.append(['del', seq[p][0]])
    return {'ops': out, 'text': ''.join(e[1] for e in seq if not e[2])}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
    1: [('insert after tombstones uses the visible neighbour', [[['e0', 'a', False], ['e1', 'b', True], ['e2', 'c', True], ['e3', 'd', False], ['e4', 'e', False]], [['insert', 2, 'X']]], {'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}), ('insert at the visible end', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', True]], [['insert', 2, 'Z'], ['insert', 3, 'W']]], {'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}), ('insert at the start', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False]], [['insert', 0, 'S']]], {'ops': [['ins', 'L1', None]], 'text': 'Sbc'}), ('delete by visible index', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True], ['e4', 'e', False], ['e5', 'f', False]], [['delete', 0], ['delete', 2]]], {'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}), ('delete last visible character', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True]], [['delete', 2]]], {'ops': [['del', 'e2']], 'text': 'ab'}), ('out-of-range edits are rejected', [[['e0', 'a', False], ['e1', 'b', False]], [['insert', 4, 'q'], ['delete', 2], ['delete', -1], ['insert', -1, 'r'], ['insert', 1, 'k']]], {'ops': [['reject', 4], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}), ('ids stay dense after a rejection', [[['e0', 'x', False], ['e1', 'y', False]], [['insert', 5, 'p'], ['insert', 1, 'm'], ['insert', 0, 'n']]], {'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}), ('typing into an empty document', [[], [['insert', 0, 'h'], ['insert', 1, 'i'], ['insert', 2, '!']]], {'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2']], 'text': 'hi!'}), ('mixed edits', [[['e0', 'h', False], ['e1', 'e', True], ['e2', 'l', False], ['e3', 'l', False], ['e4', 'o', False]], [['delete', 1], ['insert', 1, 'E'], ['insert', 4, '?']]], {'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'})],
    2: [('insert after tombstones uses the visible neighbour', [[['e0', 'a', False], ['e1', 'b', True], ['e2', 'c', True], ['e3', 'd', False], ['e4', 'e', False]], [['insert', 2, 'X']]], {'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}), ('insert at the visible end', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', True]], [['insert', 2, 'Z'], ['insert', 3, 'W']]], {'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}), ('insert at the start', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False]], [['insert', 0, 'S']]], {'ops': [['ins', 'L1', None]], 'text': 'Sbc'}), ('delete by visible index', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True], ['e4', 'e', False], ['e5', 'f', False]], [['delete', 0], ['delete', 2]]], {'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}), ('delete last visible character', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True]], [['delete', 2]]], {'ops': [['del', 'e2']], 'text': 'ab'}), ('out-of-range edits are rejected', [[['e0', 'a', False], ['e1', 'b', False]], [['insert', 5, 'q'], ['delete', 2], ['delete', -1], ['insert', -1, 'r'], ['insert', 1, 'k']]], {'ops': [['reject', 5], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}), ('ids stay dense after a rejection', [[['e0', 'x', False], ['e1', 'y', False]], [['insert', 5, 'p'], ['insert', 1, 'm'], ['insert', 0, 'n']]], {'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}), ('typing into an empty document', [[], [['insert', 0, 'h'], ['insert', 1, 'i'], ['insert', 2, '!'], ['insert', 3, '!']]], {'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2'], ['ins', 'L4', 'L3']], 'text': 'hi!!'}), ('mixed edits', [[['e0', 'h', False], ['e1', 'e', True], ['e2', 'l', False], ['e3', 'l', False], ['e4', 'o', False]], [['delete', 1], ['insert', 1, 'E'], ['insert', 4, '?']]], {'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'})],
    3: [('insert after tombstones uses the visible neighbour', [[['e0', 'a', False], ['e1', 'b', True], ['e2', 'c', True], ['e3', 'd', False], ['e4', 'e', False]], [['insert', 2, 'X']]], {'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}), ('insert at the visible end', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', True]], [['insert', 2, 'Z'], ['insert', 3, 'W']]], {'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}), ('insert at the start', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False]], [['insert', 0, 'S']]], {'ops': [['ins', 'L1', None]], 'text': 'Sbc'}), ('delete by visible index', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True], ['e4', 'e', False], ['e5', 'f', False]], [['delete', 0], ['delete', 2]]], {'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}), ('delete last visible character', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True]], [['delete', 2]]], {'ops': [['del', 'e2']], 'text': 'ab'}), ('out-of-range edits are rejected', [[['e0', 'a', False], ['e1', 'b', False]], [['insert', 6, 'q'], ['delete', 2], ['delete', -1], ['insert', -1, 'r'], ['insert', 1, 'k']]], {'ops': [['reject', 6], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}), ('ids stay dense after a rejection', [[['e0', 'x', False], ['e1', 'y', False]], [['insert', 5, 'p'], ['insert', 1, 'm'], ['insert', 0, 'n']]], {'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}), ('typing into an empty document', [[], [['insert', 0, 'h'], ['insert', 1, 'i'], ['insert', 2, '!'], ['insert', 3, '!'], ['insert', 4, '!']]], {'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2'], ['ins', 'L4', 'L3'], ['ins', 'L5', 'L4']], 'text': 'hi!!!'}), ('mixed edits', [[['e0', 'h', False], ['e1', 'e', True], ['e2', 'l', False], ['e3', 'l', False], ['e4', 'o', False]], [['delete', 1], ['insert', 1, 'E'], ['insert', 4, '?']]], {'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'})],
    4: [('insert after tombstones uses the visible neighbour', [[['e0', 'a', False], ['e1', 'b', True], ['e2', 'c', True], ['e3', 'd', False], ['e4', 'e', False]], [['insert', 2, 'X']]], {'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}), ('insert at the visible end', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', True]], [['insert', 2, 'Z'], ['insert', 3, 'W']]], {'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}), ('insert at the start', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False]], [['insert', 0, 'S']]], {'ops': [['ins', 'L1', None]], 'text': 'Sbc'}), ('delete by visible index', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True], ['e4', 'e', False], ['e5', 'f', False]], [['delete', 0], ['delete', 2]]], {'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}), ('delete last visible character', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True]], [['delete', 2]]], {'ops': [['del', 'e2']], 'text': 'ab'}), ('out-of-range edits are rejected', [[['e0', 'a', False], ['e1', 'b', False]], [['insert', 7, 'q'], ['delete', 2], ['delete', -1], ['insert', -1, 'r'], ['insert', 1, 'k']]], {'ops': [['reject', 7], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}), ('ids stay dense after a rejection', [[['e0', 'x', False], ['e1', 'y', False]], [['insert', 5, 'p'], ['insert', 1, 'm'], ['insert', 0, 'n']]], {'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}), ('typing into an empty document', [[], [['insert', 0, 'h'], ['insert', 1, 'i'], ['insert', 2, '!'], ['insert', 3, '!'], ['insert', 4, '!'], ['insert', 5, '!']]], {'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2'], ['ins', 'L4', 'L3'], ['ins', 'L5', 'L4'], ['ins', 'L6', 'L5']], 'text': 'hi!!!!'}), ('mixed edits', [[['e0', 'h', False], ['e1', 'e', True], ['e2', 'l', False], ['e3', 'l', False], ['e4', 'o', False]], [['delete', 1], ['insert', 1, 'E'], ['insert', 4, '?']]], {'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'})],
    5: [('insert after tombstones uses the visible neighbour', [[['e0', 'a', False], ['e1', 'b', True], ['e2', 'c', True], ['e3', 'd', False], ['e4', 'e', False]], [['insert', 2, 'X']]], {'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}), ('insert at the visible end', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', True]], [['insert', 2, 'Z'], ['insert', 3, 'W']]], {'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}), ('insert at the start', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False]], [['insert', 0, 'S']]], {'ops': [['ins', 'L1', None]], 'text': 'Sbc'}), ('delete by visible index', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True], ['e4', 'e', False], ['e5', 'f', False]], [['delete', 0], ['delete', 2]]], {'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}), ('delete last visible character', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True]], [['delete', 2]]], {'ops': [['del', 'e2']], 'text': 'ab'}), ('out-of-range edits are rejected', [[['e0', 'a', False], ['e1', 'b', False]], [['insert', 8, 'q'], ['delete', 2], ['delete', -1], ['insert', -1, 'r'], ['insert', 1, 'k']]], {'ops': [['reject', 8], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}), ('ids stay dense after a rejection', [[['e0', 'x', False], ['e1', 'y', False]], [['insert', 5, 'p'], ['insert', 1, 'm'], ['insert', 0, 'n']]], {'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}), ('typing into an empty document', [[], [['insert', 0, 'h'], ['insert', 1, 'i'], ['insert', 2, '!'], ['insert', 3, '!'], ['insert', 4, '!'], ['insert', 5, '!'], ['insert', 6, '!']]], {'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2'], ['ins', 'L4', 'L3'], ['ins', 'L5', 'L4'], ['ins', 'L6', 'L5'], ['ins', 'L7', 'L6']], 'text': 'hi!!!!!'}), ('mixed edits', [[['e0', 'h', False], ['e1', 'e', True], ['e2', 'l', False], ['e3', 'l', False], ['e4', 'o', False]], [['delete', 1], ['insert', 1, 'E'], ['insert', 4, '?']]], {'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'})],
}[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
insert after tombstones uses the visible neighbour{'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}{'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}Passed
insert at the visible end{'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}{'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}Passed
insert at the start{'ops': [['ins', 'L1', None]], 'text': 'Sbc'}{'ops': [['ins', 'L1', None]], 'text': 'Sbc'}Passed
delete by visible index{'ops': [['del', 'e5'], ['del', 'e2']], 'text': 'be'}{'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}Failed
delete last visible character{'ops': [['del', 'e1']], 'text': 'ac'}{'ops': [['del', 'e2']], 'text': 'ab'}Failed
out-of-range edits are rejected{'ops': [['reject', 4], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}{'ops': [['reject', 4], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}Passed
ids stay dense after a rejection{'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}{'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}Passed
typing into an empty document{'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2']], 'text': 'hi!'}{'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2']], 'text': 'hi!'}Passed
mixed edits{'ops': [['del', 'e0'], ['ins', 'L1', 'e2'], ['ins', 'L2', 'e4']], 'text': 'lElo?'}{'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'}Failed

SHA-256 / 0362b32593681f00027fa72ecb07dfb72dba31cbefd158674f0bf9cd284ea884

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(elements, edits):
    seq = [list(e) for e in elements]
    out = []
    k = 0
    for ed in edits:
        vis = [i for i, e in enumerate(seq) if not e[2]]
        idx = ed[1]
        if ed[0] == 'insert':
            if idx < 0 or idx > len(vis):
                out.append(['reject', idx])
                continue
            if idx == 0:
                after, pos = None, 0
            else:
                p = vis[idx - 1]
                after, pos = seq[p][0], p + 1
            k += 1
            nid = 'L%d' % k
            seq.insert(pos, [nid, ed[2], False])
            out.append(['ins', nid, after])
        else:
            if idx < 0 or idx >= len(vis):
                out.append(['reject', idx])
                continue
            p = vis[max(idx - 1, 0)]
            seq[p][2] = True
            out.append(['del', seq[p][0]])
    return {'ops': out, 'text': ''.join(e[1] for e in seq if not e[2])}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
    1: [('insert after tombstones uses the visible neighbour', [[['e0', 'a', False], ['e1', 'b', True], ['e2', 'c', True], ['e3', 'd', False], ['e4', 'e', False]], [['insert', 2, 'X']]], {'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}), ('insert at the visible end', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', True]], [['insert', 2, 'Z'], ['insert', 3, 'W']]], {'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}), ('insert at the start', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False]], [['insert', 0, 'S']]], {'ops': [['ins', 'L1', None]], 'text': 'Sbc'}), ('delete by visible index', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True], ['e4', 'e', False], ['e5', 'f', False]], [['delete', 0], ['delete', 2]]], {'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}), ('delete last visible character', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True]], [['delete', 2]]], {'ops': [['del', 'e2']], 'text': 'ab'}), ('out-of-range edits are rejected', [[['e0', 'a', False], ['e1', 'b', False]], [['insert', 4, 'q'], ['delete', 2], ['delete', -1], ['insert', -1, 'r'], ['insert', 1, 'k']]], {'ops': [['reject', 4], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}), ('ids stay dense after a rejection', [[['e0', 'x', False], ['e1', 'y', False]], [['insert', 5, 'p'], ['insert', 1, 'm'], ['insert', 0, 'n']]], {'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}), ('typing into an empty document', [[], [['insert', 0, 'h'], ['insert', 1, 'i'], ['insert', 2, '!']]], {'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2']], 'text': 'hi!'}), ('mixed edits', [[['e0', 'h', False], ['e1', 'e', True], ['e2', 'l', False], ['e3', 'l', False], ['e4', 'o', False]], [['delete', 1], ['insert', 1, 'E'], ['insert', 4, '?']]], {'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'})],
    2: [('insert after tombstones uses the visible neighbour', [[['e0', 'a', False], ['e1', 'b', True], ['e2', 'c', True], ['e3', 'd', False], ['e4', 'e', False]], [['insert', 2, 'X']]], {'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}), ('insert at the visible end', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', True]], [['insert', 2, 'Z'], ['insert', 3, 'W']]], {'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}), ('insert at the start', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False]], [['insert', 0, 'S']]], {'ops': [['ins', 'L1', None]], 'text': 'Sbc'}), ('delete by visible index', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True], ['e4', 'e', False], ['e5', 'f', False]], [['delete', 0], ['delete', 2]]], {'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}), ('delete last visible character', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True]], [['delete', 2]]], {'ops': [['del', 'e2']], 'text': 'ab'}), ('out-of-range edits are rejected', [[['e0', 'a', False], ['e1', 'b', False]], [['insert', 5, 'q'], ['delete', 2], ['delete', -1], ['insert', -1, 'r'], ['insert', 1, 'k']]], {'ops': [['reject', 5], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}), ('ids stay dense after a rejection', [[['e0', 'x', False], ['e1', 'y', False]], [['insert', 5, 'p'], ['insert', 1, 'm'], ['insert', 0, 'n']]], {'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}), ('typing into an empty document', [[], [['insert', 0, 'h'], ['insert', 1, 'i'], ['insert', 2, '!'], ['insert', 3, '!']]], {'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2'], ['ins', 'L4', 'L3']], 'text': 'hi!!'}), ('mixed edits', [[['e0', 'h', False], ['e1', 'e', True], ['e2', 'l', False], ['e3', 'l', False], ['e4', 'o', False]], [['delete', 1], ['insert', 1, 'E'], ['insert', 4, '?']]], {'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'})],
    3: [('insert after tombstones uses the visible neighbour', [[['e0', 'a', False], ['e1', 'b', True], ['e2', 'c', True], ['e3', 'd', False], ['e4', 'e', False]], [['insert', 2, 'X']]], {'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}), ('insert at the visible end', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', True]], [['insert', 2, 'Z'], ['insert', 3, 'W']]], {'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}), ('insert at the start', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False]], [['insert', 0, 'S']]], {'ops': [['ins', 'L1', None]], 'text': 'Sbc'}), ('delete by visible index', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True], ['e4', 'e', False], ['e5', 'f', False]], [['delete', 0], ['delete', 2]]], {'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}), ('delete last visible character', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True]], [['delete', 2]]], {'ops': [['del', 'e2']], 'text': 'ab'}), ('out-of-range edits are rejected', [[['e0', 'a', False], ['e1', 'b', False]], [['insert', 6, 'q'], ['delete', 2], ['delete', -1], ['insert', -1, 'r'], ['insert', 1, 'k']]], {'ops': [['reject', 6], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}), ('ids stay dense after a rejection', [[['e0', 'x', False], ['e1', 'y', False]], [['insert', 5, 'p'], ['insert', 1, 'm'], ['insert', 0, 'n']]], {'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}), ('typing into an empty document', [[], [['insert', 0, 'h'], ['insert', 1, 'i'], ['insert', 2, '!'], ['insert', 3, '!'], ['insert', 4, '!']]], {'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2'], ['ins', 'L4', 'L3'], ['ins', 'L5', 'L4']], 'text': 'hi!!!'}), ('mixed edits', [[['e0', 'h', False], ['e1', 'e', True], ['e2', 'l', False], ['e3', 'l', False], ['e4', 'o', False]], [['delete', 1], ['insert', 1, 'E'], ['insert', 4, '?']]], {'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'})],
    4: [('insert after tombstones uses the visible neighbour', [[['e0', 'a', False], ['e1', 'b', True], ['e2', 'c', True], ['e3', 'd', False], ['e4', 'e', False]], [['insert', 2, 'X']]], {'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}), ('insert at the visible end', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', True]], [['insert', 2, 'Z'], ['insert', 3, 'W']]], {'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}), ('insert at the start', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False]], [['insert', 0, 'S']]], {'ops': [['ins', 'L1', None]], 'text': 'Sbc'}), ('delete by visible index', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True], ['e4', 'e', False], ['e5', 'f', False]], [['delete', 0], ['delete', 2]]], {'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}), ('delete last visible character', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True]], [['delete', 2]]], {'ops': [['del', 'e2']], 'text': 'ab'}), ('out-of-range edits are rejected', [[['e0', 'a', False], ['e1', 'b', False]], [['insert', 7, 'q'], ['delete', 2], ['delete', -1], ['insert', -1, 'r'], ['insert', 1, 'k']]], {'ops': [['reject', 7], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}), ('ids stay dense after a rejection', [[['e0', 'x', False], ['e1', 'y', False]], [['insert', 5, 'p'], ['insert', 1, 'm'], ['insert', 0, 'n']]], {'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}), ('typing into an empty document', [[], [['insert', 0, 'h'], ['insert', 1, 'i'], ['insert', 2, '!'], ['insert', 3, '!'], ['insert', 4, '!'], ['insert', 5, '!']]], {'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2'], ['ins', 'L4', 'L3'], ['ins', 'L5', 'L4'], ['ins', 'L6', 'L5']], 'text': 'hi!!!!'}), ('mixed edits', [[['e0', 'h', False], ['e1', 'e', True], ['e2', 'l', False], ['e3', 'l', False], ['e4', 'o', False]], [['delete', 1], ['insert', 1, 'E'], ['insert', 4, '?']]], {'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'})],
    5: [('insert after tombstones uses the visible neighbour', [[['e0', 'a', False], ['e1', 'b', True], ['e2', 'c', True], ['e3', 'd', False], ['e4', 'e', False]], [['insert', 2, 'X']]], {'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}), ('insert at the visible end', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', True]], [['insert', 2, 'Z'], ['insert', 3, 'W']]], {'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}), ('insert at the start', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False]], [['insert', 0, 'S']]], {'ops': [['ins', 'L1', None]], 'text': 'Sbc'}), ('delete by visible index', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True], ['e4', 'e', False], ['e5', 'f', False]], [['delete', 0], ['delete', 2]]], {'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}), ('delete last visible character', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True]], [['delete', 2]]], {'ops': [['del', 'e2']], 'text': 'ab'}), ('out-of-range edits are rejected', [[['e0', 'a', False], ['e1', 'b', False]], [['insert', 8, 'q'], ['delete', 2], ['delete', -1], ['insert', -1, 'r'], ['insert', 1, 'k']]], {'ops': [['reject', 8], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}), ('ids stay dense after a rejection', [[['e0', 'x', False], ['e1', 'y', False]], [['insert', 5, 'p'], ['insert', 1, 'm'], ['insert', 0, 'n']]], {'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}), ('typing into an empty document', [[], [['insert', 0, 'h'], ['insert', 1, 'i'], ['insert', 2, '!'], ['insert', 3, '!'], ['insert', 4, '!'], ['insert', 5, '!'], ['insert', 6, '!']]], {'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2'], ['ins', 'L4', 'L3'], ['ins', 'L5', 'L4'], ['ins', 'L6', 'L5'], ['ins', 'L7', 'L6']], 'text': 'hi!!!!!'}), ('mixed edits', [[['e0', 'h', False], ['e1', 'e', True], ['e2', 'l', False], ['e3', 'l', False], ['e4', 'o', False]], [['delete', 1], ['insert', 1, 'E'], ['insert', 4, '?']]], {'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'})],
}[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
insert after tombstones uses the visible neighbour{'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}{'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}Passed
insert at the visible end{'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}{'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}Passed
insert at the start{'ops': [['ins', 'L1', None]], 'text': 'Sbc'}{'ops': [['ins', 'L1', None]], 'text': 'Sbc'}Passed
delete by visible index{'ops': [['del', 'e1'], ['del', 'e4']], 'text': 'cf'}{'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}Failed
delete last visible character{'ops': [['del', 'e1']], 'text': 'ac'}{'ops': [['del', 'e2']], 'text': 'ab'}Failed
out-of-range edits are rejected{'ops': [['reject', 4], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}{'ops': [['reject', 4], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}Passed
ids stay dense after a rejection{'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}{'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}Passed
typing into an empty document{'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2']], 'text': 'hi!'}{'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2']], 'text': 'hi!'}Passed
mixed edits{'ops': [['del', 'e0'], ['ins', 'L1', 'e2'], ['ins', 'L2', 'e4']], 'text': 'lElo?'}{'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'}Failed

SHA-256 / f8d94429bec156395c7e908ac913d82ae0a9c4c87ad8b0f86f67fe8bfdaabd72

3 / The verified repair

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

N = 1
observations = []
def solve(elements, edits):
    seq = [list(e) for e in elements]
    out = []
    k = 0
    for ed in edits:
        vis = [i for i, e in enumerate(seq) if not e[2]]
        idx = ed[1]
        if ed[0] == 'insert':
            if idx < 0 or idx > len(vis):
                out.append(['reject', idx])
                continue
            if idx == 0:
                after, pos = None, 0
            else:
                p = vis[idx - 1]
                after, pos = seq[p][0], p + 1
            k += 1
            nid = 'L%d' % k
            seq.insert(pos, [nid, ed[2], False])
            out.append(['ins', nid, after])
        else:
            if idx < 0 or idx >= len(vis):
                out.append(['reject', idx])
                continue
            p = vis[idx]
            seq[p][2] = True
            out.append(['del', seq[p][0]])
    return {'ops': out, 'text': ''.join(e[1] for e in seq if not e[2])}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
    1: [('insert after tombstones uses the visible neighbour', [[['e0', 'a', False], ['e1', 'b', True], ['e2', 'c', True], ['e3', 'd', False], ['e4', 'e', False]], [['insert', 2, 'X']]], {'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}), ('insert at the visible end', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', True]], [['insert', 2, 'Z'], ['insert', 3, 'W']]], {'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}), ('insert at the start', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False]], [['insert', 0, 'S']]], {'ops': [['ins', 'L1', None]], 'text': 'Sbc'}), ('delete by visible index', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True], ['e4', 'e', False], ['e5', 'f', False]], [['delete', 0], ['delete', 2]]], {'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}), ('delete last visible character', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True]], [['delete', 2]]], {'ops': [['del', 'e2']], 'text': 'ab'}), ('out-of-range edits are rejected', [[['e0', 'a', False], ['e1', 'b', False]], [['insert', 4, 'q'], ['delete', 2], ['delete', -1], ['insert', -1, 'r'], ['insert', 1, 'k']]], {'ops': [['reject', 4], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}), ('ids stay dense after a rejection', [[['e0', 'x', False], ['e1', 'y', False]], [['insert', 5, 'p'], ['insert', 1, 'm'], ['insert', 0, 'n']]], {'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}), ('typing into an empty document', [[], [['insert', 0, 'h'], ['insert', 1, 'i'], ['insert', 2, '!']]], {'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2']], 'text': 'hi!'}), ('mixed edits', [[['e0', 'h', False], ['e1', 'e', True], ['e2', 'l', False], ['e3', 'l', False], ['e4', 'o', False]], [['delete', 1], ['insert', 1, 'E'], ['insert', 4, '?']]], {'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'})],
    2: [('insert after tombstones uses the visible neighbour', [[['e0', 'a', False], ['e1', 'b', True], ['e2', 'c', True], ['e3', 'd', False], ['e4', 'e', False]], [['insert', 2, 'X']]], {'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}), ('insert at the visible end', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', True]], [['insert', 2, 'Z'], ['insert', 3, 'W']]], {'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}), ('insert at the start', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False]], [['insert', 0, 'S']]], {'ops': [['ins', 'L1', None]], 'text': 'Sbc'}), ('delete by visible index', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True], ['e4', 'e', False], ['e5', 'f', False]], [['delete', 0], ['delete', 2]]], {'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}), ('delete last visible character', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True]], [['delete', 2]]], {'ops': [['del', 'e2']], 'text': 'ab'}), ('out-of-range edits are rejected', [[['e0', 'a', False], ['e1', 'b', False]], [['insert', 5, 'q'], ['delete', 2], ['delete', -1], ['insert', -1, 'r'], ['insert', 1, 'k']]], {'ops': [['reject', 5], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}), ('ids stay dense after a rejection', [[['e0', 'x', False], ['e1', 'y', False]], [['insert', 5, 'p'], ['insert', 1, 'm'], ['insert', 0, 'n']]], {'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}), ('typing into an empty document', [[], [['insert', 0, 'h'], ['insert', 1, 'i'], ['insert', 2, '!'], ['insert', 3, '!']]], {'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2'], ['ins', 'L4', 'L3']], 'text': 'hi!!'}), ('mixed edits', [[['e0', 'h', False], ['e1', 'e', True], ['e2', 'l', False], ['e3', 'l', False], ['e4', 'o', False]], [['delete', 1], ['insert', 1, 'E'], ['insert', 4, '?']]], {'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'})],
    3: [('insert after tombstones uses the visible neighbour', [[['e0', 'a', False], ['e1', 'b', True], ['e2', 'c', True], ['e3', 'd', False], ['e4', 'e', False]], [['insert', 2, 'X']]], {'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}), ('insert at the visible end', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', True]], [['insert', 2, 'Z'], ['insert', 3, 'W']]], {'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}), ('insert at the start', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False]], [['insert', 0, 'S']]], {'ops': [['ins', 'L1', None]], 'text': 'Sbc'}), ('delete by visible index', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True], ['e4', 'e', False], ['e5', 'f', False]], [['delete', 0], ['delete', 2]]], {'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}), ('delete last visible character', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True]], [['delete', 2]]], {'ops': [['del', 'e2']], 'text': 'ab'}), ('out-of-range edits are rejected', [[['e0', 'a', False], ['e1', 'b', False]], [['insert', 6, 'q'], ['delete', 2], ['delete', -1], ['insert', -1, 'r'], ['insert', 1, 'k']]], {'ops': [['reject', 6], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}), ('ids stay dense after a rejection', [[['e0', 'x', False], ['e1', 'y', False]], [['insert', 5, 'p'], ['insert', 1, 'm'], ['insert', 0, 'n']]], {'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}), ('typing into an empty document', [[], [['insert', 0, 'h'], ['insert', 1, 'i'], ['insert', 2, '!'], ['insert', 3, '!'], ['insert', 4, '!']]], {'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2'], ['ins', 'L4', 'L3'], ['ins', 'L5', 'L4']], 'text': 'hi!!!'}), ('mixed edits', [[['e0', 'h', False], ['e1', 'e', True], ['e2', 'l', False], ['e3', 'l', False], ['e4', 'o', False]], [['delete', 1], ['insert', 1, 'E'], ['insert', 4, '?']]], {'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'})],
    4: [('insert after tombstones uses the visible neighbour', [[['e0', 'a', False], ['e1', 'b', True], ['e2', 'c', True], ['e3', 'd', False], ['e4', 'e', False]], [['insert', 2, 'X']]], {'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}), ('insert at the visible end', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', True]], [['insert', 2, 'Z'], ['insert', 3, 'W']]], {'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}), ('insert at the start', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False]], [['insert', 0, 'S']]], {'ops': [['ins', 'L1', None]], 'text': 'Sbc'}), ('delete by visible index', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True], ['e4', 'e', False], ['e5', 'f', False]], [['delete', 0], ['delete', 2]]], {'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}), ('delete last visible character', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True]], [['delete', 2]]], {'ops': [['del', 'e2']], 'text': 'ab'}), ('out-of-range edits are rejected', [[['e0', 'a', False], ['e1', 'b', False]], [['insert', 7, 'q'], ['delete', 2], ['delete', -1], ['insert', -1, 'r'], ['insert', 1, 'k']]], {'ops': [['reject', 7], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}), ('ids stay dense after a rejection', [[['e0', 'x', False], ['e1', 'y', False]], [['insert', 5, 'p'], ['insert', 1, 'm'], ['insert', 0, 'n']]], {'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}), ('typing into an empty document', [[], [['insert', 0, 'h'], ['insert', 1, 'i'], ['insert', 2, '!'], ['insert', 3, '!'], ['insert', 4, '!'], ['insert', 5, '!']]], {'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2'], ['ins', 'L4', 'L3'], ['ins', 'L5', 'L4'], ['ins', 'L6', 'L5']], 'text': 'hi!!!!'}), ('mixed edits', [[['e0', 'h', False], ['e1', 'e', True], ['e2', 'l', False], ['e3', 'l', False], ['e4', 'o', False]], [['delete', 1], ['insert', 1, 'E'], ['insert', 4, '?']]], {'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'})],
    5: [('insert after tombstones uses the visible neighbour', [[['e0', 'a', False], ['e1', 'b', True], ['e2', 'c', True], ['e3', 'd', False], ['e4', 'e', False]], [['insert', 2, 'X']]], {'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}), ('insert at the visible end', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', True]], [['insert', 2, 'Z'], ['insert', 3, 'W']]], {'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}), ('insert at the start', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False]], [['insert', 0, 'S']]], {'ops': [['ins', 'L1', None]], 'text': 'Sbc'}), ('delete by visible index', [[['e0', 'a', True], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True], ['e4', 'e', False], ['e5', 'f', False]], [['delete', 0], ['delete', 2]]], {'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}), ('delete last visible character', [[['e0', 'a', False], ['e1', 'b', False], ['e2', 'c', False], ['e3', 'd', True]], [['delete', 2]]], {'ops': [['del', 'e2']], 'text': 'ab'}), ('out-of-range edits are rejected', [[['e0', 'a', False], ['e1', 'b', False]], [['insert', 8, 'q'], ['delete', 2], ['delete', -1], ['insert', -1, 'r'], ['insert', 1, 'k']]], {'ops': [['reject', 8], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}), ('ids stay dense after a rejection', [[['e0', 'x', False], ['e1', 'y', False]], [['insert', 5, 'p'], ['insert', 1, 'm'], ['insert', 0, 'n']]], {'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}), ('typing into an empty document', [[], [['insert', 0, 'h'], ['insert', 1, 'i'], ['insert', 2, '!'], ['insert', 3, '!'], ['insert', 4, '!'], ['insert', 5, '!'], ['insert', 6, '!']]], {'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2'], ['ins', 'L4', 'L3'], ['ins', 'L5', 'L4'], ['ins', 'L6', 'L5'], ['ins', 'L7', 'L6']], 'text': 'hi!!!!!'}), ('mixed edits', [[['e0', 'h', False], ['e1', 'e', True], ['e2', 'l', False], ['e3', 'l', False], ['e4', 'o', False]], [['delete', 1], ['insert', 1, 'E'], ['insert', 4, '?']]], {'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'})],
}[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
insert after tombstones uses the visible neighbour{'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}{'ops': [['ins', 'L1', 'e3']], 'text': 'adXe'}Passed
insert at the visible end{'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}{'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}Passed
insert at the start{'ops': [['ins', 'L1', None]], 'text': 'Sbc'}{'ops': [['ins', 'L1', None]], 'text': 'Sbc'}Passed
delete by visible index{'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}{'ops': [['del', 'e1'], ['del', 'e5']], 'text': 'ce'}Passed
delete last visible character{'ops': [['del', 'e2']], 'text': 'ab'}{'ops': [['del', 'e2']], 'text': 'ab'}Passed
out-of-range edits are rejected{'ops': [['reject', 4], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}{'ops': [['reject', 4], ['reject', 2], ['reject', -1], ['reject', -1], ['ins', 'L1', 'e0']], 'text': 'akb'}Passed
ids stay dense after a rejection{'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}{'ops': [['reject', 5], ['ins', 'L1', 'e0'], ['ins', 'L2', None]], 'text': 'nxmy'}Passed
typing into an empty document{'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2']], 'text': 'hi!'}{'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2']], 'text': 'hi!'}Passed
mixed edits{'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'}{'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'}Passed

SHA-256 / f442879e70a927fc6310e255f5ae0a30a1772555903470c8f30318698b00183e

Verification & scope

A deterministic, bounded teaching model of one replicated data type with stipulated operation and merge rules; it is not a production CRDT library and makes no claim of conformance to any specific published design. 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:03.694406+00:00.

Case digest / 1cc95d4cc2540750c3e378a0dc528cf3b9901f1848639d182a53e5ec4871fdaf