mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Two observer-feed defects fixed in a single PR: Slice 1 — channel-scoped archive (index at ingest + idempotent backfill) The archive read path queried all owner_p kind 24200 rows for an identity, then relied on a display-time scopeByChannel filter. When the filter was missing or skipped, frames from other channels leaked into the current channel's observer feed. Fix: add an observer_channel_index table that maps (identity, relay, event_id) to channel_id. Three new Tauri commands drive this: - read_archived_observer_events_for_channel: channel-scoped paginated read via the index (replaces the raw owner_p scan in useLoadArchivedObserverEvents) - index_observer_channel_id: TS calls this after decrypting events to write index entries - read_unindexed_observer_rows: returns all owner_p kind 24200 rows not yet indexed, for the one-shot idempotent backfill Backfill strategy (choice i, backfill-before-read): a React.useEffect in useLoadArchivedObserverEvents runs once on mount, reads all unindexed rows, decrypts each, and batch-writes index entries. After backfill the channel index is authoritative — the scoped read pages it directly with no zero-match raw-page guard needed. Null/decrypt-failed channelId rows stay unscoped and are hidden from every scoped channel view (Will's ruling: option (a) — display decision only, rows stay on disk). Slice 2 — session-boundary rendering Items rendered flat with no session grouping; archived and live frames interleaved without any visual marker of where one agent session ended and another began, causing users to think archived historical context is still live. Fix: split TranscriptItem[] into contiguous session runs before calling buildTranscriptDisplayBlocks. This also fixes the pendingSystemPrompt single-slot clobber (each run gets its own lifecycle). A new session-boundary display block kind is interleaved between runs; SessionBoundaryDivider renders a horizontal rule with session start time. No boundary emitted for single-session transcripts. Liveness — "current session" gating Track latest-live-session-id per (normalized agent pubkey, channelId) in observerRelayStore, set on the handleRelayObserverEvent path, cleared in resetAgentObserverStore. Label a boundary "current session" only when it is both the newest-visible session AND equals that latest-live id; otherwise label it "most recent observed session". Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>