Skip to content

Repro: no ParticipantConnected for participants already in room at connect#342

Closed
MaxHeimbrock wants to merge 1 commit into
mainfrom
max/repro-snapshot-participant-events
Closed

Repro: no ParticipantConnected for participants already in room at connect#342
MaxHeimbrock wants to merge 1 commit into
mainfrom
max/repro-snapshot-participant-events

Conversation

@MaxHeimbrock

Copy link
Copy Markdown
Contributor

Summary

Deterministic reproduction of the field reports where a user joins a room concurrently with a remote participant (typically an agent being dispatched) and never realizes that participant is there — no ParticipantConnected, and consequently no app-side track subscription/rendering.

This PR is intentionally red. The test documents the current defect; the fix follows on this branch.

Mechanism

Whether a concurrently connecting participant lands in the local participant's connect snapshot or in the event stream is a server-side race (did it join before or after the local JoinResponse was generated). If it lands in the snapshot:

  • the Rust SDK creates it silently from join_response.other_participants (livekit/src/room/mod.rs:744 — only handle_participant_update ever dispatches ParticipantConnected, and only for participants not already known),
  • the FFI packs it into the ConnectCallback payload (build_initial_states) without events,
  • Unity adds it to RemoteParticipants via CreateRemoteParticipantWithTracks (Room.cs:596) without raising room-level ParticipantConnected or TrackPublished.

So even a handler wired before Connect() never fires. The data is all there — only the events are missing. The ReadyForRoomEvent handshake is not at fault: the buffered-delta path it protects was verified watertight at all three layers.

Test design

Three participants make the race deterministic and the failure fast (~3s, no timeout burn):

  1. An "agent" fully connects first → guaranteed into the subscriber's snapshot.
  2. The subscriber wires ParticipantConnected before Connect(), then connects.
  3. A late joiner connects after → its ParticipantConnected (regular delta path) serves as an in-order control: room events are delivered in order, so once the control event fired, the agent's event would already have been dispatched if it were ever coming.

Current failure output:

ParticipantConnected never fired for 'snapshot-agent', which was already in the
room when the subscriber connected (snapshot participant). It IS present in
RemoteParticipants, so only the event is missing. Received: [snapshot-late-joiner]

Test plan

  • Scripts~/run_unity.sh test -m PlayMode -f SnapshotParticipantEventsTests against livekit-server --dev — fails on the repro assertion, control assertions pass
  • Goes green with the upcoming fix (synthesizing the events for snapshot participants in Room.OnConnect)

🤖 Generated with Claude Code

…oom at connect

A remote participant that is already in the room when the local
participant connects (e.g. an agent dispatched concurrently with the
user's connect) is delivered in the connect snapshot instead of as a
ParticipantConnected delta. No layer (Rust SDK, FFI, Unity) ever raises
ParticipantConnected for snapshot participants, so apps driving their
"participant joined" logic purely from that event never learn the
participant exists — although it is present in Room.RemoteParticipants.

The test connects an "agent" first, wires ParticipantConnected before
the subscriber's Connect(), and uses a third late-joining participant
as an in-order control: once the control's event has fired, any event
for the agent would already have been dispatched, so the failing case
is fast and deterministic.

Currently fails (by design) with:
  ParticipantConnected never fired for 'snapshot-agent' ... It IS
  present in RemoteParticipants, so only the event is missing.
  Received: [snapshot-late-joiner]

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant