- `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.
Stream large receives to disk with chunk acks to cap renderer RAM, evict
off-screen display blobs, and route exports through a disk-aware download
service. Fix the high-memory dialog (backdrop dismiss, copy, log actions),
allow diagnostics paths in the path jail, and restore persisted image
hydration after reload.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add AGENTS.md, CLAUDE.md, and the agents-docs/ tree (workflow, lessons,
engineering standards, context map, ADR seed, feature template) plus a
domain-bearing CONTEXT.md for each of the six subdomains: toju-app,
electron, server, e2e, website, docs-site.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
stale server sockets, passive non-initiators, and race conditions
during peer connection setup.
Fix users unable to see or hear each other in voice channels due to
stale server sockets, passive non-initiators, and race conditions
during peer connection setup.
Server:
- Close stale WebSocket connections sharing the same oderId in
handleIdentify instead of letting them linger up to 45s
- Make user_joined/user_left broadcasts identity-aware so duplicate
sockets don't produce phantom join/leave events
- Include serverIds in user_left payload for multi-room presence
- Simplify findUserByOderId now that stale sockets are cleaned up
Client - signaling:
- Add fallback offer system with 1s timer for missed user_joined races
- Add non-initiator takeover after 5s when the initiator fails to send
an offer (NON_INITIATOR_GIVE_UP_MS)
- Scope peerServerMap per signaling URL to prevent cross-server
collisions
- Add socket identity guards on all signaling event handlers
- Replace canReusePeerConnection with hasActivePeerConnection and
isPeerConnectionNegotiating with extended grace periods
Client - peer connections:
- Extract replaceUnusablePeer helper to deduplicate stale peer
replacement in offer and ICE handlers
- Add stale connectionstatechange guard to ignore events from replaced
RTCPeerConnection instances
- Use deterministic initiator election in peer recovery reconnects
- Track createdAt on PeerData for staleness detection
Client - presence:
- Add multi-room presence tracking via presenceServerIds on User
- Replace clearUsers + individual userJoined with syncServerPresence
for atomic server roster updates
- Make userLeft handle partial server removal instead of full eviction
Documentation:
- Add server-side connection hygiene, non-initiator takeover, and stale
peer replacement sections to the realtime README