Files
buzz/desktop
npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 dde0aac1a7 fix(readState): gate NIP-RS clear transitions and observer fallback authority
Four correctness defects in the 384ebc9d7 merge resolution:

1. [CRITICAL] markChannelRead/markAllChannelsRead bypassed the NIP-RS clear
   transition. Both paths deleted forced-unread state unconditionally without
   calling applyOverrideRead/applyMarkAllReadTransition. A refused clear left
   the authoritative override active while local presentation was wiped.
   Fix: advance frontier first, then call applyOverrideRead (C-bump); gate
   forcedUnread deletion and observed evidence removal on overrideCleared
   outcome. markAllChannelsRead calls applyMarkAllReadTransition per channel
   and routes observed deletion through observedPersistence.removeChannel.

2. [IMPORTANT] Sidebar projection used forcedUnreadRef (stale-prone local
   cache) instead of getOverrideLiveness (manager-authoritative). A remotely
   synced override could fail to light the sidebar.
   Fix: derive isForcedUnread from getOverrideLiveness(channel.id)?.active.

3. [IMPORTANT] Observer fallback (no complete projection) decoded fetched
   events with mergeReadStateEvents (frontier-only) and set override
   authority to an empty map, silently dropping active remote registers.
   Fix: use mergeReadStateEventsStructured in the fallback; use
   structured.overrides as authority; also check authoritative register in
   the channel evaluation loop before falling back to forcedUnreadMap.

4. [IMPORTANT] handleMarkMessageUnread mutated forcedUnreadMsgRef before
   calling markChannelUnread, ignoring the boolean result. A refused manager
   accept (budget_exhausted, load_incomplete) produced phantom unread state.
   Fix: call markChannelUnread first; mutate overlay only on true.

Also adds production-path witnesses:
- adversarial-7 (communityUnreadObserver): active fetched register with no
  complete projection lights the rail (positive fallback coverage).
- adversarial-5/6 (nip-rs-unread-ui): refused-clear contract for
  markChannelRead gate; spec-order frontier-advance-before-cbump.
- useUnreadChannels.test.mjs: updated markAllChannelsRead happy-path to
  reflect NIP-RS-gated semantics (no longer unconditional clearAll).

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
2026-08-04 18:53:07 -04:00
..
2026-08-03 21:51:17 -04:00
2026-03-09 13:02:11 -07:00
2026-08-03 21:51:17 -04:00
2026-06-11 15:06:24 +00:00
2026-03-09 13:02:11 -07:00

Buzz

Desktop chat shell with:

  • Tauri + React + TypeScript + Vite
  • Tailwind CSS
  • shadcn/ui-ready shared components
  • Biome (lint/format/check)
  • Feature-driven frontend structure

Scripts

  • pnpm dev - run the web frontend
  • pnpm tauri dev - run the desktop app
  • pnpm build - typecheck and build frontend
  • pnpm typecheck - TypeScript checks
  • pnpm lint - Biome lint
  • pnpm format - Biome format (write)
  • pnpm check - Biome check

Structure

  • src/shared - reusable app-wide code (ui, lib, styles)
  • src/features - feature modules (vertical slices)
  • src/app - top-level app composition