FAILURE MAP
← Case archive

FA-75166 / CRDT convergence / Open access

Visible index translation: typing at the end of the document is rejected · case 01

Appending a character after the last visible character is refused.

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

ROOT CAUSE

The insert bound uses the delete rule, excluding the position equal to the visible length.

VERIFIED REPAIR

Inserts accept every index from zero through the visible length inclusive.

Unsuccessful approach: Special-casing the empty document still refuses appends to non-empty text.

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]
            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': [['reject', 2], ['reject', 3]], 'text': 'ab'}{'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}Failed
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': [['reject', 0], ['reject', 1], ['reject', 2]], 'text': ''}{'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2']], 'text': 'hi!'}Failed
mixed edits{'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['reject', 4]], 'text': 'hElo'}{'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'}Failed

SHA-256 / 8ead4d446f964b3a93bf3ffefbcb4fc2d196c2b4f0ce4c98c9d8abe6ef41b4ce

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) and idx != 0):
                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': [['reject', 2], ['reject', 3]], 'text': 'ab'}{'ops': [['ins', 'L1', 'e1'], ['ins', 'L2', 'L1']], 'text': 'abZW'}Failed
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], ['reject', 1], ['reject', 2]], 'text': 'h'}{'ops': [['ins', 'L1', None], ['ins', 'L2', 'L1'], ['ins', 'L3', 'L2']], 'text': 'hi!'}Failed
mixed edits{'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['reject', 4]], 'text': 'hElo'}{'ops': [['del', 'e2'], ['ins', 'L1', 'e0'], ['ins', 'L2', 'e4']], 'text': 'hElo?'}Failed

SHA-256 / 105dd6023f999719c4d161be34040149cb02755f26770169b5f0ce6821761f21

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

Case digest / f684b9864a2e953837e3a0b0b1fd16852563a37694efc4b77c7228b60b30940e