Skip to content

fix: heal missed Pulse peer discovery without widening LiveKit fan-out - #9637

Draft
eordano wants to merge 1 commit into
devfrom
bugsweep/avatar-roundtrip-materialize
Draft

fix: heal missed Pulse peer discovery without widening LiveKit fan-out#9637
eordano wants to merge 1 commit into
devfrom
bugsweep/avatar-roundtrip-materialize

Conversation

@eordano

@eordano eordano commented Aug 6, 2026

Copy link
Copy Markdown
Member

Remote avatars intermittently disappear after teleporting to a World and back to Genesis Plaza (and, per the 2026-08-05 recurrence, even without teleporting, under archipelago fragmentation). The remote-avatar pipeline is announcement-driven with no reconciliation loop: since the Pulse integration (PR #7291), a peer is announced to an observer exactly once per interest-set entry, and while Pulse is active LiveKit's AnnounceProfileVersion broadcast is targeted only at wallets that already announced to us. Any dropped, negated, or realm-raced Pulse join therefore produces a permanently invisible peer -- there is no client- or server-side membership reconciliation. (The filed v0.154/ v0.155 100%-repro mechanism, PR #9041's ForceRelease of Pulse-sourced avatars on teleport, is already reverted at the pin; this addresses the residual one-shot-discovery fragility class that still recurs.)

  • LiveKitMessagesBroadcaster: while Pulse is active, fall back to an untargeted AnnounceProfileVersion broadcast on the island+scene pipes at a slow cadence (~10s) instead of only the targeted send, so any peer whose Pulse join we missed self-heals over a LiveKit room we demonstrably share. To avoid duplicating the Pulse movement/emote stream room-wide, Send's recipient lists now skip any wallet with a live PeerIdCache session -- recruitment into announcedWallets stays unconditional, but effective fan-out composition for Pulse-live peers is unchanged from HEAD.
  • PulseMultiplayerBus.PlayerState: HandlePlayerLeft now ignores a leave whose SubjectId no longer matches the wallet's current peer id (a late/re-ordered leave for a superseded session), closing the window where a stale leave deletes a freshly re-joined avatar.
  • PeerIdCache: Remove/RemoveWhereNotInRealm only clear the wallet's reverse mapping when it still points at the peer id being removed, so a dangling forward entry from a re-join can't destroy the live session's reverse lookup out from under the new guard.
  • Thread PeerIdCache through PulseContainer -> MultiplayerContainer -> LiveKitMultiplayerContainer so the broadcaster can filter by live session.

Adversarial review (NEEDS-FIX) found the first pass's announce fallback recruited every Pulse-active peer into announcedWallets within one interval, turning targeted LiveKit movement/emotes into full-room fan-out that duplicated the Pulse stream. This revision keeps the fallback announce-only and filters Send by live PeerIdCache membership, so only genuinely missing peers get materialized and fan-out composition matches HEAD.

Add EditMode tests for the join-epoch guard (join/re-join/stale-leave sequencing) and for the broadcaster's fallback-materializes / send-path-excludes-live-session behavior.

Addresses #9337.

Remote avatars intermittently disappear after teleporting to a World
and back to Genesis Plaza (and, per the 2026-08-05 recurrence, even
without teleporting, under archipelago fragmentation). The remote-avatar
pipeline is announcement-driven with no reconciliation loop: since the
Pulse integration (PR #7291), a peer is announced to an observer exactly
once per interest-set entry, and while Pulse is active LiveKit's
AnnounceProfileVersion broadcast is targeted only at wallets that
already announced to us. Any dropped, negated, or realm-raced Pulse
join therefore produces a permanently invisible peer -- there is no
client- or server-side membership reconciliation. (The filed v0.154/
v0.155 100%-repro mechanism, PR #9041's ForceRelease of Pulse-sourced
avatars on teleport, is already reverted at the pin; this addresses the
residual one-shot-discovery fragility class that still recurs.)

- LiveKitMessagesBroadcaster: while Pulse is active, fall back to an
  untargeted AnnounceProfileVersion broadcast on the island+scene pipes
  at a slow cadence (~10s) instead of only the targeted send, so any
  peer whose Pulse join we missed self-heals over a LiveKit room we
  demonstrably share. To avoid duplicating the Pulse movement/emote
  stream room-wide, Send's recipient lists now skip any wallet with a
  live PeerIdCache session -- recruitment into announcedWallets stays
  unconditional, but effective fan-out composition for Pulse-live peers
  is unchanged from HEAD.
- PulseMultiplayerBus.PlayerState: HandlePlayerLeft now ignores a leave
  whose SubjectId no longer matches the wallet's current peer id (a
  late/re-ordered leave for a superseded session), closing the window
  where a stale leave deletes a freshly re-joined avatar.
- PeerIdCache: Remove/RemoveWhereNotInRealm only clear the wallet's
  reverse mapping when it still points at the peer id being removed, so
  a dangling forward entry from a re-join can't destroy the live
  session's reverse lookup out from under the new guard.
- Thread PeerIdCache through PulseContainer -> MultiplayerContainer ->
  LiveKitMultiplayerContainer so the broadcaster can filter by live
  session.

Adversarial review (NEEDS-FIX) found the first pass's announce fallback
recruited every Pulse-active peer into announcedWallets within one
interval, turning targeted LiveKit movement/emotes into full-room
fan-out that duplicated the Pulse stream. This revision keeps the
fallback announce-only and filters Send by live PeerIdCache membership,
so only genuinely missing peers get materialized and fan-out
composition matches HEAD.

Add EditMode tests for the join-epoch guard (join/re-join/stale-leave
sequencing) and for the broadcaster's fallback-materializes /
send-path-excludes-live-session behavior.

Fixes #9337.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

badge

Build skipped — no changes detected under Explorer/.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

badge

Lint ratchet not evaluated for this run.

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