SkateSpots/CREW_CHAT_AUDIT.md
SkateSpots 8e7c5bfa09 fix(crew-chat): show sent messages, stop re-decrypting the inbox
Audit of the crew Chat tab (see CREW_CHAT_AUDIT.md):
- A sent crew message never appeared: useSendDirectMessage invalidated the list
  keys but not ['group-messages', gid, ...] (the thread key). Now optimistically
  inserts the sender's own plaintext (no refetch -> no Amber pop-ups).
- Every reader decrypted every wrap under its own query key, so each view
  (Messages, then each crew thread) re-decrypted the whole inbox. Added a shared,
  coalesced, bounded session decrypt cache (decryptGiftWrap), successes only.
- Threads dedup by rumor id; CrewChat guards double-send with a ref; the Cordn
  path optimistically inserts and invalidates only for silent signers.
2026-10-13 00:21:42 +07:00

27 lines
3.4 KiB
Markdown

# Crew chat — audit (2026-10-13)
Scope: the crew page's **Chat** tab (`CrewChat.tsx`) across both transports — the
built-in **NIP-17** group chat and the **Cordn sealed-relay** path (`useCordnChat`)
— plus the shared DM readers it depends on (`useDirectMessages.ts`).
## Findings
| # | Sev | Status | Finding |
|---|---|---|---|
| 1 | High | **Fixed** | **A sent crew message didn't appear.** `useSendDirectMessage` invalidated `direct-messages` / `conversations` / `group-conversations`, but the crew thread reads `['group-messages', gid, …]` — never invalidated. For a silent signer it showed up on the next 60 s poll; for **Amber (no polling, session-cached) it never did**. Fixed with an **optimistic cache insert** of the sender's own plaintext (no refetch → no extra signer pop-ups). |
| 2 | High | **Fixed (1.6.4)** | **Amber "didn't respond" on send.** The per-recipient gift wraps (and the sealed-relay roster seal) were created with `Promise.all` — concurrent `nostrsigner:` intents collide, one is answered and the rest hit the 60 s native timeout. Now sequential for an interactive signer. |
| 3 | High | **Fixed** | **Every chat view re-decrypted the whole inbox.** Each reader (`useConversations`, `useConversation`, `useGroupConversations`, `useGroupConversation`) decrypted *every* wrap — 2 signer ops each — and each has its own query key, so opening Messages decrypted everything, then opening one crew thread decrypted it **all again**, and again per thread. Added a **shared, coalesced, bounded session decrypt cache** (`decryptGiftWrap`) keyed `viewerPk:wrapId`; only successes are cached, so a transient failure retries. |
| 4 | Med | **Fixed** | No dedup by rumor id in a thread — a re-sent rumor (same id, two wraps) could render twice. Threads now dedup by id before sorting. |
| 5 | Med | **Fixed** | **Double-send**: pressing Enter twice before React re-rendered `isPending` sent twice. Added an in-flight ref guard. |
| 6 | Med | **Fixed** | The **Cordn** path invalidated its query on every send → an Amber refetch storm. Now optimistically inserts the sent message and only invalidates for silent signers. |
| 7 | Med | Open | **Transport switches silently.** A crew with a `coordinator` tag uses the **sealed-relay Cordn** path; without one it uses **NIP-17**. They have separate histories, so a crew that later gains a coordinator appears to "lose" its chat. New crews now get the SkateSpots coordinator by default, so most new crews take the Cordn path. Needs a product decision: label it clearly, or standardise on one. |
| 8 | Med | Open | **Read limit 200.** Threads fetch the N most recent wraps addressed to the viewer and filter client-side (the wrap hides its participants, so the relay can't filter). A busy inbox can push older crew messages out of the window → the chat looks empty. Could raise the limit for group threads. |
| 9 | Low | Open | No images/attachments in the crew **Chat** (text only). The MLS **Private chat** got images; the NIP-17 path didn't. |
| 10 | Info | — | With the cache, an Amber read is now **one decrypt per wrap per session** instead of one per view. Sends still cost 2 approvals per member (NIP-17) vs ~1 per message on the MLS path. |
## Net effect
- Sending now shows your own message immediately.
- Opening Messages ⇄ a crew thread ⇄ another crew thread no longer re-prompts.
- Amber stops timing out mid-send.
Not click-tested in a real browser this session; `npm test` + `check-i18n` green.