mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-09 16:14:40 +00:00
EventListMatchingFilter had the same mutable-sort-key defect as NoteListMatchingFilter: it stored Notes in a ConcurrentSkipListSet ordered by the live created_at, so a newer replaceable version (which mutates the shared AddressableNote in place) stranded its node and let the same instance be inserted twice — the emitted event list then carried the same event twice. It hadn't surfaced as a crash only because its consumers (app recommendations, relay groups, room reactions) happen to dedup downstream. Apply the same capture-key + idHex-dedup + per-key compute design, but preserve EventListMatchingFilter's update-reflecting semantics: an addressable update re-emits (the snapshot reads the refreshed event live off the note) rather than being ignored. It keeps the entry's captured position instead of re-sorting — re-sorting via remove+add let two entries with different captured keys for the same note transiently coexist and both read the same live event, duplicating it. Also harden both filters' emission: a ConcurrentSkipListSet iterator is weakly consistent, so under concurrent add/remove churn a single traversal can momentarily surface a key twice. snapshot() now dedups by idHex so the emitted list — the LazyColumn's source of keys — is always unique, regardless of transient internal states. Corrected the over-claimed "can never hold two" docstrings accordingly. Adds EventListMatchingFilterTest mirroring the note tests: update-reflection, version-note re-emit, sorted order, remove-after-mutation, and two concurrency stress tests (with/without limit) that failed before this fix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ah1aCniyjnzc27x4pwq2Df