FAILURE MAP
← Case archive

FA-76121 / Chat ordering and read receipts / Open access

Aggregate emoji reactions with a per-user limit: limit boundary · case 01

A user can place one more distinct emoji than the configured limit.

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

ROOT CAUSE

The limit boundary decision evaluates `per_user.get(user, 0) > limit` where the contract requires `per_user.get(user, 0) >= limit`.

VERIFIED REPAIR

Use `per_user.get(user, 0) >= limit` for the limit boundary decision and keep every other rule of the model unchanged.

Unsuccessful approach: Special-casing a limit of one disables the limit entirely for single-reaction rooms. The attempted `per_user.get(user, 0) > limit - 1 if limit > 1 else False` still disagrees with a fixture.

Case 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.

Why this case matters

Reaction chips reorder and recount live; wrong state handling shows phantom or misordered reactions.

1 / The failure

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

N = 1
observations = []
def solve(events, viewer, limit):
    current = {}
    first = {}
    per_user = {}
    for seq, user, emoji, action in sorted(events):
        users = current.get(emoji, set())
        if action == 'add':
            if user in users or per_user.get(user, 0) > limit:
                continue
            if not users:
                first[emoji] = seq
            users.add(user)
            current[emoji] = users
            per_user[user] = per_user.get(user, 0) + 1
        elif user in users:
            users.discard(user)
            per_user[user] = per_user.get(user, 0) - 1
    rows = [[e, len(u), viewer in u] for e, u in current.items() if u]
    rows.sort(key=lambda r: first[r[0]])
    return rows
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
_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]])]}
for _label, _args, _expected in _CASES[N]:
    check(_label, solve(*_args), _expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
remove delivered before add[][]Passed
emoji vanishes and returns[['ok', 1, False], ['up', 1, False]][['ok', 1, False], ['up', 1, False]]Passed
second user joins an emoji[['up', 2, True], ['ok', 1, False]][['up', 2, True], ['ok', 1, False]]Passed
only reaction removed[][]Passed
limit reached[['a', 1, True], ['b', 1, True], ['c', 1, True]][['a', 1, True], ['b', 1, True]]Failed
stray remove does not free a slot[['a', 1, False], ['b', 1, False]][['a', 1, False]]Failed
removal frees a slot[['b', 1, True]][['b', 1, True]]Passed

SHA-256 / c85a3c4c2defd4e920ec64bd5680393adbcc1c48ae1fb2a2eb54670760454a5f

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(events, viewer, limit):
    current = {}
    first = {}
    per_user = {}
    for seq, user, emoji, action in sorted(events):
        users = current.get(emoji, set())
        if action == 'add':
            if user in users or per_user.get(user, 0) > limit - 1 if limit > 1 else False:
                continue
            if not users:
                first[emoji] = seq
            users.add(user)
            current[emoji] = users
            per_user[user] = per_user.get(user, 0) + 1
        elif user in users:
            users.discard(user)
            per_user[user] = per_user.get(user, 0) - 1
    rows = [[e, len(u), viewer in u] for e, u in current.items() if u]
    rows.sort(key=lambda r: first[r[0]])
    return rows
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
_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]])]}
for _label, _args, _expected in _CASES[N]:
    check(_label, solve(*_args), _expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
remove delivered before add[][]Passed
emoji vanishes and returns[['ok', 1, False], ['up', 1, False]][['ok', 1, False], ['up', 1, False]]Passed
second user joins an emoji[['up', 2, True], ['ok', 1, False]][['up', 2, True], ['ok', 1, False]]Passed
only reaction removed[][]Passed
limit reached[['a', 1, True], ['b', 1, True]][['a', 1, True], ['b', 1, True]]Passed
stray remove does not free a slot[['a', 1, False], ['b', 1, False]][['a', 1, False]]Failed
removal frees a slot[['b', 1, True]][['b', 1, True]]Passed

SHA-256 / 318e3ba984d74272a9a45bf07b8544462e2b6979ecb72b57bb5e09a0397afd33

3 / The verified repair

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

N = 1
observations = []
def solve(events, viewer, limit):
    current = {}
    first = {}
    per_user = {}
    for seq, user, emoji, action in sorted(events):
        users = current.get(emoji, set())
        if action == 'add':
            if user in users or per_user.get(user, 0) >= limit:
                continue
            if not users:
                first[emoji] = seq
            users.add(user)
            current[emoji] = users
            per_user[user] = per_user.get(user, 0) + 1
        elif user in users:
            users.discard(user)
            per_user[user] = per_user.get(user, 0) - 1
    rows = [[e, len(u), viewer in u] for e, u in current.items() if u]
    rows.sort(key=lambda r: first[r[0]])
    return rows
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
_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]])]}
for _label, _args, _expected in _CASES[N]:
    check(_label, solve(*_args), _expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
remove delivered before add[][]Passed
emoji vanishes and returns[['ok', 1, False], ['up', 1, False]][['ok', 1, False], ['up', 1, False]]Passed
second user joins an emoji[['up', 2, True], ['ok', 1, False]][['up', 2, True], ['ok', 1, False]]Passed
only reaction removed[][]Passed
limit reached[['a', 1, True], ['b', 1, True]][['a', 1, True], ['b', 1, True]]Passed
stray remove does not free a slot[['a', 1, False]][['a', 1, False]]Passed
removal frees a slot[['b', 1, True]][['b', 1, True]]Passed

SHA-256 / f1af2795151369d018dc4012151479af292d981942cd286de3b2dce95869da14

Verification & scope

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.

Observations recorded using Python 3.12.14 at 2026-09-29T14:49:13.391549+00:00.

Case digest / 0129571298123e2ddd3be71132e8008e066e666bbcbc4bdf7ecd981aded129af