7f613d6003
The previous commit interned at Event.fromJson, which is too early — the deserializer can produce events with manipulated id fields that don't match their content. Move interning to the post-validation boundary: events are only canonicalised when read back from durable storage, where they were valid when written. - Revert Event.fromJson to plain OptimizedJsonMapper.fromJson. - Revert ObservableEventStore.insert interning. Substituting the caller's event for a previously-cached one with the same id but potentially different sig was a write-side surprise; we leave the caller's instance alone. - Intern at SQLiteStatement.toEvent (read deserialization). - Intern at FsEventStore.readEvent (FS reads). The interner is also now constructor-injected through every store layer (SQLiteEventStore, EventStore, QueryBuilder, FsEventStore) defaulting to EventInterner.Default. BaseDBTest gives each parallel forEachDB store its own EventInterner — without this, parallel test runs that sign "same id, different sig" events through the shared Default would see the first run's sig leak across all DBs. All 240 store + projection + interner tests pass. https://claude.ai/code/session_01Jny85MTu1ynKgFBgysfWu5