{"abstract":"An emoji that disappeared and was added again keeps its old position instead of moving to the end.","category":"Chat ordering and read receipts","checks":7,"contract":"events [seq, user, emoji, action] are applied in seq order. A user holds each emoji at most once and at most `limit` distinct emoji per message; an add beyond the limit is ignored. A remove only releases a reaction the user holds. Result rows [emoji, count, mine] for emoji with at least one user, ordered by the seq at which the emoji most recently went from zero to one user.","evaluation_group":"w2-chat_ordering_and_read_receipts-reaction-aggregation","failed_approach":"Restarting when at most one user holds the emoji also moves chips when a second user joins. The attempted `if len(users) <= 1:` still disagrees with a fixture.","family":"w2-chat_ordering_and_read_receipts-reaction-aggregation-run-restart","id":"FA-76111","implementations":{"attempt":{"sha256":"78c5384d08428f40f084c78503ca977aa40f1163d3b8f33fc3a4019c717eb3fd","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(events, viewer, limit):\n    current = {}\n    first = {}\n    per_user = {}\n    for seq, user, emoji, action in sorted(events):\n        users = current.get(emoji, set())\n        if action == 'add':\n            if user in users or per_user.get(user, 0) >= limit:\n                continue\n            if len(users) <= 1:\n                first[emoji] = seq\n            users.add(user)\n            current[emoji] = users\n            per_user[user] = per_user.get(user, 0) + 1\n        elif user in users:\n            users.discard(user)\n            per_user[user] = per_user.get(user, 0) - 1\n    rows = [[e, len(u), viewer in u] for e, u in current.items() if u]\n    rows.sort(key=lambda r: first[r[0]])\n    return rows\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\n_CASES = {1: [('remove delivered before add', ([[3, 'bo', 'up', 'remove'], [2, 'bo', 'up', 'add']], 'me', 3), []), ('emoji vanishes and returns', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'bo', 'up', 'remove'], [5, 'di', 'up', 'add']], 'me', 3), [['ok', 1, False], ['up', 1, False]]), ('second user joins an emoji', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'di', 'up', 'add']], 'di', 3), [['up', 2, True], ['ok', 1, False]]), ('only reaction removed', ([[1, 'me', 'up', 'add'], [2, 'me', 'up', 'remove']], 'me', 2), []), ('limit reached', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'b', 'add'], [3, 'bo', 'c', 'add']], 'bo', 2), [['a', 1, True], ['b', 1, True]]), ('stray remove does not free a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'z', 'remove'], [3, 'bo', 'b', 'add']], 'me', 1), [['a', 1, False]]), ('removal frees a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'a', 'remove'], [3, 'bo', 'b', 'add']], 'bo', 1), [['b', 1, True]])], 2: [('remove delivered before add', ([[4, 'bo', 'up', 'remove'], [3, 'bo', 'up', 'add']], 'me', 3), []), ('emoji vanishes and returns', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'bo', 'up', 'remove'], [6, 'di', 'up', 'add']], 'me', 3), [['ok', 1, False], ['up', 1, False]]), ('second user joins an emoji', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'di', 'up', 'add']], 'di', 3), [['up', 2, True], ['ok', 1, False]]), ('only reaction removed', ([[1, 'me', 'up', 'add'], [2, 'me', 'up', 'remove']], 'me', 2), []), ('limit reached', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'b', 'add'], [3, 'bo', 'c', 'add']], 'bo', 2), [['a', 1, True], ['b', 1, True]]), ('stray remove does not free a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'z', 'remove'], [3, 'bo', 'b', 'add']], 'me', 1), [['a', 1, False]]), ('removal frees a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'a', 'remove'], [3, 'bo', 'b', 'add']], 'bo', 1), [['b', 1, True]])], 3: [('remove delivered before add', ([[5, 'bo', 'up', 'remove'], [4, 'bo', 'up', 'add']], 'me', 3), []), ('emoji vanishes and returns', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'bo', 'up', 'remove'], [7, 'di', 'up', 'add']], 'me', 3), [['ok', 1, False], ['up', 1, False]]), ('second user joins an emoji', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'di', 'up', 'add']], 'di', 3), [['up', 2, True], ['ok', 1, False]]), ('only reaction removed', ([[1, 'me', 'up', 'add'], [2, 'me', 'up', 'remove']], 'me', 2), []), ('limit reached', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'b', 'add'], [3, 'bo', 'c', 'add']], 'bo', 2), [['a', 1, True], ['b', 1, True]]), ('stray remove does not free a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'z', 'remove'], [3, 'bo', 'b', 'add']], 'me', 1), [['a', 1, False]]), ('removal frees a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'a', 'remove'], [3, 'bo', 'b', 'add']], 'bo', 1), [['b', 1, True]])], 4: [('remove delivered before add', ([[6, 'bo', 'up', 'remove'], [5, 'bo', 'up', 'add']], 'me', 3), []), ('emoji vanishes and returns', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'bo', 'up', 'remove'], [8, 'di', 'up', 'add']], 'me', 3), [['ok', 1, False], ['up', 1, False]]), ('second user joins an emoji', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'di', 'up', 'add']], 'di', 3), [['up', 2, True], ['ok', 1, False]]), ('only reaction removed', ([[1, 'me', 'up', 'add'], [2, 'me', 'up', 'remove']], 'me', 2), []), ('limit reached', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'b', 'add'], [3, 'bo', 'c', 'add']], 'bo', 2), [['a', 1, True], ['b', 1, True]]), ('stray remove does not free a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'z', 'remove'], [3, 'bo', 'b', 'add']], 'me', 1), [['a', 1, False]]), ('removal frees a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'a', 'remove'], [3, 'bo', 'b', 'add']], 'bo', 1), [['b', 1, True]])], 5: [('remove delivered before add', ([[7, 'bo', 'up', 'remove'], [6, 'bo', 'up', 'add']], 'me', 3), []), ('emoji vanishes and returns', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'bo', 'up', 'remove'], [9, 'di', 'up', 'add']], 'me', 3), [['ok', 1, False], ['up', 1, False]]), ('second user joins an emoji', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'di', 'up', 'add']], 'di', 3), [['up', 2, True], ['ok', 1, False]]), ('only reaction removed', ([[1, 'me', 'up', 'add'], [2, 'me', 'up', 'remove']], 'me', 2), []), ('limit reached', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'b', 'add'], [3, 'bo', 'c', 'add']], 'bo', 2), [['a', 1, True], ['b', 1, True]]), ('stray remove does not free a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'z', 'remove'], [3, 'bo', 'b', 'add']], 'me', 1), [['a', 1, False]]), ('removal frees a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'a', 'remove'], [3, 'bo', 'b', 'add']], 'bo', 1), [['b', 1, True]])]}\nfor _label, _args, _expected in _CASES[N]:\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":"15cbd58dbbd5549ef5e6e2068931233f9212e169467a649e62f37f97fc1f23de","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(events, viewer, limit):\n    current = {}\n    first = {}\n    per_user = {}\n    for seq, user, emoji, action in sorted(events):\n        users = current.get(emoji, set())\n        if action == 'add':\n            if user in users or per_user.get(user, 0) >= limit:\n                continue\n            if emoji not in first:\n                first[emoji] = seq\n            users.add(user)\n            current[emoji] = users\n            per_user[user] = per_user.get(user, 0) + 1\n        elif user in users:\n            users.discard(user)\n            per_user[user] = per_user.get(user, 0) - 1\n    rows = [[e, len(u), viewer in u] for e, u in current.items() if u]\n    rows.sort(key=lambda r: first[r[0]])\n    return rows\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\n_CASES = {1: [('remove delivered before add', ([[3, 'bo', 'up', 'remove'], [2, 'bo', 'up', 'add']], 'me', 3), []), ('emoji vanishes and returns', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'bo', 'up', 'remove'], [5, 'di', 'up', 'add']], 'me', 3), [['ok', 1, False], ['up', 1, False]]), ('second user joins an emoji', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'di', 'up', 'add']], 'di', 3), [['up', 2, True], ['ok', 1, False]]), ('only reaction removed', ([[1, 'me', 'up', 'add'], [2, 'me', 'up', 'remove']], 'me', 2), []), ('limit reached', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'b', 'add'], [3, 'bo', 'c', 'add']], 'bo', 2), [['a', 1, True], ['b', 1, True]]), ('stray remove does not free a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'z', 'remove'], [3, 'bo', 'b', 'add']], 'me', 1), [['a', 1, False]]), ('removal frees a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'a', 'remove'], [3, 'bo', 'b', 'add']], 'bo', 1), [['b', 1, True]])], 2: [('remove delivered before add', ([[4, 'bo', 'up', 'remove'], [3, 'bo', 'up', 'add']], 'me', 3), []), ('emoji vanishes and returns', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'bo', 'up', 'remove'], [6, 'di', 'up', 'add']], 'me', 3), [['ok', 1, False], ['up', 1, False]]), ('second user joins an emoji', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'di', 'up', 'add']], 'di', 3), [['up', 2, True], ['ok', 1, False]]), ('only reaction removed', ([[1, 'me', 'up', 'add'], [2, 'me', 'up', 'remove']], 'me', 2), []), ('limit reached', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'b', 'add'], [3, 'bo', 'c', 'add']], 'bo', 2), [['a', 1, True], ['b', 1, True]]), ('stray remove does not free a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'z', 'remove'], [3, 'bo', 'b', 'add']], 'me', 1), [['a', 1, False]]), ('removal frees a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'a', 'remove'], [3, 'bo', 'b', 'add']], 'bo', 1), [['b', 1, True]])], 3: [('remove delivered before add', ([[5, 'bo', 'up', 'remove'], [4, 'bo', 'up', 'add']], 'me', 3), []), ('emoji vanishes and returns', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'bo', 'up', 'remove'], [7, 'di', 'up', 'add']], 'me', 3), [['ok', 1, False], ['up', 1, False]]), ('second user joins an emoji', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'di', 'up', 'add']], 'di', 3), [['up', 2, True], ['ok', 1, False]]), ('only reaction removed', ([[1, 'me', 'up', 'add'], [2, 'me', 'up', 'remove']], 'me', 2), []), ('limit reached', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'b', 'add'], [3, 'bo', 'c', 'add']], 'bo', 2), [['a', 1, True], ['b', 1, True]]), ('stray remove does not free a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'z', 'remove'], [3, 'bo', 'b', 'add']], 'me', 1), [['a', 1, False]]), ('removal frees a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'a', 'remove'], [3, 'bo', 'b', 'add']], 'bo', 1), [['b', 1, True]])], 4: [('remove delivered before add', ([[6, 'bo', 'up', 'remove'], [5, 'bo', 'up', 'add']], 'me', 3), []), ('emoji vanishes and returns', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'bo', 'up', 'remove'], [8, 'di', 'up', 'add']], 'me', 3), [['ok', 1, False], ['up', 1, False]]), ('second user joins an emoji', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'di', 'up', 'add']], 'di', 3), [['up', 2, True], ['ok', 1, False]]), ('only reaction removed', ([[1, 'me', 'up', 'add'], [2, 'me', 'up', 'remove']], 'me', 2), []), ('limit reached', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'b', 'add'], [3, 'bo', 'c', 'add']], 'bo', 2), [['a', 1, True], ['b', 1, True]]), ('stray remove does not free a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'z', 'remove'], [3, 'bo', 'b', 'add']], 'me', 1), [['a', 1, False]]), ('removal frees a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'a', 'remove'], [3, 'bo', 'b', 'add']], 'bo', 1), [['b', 1, True]])], 5: [('remove delivered before add', ([[7, 'bo', 'up', 'remove'], [6, 'bo', 'up', 'add']], 'me', 3), []), ('emoji vanishes and returns', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'bo', 'up', 'remove'], [9, 'di', 'up', 'add']], 'me', 3), [['ok', 1, False], ['up', 1, False]]), ('second user joins an emoji', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'di', 'up', 'add']], 'di', 3), [['up', 2, True], ['ok', 1, False]]), ('only reaction removed', ([[1, 'me', 'up', 'add'], [2, 'me', 'up', 'remove']], 'me', 2), []), ('limit reached', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'b', 'add'], [3, 'bo', 'c', 'add']], 'bo', 2), [['a', 1, True], ['b', 1, True]]), ('stray remove does not free a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'z', 'remove'], [3, 'bo', 'b', 'add']], 'me', 1), [['a', 1, False]]), ('removal frees a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'a', 'remove'], [3, 'bo', 'b', 'add']], 'bo', 1), [['b', 1, True]])]}\nfor _label, _args, _expected in _CASES[N]:\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":"f1af2795151369d018dc4012151479af292d981942cd286de3b2dce95869da14","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(events, viewer, limit):\n    current = {}\n    first = {}\n    per_user = {}\n    for seq, user, emoji, action in sorted(events):\n        users = current.get(emoji, set())\n        if action == 'add':\n            if user in users or per_user.get(user, 0) >= limit:\n                continue\n            if not users:\n                first[emoji] = seq\n            users.add(user)\n            current[emoji] = users\n            per_user[user] = per_user.get(user, 0) + 1\n        elif user in users:\n            users.discard(user)\n            per_user[user] = per_user.get(user, 0) - 1\n    rows = [[e, len(u), viewer in u] for e, u in current.items() if u]\n    rows.sort(key=lambda r: first[r[0]])\n    return rows\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\n_CASES = {1: [('remove delivered before add', ([[3, 'bo', 'up', 'remove'], [2, 'bo', 'up', 'add']], 'me', 3), []), ('emoji vanishes and returns', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'bo', 'up', 'remove'], [5, 'di', 'up', 'add']], 'me', 3), [['ok', 1, False], ['up', 1, False]]), ('second user joins an emoji', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'di', 'up', 'add']], 'di', 3), [['up', 2, True], ['ok', 1, False]]), ('only reaction removed', ([[1, 'me', 'up', 'add'], [2, 'me', 'up', 'remove']], 'me', 2), []), ('limit reached', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'b', 'add'], [3, 'bo', 'c', 'add']], 'bo', 2), [['a', 1, True], ['b', 1, True]]), ('stray remove does not free a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'z', 'remove'], [3, 'bo', 'b', 'add']], 'me', 1), [['a', 1, False]]), ('removal frees a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'a', 'remove'], [3, 'bo', 'b', 'add']], 'bo', 1), [['b', 1, True]])], 2: [('remove delivered before add', ([[4, 'bo', 'up', 'remove'], [3, 'bo', 'up', 'add']], 'me', 3), []), ('emoji vanishes and returns', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'bo', 'up', 'remove'], [6, 'di', 'up', 'add']], 'me', 3), [['ok', 1, False], ['up', 1, False]]), ('second user joins an emoji', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'di', 'up', 'add']], 'di', 3), [['up', 2, True], ['ok', 1, False]]), ('only reaction removed', ([[1, 'me', 'up', 'add'], [2, 'me', 'up', 'remove']], 'me', 2), []), ('limit reached', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'b', 'add'], [3, 'bo', 'c', 'add']], 'bo', 2), [['a', 1, True], ['b', 1, True]]), ('stray remove does not free a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'z', 'remove'], [3, 'bo', 'b', 'add']], 'me', 1), [['a', 1, False]]), ('removal frees a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'a', 'remove'], [3, 'bo', 'b', 'add']], 'bo', 1), [['b', 1, True]])], 3: [('remove delivered before add', ([[5, 'bo', 'up', 'remove'], [4, 'bo', 'up', 'add']], 'me', 3), []), ('emoji vanishes and returns', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'bo', 'up', 'remove'], [7, 'di', 'up', 'add']], 'me', 3), [['ok', 1, False], ['up', 1, False]]), ('second user joins an emoji', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'di', 'up', 'add']], 'di', 3), [['up', 2, True], ['ok', 1, False]]), ('only reaction removed', ([[1, 'me', 'up', 'add'], [2, 'me', 'up', 'remove']], 'me', 2), []), ('limit reached', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'b', 'add'], [3, 'bo', 'c', 'add']], 'bo', 2), [['a', 1, True], ['b', 1, True]]), ('stray remove does not free a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'z', 'remove'], [3, 'bo', 'b', 'add']], 'me', 1), [['a', 1, False]]), ('removal frees a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'a', 'remove'], [3, 'bo', 'b', 'add']], 'bo', 1), [['b', 1, True]])], 4: [('remove delivered before add', ([[6, 'bo', 'up', 'remove'], [5, 'bo', 'up', 'add']], 'me', 3), []), ('emoji vanishes and returns', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'bo', 'up', 'remove'], [8, 'di', 'up', 'add']], 'me', 3), [['ok', 1, False], ['up', 1, False]]), ('second user joins an emoji', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'di', 'up', 'add']], 'di', 3), [['up', 2, True], ['ok', 1, False]]), ('only reaction removed', ([[1, 'me', 'up', 'add'], [2, 'me', 'up', 'remove']], 'me', 2), []), ('limit reached', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'b', 'add'], [3, 'bo', 'c', 'add']], 'bo', 2), [['a', 1, True], ['b', 1, True]]), ('stray remove does not free a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'z', 'remove'], [3, 'bo', 'b', 'add']], 'me', 1), [['a', 1, False]]), ('removal frees a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'a', 'remove'], [3, 'bo', 'b', 'add']], 'bo', 1), [['b', 1, True]])], 5: [('remove delivered before add', ([[7, 'bo', 'up', 'remove'], [6, 'bo', 'up', 'add']], 'me', 3), []), ('emoji vanishes and returns', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'bo', 'up', 'remove'], [9, 'di', 'up', 'add']], 'me', 3), [['ok', 1, False], ['up', 1, False]]), ('second user joins an emoji', ([[1, 'bo', 'up', 'add'], [2, 'cy', 'ok', 'add'], [3, 'di', 'up', 'add']], 'di', 3), [['up', 2, True], ['ok', 1, False]]), ('only reaction removed', ([[1, 'me', 'up', 'add'], [2, 'me', 'up', 'remove']], 'me', 2), []), ('limit reached', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'b', 'add'], [3, 'bo', 'c', 'add']], 'bo', 2), [['a', 1, True], ['b', 1, True]]), ('stray remove does not free a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'z', 'remove'], [3, 'bo', 'b', 'add']], 'me', 1), [['a', 1, False]]), ('removal frees a slot', ([[1, 'bo', 'a', 'add'], [2, 'bo', 'a', 'remove'], [3, 'bo', 'b', 'add']], 'bo', 1), [['b', 1, True]])]}\nfor _label, _args, _expected in _CASES[N]:\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":"Stipulated offline chat model; not a complete messaging protocol, client or server implementation. 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-chat_ordering_and_read_receipts-reaction-aggregation-run-restart","generated_at":"2026-09-29T14:49:13.305883+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Reaction chips reorder and recount live; wrong state handling shows phantom or misordered reactions.","repair":"Use `if not users:` for the run restart decision and keep every other rule of the model unchanged.","root_cause":"The run restart decision evaluates `if emoji not in first:` where the contract requires `if not users:`.","sha256":"7e1492a27f477b2c2a849c6516034d4da50d5284527774e0ea038b2859bbe3f8","title":"Aggregate emoji reactions with a per-user limit: run restart · case 01","variant":1,"variant_policy":"N selects a different enumerated fixture set (shifted clocks, identifiers and sizes); boundary fixtures recur across variants.","verification":{"attempt":{"elapsed_ms":40.657,"exit_code":1,"observations":[{"actual":[],"check":"remove delivered before add","expected":[],"passed":true},{"actual":[["ok",1,false],["up",1,false]],"check":"emoji vanishes and returns","expected":[["ok",1,false],["up",1,false]],"passed":true},{"actual":[["ok",1,false],["up",2,true]],"check":"second user joins an emoji","expected":[["up",2,true],["ok",1,false]],"passed":false},{"actual":[],"check":"only reaction removed","expected":[],"passed":true},{"actual":[["a",1,true],["b",1,true]],"check":"limit reached","expected":[["a",1,true],["b",1,true]],"passed":true},{"actual":[["a",1,false]],"check":"stray remove does not free a slot","expected":[["a",1,false]],"passed":true},{"actual":[["b",1,true]],"check":"removal frees a slot","expected":[["b",1,true]],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"remove delivered before add\", \"actual\": [], \"expected\": [], \"passed\": true}, {\"check\": \"emoji vanishes and returns\", \"actual\": [[\"ok\", 1, false], [\"up\", 1, false]], \"expected\": [[\"ok\", 1, false], [\"up\", 1, false]], \"passed\": true}, {\"check\": \"second user joins an emoji\", \"actual\": [[\"ok\", 1, false], [\"up\", 2, true]], \"expected\": [[\"up\", 2, true], [\"ok\", 1, false]], \"passed\": false}, {\"check\": \"only reaction removed\", \"actual\": [], \"expected\": [], \"passed\": true}, {\"check\": \"limit reached\", \"actual\": [[\"a\", 1, true], [\"b\", 1, true]], \"expected\": [[\"a\", 1, true], [\"b\", 1, true]], \"passed\": true}, {\"check\": \"stray remove does not free a slot\", \"actual\": [[\"a\", 1, false]], \"expected\": [[\"a\", 1, false]], \"passed\": true}, {\"check\": \"removal frees a slot\", \"actual\": [[\"b\", 1, true]], \"expected\": [[\"b\", 1, true]], \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":42.992,"exit_code":1,"observations":[{"actual":[],"check":"remove delivered before add","expected":[],"passed":true},{"actual":[["up",1,false],["ok",1,false]],"check":"emoji vanishes and returns","expected":[["ok",1,false],["up",1,false]],"passed":false},{"actual":[["up",2,true],["ok",1,false]],"check":"second user joins an emoji","expected":[["up",2,true],["ok",1,false]],"passed":true},{"actual":[],"check":"only reaction removed","expected":[],"passed":true},{"actual":[["a",1,true],["b",1,true]],"check":"limit reached","expected":[["a",1,true],["b",1,true]],"passed":true},{"actual":[["a",1,false]],"check":"stray remove does not free a slot","expected":[["a",1,false]],"passed":true},{"actual":[["b",1,true]],"check":"removal frees a slot","expected":[["b",1,true]],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"remove delivered before add\", \"actual\": [], \"expected\": [], \"passed\": true}, {\"check\": \"emoji vanishes and returns\", \"actual\": [[\"up\", 1, false], [\"ok\", 1, false]], \"expected\": [[\"ok\", 1, false], [\"up\", 1, false]], \"passed\": false}, {\"check\": \"second user joins an emoji\", \"actual\": [[\"up\", 2, true], [\"ok\", 1, false]], \"expected\": [[\"up\", 2, true], [\"ok\", 1, false]], \"passed\": true}, {\"check\": \"only reaction removed\", \"actual\": [], \"expected\": [], \"passed\": true}, {\"check\": \"limit reached\", \"actual\": [[\"a\", 1, true], [\"b\", 1, true]], \"expected\": [[\"a\", 1, true], [\"b\", 1, true]], \"passed\": true}, {\"check\": \"stray remove does not free a slot\", \"actual\": [[\"a\", 1, false]], \"expected\": [[\"a\", 1, false]], \"passed\": true}, {\"check\": \"removal frees a slot\", \"actual\": [[\"b\", 1, true]], \"expected\": [[\"b\", 1, true]], \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":41.105,"exit_code":0,"observations":[{"actual":[],"check":"remove delivered before add","expected":[],"passed":true},{"actual":[["ok",1,false],["up",1,false]],"check":"emoji vanishes and returns","expected":[["ok",1,false],["up",1,false]],"passed":true},{"actual":[["up",2,true],["ok",1,false]],"check":"second user joins an emoji","expected":[["up",2,true],["ok",1,false]],"passed":true},{"actual":[],"check":"only reaction removed","expected":[],"passed":true},{"actual":[["a",1,true],["b",1,true]],"check":"limit reached","expected":[["a",1,true],["b",1,true]],"passed":true},{"actual":[["a",1,false]],"check":"stray remove does not free a slot","expected":[["a",1,false]],"passed":true},{"actual":[["b",1,true]],"check":"removal frees a slot","expected":[["b",1,true]],"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"remove delivered before add\", \"actual\": [], \"expected\": [], \"passed\": true}, {\"check\": \"emoji vanishes and returns\", \"actual\": [[\"ok\", 1, false], [\"up\", 1, false]], \"expected\": [[\"ok\", 1, false], [\"up\", 1, false]], \"passed\": true}, {\"check\": \"second user joins an emoji\", \"actual\": [[\"up\", 2, true], [\"ok\", 1, false]], \"expected\": [[\"up\", 2, true], [\"ok\", 1, false]], \"passed\": true}, {\"check\": \"only reaction removed\", \"actual\": [], \"expected\": [], \"passed\": true}, {\"check\": \"limit reached\", \"actual\": [[\"a\", 1, true], [\"b\", 1, true]], \"expected\": [[\"a\", 1, true], [\"b\", 1, true]], \"passed\": true}, {\"check\": \"stray remove does not free a slot\", \"actual\": [[\"a\", 1, false]], \"expected\": [[\"a\", 1, false]], \"passed\": true}, {\"check\": \"removal frees a slot\", \"actual\": [[\"b\", 1, true]], \"expected\": [[\"b\", 1, true]], \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}