Per-user opt-out: /bridge optout excludes a Discord user from capture and ghosting #63
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#63
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?
Part of the #43 ToS follow-ups (Dev Policy §2/§3/§7: leave a way to abstain from being bridged).
A Discord user who does not want their voice relayed should be able to run
/bridge optout(and/bridge optin) on the approval bot. Effect, per (user, guild) or global-per-user:ensure_ghost/note_presence),Notes: the privacy policy (docs/privacy-policy.md) currently says "leave the channel or ask a manager to unlink" and flags the command as planned — update it when this ships. The interaction plumbing from #47 (
/bridgecommand, permission-checked handler, pool→mgmt channel) is reusable; opt-out needs no Matrix-side round-trip if the list lives pool-side.Shipped: merged to master
cfda71b, released in v0.3.0-alpha.12./bridge optoutand/bridge optin, open to every Discord user (the/bridgecommand dropped its command-level Manage Server restriction — Discord has no per-subcommand permissions — and the approve subcommand keeps its server-side Manage Server check instead). Scope is global per user id across the instance, persisted at<data_dir>/optout.toml(banlist-style module, atomic writes).Enforcement is defense-in-depth, all pool-side:
VoiceReceiver::demux_tick): an opted-out user's frames are dropped even if a ghost sink lingers mid-retirement.ensure_ghost): gated — covers live voice events and the anchor's member-seeding path.apply_optout).Live-tested on staging 2026-07-07: optout → ephemeral confirmation, ghost tile vanished from the Element Call, file written; staging restart with the user still in voice → the ghost re-seeding skipped them (persistence + seeding gate proven); optin + rejoin → ghost returned. 249 tests + clippy green.
Deviation from the issue text: recorded via
tracingINFO rather than the mgmtaudit.jsonl(the pool has no audit file; the audit log is a mgmt-side construct). Fine for now — the persisted list itself is the authoritative record.linkpending-code reply #80