Files
Toju/emergency-fix/09-identity-cross-signal.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

5.1 KiB
Raw Blame History

09 — Cross-signal identity (calls, DMs, voice routing)

User theme: “Calls dont ring / Im In Voice alone / DMs fork / voice fails only with people on other homes.”
Severity: P0.
Coupling: Depends on silent provision (04) creating foreign actor ids at all.


How identity is supposed to work (user view)

  • You have one profile on this device.
  • People may see slightly different usernames on other signal hosts (suffix / #prefix tag) — still you.
  • Calling or DMing someone you met in any community should reach them, not a ghost.
  • You should never end up with two chat threads that are secretly the same person.
  • Voice in a shared room should work even if you registered on different home signal servers.

How identity is supposed to work (system)

Id Meaning
Home user id Local profile / NgRx User.id
Foreign actor id Credential userId for that signal URL
Peer map key Usually the oderId seen on that signals presence
targetUserId on WS relay Must equal callees connected oderId on that server
DM conversationId Should canonicalize to one thread per human pair on this device

Self-admission for inbound events must accept all aliases: home id, entity id, peer id, every valid provisioned credential user id.

Outbound delivery must pick a routable id (one the signaling server can map to an open connection), not merely the home id stored on a people card.


What is implemented vs claimed

Capability Status (2026-08-12 tree)
Inbound direct-call alias admission + normalize Presentdirect-call-participant-identity.rules.ts
DM self-id alias sets Presentdirect-message-identity.rules.ts (narrower than lessons conversation merge)
Outbound collectRecipientDeliveryCandidateIds / pickRoutableRecipientId Absent — lesson describes as if shipped
DirectCallService.resolveRoutableRecipientId / recipientUnreachable UX Absent
resolveDirectConversationId / mergeAliasDirectConversations Absent
Room join uses resolveActorUserIdForServer Presentroom-signaling-connection.ts
Initiator election uses per-signal actor id Weak / home-biased — see 06

Treat LESSONS entries for outbound call routing and DM canonicalize as specifications of unfinished work, not as completed history.


Failure modes

1 — Outbound call: silent “In Voice”

Caller joins call session; PeerDeliveryService cannot resolve signaling peer id (home id ≠ connected actor id); ring never sent or wrong targetUserId; delivery result ignored.

2 — Inbound call: dropped ring (historical)

Fixed for admission aliases; still verify e2e dm-header-call-ring across secondary signal registration. Do not assume outbound is fixed because inbound is.

3 — DM thread fork

Incoming messages keyed by foreign actor conversation id → UI shows empty home-id thread; replies land elsewhere.

4 — Voice peer election / routing alias miss

Home vs actor mismatch → no PC or one-way audio (06).

5 — People search / friends store home ids only

Cards display home identity; without alias expansion at send time, every cross-signal action is fragile.


Key files

  • domains/direct-call/ (+ direct-call-participant-identity.rules.ts)
  • domains/direct-message/ (+ direct-message-identity.rules.ts, PeerDeliveryService)
  • domains/authentication/ credential store + resolveActorUserIdForServer
  • infrastructure/realtime/signaling-transport-handler.ts (home vs per-URL credentials)
  • Lessons (aspirational): outbound routing + DM canonicalize sections in LESSONS.md
  • E2E intent: e2e/tests/voice/dm-header-call-ring.spec.ts (scope expand if needed)

  1. Instrument one cross-home repro: log home id, actor ids, peer map keys, targetUserId, conversation ids.
  2. Outbound delivery — implement lesson APIs for real: collect aliases, pick routable, always attempt send, surface unreachable error (stop fake In Voice).
  3. DM canonicalize + merge — single thread; remap inbound; merge duplicates on load.
  4. Voice initiator / routing — per-signal local actor id (06).
  5. Rewrite lesson examples if names differ so future agents dont hunt phantom files.

Proof of done

  1. User1 home A, User2 home B, meet in room on A: DM-header call rings Bs modal; B answers; both hear audio.
  2. Same pair: DM replies appear in one thread on both clients.
  3. People-card call when only shared presence is under actor id: still rings or shows unreachable (never silent In Voice).
  4. Unit tests for alias collect/pick and conversation merge.
  5. E2E cross-signal call + DM (expand scope with user approval for e2e/).

Interview choices

Option Focus first
A (recommended) Outbound routable id + unreachable UX
B DM canonicalize/merge first
C Voice initiator per-signal id first
D Full identity service refactor (large — avoid in emergency)