Puppet not re-joining its assigned channel after a mod force-move #62
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
dark/nether-voicebridge#62
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Bug (known gap, surfaced by the #38 test-framework design)
When a guild moderator force-moves a bridge puppet bot to a different voice channel, the puppet stays there — it never re-joins its assigned channel. The bridged Matrix speaker keeps "speaking" into the wrong channel (or effectively goes silent for the bridged call) until the puppet is next re-allocated.
Why
voice_state_update:crates/discord/src/puppet.rs:1982early-returns onis_bridge_bot(user_id), so an externally-caused channel change is invisible to the allocator.DriverDisconnectrecovery (epoch-checked rejoin +sweep_voice_healthbackstop) does not cover this case: a move keeps the voice connection alive, so noDriverDisconnectfires and the health sweep sees a healthy (but misplaced) connection.A mod disconnect of a puppet, by contrast, IS recovered since #46 — that's the adjacent case and it works.
Expected behavior
Watch the puppet's own
voice_state_update, compare the actual channel against the assigned one, and re-issue a join to the assigned channel (epoch-guarded, same shape as the disconnect recovery).Test-framework linkage
This is scenario 10,
force_move_no_rejoinin the catalogue (docs/nether-voicebridge-testing-design.md): the live E2E suite encodes the expected behavior and marks itKnownFailreferencing this issue. Per the framework's locked policy, the fix happens here — never inside test work. When this is fixed, the scenario flips to a must-pass regression guard (the suite reports "unexpectedly fixed" until the expectation is updated).Fixed: merged to master
5f7587d(rides v0.3.0-alpha.11).As filed: the pool discarded its own bots'
voice_state_updates (echo-exclusion), and neither the #46 disconnect recovery (noDriverDisconnectfires on a move) nor the health sweep (current_channel().is_none()— a moved bot is still in a channel) covered a moderator force-move.Fix, event + sweep, mirroring #46's shape:
ready-confirmed). A bot seeing its OWN voice-state event forwards aVerifyConnectedprobe to its command loop, delayed 1 s so songbird's view settles. The probe carries no channel snapshot — it re-evaluates songbird's current state at processing time, so probes queued behind an in-flight recovery are no-ops (an earlier snapshot design replayed stale displacement and double-rejoined; caught live).voice_displaced: out of voice entirely OR connected to a channel other than the assignedGuildConn.chan.channel_id. The periodic sweep gets the same check as backstop.rejoin_puppetlets the gateway leave settle (1.5 s) when the connection was LIVE before rejoining — a live connection's leave echo used to cancel the immediate rejoin ("request was cancelled/dropped"), needlessly quarantining the bot and failing over to a different one (caught live). The dead-connection recovery keeps its proven full-speed timing.Live-verified on staging 2026-07-07: three force-moves, each recovered by the SAME bot back in its assigned channel in ~3 s (1 s probe delay + 1.5 s settle + join), zero quarantines, zero failovers, zero errors. 236 tests + clippy green.