S8: main DRB bot optional end to end + owner-flow integration tests (server-26#225)
- Copy: picker, admin Servers/Streams/How-it-works, org Discord card, bot /help and the server-limit refusal no longer imply the DRB server bot is required; a radio bot alone is enough. - Admin overview: per-server main_bot_present, radio_bots, linked_via, directory_source; Servers tab gets a Bots column. - discord_web docstring: states the reversed "never calls Discord" rule (plan finding 5) and the optional server bot. - Server bot directory cog: re-push (which drops C2's cached permission answers) on overwrite changes, role permission changes and role deletes. - tests/test_discord_owner_flows.py: one-bot org (BYO bot, owner-set preferred, OAuth link, picker, start, reconciler) and full setup (server bot + 4 radio bots: placement, shared channel, every refusal explained), against a modelled Discord over httpx.MockTransport. - storage.download_audio removed: no caller on main since #233. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
f49dc86111
commit
9c124d4c8b
@@ -43,8 +43,8 @@ function Kpi({ k, v, s }: { k: string; v: string; s: string }) {
|
||||
|
||||
function HowItWorks() {
|
||||
const steps = [
|
||||
["1 · Desired", "/join in Discord or this page writes a discord_streams doc."],
|
||||
["2 · Lease", "C2 picks an online node on that system and a radio bot already in that server, in one transaction."],
|
||||
["1 · Desired", "A node page's picker, this page, or /join (DRB server bot) writes a discord_streams doc."],
|
||||
["2 · Lease", "C2 picks an online node on that system and a radio bot already in that server that Discord lets View, Connect and Speak in the channel — the system's preferred bot first — in one transaction."],
|
||||
["3 · Reconcile", "A retained MQTT message tells the node its full channel list (token ids, never token strings)."],
|
||||
["4 · Voice", "The node logs in as the leased bot and plays its PulseAudio capture — never Icecast."],
|
||||
["5 · Actual", "The node reports each channel's real state; this page and the Discord reply show it."],
|
||||
@@ -54,6 +54,12 @@ function HowItWorks() {
|
||||
title="How a radio channel stays up"
|
||||
note="Node reboot, C2 sweep, Discord voice drop: the node re-reads its desired state and reconnects; persistent channels whose node went away are re-placed on another node. A channel desired-on but not connected for 2 minutes turns red on the Radio channels tab."
|
||||
>
|
||||
<p className="px-4 pt-4 text-xs text-ink-2">
|
||||
<b className="text-ink">The DRB server bot is optional.</b> One radio bot in a Discord server is enough: adding it
|
||||
through <i>Connect a Discord server</i> (Settings → Organization) links the server, and C2 reads its voice
|
||||
channels and permissions with that bot. The server bot adds the slash commands (/join, /leave, /status,
|
||||
/drb link) and pushes its own channel list; both ways keep working side by side.
|
||||
</p>
|
||||
<div className="grid gap-2 p-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-5">
|
||||
{steps.map(([t, d]) => (
|
||||
<div key={t} className="bg-raised border border-line rounded-lg p-3 text-xs text-ink-muted">
|
||||
|
||||
Reference in New Issue
Block a user