{"abstract":"A peer silent for exactly the timeout remains visible one tick too long.","category":"CRDT convergence","checks":9,"contract":"Presence updates [\"update\", client, clock, state|None, now] are accepted when clock exceeds the last accepted clock for that client, or when it equals it, the state is None and the client is present. Accepted updates record the clock; a None state removes the client (logging a removal only if it was present); otherwise [state, now] is stored. [\"tick\", now] removes, in client order, every client other than self_id whose last update is at least timeout old. Return present [client, state] pairs and the removal log.","contract_signature":"events, self_id, timeout","evaluation_group":"w2-crdt-convergence-awareness-presence","failed_approach":"Measuring age against the presence clock instead of the arrival time mixes a logical counter with wall time.","family":"w2-crdt-convergence-awareness-presence-timeout-boundary","id":"FA-75281","implementations":{"attempt":{"sha256":"7dde383efbcfc70c711a05cfecca9e3da83e761e4c834a1cc93299d26e5feded","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(events, self_id, timeout):\n    table = {}\n    clocks = {}\n    removed = []\n    for ev in events:\n        if ev[0] == 'update':\n            _, c, clk, st, now = ev\n            cur = clocks.get(c, -1)\n            if clk > cur or (clk == cur and st is None and c in table):\n                clocks[c] = clk\n                if st is None:\n                    if table.pop(c, None) is not None:\n                        removed.append(c)\n                else:\n                    table[c] = [st, now]\n        else:\n            now = ev[1]\n            for c in sorted(table):\n                if c != self_id and now - clocks[c] >= timeout:\n                    del table[c]\n                    removed.append(c)\n    return {'present': sorted([c, v[0]] for c, v in table.items()), 'removed': removed}\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = {\n    1: [('newer update replaces', [[['update', 'c1', 1, 'idle', 0], ['update', 'c1', 2, 'typing', 5]], 'me1', 30], {'present': [['c1', 'typing']], 'removed': []}), ('stale update after timeout is rejected', [[['update', 'c1', 3, 'on', 0], ['tick', 30], ['update', 'c1', 3, 'on', 31], ['update', 'c1', 2, 'old', 32]], 'me1', 30], {'present': [], 'removed': ['c1']}), ('offline notice at the same clock removes', [[['update', 'c2', 1, 'on', 0], ['update', 'c2', 1, None, 1]], 'me1', 30], {'present': [], 'removed': ['c2']}), ('same-clock state change is ignored', [[['update', 'c2', 1, 'on', 0], ['update', 'c2', 1, 'changed', 1]], 'me1', 30], {'present': [['c2', 'on']], 'removed': []}), ('timeout boundary', [[['update', 'c3', 1, 'x', 10], ['tick', 39], ['update', 'c4', 1, 'y', 20], ['tick', 40]], 'me1', 30], {'present': [['c4', 'y']], 'removed': ['c3']}), ('own state never expires', [[['update', 'me1', 1, 'self', 0], ['tick', 500], ['update', 'me', 7, 'other', 490], ['tick', 600]], 'me1', 30], {'present': [['me1', 'self']], 'removed': ['me']}), ('activity refreshes the timer', [[['update', 'c5', 1, 'a', 0], ['update', 'c5', 2, 'b', 25], ['tick', 40]], 'me1', 30], {'present': [['c5', 'b']], 'removed': []}), ('offline notice for an unknown client', [[['update', 'c6', 4, None, 0], ['update', 'c6', 3, 'late', 1], ['update', 'c7', 1, 'on', 2], ['update', 'c7', 2, None, 3], ['update', 'c7', 2, None, 4]], 'me1', 30], {'present': [], 'removed': ['c7']}), ('large clocks and short timeout', [[['update', 'c8', 101, 's', 3], ['tick', 5], ['tick', 13]], 'me1', 10], {'present': [], 'removed': ['c8']})],\n    2: [('newer update replaces', [[['update', 'c1', 1, 'idle', 0], ['update', 'c1', 2, 'typing', 5]], 'me2', 30], {'present': [['c1', 'typing']], 'removed': []}), ('stale update after timeout is rejected', [[['update', 'c1', 3, 'on', 0], ['tick', 30], ['update', 'c1', 3, 'on', 31], ['update', 'c1', 2, 'old', 32]], 'me2', 30], {'present': [], 'removed': ['c1']}), ('offline notice at the same clock removes', [[['update', 'c2', 2, 'on', 0], ['update', 'c2', 2, None, 1]], 'me2', 30], {'present': [], 'removed': ['c2']}), ('same-clock state change is ignored', [[['update', 'c2', 2, 'on', 0], ['update', 'c2', 2, 'changed', 1]], 'me2', 30], {'present': [['c2', 'on']], 'removed': []}), ('timeout boundary', [[['update', 'c3', 1, 'x', 10], ['tick', 39], ['update', 'c4', 1, 'y', 20], ['tick', 40]], 'me2', 30], {'present': [['c4', 'y']], 'removed': ['c3']}), ('own state never expires', [[['update', 'me2', 1, 'self', 0], ['tick', 500], ['update', 'me', 7, 'other', 490], ['tick', 600]], 'me2', 30], {'present': [['me2', 'self']], 'removed': ['me']}), ('activity refreshes the timer', [[['update', 'c5', 1, 'a', 0], ['update', 'c5', 2, 'b', 25], ['tick', 40]], 'me2', 30], {'present': [['c5', 'b']], 'removed': []}), ('offline notice for an unknown client', [[['update', 'c6', 4, None, 0], ['update', 'c6', 3, 'late', 1], ['update', 'c7', 1, 'on', 2], ['update', 'c7', 2, None, 3], ['update', 'c7', 2, None, 4]], 'me2', 30], {'present': [], 'removed': ['c7']}), ('large clocks and short timeout', [[['update', 'c8', 102, 's', 3], ['tick', 5], ['tick', 13]], 'me2', 10], {'present': [], 'removed': ['c8']})],\n    3: [('newer update replaces', [[['update', 'c1', 1, 'idle', 0], ['update', 'c1', 2, 'typing', 5]], 'me3', 30], {'present': [['c1', 'typing']], 'removed': []}), ('stale update after timeout is rejected', [[['update', 'c1', 3, 'on', 0], ['tick', 30], ['update', 'c1', 3, 'on', 31], ['update', 'c1', 2, 'old', 32]], 'me3', 30], {'present': [], 'removed': ['c1']}), ('offline notice at the same clock removes', [[['update', 'c2', 3, 'on', 0], ['update', 'c2', 3, None, 1]], 'me3', 30], {'present': [], 'removed': ['c2']}), ('same-clock state change is ignored', [[['update', 'c2', 3, 'on', 0], ['update', 'c2', 3, 'changed', 1]], 'me3', 30], {'present': [['c2', 'on']], 'removed': []}), ('timeout boundary', [[['update', 'c3', 1, 'x', 10], ['tick', 39], ['update', 'c4', 1, 'y', 20], ['tick', 40]], 'me3', 30], {'present': [['c4', 'y']], 'removed': ['c3']}), ('own state never expires', [[['update', 'me3', 1, 'self', 0], ['tick', 500], ['update', 'me', 7, 'other', 490], ['tick', 600]], 'me3', 30], {'present': [['me3', 'self']], 'removed': ['me']}), ('activity refreshes the timer', [[['update', 'c5', 1, 'a', 0], ['update', 'c5', 2, 'b', 25], ['tick', 40]], 'me3', 30], {'present': [['c5', 'b']], 'removed': []}), ('offline notice for an unknown client', [[['update', 'c6', 4, None, 0], ['update', 'c6', 3, 'late', 1], ['update', 'c7', 1, 'on', 2], ['update', 'c7', 2, None, 3], ['update', 'c7', 2, None, 4]], 'me3', 30], {'present': [], 'removed': ['c7']}), ('large clocks and short timeout', [[['update', 'c8', 103, 's', 3], ['tick', 5], ['tick', 13]], 'me3', 10], {'present': [], 'removed': ['c8']})],\n    4: [('newer update replaces', [[['update', 'c1', 1, 'idle', 0], ['update', 'c1', 2, 'typing', 5]], 'me4', 30], {'present': [['c1', 'typing']], 'removed': []}), ('stale update after timeout is rejected', [[['update', 'c1', 3, 'on', 0], ['tick', 30], ['update', 'c1', 3, 'on', 31], ['update', 'c1', 2, 'old', 32]], 'me4', 30], {'present': [], 'removed': ['c1']}), ('offline notice at the same clock removes', [[['update', 'c2', 4, 'on', 0], ['update', 'c2', 4, None, 1]], 'me4', 30], {'present': [], 'removed': ['c2']}), ('same-clock state change is ignored', [[['update', 'c2', 4, 'on', 0], ['update', 'c2', 4, 'changed', 1]], 'me4', 30], {'present': [['c2', 'on']], 'removed': []}), ('timeout boundary', [[['update', 'c3', 1, 'x', 10], ['tick', 39], ['update', 'c4', 1, 'y', 20], ['tick', 40]], 'me4', 30], {'present': [['c4', 'y']], 'removed': ['c3']}), ('own state never expires', [[['update', 'me4', 1, 'self', 0], ['tick', 500], ['update', 'me', 7, 'other', 490], ['tick', 600]], 'me4', 30], {'present': [['me4', 'self']], 'removed': ['me']}), ('activity refreshes the timer', [[['update', 'c5', 1, 'a', 0], ['update', 'c5', 2, 'b', 25], ['tick', 40]], 'me4', 30], {'present': [['c5', 'b']], 'removed': []}), ('offline notice for an unknown client', [[['update', 'c6', 4, None, 0], ['update', 'c6', 3, 'late', 1], ['update', 'c7', 1, 'on', 2], ['update', 'c7', 2, None, 3], ['update', 'c7', 2, None, 4]], 'me4', 30], {'present': [], 'removed': ['c7']}), ('large clocks and short timeout', [[['update', 'c8', 104, 's', 3], ['tick', 5], ['tick', 13]], 'me4', 10], {'present': [], 'removed': ['c8']})],\n    5: [('newer update replaces', [[['update', 'c1', 1, 'idle', 0], ['update', 'c1', 2, 'typing', 5]], 'me5', 30], {'present': [['c1', 'typing']], 'removed': []}), ('stale update after timeout is rejected', [[['update', 'c1', 3, 'on', 0], ['tick', 30], ['update', 'c1', 3, 'on', 31], ['update', 'c1', 2, 'old', 32]], 'me5', 30], {'present': [], 'removed': ['c1']}), ('offline notice at the same clock removes', [[['update', 'c2', 5, 'on', 0], ['update', 'c2', 5, None, 1]], 'me5', 30], {'present': [], 'removed': ['c2']}), ('same-clock state change is ignored', [[['update', 'c2', 5, 'on', 0], ['update', 'c2', 5, 'changed', 1]], 'me5', 30], {'present': [['c2', 'on']], 'removed': []}), ('timeout boundary', [[['update', 'c3', 1, 'x', 10], ['tick', 39], ['update', 'c4', 1, 'y', 20], ['tick', 40]], 'me5', 30], {'present': [['c4', 'y']], 'removed': ['c3']}), ('own state never expires', [[['update', 'me5', 1, 'self', 0], ['tick', 500], ['update', 'me', 7, 'other', 490], ['tick', 600]], 'me5', 30], {'present': [['me5', 'self']], 'removed': ['me']}), ('activity refreshes the timer', [[['update', 'c5', 1, 'a', 0], ['update', 'c5', 2, 'b', 25], ['tick', 40]], 'me5', 30], {'present': [['c5', 'b']], 'removed': []}), ('offline notice for an unknown client', [[['update', 'c6', 4, None, 0], ['update', 'c6', 3, 'late', 1], ['update', 'c7', 1, 'on', 2], ['update', 'c7', 2, None, 3], ['update', 'c7', 2, None, 4]], 'me5', 30], {'present': [], 'removed': ['c7']}), ('large clocks and short timeout', [[['update', 'c8', 105, 's', 3], ['tick', 5], ['tick', 13]], 'me5', 10], {'present': [], 'removed': ['c8']})],\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":"a57505d0e483f4c31b4bf71c75826933fef927a68b52015ce0971dd72d3ac07c","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(events, self_id, timeout):\n    table = {}\n    clocks = {}\n    removed = []\n    for ev in events:\n        if ev[0] == 'update':\n            _, c, clk, st, now = ev\n            cur = clocks.get(c, -1)\n            if clk > cur or (clk == cur and st is None and c in table):\n                clocks[c] = clk\n                if st is None:\n                    if table.pop(c, None) is not None:\n                        removed.append(c)\n                else:\n                    table[c] = [st, now]\n        else:\n            now = ev[1]\n            for c in sorted(table):\n                if c != self_id and now - table[c][1] > timeout:\n                    del table[c]\n                    removed.append(c)\n    return {'present': sorted([c, v[0]] for c, v in table.items()), 'removed': removed}\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = {\n    1: [('newer update replaces', [[['update', 'c1', 1, 'idle', 0], ['update', 'c1', 2, 'typing', 5]], 'me1', 30], {'present': [['c1', 'typing']], 'removed': []}), ('stale update after timeout is rejected', [[['update', 'c1', 3, 'on', 0], ['tick', 30], ['update', 'c1', 3, 'on', 31], ['update', 'c1', 2, 'old', 32]], 'me1', 30], {'present': [], 'removed': ['c1']}), ('offline notice at the same clock removes', [[['update', 'c2', 1, 'on', 0], ['update', 'c2', 1, None, 1]], 'me1', 30], {'present': [], 'removed': ['c2']}), ('same-clock state change is ignored', [[['update', 'c2', 1, 'on', 0], ['update', 'c2', 1, 'changed', 1]], 'me1', 30], {'present': [['c2', 'on']], 'removed': []}), ('timeout boundary', [[['update', 'c3', 1, 'x', 10], ['tick', 39], ['update', 'c4', 1, 'y', 20], ['tick', 40]], 'me1', 30], {'present': [['c4', 'y']], 'removed': ['c3']}), ('own state never expires', [[['update', 'me1', 1, 'self', 0], ['tick', 500], ['update', 'me', 7, 'other', 490], ['tick', 600]], 'me1', 30], {'present': [['me1', 'self']], 'removed': ['me']}), ('activity refreshes the timer', [[['update', 'c5', 1, 'a', 0], ['update', 'c5', 2, 'b', 25], ['tick', 40]], 'me1', 30], {'present': [['c5', 'b']], 'removed': []}), ('offline notice for an unknown client', [[['update', 'c6', 4, None, 0], ['update', 'c6', 3, 'late', 1], ['update', 'c7', 1, 'on', 2], ['update', 'c7', 2, None, 3], ['update', 'c7', 2, None, 4]], 'me1', 30], {'present': [], 'removed': ['c7']}), ('large clocks and short timeout', [[['update', 'c8', 101, 's', 3], ['tick', 5], ['tick', 13]], 'me1', 10], {'present': [], 'removed': ['c8']})],\n    2: [('newer update replaces', [[['update', 'c1', 1, 'idle', 0], ['update', 'c1', 2, 'typing', 5]], 'me2', 30], {'present': [['c1', 'typing']], 'removed': []}), ('stale update after timeout is rejected', [[['update', 'c1', 3, 'on', 0], ['tick', 30], ['update', 'c1', 3, 'on', 31], ['update', 'c1', 2, 'old', 32]], 'me2', 30], {'present': [], 'removed': ['c1']}), ('offline notice at the same clock removes', [[['update', 'c2', 2, 'on', 0], ['update', 'c2', 2, None, 1]], 'me2', 30], {'present': [], 'removed': ['c2']}), ('same-clock state change is ignored', [[['update', 'c2', 2, 'on', 0], ['update', 'c2', 2, 'changed', 1]], 'me2', 30], {'present': [['c2', 'on']], 'removed': []}), ('timeout boundary', [[['update', 'c3', 1, 'x', 10], ['tick', 39], ['update', 'c4', 1, 'y', 20], ['tick', 40]], 'me2', 30], {'present': [['c4', 'y']], 'removed': ['c3']}), ('own state never expires', [[['update', 'me2', 1, 'self', 0], ['tick', 500], ['update', 'me', 7, 'other', 490], ['tick', 600]], 'me2', 30], {'present': [['me2', 'self']], 'removed': ['me']}), ('activity refreshes the timer', [[['update', 'c5', 1, 'a', 0], ['update', 'c5', 2, 'b', 25], ['tick', 40]], 'me2', 30], {'present': [['c5', 'b']], 'removed': []}), ('offline notice for an unknown client', [[['update', 'c6', 4, None, 0], ['update', 'c6', 3, 'late', 1], ['update', 'c7', 1, 'on', 2], ['update', 'c7', 2, None, 3], ['update', 'c7', 2, None, 4]], 'me2', 30], {'present': [], 'removed': ['c7']}), ('large clocks and short timeout', [[['update', 'c8', 102, 's', 3], ['tick', 5], ['tick', 13]], 'me2', 10], {'present': [], 'removed': ['c8']})],\n    3: [('newer update replaces', [[['update', 'c1', 1, 'idle', 0], ['update', 'c1', 2, 'typing', 5]], 'me3', 30], {'present': [['c1', 'typing']], 'removed': []}), ('stale update after timeout is rejected', [[['update', 'c1', 3, 'on', 0], ['tick', 30], ['update', 'c1', 3, 'on', 31], ['update', 'c1', 2, 'old', 32]], 'me3', 30], {'present': [], 'removed': ['c1']}), ('offline notice at the same clock removes', [[['update', 'c2', 3, 'on', 0], ['update', 'c2', 3, None, 1]], 'me3', 30], {'present': [], 'removed': ['c2']}), ('same-clock state change is ignored', [[['update', 'c2', 3, 'on', 0], ['update', 'c2', 3, 'changed', 1]], 'me3', 30], {'present': [['c2', 'on']], 'removed': []}), ('timeout boundary', [[['update', 'c3', 1, 'x', 10], ['tick', 39], ['update', 'c4', 1, 'y', 20], ['tick', 40]], 'me3', 30], {'present': [['c4', 'y']], 'removed': ['c3']}), ('own state never expires', [[['update', 'me3', 1, 'self', 0], ['tick', 500], ['update', 'me', 7, 'other', 490], ['tick', 600]], 'me3', 30], {'present': [['me3', 'self']], 'removed': ['me']}), ('activity refreshes the timer', [[['update', 'c5', 1, 'a', 0], ['update', 'c5', 2, 'b', 25], ['tick', 40]], 'me3', 30], {'present': [['c5', 'b']], 'removed': []}), ('offline notice for an unknown client', [[['update', 'c6', 4, None, 0], ['update', 'c6', 3, 'late', 1], ['update', 'c7', 1, 'on', 2], ['update', 'c7', 2, None, 3], ['update', 'c7', 2, None, 4]], 'me3', 30], {'present': [], 'removed': ['c7']}), ('large clocks and short timeout', [[['update', 'c8', 103, 's', 3], ['tick', 5], ['tick', 13]], 'me3', 10], {'present': [], 'removed': ['c8']})],\n    4: [('newer update replaces', [[['update', 'c1', 1, 'idle', 0], ['update', 'c1', 2, 'typing', 5]], 'me4', 30], {'present': [['c1', 'typing']], 'removed': []}), ('stale update after timeout is rejected', [[['update', 'c1', 3, 'on', 0], ['tick', 30], ['update', 'c1', 3, 'on', 31], ['update', 'c1', 2, 'old', 32]], 'me4', 30], {'present': [], 'removed': ['c1']}), ('offline notice at the same clock removes', [[['update', 'c2', 4, 'on', 0], ['update', 'c2', 4, None, 1]], 'me4', 30], {'present': [], 'removed': ['c2']}), ('same-clock state change is ignored', [[['update', 'c2', 4, 'on', 0], ['update', 'c2', 4, 'changed', 1]], 'me4', 30], {'present': [['c2', 'on']], 'removed': []}), ('timeout boundary', [[['update', 'c3', 1, 'x', 10], ['tick', 39], ['update', 'c4', 1, 'y', 20], ['tick', 40]], 'me4', 30], {'present': [['c4', 'y']], 'removed': ['c3']}), ('own state never expires', [[['update', 'me4', 1, 'self', 0], ['tick', 500], ['update', 'me', 7, 'other', 490], ['tick', 600]], 'me4', 30], {'present': [['me4', 'self']], 'removed': ['me']}), ('activity refreshes the timer', [[['update', 'c5', 1, 'a', 0], ['update', 'c5', 2, 'b', 25], ['tick', 40]], 'me4', 30], {'present': [['c5', 'b']], 'removed': []}), ('offline notice for an unknown client', [[['update', 'c6', 4, None, 0], ['update', 'c6', 3, 'late', 1], ['update', 'c7', 1, 'on', 2], ['update', 'c7', 2, None, 3], ['update', 'c7', 2, None, 4]], 'me4', 30], {'present': [], 'removed': ['c7']}), ('large clocks and short timeout', [[['update', 'c8', 104, 's', 3], ['tick', 5], ['tick', 13]], 'me4', 10], {'present': [], 'removed': ['c8']})],\n    5: [('newer update replaces', [[['update', 'c1', 1, 'idle', 0], ['update', 'c1', 2, 'typing', 5]], 'me5', 30], {'present': [['c1', 'typing']], 'removed': []}), ('stale update after timeout is rejected', [[['update', 'c1', 3, 'on', 0], ['tick', 30], ['update', 'c1', 3, 'on', 31], ['update', 'c1', 2, 'old', 32]], 'me5', 30], {'present': [], 'removed': ['c1']}), ('offline notice at the same clock removes', [[['update', 'c2', 5, 'on', 0], ['update', 'c2', 5, None, 1]], 'me5', 30], {'present': [], 'removed': ['c2']}), ('same-clock state change is ignored', [[['update', 'c2', 5, 'on', 0], ['update', 'c2', 5, 'changed', 1]], 'me5', 30], {'present': [['c2', 'on']], 'removed': []}), ('timeout boundary', [[['update', 'c3', 1, 'x', 10], ['tick', 39], ['update', 'c4', 1, 'y', 20], ['tick', 40]], 'me5', 30], {'present': [['c4', 'y']], 'removed': ['c3']}), ('own state never expires', [[['update', 'me5', 1, 'self', 0], ['tick', 500], ['update', 'me', 7, 'other', 490], ['tick', 600]], 'me5', 30], {'present': [['me5', 'self']], 'removed': ['me']}), ('activity refreshes the timer', [[['update', 'c5', 1, 'a', 0], ['update', 'c5', 2, 'b', 25], ['tick', 40]], 'me5', 30], {'present': [['c5', 'b']], 'removed': []}), ('offline notice for an unknown client', [[['update', 'c6', 4, None, 0], ['update', 'c6', 3, 'late', 1], ['update', 'c7', 1, 'on', 2], ['update', 'c7', 2, None, 3], ['update', 'c7', 2, None, 4]], 'me5', 30], {'present': [], 'removed': ['c7']}), ('large clocks and short timeout', [[['update', 'c8', 105, 's', 3], ['tick', 5], ['tick', 13]], 'me5', 10], {'present': [], 'removed': ['c8']})],\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-awareness-presence-timeout-boundary","generated_at":"2026-09-29T14:49:05.176672+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Ephemeral presence rides alongside document CRDTs and must neither resurrect departed peers nor expire the local user.","root_cause":"Expiry uses a strict comparison with the timeout.","sha256":"eb0c576eb287bf833946b4218cd79a31da97778a4174b413577b4dc39afd95eb","title":"Awareness presence table: a client exactly at the timeout is kept · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verified":true,"visibility":"public","verification":{"attempt":{"elapsed_ms":87.041,"exit_code":1,"observations":[{"actual":{"present":[["c1","typing"]],"removed":[]},"check":"newer update replaces","expected":{"present":[["c1","typing"]],"removed":[]},"passed":true},{"actual":{"present":[["c1","on"]],"removed":[]},"check":"stale update after timeout is rejected","expected":{"present":[],"removed":["c1"]},"passed":false},{"actual":{"present":[],"removed":["c2"]},"check":"offline notice at the same clock removes","expected":{"present":[],"removed":["c2"]},"passed":true},{"actual":{"present":[["c2","on"]],"removed":[]},"check":"same-clock state change is ignored","expected":{"present":[["c2","on"]],"removed":[]},"passed":true},{"actual":{"present":[],"removed":["c3","c4"]},"check":"timeout boundary","expected":{"present":[["c4","y"]],"removed":["c3"]},"passed":false},{"actual":{"present":[["me1","self"]],"removed":["me"]},"check":"own state never expires","expected":{"present":[["me1","self"]],"removed":["me"]},"passed":true},{"actual":{"present":[],"removed":["c5"]},"check":"activity refreshes the timer","expected":{"present":[["c5","b"]],"removed":[]},"passed":false},{"actual":{"present":[],"removed":["c7"]},"check":"offline notice for an unknown client","expected":{"present":[],"removed":["c7"]},"passed":true},{"actual":{"present":[["c8","s"]],"removed":[]},"check":"large clocks and short timeout","expected":{"present":[],"removed":["c8"]},"passed":false}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"newer update replaces\", \"actual\": {\"present\": [[\"c1\", \"typing\"]], \"removed\": []}, \"expected\": {\"present\": [[\"c1\", \"typing\"]], \"removed\": []}, \"passed\": true}, {\"check\": \"stale update after timeout is rejected\", \"actual\": {\"present\": [[\"c1\", \"on\"]], \"removed\": []}, \"expected\": {\"present\": [], \"removed\": [\"c1\"]}, \"passed\": false}, {\"check\": \"offline notice at the same clock removes\", \"actual\": {\"present\": [], \"removed\": [\"c2\"]}, \"expected\": {\"present\": [], \"removed\": [\"c2\"]}, \"passed\": true}, {\"check\": \"same-clock state change is ignored\", \"actual\": {\"present\": [[\"c2\", \"on\"]], \"removed\": []}, \"expected\": {\"present\": [[\"c2\", \"on\"]], \"removed\": []}, \"passed\": true}, {\"check\": \"timeout boundary\", \"actual\": {\"present\": [], \"removed\": [\"c3\", \"c4\"]}, \"expected\": {\"present\": [[\"c4\", \"y\"]], \"removed\": [\"c3\"]}, \"passed\": false}, {\"check\": \"own state never expires\", \"actual\": {\"present\": [[\"me1\", \"self\"]], \"removed\": [\"me\"]}, \"expected\": {\"present\": [[\"me1\", \"self\"]], \"removed\": [\"me\"]}, \"passed\": true}, {\"check\": \"activity refreshes the timer\", \"actual\": {\"present\": [], \"removed\": [\"c5\"]}, \"expected\": {\"present\": [[\"c5\", \"b\"]], \"removed\": []}, \"passed\": false}, {\"check\": \"offline notice for an unknown client\", \"actual\": {\"present\": [], \"removed\": [\"c7\"]}, \"expected\": {\"present\": [], \"removed\": [\"c7\"]}, \"passed\": true}, {\"check\": \"large clocks and short timeout\", \"actual\": {\"present\": [[\"c8\", \"s\"]], \"removed\": []}, \"expected\": {\"present\": [], \"removed\": [\"c8\"]}, \"passed\": false}], \"passed\": false}\n"},"broken":{"elapsed_ms":59.234,"exit_code":1,"observations":[{"actual":{"present":[["c1","typing"]],"removed":[]},"check":"newer update replaces","expected":{"present":[["c1","typing"]],"removed":[]},"passed":true},{"actual":{"present":[["c1","on"]],"removed":[]},"check":"stale update after timeout is rejected","expected":{"present":[],"removed":["c1"]},"passed":false},{"actual":{"present":[],"removed":["c2"]},"check":"offline notice at the same clock removes","expected":{"present":[],"removed":["c2"]},"passed":true},{"actual":{"present":[["c2","on"]],"removed":[]},"check":"same-clock state change is ignored","expected":{"present":[["c2","on"]],"removed":[]},"passed":true},{"actual":{"present":[["c3","x"],["c4","y"]],"removed":[]},"check":"timeout boundary","expected":{"present":[["c4","y"]],"removed":["c3"]},"passed":false},{"actual":{"present":[["me1","self"]],"removed":["me"]},"check":"own state never expires","expected":{"present":[["me1","self"]],"removed":["me"]},"passed":true},{"actual":{"present":[["c5","b"]],"removed":[]},"check":"activity refreshes the timer","expected":{"present":[["c5","b"]],"removed":[]},"passed":true},{"actual":{"present":[],"removed":["c7"]},"check":"offline notice for an unknown client","expected":{"present":[],"removed":["c7"]},"passed":true},{"actual":{"present":[["c8","s"]],"removed":[]},"check":"large clocks and short timeout","expected":{"present":[],"removed":["c8"]},"passed":false}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"newer update replaces\", \"actual\": {\"present\": [[\"c1\", \"typing\"]], \"removed\": []}, \"expected\": {\"present\": [[\"c1\", \"typing\"]], \"removed\": []}, \"passed\": true}, {\"check\": \"stale update after timeout is rejected\", \"actual\": {\"present\": [[\"c1\", \"on\"]], \"removed\": []}, \"expected\": {\"present\": [], \"removed\": [\"c1\"]}, \"passed\": false}, {\"check\": \"offline notice at the same clock removes\", \"actual\": {\"present\": [], \"removed\": [\"c2\"]}, \"expected\": {\"present\": [], \"removed\": [\"c2\"]}, \"passed\": true}, {\"check\": \"same-clock state change is ignored\", \"actual\": {\"present\": [[\"c2\", \"on\"]], \"removed\": []}, \"expected\": {\"present\": [[\"c2\", \"on\"]], \"removed\": []}, \"passed\": true}, {\"check\": \"timeout boundary\", \"actual\": {\"present\": [[\"c3\", \"x\"], [\"c4\", \"y\"]], \"removed\": []}, \"expected\": {\"present\": [[\"c4\", \"y\"]], \"removed\": [\"c3\"]}, \"passed\": false}, {\"check\": \"own state never expires\", \"actual\": {\"present\": [[\"me1\", \"self\"]], \"removed\": [\"me\"]}, \"expected\": {\"present\": [[\"me1\", \"self\"]], \"removed\": [\"me\"]}, \"passed\": true}, {\"check\": \"activity refreshes the timer\", \"actual\": {\"present\": [[\"c5\", \"b\"]], \"removed\": []}, \"expected\": {\"present\": [[\"c5\", \"b\"]], \"removed\": []}, \"passed\": true}, {\"check\": \"offline notice for an unknown client\", \"actual\": {\"present\": [], \"removed\": [\"c7\"]}, \"expected\": {\"present\": [], \"removed\": [\"c7\"]}, \"passed\": true}, {\"check\": \"large clocks and short timeout\", \"actual\": {\"present\": [[\"c8\", \"s\"]], \"removed\": []}, \"expected\": {\"present\": [], \"removed\": [\"c8\"]}, \"passed\": false}], \"passed\": false}\n"}},"member_only":{"stages":["fixed"],"fields":["implementations.fixed","verification.fixed","harness","repair"],"note":"The verified repair, its recorded checks, the repair description, and the scoring harness are available to members."}}