In-channel disclosure notice when a bridge link activates #64

Closed
opened 2026-07-07 01:23:35 +00:00 by robocub · 2 comments
Collaborator

Part of the #43 ToS follow-ups (Dev Policy §2/§3: make "this channel is relayed off-platform" unmistakable).

Today's disclosure: the [Matrix] nickname prefix, the Manage-Server approval, and (since the ToS-followups branch) the PUBLIC /bridge approve outcome in the channel where the command ran. Missing: a notice in the bridged voice channel itself (its text chat), visible to people who join later and never saw the approval.

Proposal: when a link activates (and on unlink), the approval bot posts to the voice channel's text chat: "🔗 This voice channel is bridged to a Matrix room — voice is relayed off-platform (live only, never recorded). Approved by . Policy: <privacy_policy_url>." Needs Send Messages permission on the channel; degrade gracefully (log a WARN) without it. Plumbing: the mgmt side owns link lifecycle, the pool owns Discord HTTP — reuse the #47 adapter direction or extend the approval reply path with the channel id.

Part of the #43 ToS follow-ups (Dev Policy §2/§3: make "this channel is relayed off-platform" unmistakable). Today's disclosure: the `[Matrix]` nickname prefix, the Manage-Server approval, and (since the ToS-followups branch) the PUBLIC `/bridge approve` outcome in the channel where the command ran. Missing: a notice **in the bridged voice channel itself** (its text chat), visible to people who join later and never saw the approval. Proposal: when a link activates (and on unlink), the approval bot posts to the voice channel's text chat: "🔗 This voice channel is bridged to a Matrix room — voice is relayed off-platform (live only, never recorded). Approved by <manager>. Policy: <privacy_policy_url>." Needs Send Messages permission on the channel; degrade gracefully (log a WARN) without it. Plumbing: the mgmt side owns link lifecycle, the pool owns Discord HTTP — reuse the #47 adapter direction or extend the approval reply path with the channel id.
Author
Collaborator

Link side shipped: merged to master cfda71b, released in v0.3.0-alpha.12. Leaving this open for the unlink side.

On a successful /bridge approve, the approval bot now posts into the bridged voice channel's text chat: "🔗 This voice channel is now bridged to a Matrix room — voice is relayed off-platform (live only, never recorded). Approved by ." plus the privacy_policy_url line. Plumbing: the approval reply oneshot now carries nvb_config::ApprovalOutcome (text + optional notice channel/message) — the shared type crosses the discord↔matrix-rtc boundary through the binary's adapter untouched; mgmt populates the notice from the pending link's channel_id on commit success. Missing Send Messages on the voice channel degrades to a WARN plus the public approval record in the invoking channel. Live-verified on staging 2026-07-07 (notice posted with policy link, exact text confirmed).

Remaining (why this stays open): the unlink-side notice ("this channel is no longer bridged") has no seam — there is no mgmt→pool push channel, and unlink/reconcile teardown runs without a Discord Context in hand. Needs new plumbing (e.g. an mgmt→pool notification mpsc consumed by the command-bot's loop).

**Link side shipped: merged to master `cfda71b`, released in v0.3.0-alpha.12. Leaving this open for the unlink side.** On a successful `/bridge approve`, the approval bot now posts into the bridged voice channel's text chat: "🔗 This voice channel is now bridged to a Matrix room — voice is relayed off-platform (live only, never recorded). Approved by <user>." plus the `privacy_policy_url` line. Plumbing: the approval reply oneshot now carries `nvb_config::ApprovalOutcome` (text + optional notice channel/message) — the shared type crosses the discord↔matrix-rtc boundary through the binary's adapter untouched; mgmt populates the notice from the pending link's `channel_id` on commit success. Missing Send Messages on the voice channel degrades to a WARN plus the public approval record in the invoking channel. Live-verified on staging 2026-07-07 (notice posted with policy link, exact text confirmed). **Remaining (why this stays open): the unlink-side notice** ("this channel is no longer bridged") has no seam — there is no mgmt→pool push channel, and unlink/reconcile teardown runs without a Discord `Context` in hand. Needs new plumbing (e.g. an mgmt→pool notification mpsc consumed by the command-bot's loop).
Author
Collaborator

Unlink side shipped: merged to master 633d27c (v0.3.0-alpha.13) — closing.

The missing mgmt→pool seam now exists: a DiscordNotice mpsc (shared type in nvb-config) from the management bot to the pool's command bot, whose ready spawns a consumer that posts each notice via ChannelId::say (best-effort; missing Send Messages degrades to a WARN, and the Arc<Http> REST client survives gateway reconnects).

Senders:

  • unlink: reads the tenant's channel id before removal (new nvb_config::tenant_discord_channel) and posts "🔌 This voice channel is no longer bridged to Matrix — the link was removed." after a successful reconcile.
  • ban teardown sweep: remove_tenant_entries_matching now returns (name, channel_id) pairs (RemovedTenant); each affected channel gets the same neutral text — the ban itself is deliberately not broadcast in-channel.
  • SIGHUP/hand-edit removals bypass the management bot and are documented out of scope.

Live-verified on staging 2026-07-07: link+approve → 🔗 notice, unlink🔌 notice, both observed in the voice channel's text chat; 0 errors; prod restored (5-bridge baseline). 260 tests + clippy green. The ban-path send shares the same pipe; its channel-id extraction is unit-tested.

With this, the full disclosure story is in place: public approval record + link notice + unlink/teardown notice + [Matrix]-prefixed participants + /bridge optout (#63) + the privacy policy link everywhere.

**Unlink side shipped: merged to master `633d27c` (v0.3.0-alpha.13) — closing.** The missing mgmt→pool seam now exists: a `DiscordNotice` mpsc (shared type in nvb-config) from the management bot to the pool's command bot, whose `ready` spawns a consumer that posts each notice via `ChannelId::say` (best-effort; missing Send Messages degrades to a WARN, and the `Arc<Http>` REST client survives gateway reconnects). Senders: - **`unlink`**: reads the tenant's channel id before removal (new `nvb_config::tenant_discord_channel`) and posts "🔌 This voice channel is no longer bridged to Matrix — the link was removed." after a successful reconcile. - **`ban` teardown sweep**: `remove_tenant_entries_matching` now returns `(name, channel_id)` pairs (`RemovedTenant`); each affected channel gets the same neutral text — the ban itself is deliberately not broadcast in-channel. - SIGHUP/hand-edit removals bypass the management bot and are documented out of scope. **Live-verified on staging 2026-07-07**: link+approve → 🔗 notice, `unlink` → 🔌 notice, both observed in the voice channel's text chat; 0 errors; prod restored (5-bridge baseline). 260 tests + clippy green. The ban-path send shares the same pipe; its channel-id extraction is unit-tested. With this, the full disclosure story is in place: public approval record + link notice + unlink/teardown notice + `[Matrix]`-prefixed participants + `/bridge optout` (#63) + the privacy policy link everywhere.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
dark/nether-voicebridge#64
No description provided.