- `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.
4.3 KiB
08 — Messaging visibility (“messages not seen”)
User theme: “I sent a message but they don’t 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_syncwhen 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 don’t sync for multi-client users” root cause (serialized identify).
2 — Live works, history doesn’t
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)
- Did both users
identify+join_serveron the same signal URL as the room? - Is there an open DC between them? (
connectedPeers, debug metrics) - Does live send emit both DC and
chat_message? - On receive, is
roomIdin saved/current rooms? - For DM: conversation id aliases; delivery state machine stuck at QUEUED?
- Multi-device:
account_sync_peer_onlinefired; batches received?
Proof of done
- Two clients: send N messages with DC disabled (force) → live still appears via WS.
- Re-enable DC → inventory brings missing history.
- Third client late join → receives recent history from a peer with DB.
- Cross-home users in foreign room: messages visible both ways without authorize prompt.
- Cross-signal DM: single conversation thread; replies visible to both.
- Multi-device: second device gets
chat-sync-batchafter identify. - Regression covering identify-before-join (presence + chat broadcast).
Fix order
- Auth + identify (
04/05) — without presence, messaging “fixes” are theater. - Ensure fallback + DC resync on repair (
07). - Identity canonicalize for DMs (
09). - Attachment re-queue invariants.
- Correct stale chat README inventory number.