Skip to content

state: dedupe Reaction events by author#137

Merged
intendednull merged 1 commit into
mainfrom
claude/issue-111-state-reactions-dedup
Apr 11, 2026
Merged

state: dedupe Reaction events by author#137
intendednull merged 1 commit into
mainfrom
claude/issue-111-state-reactions-dedup

Conversation

@intendednull
Copy link
Copy Markdown
Owner

Summary

  • Switch ChatMessage::reactions from BTreeMap<String, Vec<EndpointId>> to BTreeMap<String, BTreeSet<EndpointId>> so each peer can only be registered once per (message, emoji).
  • Change the EventKind::Reaction handler in materialize.rs to use BTreeSet::insert instead of Vec::push, eliminating duplicate reactor entries when the same author emits (or replays) the same Reaction event twice.
  • Add a state-machine regression test same_author_duplicate_reaction_is_idempotent and tighten the existing duplicate_reaction_from_same_peer assertion from "may dedupe or not" to "must dedupe exactly".

Why

The previous Vec-backed shape meant a retransmitted or replayed Reaction would inflate the reactor list, causing UI reaction miscounts and StateHash divergence between peers that received different delivery counts of the same event. Deduping by author in the materialized state is both the simplest fix and the most compatible — the wire format of EventKind::Reaction is unchanged.

Scope notes

  • The wire/event format is untouched. Only the in-memory materialized state shape changed.
  • DisplayMessage.reactions in willow-client is a separate HashMap<String, Vec<String>> of display names and is unaffected.
  • Consumers that iterate .reactions (e.g. willow-client::views::messages_view) work unchanged because they only use .iter().

Test plan

  • cargo test -p willow-state — 156 tests pass including the new same_author_duplicate_reaction_is_idempotent regression
  • cargo test -p willow-client — 66 tests pass
  • cargo clippy --workspace -- -D warnings — clean
  • cargo fmt --check — clean
  • cargo check --target wasm32-unknown-unknown for the state/client/channel/messaging/crypto/identity/transport/common/network/actor crates — clean

Closes #111
Progresses #108

Each peer can react with a given emoji at most once. Switch
ChatMessage::reactions from BTreeMap<String, Vec<EndpointId>> to
BTreeMap<String, BTreeSet<EndpointId>> and use insert() in the
materializer so duplicate Reaction events from the same author
collapse to a single entry.

Without this change, an author replaying or retransmitting a
Reaction would inflate the reactor list, causing UI miscounts
and state-hash divergence between peers.

Closes #111
Progresses #108
@intendednull intendednull merged commit 62b4425 into main Apr 11, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[state] Reaction event does not dedupe by author

2 participants