4b7e0e880c
Implements the A+B+C+D plan in geode/plans/2026-05-07-negentropy-large-corpus.md:
- A: id-and-time-only snapshot. Adds IEventStore.snapshotIdsForNegentropy
returning IdAndTime(createdAt, id) with no Event materialization. SQLite
override projects directly off event_headers (~40 B/entry instead of
~1 KB/entry; matches strfry's MemoryView footprint).
- B: snapshot-size cap. New [negentropy] config section with
max_sync_events=1_000_000 (mirrors strfry's relay__negentropy__maxSyncEvents).
Overflow returns NEG-ERR "blocked: too many query results" (strfry-exact
wording). No default since-window (strfry honors filters as-is; bounding
silently would break interop).
- C: 500_000-byte frame cap. NegentropyServerSession.DEFAULT_FRAME_SIZE_LIMIT
matches strfry's hard-coded Negentropy ne(storage, 500'000). Configurable
via [negentropy].frame_size_limit.
- D: per-connection session cap = 200 (matches strfry). Overflow sends NOTICE
"too many concurrent NEG requests" (strfry parity).
Error-string interop:
- NEG-MSG with unknown subId → "closed: unknown subscription handle"
- reconcile() parse failure → "PROTOCOL-ERROR"
- snapshot overflow → "blocked: too many query results"
- per-conn cap → NOTICE "too many concurrent NEG requests"
NegentropySettings flows: RelayConfig.NegentropySection → Relay → NostrServer
→ RelaySession → NegSessionRegistry. RelayHub takes optional settings for
tests that need to exercise the caps.
Tests:
- SnapshotIdsForNegentropyTest covers projection correctness across all
indexing strategies + the maxEntries+1 sentinel contract.
- Nip77NegentropyTest gains negOpenSnapshotOverflowReturnsStrFryNegErr
and negOpenPerConnectionCapEmitsNotice.
- Existing negMsgWithoutOpenReturnsNegErr updated to assert strfry wording.