Files
amethyst/quartz
Claude 86537edef5 refactor(quartz): introduce ObservableEventStore so projections see ephemerals
Splits "events accepted for persistence" from "events accepted for
observation". The new ObservableEventStore wraps any IEventStore and
owns events: SharedFlow<Event>:

- Non-ephemeral events forward to the inner store; success → emit, any
  rejection (expired, NIP-09 / NIP-62 tombstone, NIP-01 supersession
  loser) → no emit.
- Ephemeral events (kinds 20000-29999) skip persistence entirely but
  still emit, so an open EventStoreProjection renders them while alive.
  They vanish from any future seed because the DB never had them.

Reverts the previous round of plumbing inside SQLiteEventStore /
FsEventStore: stores no longer carry an inserts SharedFlow. IEventStore
goes back to a clean read/write contract. ObservableEventStore is the
single place that decides what makes it onto the projection bus.

EventStore (the SQLite convenience class) embeds an ObservableEventStore
internally so existing call sites like `store.observe(filter, scope)`
keep working without changes.

EventStoreProjection now collects via Flow.onSubscription so the
collector subscription is established before the seed query runs —
fixes a race where an insert immediately after `ready.await()` could
land in the SharedFlow before the collector was subscribed.

Tests:
- ephemeralEventsAppearInProjection — kind-22000 event reaches items
  but isn't queryable from the inner store, and a fresh projection
  on the same store gets an empty seed.
- 14/14 projection tests + 219/219 other store tests pass.

https://claude.ai/code/session_01Jny85MTu1ynKgFBgysfWu5
2026-04-29 20:34:56 +00:00
..