Implementation Plan: Fix NR Read Behavior for Reactions and Zaps
Status
- 1. Direct Activity Target Extraction
- Implement
extractDirectActivityTargetId(event: NostrEvent): string | nullinplugins/nr/activity.tssupporting kind 7 (last e tag or marker=reply) and kind 9735 (viaparseZapReceipt), preserving kind 6/16 repost target logic. - Update
parseAndStoreEventto populatenr_activity_targetswith only the exact direct target.
- Implement
- 2. Durable Read State Persistence (
nr_read_events)- Create
nr_read_events(event_id TEXT PRIMARY KEY, read_at INTEGER NOT NULL)schema increateNrTable. - Migrate/backfill existing read events from
nr_eventsintonr_read_events. - Add
isEventRead(db, eventId)helper function to query read status acrossnr_read_eventsandnr_events.
- Create
- 3. Read Cascades & Mark/Read Command Adapters
- Update
markEventIdsStateto cascaderead_atto direct activities innr_activity_targetsfor all selected and related events. - Sync
markEventIdsStatewithnr_read_events(insert onread, delete onunread). - Update
markEventStateto persist target ID tonr_read_events. - Ensure store-first in
adaptMarkCommandruns before multi-ID check ifevent_jsonis provided.
- Update
- 4. Future Fetch Handling in
parseAndStoreEvent- In
parseAndStoreEvent, check if direct target is read in eithernr_read_eventsornr_events.read_at. - Inherit
read_atfor incoming activity events and sync tonr_read_events.
- In
- 5. List Queries and Unread Slot Counts
- Update
unreadTargetPredicateinlistTagsandlistEventsForTag. - Update target filter in
listForYouCandidates. - Update
target_readcalculation inlistUnreadFetchSlots. - Update
activityTargetPredicatein timeline/activity queries. - Ensure archive mode preserves its existing behavior.
- Update
- 6. Client-Side Immediate Removal & Rendering
- Update
activityTarget()inplugins/nr/commands/list/renderers/event-nodes.tsto locate exact direct target matchingextractDirectActivityTargetIdinstead of blindcontext[0]. - Update
markAction()/readAction()to emitremoveEntitymutations for all relevant entity keys (entityEventId,eventIds, and associated activity IDs). - Update
mergedActivityNode()to pass all activity IDs inreadActionOverrideto both the overflow menu and profile post node. - Ensure conversation cards containing read parent context are not removed merely because the parent is read.
- Ensure
activityEventNode()has its ownentityKeyand removes both activity and target on read.
- Update
- 7. Existing Data Migration & Backfill
- Clean up false targets in
nr_activity_targetsfor kinds 7 and 9735. - Mark existing cached activities as read if their target is read.
- Clean up false targets in
- 8. Static Checks & Verification
- Run
bunx tsc --noEmitto verify type safety (passed with 0 errors). - Verified all 9 acceptance scenarios and client rendering checks with in-memory test script (
scratch/verify_read_behavior.ts).
- Run