Files
Toju/emergency-fix/08-messaging-visibility.md
T
myxelium e49b3ec112 chore: dev-stack switches, shared e2e harness, and desktop shell rules
- `LIVE_RELOAD=false npm run dev` keeps the renderer alive across a machine
  suspend; the reload client otherwise destroys the session under test.
- `dev-peer.sh` plus a separate userdata dir runs a second local peer.
- `tools/voice-probe.js` samples peer state and RTP counters from a live
  window, persisting to localStorage so a renderer reload cannot erase it.
- e2e helpers for voice pairs, peer-role election, and a TURN relay.
- Electron single-instance and dev-client-load decisions move into rules
  files with colocated specs.
2026-08-14 03:19:29 +02:00

111 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 08 — Messaging visibility (“messages not seen”)
> **User theme:** “I sent a message but they dont see it / history missing / only some devices have chat.”
> **Severity:** P0.
---
## How messaging is supposed to work (user view)
### Server text channels
- Send in a text channel → everyone currently in that community sees it quickly.
- If someone was offline or just joined, they still get recent history after connecting to peers (or from their other logged-in device).
- Edits, deletes, reactions converge.
- Typing indicators are ephemeral.
- The **signal server does not keep a chat log** — history lives on clients.
### Direct messages
- 1:1 and group DMs deliver even without a shared community when signaling can reach the peer.
- Delivery ticks: queued → sent → delivered → acknowledged (monotonic).
- Offline: queue until peer/network returns.
### Multi-device
- Second device receives live + catch-up via `account_sync` when siblings are online.
---
## How messaging is supposed to work (system)
| Path | Role |
|------|------|
| P2P `chat-message` / revisions | Primary live + sync plane |
| WS `chat_message` | Narrow **live** fallback to room members |
| Inventory / sync-batch | Catch-up on DC (limit 20_000, chunk 200) |
| `account_sync` chat batches | Sibling devices |
| DM PeerDelivery | DC → signaling → offline queue |
Feature contract: `agents-docs/features/messaging.md`.
Domain: `domains/chat/`, `domains/direct-message/`, `store/messages/`.
---
## Failure modes
### 1 — Invisible membership → no live fallback
If identify/join failed (`04`/`05`), user is not in server membership → server never broadcasts `chat_message` to them; peers may not offer DC. **Classic “chats dont sync for multi-client users”** root cause (serialized identify).
### 2 — Live works, history doesnt
DC down: live WS fallback OK; inventory never runs → “they only see new messages after refresh if a peer happens to sync later” / empty history for late joiners.
### 3 — Sync poll too slow after “clean” cycle
Fast poll 10s while catching up; **15 min** when clean. A false “clean” leaves long windows without repair.
### 4 — Cross-signal identity forks DMs
Incoming DM `conversationId` carries foreign actor id → second empty thread; replies invisible on the thread the user is watching (`09`). Lessons claim canonicalize/merge — **symbols not in tree**.
### 5 — Recipient alias miss
DM/call ignored if local admission only checks home id. Inbound DM aliases largely fixed; verify call + any new surfaces.
### 6 — Attachment-only emptiness
Message text arrives; image stuck “Waiting…” — announce/bind race (lesson). Looks like “message incomplete / not really received.”
### 7 — NgRx prune confusion
Inactive rooms pruned to 100 messages in memory; DB still has more. User switching rooms may think history vanished until reload/sync — document vs bug.
### 8 — Doc lie on inventory cap
Chat domain README still says **1000**; code `INVENTORY_LIMIT = 20_000`.
---
## Investigation checklist (agents)
1. Did both users `identify` + `join_server` on the **same** signal URL as the room?
2. Is there an open DC between them? (`connectedPeers`, debug metrics)
3. Does live send emit both DC and `chat_message`?
4. On receive, is `roomId` in saved/current rooms?
5. For DM: conversation id aliases; delivery state machine stuck at QUEUED?
6. Multi-device: `account_sync_peer_online` fired; batches received?
---
## Proof of done
1. Two clients: send N messages with DC disabled (force) → live still appears via WS.
2. Re-enable DC → inventory brings missing history.
3. Third client late join → receives recent history from a peer with DB.
4. Cross-home users in foreign room: messages visible both ways without authorize prompt.
5. Cross-signal DM: single conversation thread; replies visible to both.
6. Multi-device: second device gets `chat-sync-batch` after identify.
7. Regression covering identify-before-join (presence + chat broadcast).
---
## Fix order
1. Auth + identify (`04`/`05`) — without presence, messaging “fixes” are theater.
2. Ensure fallback + DC resync on repair (`07`).
3. Identity canonicalize for DMs (`09`).
4. Attachment re-queue invariants.
5. Correct stale chat README inventory number.