fix(protocol): deliver self-initiated state changes to the actor too
A connected Windows client would randomly snap from its joined channel back to Lobby. Root cause was a state-sync inconsistency, not a drop: the server delivered self-initiated state changes (channel join/leave, stream announce/stop) only as a private *Result to the actor and broadcast the authoritative UserEvent::UPDATED to everyone else. The core never applied the result to its SessionModel, so vc_list_users() kept self in the old channel; the Windows HandleUserUpdated rebuilds _currentChannelId from vc_list_users() on any user's UPDATED event, so the next unrelated event surfaced the stale self-channel. Fix, per the response-vs-broadcast contract now documented in docs/protocol.md §6: the *Result is pure ack/correlation/actor-private payload; the resulting state change is broadcast to every client INCLUDING the actor, and clients apply it to their local model rather than re-deriving own state from a *Result. - server: join/leave/stream announce+stop broadcast with exclude=0 - server: text fan-out includes the sender (channel + private echo) - core: response handlers no longer mutate session_model_ - windows: drop optimistic text echo; render own message via the relay - docs/protocol.md §6: document the response-vs-broadcast contract Registry-level admin broadcasts (move/mute/kick/channel CRUD) already used exclude=0 and were correct. ctest build/m1-dev 18/18 green; VoiceCat.App builds 0 warnings. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
22
PROGRESS.md
22
PROGRESS.md
@@ -24,6 +24,28 @@ up instantly. Newest status at the top.
|
||||
channel CRUD with full per-channel Opus audio config, user moderation (kick/ban/move/server
|
||||
mute/server deafen/set permissions), and server account management. `dotnet test` of the
|
||||
Windows solution passes. Still to do: DRED/audio-quality polish.
|
||||
- **Done:** **Fixed "randomly bumped to Lobby" in the Windows client — actors were excluded
|
||||
from their own state-change broadcasts** (2026-06-17, reported live: a connected client would
|
||||
intermittently snap from its joined channel back to Lobby in the UI). Root cause was a design
|
||||
inconsistency, not a disconnect: the server delivered self-initiated state changes (channel
|
||||
join/leave, stream announce/stop) only as a private `*Result` to the actor and broadcast the
|
||||
authoritative `UserEvent::UPDATED` to *everyone else*. The core never applied the join result
|
||||
to its `SessionModel`, so `vc_list_users()` kept self in the old channel; the Windows
|
||||
`HandleUserUpdated` rebuilds `_currentChannelId` from `vc_list_users()` on **any** user's
|
||||
UPDATED event, so the next unrelated event (someone joining, announcing/stopping a stream,
|
||||
being muted) surfaced the stale self-channel → "bumped to Lobby." Flaky because it depended on
|
||||
other users' activity. **Fix (broad, per the actor-sees-own-changes principle):** the server
|
||||
now broadcasts these `UserEvent::UPDATED`s to **all** clients including the actor
|
||||
(`server/src/conn_session.cpp`, `broadcast(…, /*exclude*/ 0)`), and text fan-out now includes
|
||||
the sender (`resolve_text_targets`), so every client converges via one authoritative path.
|
||||
The `*Result` is now purely ack/correlation/actor-private payload; response handlers no longer
|
||||
mutate the local model. Windows client drops its optimistic text echo (the relay comes back)
|
||||
and renders the sender's own message via `HandleTextMessage`. Documented the
|
||||
response-vs-broadcast contract in `docs/protocol.md` §6. Registry-level admin broadcasts
|
||||
(move/mute/kick/channel CRUD) already used `exclude=0` and were correct. `ctest --test-dir
|
||||
build/m1-dev` — **18/18 green** (PowerShell); Windows `VoiceCat.App` builds 0 warnings.
|
||||
**Latent, not fixed:** the client never sends the `Ping` keepalive that `docs/protocol.md` §7
|
||||
describes (only the server answers pings) — unrelated to this bug, noted for later.
|
||||
- **Done:** **Fixed a *second* silent-playback bug — the playout clock free-ran and drifted off
|
||||
the stream** (2026-06-17, reported live: both `vccli` and the Windows client showed `talking=1/0`
|
||||
correctly on VAD/PTT, mic + screen-share were recognized by peers, but nothing was audible).
|
||||
|
||||
Reference in New Issue
Block a user