70afcd10ca
The previous design wrapped a mutable HashSet in an AtomicReference, which makes the *reference* thread-safe but not the set's internals. The historical-replay closure ran `seenIds.load()?.add(event.id)` from the subscriber's coroutine while `deliver` ran `seen.contains(event.id)` from the publisher's coroutine — concurrent add/contains can corrupt buckets or throw CME. The pre-index implementation didn't have this race because both operations ran on the same Flow collector coroutine. Index-driven dispatch put them on different coroutines. Switch to AtomicReference<Set<String>?> over an immutable Set with a CAS-loop on add. Reads in `deliver` always see a fully-constructed snapshot. Single-writer in steady state so the CAS typically succeeds first try; the loop only matters across the `seenIds.store(null)` post-EOSE handoff. Also: - hoist `NostrSignerSync(keys[target])` out of the per-iteration loop in LoadBenchmark.fanoutScaling. - add FilterIndex tests for `tagsAll` selection, multi-char tag fall-through, and re-register key-union semantics.