{"abstract":"A member that has never reported is treated as caught up.","category":"CRDT convergence","checks":9,"contract":"Tombstones are [element, origin, seq]. acks maps replica -> {origin: highest delivered seq}. The live membership is members minus departed. A tombstone is causally stable, and may be purged, when every live member has reported an ack for its origin at or above seq; a live member with no report counts as zero. Other reporters are ignored. Return sorted purged and kept elements.","evaluation_group":"w2-crdt-convergence-tombstone-stability-gc","failed_approach":"Taking the union with reporters also lets observers and departed members hold back collection.","family":"w2-crdt-convergence-tombstone-stability-gc-member-source","id":"FA-75126","implementations":{"attempt":{"sha256":"6a8357a074da4bf884632fba2b69e1c3e18ad1119271ec3ce67e822dca23906d","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(tombstones, acks, members, departed):\n    live = [mb for mb in members if mb not in departed]\n    stable = {}\n    for origin in sorted({t[1] for t in tombstones}):\n        stable[origin] = min(acks.get(mb, {}).get(origin, 0) for mb in set(live) | set(acks))\n    purged, kept = [], []\n    for elem, origin, seq in tombstones:\n        if stable[origin] >= seq:\n            purged.append(elem)\n        else:\n            kept.append(elem)\n    return {'purged': sorted(purged), 'kept': sorted(kept)}\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = {\n    1: [('all members acknowledged', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 3, 'b': 2}, 'c': {'a': 3, 'b': 3}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('one lagging member blocks', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 1, 'b': 2}, 'c': {'a': 3, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y'], 'kept': ['z']}), ('a silent member blocks', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 3, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': [], 'kept': ['x', 'y', 'z']}), ('departed members do not block', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 3, 'b': 2}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('departed member stale report is ignored', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 3, 'b': 2}, 'c': {'a': 0}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('ack exactly equal to the tombstone', [[['q', 'b', 1]], {'a': {'b': 1}, 'b': {'b': 1}}, ['a', 'b'], []], {'purged': ['q'], 'kept': []}), ('ack one below the tombstone', [[['q', 'b', 2]], {'a': {'b': 1}, 'b': {'b': 2}}, ['a', 'b'], []], {'purged': [], 'kept': ['q']}), ('observer outside membership is ignored', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 3, 'b': 2}, 'obs': {}}, ['a', 'b'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('majority is not enough', [[['m', 'c', 1]], {'a': {'c': 1}, 'b': {'c': 1}, 'c': {'c': 1}, 'd': {}}, ['a', 'b', 'c', 'd'], []], {'purged': [], 'kept': ['m']})],\n    2: [('all members acknowledged', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 4, 'b': 2}, 'c': {'a': 4, 'b': 3}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('one lagging member blocks', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 2, 'b': 2}, 'c': {'a': 4, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y'], 'kept': ['z']}), ('a silent member blocks', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 4, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': [], 'kept': ['x', 'y', 'z']}), ('departed members do not block', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 4, 'b': 2}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('departed member stale report is ignored', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 4, 'b': 2}, 'c': {'a': 0}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('ack exactly equal to the tombstone', [[['q', 'b', 2]], {'a': {'b': 2}, 'b': {'b': 2}}, ['a', 'b'], []], {'purged': ['q'], 'kept': []}), ('ack one below the tombstone', [[['q', 'b', 3]], {'a': {'b': 2}, 'b': {'b': 3}}, ['a', 'b'], []], {'purged': [], 'kept': ['q']}), ('observer outside membership is ignored', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 4, 'b': 2}, 'obs': {}}, ['a', 'b'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('majority is not enough', [[['m', 'c', 1]], {'a': {'c': 1}, 'b': {'c': 1}, 'c': {'c': 1}, 'd': {}}, ['a', 'b', 'c', 'd'], []], {'purged': [], 'kept': ['m']})],\n    3: [('all members acknowledged', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 5, 'b': 2}, 'c': {'a': 5, 'b': 3}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('one lagging member blocks', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 3, 'b': 2}, 'c': {'a': 5, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y'], 'kept': ['z']}), ('a silent member blocks', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 5, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': [], 'kept': ['x', 'y', 'z']}), ('departed members do not block', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 5, 'b': 2}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('departed member stale report is ignored', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 5, 'b': 2}, 'c': {'a': 0}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('ack exactly equal to the tombstone', [[['q', 'b', 3]], {'a': {'b': 3}, 'b': {'b': 3}}, ['a', 'b'], []], {'purged': ['q'], 'kept': []}), ('ack one below the tombstone', [[['q', 'b', 4]], {'a': {'b': 3}, 'b': {'b': 4}}, ['a', 'b'], []], {'purged': [], 'kept': ['q']}), ('observer outside membership is ignored', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 5, 'b': 2}, 'obs': {}}, ['a', 'b'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('majority is not enough', [[['m', 'c', 1]], {'a': {'c': 1}, 'b': {'c': 1}, 'c': {'c': 1}, 'd': {}}, ['a', 'b', 'c', 'd'], []], {'purged': [], 'kept': ['m']})],\n    4: [('all members acknowledged', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 6, 'b': 2}, 'c': {'a': 6, 'b': 3}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('one lagging member blocks', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 4, 'b': 2}, 'c': {'a': 6, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y'], 'kept': ['z']}), ('a silent member blocks', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 6, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': [], 'kept': ['x', 'y', 'z']}), ('departed members do not block', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 6, 'b': 2}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('departed member stale report is ignored', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 6, 'b': 2}, 'c': {'a': 0}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('ack exactly equal to the tombstone', [[['q', 'b', 4]], {'a': {'b': 4}, 'b': {'b': 4}}, ['a', 'b'], []], {'purged': ['q'], 'kept': []}), ('ack one below the tombstone', [[['q', 'b', 5]], {'a': {'b': 4}, 'b': {'b': 5}}, ['a', 'b'], []], {'purged': [], 'kept': ['q']}), ('observer outside membership is ignored', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 6, 'b': 2}, 'obs': {}}, ['a', 'b'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('majority is not enough', [[['m', 'c', 1]], {'a': {'c': 1}, 'b': {'c': 1}, 'c': {'c': 1}, 'd': {}}, ['a', 'b', 'c', 'd'], []], {'purged': [], 'kept': ['m']})],\n    5: [('all members acknowledged', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 7, 'b': 2}, 'c': {'a': 7, 'b': 3}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('one lagging member blocks', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 5, 'b': 2}, 'c': {'a': 7, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y'], 'kept': ['z']}), ('a silent member blocks', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 7, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': [], 'kept': ['x', 'y', 'z']}), ('departed members do not block', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 7, 'b': 2}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('departed member stale report is ignored', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 7, 'b': 2}, 'c': {'a': 0}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('ack exactly equal to the tombstone', [[['q', 'b', 5]], {'a': {'b': 5}, 'b': {'b': 5}}, ['a', 'b'], []], {'purged': ['q'], 'kept': []}), ('ack one below the tombstone', [[['q', 'b', 6]], {'a': {'b': 5}, 'b': {'b': 6}}, ['a', 'b'], []], {'purged': [], 'kept': ['q']}), ('observer outside membership is ignored', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 7, 'b': 2}, 'obs': {}}, ['a', 'b'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('majority is not enough', [[['m', 'c', 1]], {'a': {'c': 1}, 'b': {'c': 1}, 'c': {'c': 1}, 'd': {}}, ['a', 'b', 'c', 'd'], []], {'purged': [], 'kept': ['m']})],\n}[N]\nfor label, args, expected in cases:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"broken":{"sha256":"f2046e3d1a9b0a3d6416c000006c3e4ed4eaeabeb9bd1d8bf98c961c43ec7ccd","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(tombstones, acks, members, departed):\n    live = [mb for mb in members if mb not in departed]\n    stable = {}\n    for origin in sorted({t[1] for t in tombstones}):\n        stable[origin] = min(acks.get(mb, {}).get(origin, 0) for mb in acks if mb not in departed)\n    purged, kept = [], []\n    for elem, origin, seq in tombstones:\n        if stable[origin] >= seq:\n            purged.append(elem)\n        else:\n            kept.append(elem)\n    return {'purged': sorted(purged), 'kept': sorted(kept)}\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = {\n    1: [('all members acknowledged', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 3, 'b': 2}, 'c': {'a': 3, 'b': 3}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('one lagging member blocks', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 1, 'b': 2}, 'c': {'a': 3, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y'], 'kept': ['z']}), ('a silent member blocks', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 3, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': [], 'kept': ['x', 'y', 'z']}), ('departed members do not block', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 3, 'b': 2}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('departed member stale report is ignored', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 3, 'b': 2}, 'c': {'a': 0}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('ack exactly equal to the tombstone', [[['q', 'b', 1]], {'a': {'b': 1}, 'b': {'b': 1}}, ['a', 'b'], []], {'purged': ['q'], 'kept': []}), ('ack one below the tombstone', [[['q', 'b', 2]], {'a': {'b': 1}, 'b': {'b': 2}}, ['a', 'b'], []], {'purged': [], 'kept': ['q']}), ('observer outside membership is ignored', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 3, 'b': 2}, 'obs': {}}, ['a', 'b'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('majority is not enough', [[['m', 'c', 1]], {'a': {'c': 1}, 'b': {'c': 1}, 'c': {'c': 1}, 'd': {}}, ['a', 'b', 'c', 'd'], []], {'purged': [], 'kept': ['m']})],\n    2: [('all members acknowledged', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 4, 'b': 2}, 'c': {'a': 4, 'b': 3}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('one lagging member blocks', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 2, 'b': 2}, 'c': {'a': 4, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y'], 'kept': ['z']}), ('a silent member blocks', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 4, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': [], 'kept': ['x', 'y', 'z']}), ('departed members do not block', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 4, 'b': 2}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('departed member stale report is ignored', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 4, 'b': 2}, 'c': {'a': 0}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('ack exactly equal to the tombstone', [[['q', 'b', 2]], {'a': {'b': 2}, 'b': {'b': 2}}, ['a', 'b'], []], {'purged': ['q'], 'kept': []}), ('ack one below the tombstone', [[['q', 'b', 3]], {'a': {'b': 2}, 'b': {'b': 3}}, ['a', 'b'], []], {'purged': [], 'kept': ['q']}), ('observer outside membership is ignored', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 4, 'b': 2}, 'obs': {}}, ['a', 'b'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('majority is not enough', [[['m', 'c', 1]], {'a': {'c': 1}, 'b': {'c': 1}, 'c': {'c': 1}, 'd': {}}, ['a', 'b', 'c', 'd'], []], {'purged': [], 'kept': ['m']})],\n    3: [('all members acknowledged', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 5, 'b': 2}, 'c': {'a': 5, 'b': 3}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('one lagging member blocks', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 3, 'b': 2}, 'c': {'a': 5, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y'], 'kept': ['z']}), ('a silent member blocks', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 5, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': [], 'kept': ['x', 'y', 'z']}), ('departed members do not block', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 5, 'b': 2}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('departed member stale report is ignored', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 5, 'b': 2}, 'c': {'a': 0}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('ack exactly equal to the tombstone', [[['q', 'b', 3]], {'a': {'b': 3}, 'b': {'b': 3}}, ['a', 'b'], []], {'purged': ['q'], 'kept': []}), ('ack one below the tombstone', [[['q', 'b', 4]], {'a': {'b': 3}, 'b': {'b': 4}}, ['a', 'b'], []], {'purged': [], 'kept': ['q']}), ('observer outside membership is ignored', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 5, 'b': 2}, 'obs': {}}, ['a', 'b'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('majority is not enough', [[['m', 'c', 1]], {'a': {'c': 1}, 'b': {'c': 1}, 'c': {'c': 1}, 'd': {}}, ['a', 'b', 'c', 'd'], []], {'purged': [], 'kept': ['m']})],\n    4: [('all members acknowledged', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 6, 'b': 2}, 'c': {'a': 6, 'b': 3}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('one lagging member blocks', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 4, 'b': 2}, 'c': {'a': 6, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y'], 'kept': ['z']}), ('a silent member blocks', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 6, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': [], 'kept': ['x', 'y', 'z']}), ('departed members do not block', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 6, 'b': 2}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('departed member stale report is ignored', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 6, 'b': 2}, 'c': {'a': 0}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('ack exactly equal to the tombstone', [[['q', 'b', 4]], {'a': {'b': 4}, 'b': {'b': 4}}, ['a', 'b'], []], {'purged': ['q'], 'kept': []}), ('ack one below the tombstone', [[['q', 'b', 5]], {'a': {'b': 4}, 'b': {'b': 5}}, ['a', 'b'], []], {'purged': [], 'kept': ['q']}), ('observer outside membership is ignored', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 6, 'b': 2}, 'obs': {}}, ['a', 'b'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('majority is not enough', [[['m', 'c', 1]], {'a': {'c': 1}, 'b': {'c': 1}, 'c': {'c': 1}, 'd': {}}, ['a', 'b', 'c', 'd'], []], {'purged': [], 'kept': ['m']})],\n    5: [('all members acknowledged', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 7, 'b': 2}, 'c': {'a': 7, 'b': 3}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('one lagging member blocks', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 5, 'b': 2}, 'c': {'a': 7, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y'], 'kept': ['z']}), ('a silent member blocks', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 7, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': [], 'kept': ['x', 'y', 'z']}), ('departed members do not block', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 7, 'b': 2}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('departed member stale report is ignored', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 7, 'b': 2}, 'c': {'a': 0}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('ack exactly equal to the tombstone', [[['q', 'b', 5]], {'a': {'b': 5}, 'b': {'b': 5}}, ['a', 'b'], []], {'purged': ['q'], 'kept': []}), ('ack one below the tombstone', [[['q', 'b', 6]], {'a': {'b': 5}, 'b': {'b': 6}}, ['a', 'b'], []], {'purged': [], 'kept': ['q']}), ('observer outside membership is ignored', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 7, 'b': 2}, 'obs': {}}, ['a', 'b'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('majority is not enough', [[['m', 'c', 1]], {'a': {'c': 1}, 'b': {'c': 1}, 'c': {'c': 1}, 'd': {}}, ['a', 'b', 'c', 'd'], []], {'purged': [], 'kept': ['m']})],\n}[N]\nfor label, args, expected in cases:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"fixed":{"sha256":"ba1a97253e6c3733fedcf87fe984fcfff0d86b28e4dc15c54509efb7494a1142","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(tombstones, acks, members, departed):\n    live = [mb for mb in members if mb not in departed]\n    stable = {}\n    for origin in sorted({t[1] for t in tombstones}):\n        stable[origin] = min(acks.get(mb, {}).get(origin, 0) for mb in live)\n    purged, kept = [], []\n    for elem, origin, seq in tombstones:\n        if stable[origin] >= seq:\n            purged.append(elem)\n        else:\n            kept.append(elem)\n    return {'purged': sorted(purged), 'kept': sorted(kept)}\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = {\n    1: [('all members acknowledged', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 3, 'b': 2}, 'c': {'a': 3, 'b': 3}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('one lagging member blocks', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 1, 'b': 2}, 'c': {'a': 3, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y'], 'kept': ['z']}), ('a silent member blocks', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 3, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': [], 'kept': ['x', 'y', 'z']}), ('departed members do not block', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 3, 'b': 2}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('departed member stale report is ignored', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 3, 'b': 2}, 'c': {'a': 0}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('ack exactly equal to the tombstone', [[['q', 'b', 1]], {'a': {'b': 1}, 'b': {'b': 1}}, ['a', 'b'], []], {'purged': ['q'], 'kept': []}), ('ack one below the tombstone', [[['q', 'b', 2]], {'a': {'b': 1}, 'b': {'b': 2}}, ['a', 'b'], []], {'purged': [], 'kept': ['q']}), ('observer outside membership is ignored', [[['x', 'a', 1], ['y', 'b', 2], ['z', 'a', 3]], {'a': {'a': 3, 'b': 2}, 'b': {'a': 3, 'b': 2}, 'obs': {}}, ['a', 'b'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('majority is not enough', [[['m', 'c', 1]], {'a': {'c': 1}, 'b': {'c': 1}, 'c': {'c': 1}, 'd': {}}, ['a', 'b', 'c', 'd'], []], {'purged': [], 'kept': ['m']})],\n    2: [('all members acknowledged', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 4, 'b': 2}, 'c': {'a': 4, 'b': 3}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('one lagging member blocks', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 2, 'b': 2}, 'c': {'a': 4, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y'], 'kept': ['z']}), ('a silent member blocks', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 4, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': [], 'kept': ['x', 'y', 'z']}), ('departed members do not block', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 4, 'b': 2}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('departed member stale report is ignored', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 4, 'b': 2}, 'c': {'a': 0}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('ack exactly equal to the tombstone', [[['q', 'b', 2]], {'a': {'b': 2}, 'b': {'b': 2}}, ['a', 'b'], []], {'purged': ['q'], 'kept': []}), ('ack one below the tombstone', [[['q', 'b', 3]], {'a': {'b': 2}, 'b': {'b': 3}}, ['a', 'b'], []], {'purged': [], 'kept': ['q']}), ('observer outside membership is ignored', [[['x', 'a', 2], ['y', 'b', 2], ['z', 'a', 4]], {'a': {'a': 4, 'b': 2}, 'b': {'a': 4, 'b': 2}, 'obs': {}}, ['a', 'b'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('majority is not enough', [[['m', 'c', 1]], {'a': {'c': 1}, 'b': {'c': 1}, 'c': {'c': 1}, 'd': {}}, ['a', 'b', 'c', 'd'], []], {'purged': [], 'kept': ['m']})],\n    3: [('all members acknowledged', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 5, 'b': 2}, 'c': {'a': 5, 'b': 3}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('one lagging member blocks', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 3, 'b': 2}, 'c': {'a': 5, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y'], 'kept': ['z']}), ('a silent member blocks', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 5, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': [], 'kept': ['x', 'y', 'z']}), ('departed members do not block', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 5, 'b': 2}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('departed member stale report is ignored', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 5, 'b': 2}, 'c': {'a': 0}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('ack exactly equal to the tombstone', [[['q', 'b', 3]], {'a': {'b': 3}, 'b': {'b': 3}}, ['a', 'b'], []], {'purged': ['q'], 'kept': []}), ('ack one below the tombstone', [[['q', 'b', 4]], {'a': {'b': 3}, 'b': {'b': 4}}, ['a', 'b'], []], {'purged': [], 'kept': ['q']}), ('observer outside membership is ignored', [[['x', 'a', 3], ['y', 'b', 2], ['z', 'a', 5]], {'a': {'a': 5, 'b': 2}, 'b': {'a': 5, 'b': 2}, 'obs': {}}, ['a', 'b'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('majority is not enough', [[['m', 'c', 1]], {'a': {'c': 1}, 'b': {'c': 1}, 'c': {'c': 1}, 'd': {}}, ['a', 'b', 'c', 'd'], []], {'purged': [], 'kept': ['m']})],\n    4: [('all members acknowledged', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 6, 'b': 2}, 'c': {'a': 6, 'b': 3}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('one lagging member blocks', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 4, 'b': 2}, 'c': {'a': 6, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y'], 'kept': ['z']}), ('a silent member blocks', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 6, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': [], 'kept': ['x', 'y', 'z']}), ('departed members do not block', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 6, 'b': 2}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('departed member stale report is ignored', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 6, 'b': 2}, 'c': {'a': 0}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('ack exactly equal to the tombstone', [[['q', 'b', 4]], {'a': {'b': 4}, 'b': {'b': 4}}, ['a', 'b'], []], {'purged': ['q'], 'kept': []}), ('ack one below the tombstone', [[['q', 'b', 5]], {'a': {'b': 4}, 'b': {'b': 5}}, ['a', 'b'], []], {'purged': [], 'kept': ['q']}), ('observer outside membership is ignored', [[['x', 'a', 4], ['y', 'b', 2], ['z', 'a', 6]], {'a': {'a': 6, 'b': 2}, 'b': {'a': 6, 'b': 2}, 'obs': {}}, ['a', 'b'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('majority is not enough', [[['m', 'c', 1]], {'a': {'c': 1}, 'b': {'c': 1}, 'c': {'c': 1}, 'd': {}}, ['a', 'b', 'c', 'd'], []], {'purged': [], 'kept': ['m']})],\n    5: [('all members acknowledged', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 7, 'b': 2}, 'c': {'a': 7, 'b': 3}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('one lagging member blocks', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 5, 'b': 2}, 'c': {'a': 7, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': ['x', 'y'], 'kept': ['z']}), ('a silent member blocks', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 7, 'b': 2}}, ['a', 'b', 'c'], []], {'purged': [], 'kept': ['x', 'y', 'z']}), ('departed members do not block', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 7, 'b': 2}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('departed member stale report is ignored', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 7, 'b': 2}, 'c': {'a': 0}}, ['a', 'b', 'c'], ['c']], {'purged': ['x', 'y', 'z'], 'kept': []}), ('ack exactly equal to the tombstone', [[['q', 'b', 5]], {'a': {'b': 5}, 'b': {'b': 5}}, ['a', 'b'], []], {'purged': ['q'], 'kept': []}), ('ack one below the tombstone', [[['q', 'b', 6]], {'a': {'b': 5}, 'b': {'b': 6}}, ['a', 'b'], []], {'purged': [], 'kept': ['q']}), ('observer outside membership is ignored', [[['x', 'a', 5], ['y', 'b', 2], ['z', 'a', 7]], {'a': {'a': 7, 'b': 2}, 'b': {'a': 7, 'b': 2}, 'obs': {}}, ['a', 'b'], []], {'purged': ['x', 'y', 'z'], 'kept': []}), ('majority is not enough', [[['m', 'c', 1]], {'a': {'c': 1}, 'b': {'c': 1}, 'c': {'c': 1}, 'd': {}}, ['a', 'b', 'c', 'd'], []], {'purged': [], 'kept': ['m']})],\n}[N]\nfor label, args, expected in cases:\n    check(label, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"}},"limitations":"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.","method":"Deterministic executable model with adversarial boundary fixtures.","provenance":{"created_by":"Failure Map","dependencies":"Python standard library","family":"w2-crdt-convergence-tombstone-stability-gc-member-source","generated_at":"2026-09-29T14:49:03.205686+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Sequence and set CRDTs can only discard tombstones once every replica is guaranteed to have seen the deletion.","repair":"Iterate the live membership and treat a missing report as zero.","root_cause":"Stability iterates over replicas that reported acknowledgements instead of the live membership.","sha256":"08765a13dc75b66f547c0988791551f7b9f528ae22693fecc9f2ae4916dec8ec","title":"Tombstone garbage collection by causal stability: silent members do not block purging · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":47.221,"exit_code":1,"observations":[{"actual":{"kept":[],"purged":["x","y","z"]},"check":"all members acknowledged","expected":{"kept":[],"purged":["x","y","z"]},"passed":true},{"actual":{"kept":["z"],"purged":["x","y"]},"check":"one lagging member blocks","expected":{"kept":["z"],"purged":["x","y"]},"passed":true},{"actual":{"kept":["x","y","z"],"purged":[]},"check":"a silent member blocks","expected":{"kept":["x","y","z"],"purged":[]},"passed":true},{"actual":{"kept":[],"purged":["x","y","z"]},"check":"departed members do not block","expected":{"kept":[],"purged":["x","y","z"]},"passed":true},{"actual":{"kept":["x","y","z"],"purged":[]},"check":"departed member stale report is ignored","expected":{"kept":[],"purged":["x","y","z"]},"passed":false},{"actual":{"kept":[],"purged":["q"]},"check":"ack exactly equal to the tombstone","expected":{"kept":[],"purged":["q"]},"passed":true},{"actual":{"kept":["q"],"purged":[]},"check":"ack one below the tombstone","expected":{"kept":["q"],"purged":[]},"passed":true},{"actual":{"kept":["x","y","z"],"purged":[]},"check":"observer outside membership is ignored","expected":{"kept":[],"purged":["x","y","z"]},"passed":false},{"actual":{"kept":["m"],"purged":[]},"check":"majority is not enough","expected":{"kept":["m"],"purged":[]},"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"all members acknowledged\", \"actual\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"expected\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"passed\": true}, {\"check\": \"one lagging member blocks\", \"actual\": {\"purged\": [\"x\", \"y\"], \"kept\": [\"z\"]}, \"expected\": {\"purged\": [\"x\", \"y\"], \"kept\": [\"z\"]}, \"passed\": true}, {\"check\": \"a silent member blocks\", \"actual\": {\"purged\": [], \"kept\": [\"x\", \"y\", \"z\"]}, \"expected\": {\"purged\": [], \"kept\": [\"x\", \"y\", \"z\"]}, \"passed\": true}, {\"check\": \"departed members do not block\", \"actual\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"expected\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"passed\": true}, {\"check\": \"departed member stale report is ignored\", \"actual\": {\"purged\": [], \"kept\": [\"x\", \"y\", \"z\"]}, \"expected\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"passed\": false}, {\"check\": \"ack exactly equal to the tombstone\", \"actual\": {\"purged\": [\"q\"], \"kept\": []}, \"expected\": {\"purged\": [\"q\"], \"kept\": []}, \"passed\": true}, {\"check\": \"ack one below the tombstone\", \"actual\": {\"purged\": [], \"kept\": [\"q\"]}, \"expected\": {\"purged\": [], \"kept\": [\"q\"]}, \"passed\": true}, {\"check\": \"observer outside membership is ignored\", \"actual\": {\"purged\": [], \"kept\": [\"x\", \"y\", \"z\"]}, \"expected\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"passed\": false}, {\"check\": \"majority is not enough\", \"actual\": {\"purged\": [], \"kept\": [\"m\"]}, \"expected\": {\"purged\": [], \"kept\": [\"m\"]}, \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":44.919,"exit_code":1,"observations":[{"actual":{"kept":[],"purged":["x","y","z"]},"check":"all members acknowledged","expected":{"kept":[],"purged":["x","y","z"]},"passed":true},{"actual":{"kept":["z"],"purged":["x","y"]},"check":"one lagging member blocks","expected":{"kept":["z"],"purged":["x","y"]},"passed":true},{"actual":{"kept":[],"purged":["x","y","z"]},"check":"a silent member blocks","expected":{"kept":["x","y","z"],"purged":[]},"passed":false},{"actual":{"kept":[],"purged":["x","y","z"]},"check":"departed members do not block","expected":{"kept":[],"purged":["x","y","z"]},"passed":true},{"actual":{"kept":[],"purged":["x","y","z"]},"check":"departed member stale report is ignored","expected":{"kept":[],"purged":["x","y","z"]},"passed":true},{"actual":{"kept":[],"purged":["q"]},"check":"ack exactly equal to the tombstone","expected":{"kept":[],"purged":["q"]},"passed":true},{"actual":{"kept":["q"],"purged":[]},"check":"ack one below the tombstone","expected":{"kept":["q"],"purged":[]},"passed":true},{"actual":{"kept":["x","y","z"],"purged":[]},"check":"observer outside membership is ignored","expected":{"kept":[],"purged":["x","y","z"]},"passed":false},{"actual":{"kept":["m"],"purged":[]},"check":"majority is not enough","expected":{"kept":["m"],"purged":[]},"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"all members acknowledged\", \"actual\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"expected\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"passed\": true}, {\"check\": \"one lagging member blocks\", \"actual\": {\"purged\": [\"x\", \"y\"], \"kept\": [\"z\"]}, \"expected\": {\"purged\": [\"x\", \"y\"], \"kept\": [\"z\"]}, \"passed\": true}, {\"check\": \"a silent member blocks\", \"actual\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"expected\": {\"purged\": [], \"kept\": [\"x\", \"y\", \"z\"]}, \"passed\": false}, {\"check\": \"departed members do not block\", \"actual\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"expected\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"passed\": true}, {\"check\": \"departed member stale report is ignored\", \"actual\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"expected\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"passed\": true}, {\"check\": \"ack exactly equal to the tombstone\", \"actual\": {\"purged\": [\"q\"], \"kept\": []}, \"expected\": {\"purged\": [\"q\"], \"kept\": []}, \"passed\": true}, {\"check\": \"ack one below the tombstone\", \"actual\": {\"purged\": [], \"kept\": [\"q\"]}, \"expected\": {\"purged\": [], \"kept\": [\"q\"]}, \"passed\": true}, {\"check\": \"observer outside membership is ignored\", \"actual\": {\"purged\": [], \"kept\": [\"x\", \"y\", \"z\"]}, \"expected\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"passed\": false}, {\"check\": \"majority is not enough\", \"actual\": {\"purged\": [], \"kept\": [\"m\"]}, \"expected\": {\"purged\": [], \"kept\": [\"m\"]}, \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":43.958,"exit_code":0,"observations":[{"actual":{"kept":[],"purged":["x","y","z"]},"check":"all members acknowledged","expected":{"kept":[],"purged":["x","y","z"]},"passed":true},{"actual":{"kept":["z"],"purged":["x","y"]},"check":"one lagging member blocks","expected":{"kept":["z"],"purged":["x","y"]},"passed":true},{"actual":{"kept":["x","y","z"],"purged":[]},"check":"a silent member blocks","expected":{"kept":["x","y","z"],"purged":[]},"passed":true},{"actual":{"kept":[],"purged":["x","y","z"]},"check":"departed members do not block","expected":{"kept":[],"purged":["x","y","z"]},"passed":true},{"actual":{"kept":[],"purged":["x","y","z"]},"check":"departed member stale report is ignored","expected":{"kept":[],"purged":["x","y","z"]},"passed":true},{"actual":{"kept":[],"purged":["q"]},"check":"ack exactly equal to the tombstone","expected":{"kept":[],"purged":["q"]},"passed":true},{"actual":{"kept":["q"],"purged":[]},"check":"ack one below the tombstone","expected":{"kept":["q"],"purged":[]},"passed":true},{"actual":{"kept":[],"purged":["x","y","z"]},"check":"observer outside membership is ignored","expected":{"kept":[],"purged":["x","y","z"]},"passed":true},{"actual":{"kept":["m"],"purged":[]},"check":"majority is not enough","expected":{"kept":["m"],"purged":[]},"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"all members acknowledged\", \"actual\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"expected\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"passed\": true}, {\"check\": \"one lagging member blocks\", \"actual\": {\"purged\": [\"x\", \"y\"], \"kept\": [\"z\"]}, \"expected\": {\"purged\": [\"x\", \"y\"], \"kept\": [\"z\"]}, \"passed\": true}, {\"check\": \"a silent member blocks\", \"actual\": {\"purged\": [], \"kept\": [\"x\", \"y\", \"z\"]}, \"expected\": {\"purged\": [], \"kept\": [\"x\", \"y\", \"z\"]}, \"passed\": true}, {\"check\": \"departed members do not block\", \"actual\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"expected\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"passed\": true}, {\"check\": \"departed member stale report is ignored\", \"actual\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"expected\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"passed\": true}, {\"check\": \"ack exactly equal to the tombstone\", \"actual\": {\"purged\": [\"q\"], \"kept\": []}, \"expected\": {\"purged\": [\"q\"], \"kept\": []}, \"passed\": true}, {\"check\": \"ack one below the tombstone\", \"actual\": {\"purged\": [], \"kept\": [\"q\"]}, \"expected\": {\"purged\": [], \"kept\": [\"q\"]}, \"passed\": true}, {\"check\": \"observer outside membership is ignored\", \"actual\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"expected\": {\"purged\": [\"x\", \"y\", \"z\"], \"kept\": []}, \"passed\": true}, {\"check\": \"majority is not enough\", \"actual\": {\"purged\": [], \"kept\": [\"m\"]}, \"expected\": {\"purged\": [], \"kept\": [\"m\"]}, \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}