Discord: check bot permissions before handing a token to a node (#225 S3) #249

Merged
logan merged 2 commits from feat/225-s3-perm-check into main 2026-10-05 02:38:49 -04:00
2 Commits
Author SHA1 Message Date
Logan CusanoandClaude Opus 5.5 8bdcfcae9c S3 review: overview pool-cap check, membership re-read on pool_full (server-26#225)
- guild_overview offered an invite link to a full pool bot whenever it was
  in ANY server (`if member` tested the non-empty guild_ids list, not
  membership of this guild). Now: in this guild, or invitable.
- start_stream re-reads membership once on pool_full as it already does on
  no_bot_in_guild, so a full pool bot an admin just invited by hand is found.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 02:30:51 -04:00
Logan CusanoandClaude Opus 5.5 2c2cf9d9be Discord: check bot permissions before handing a token to a node (server-26#225 S3)
start_stream now asks Discord (cached REST snapshots, S2) whether each bot
it could pick may View, Connect and Speak in the voice channel, before the
lease. Covers all four entry points: bot POST /discord/streams, web picker,
nodes discord_join, and the reconciler's re-place.

- pick_token: denied bots skipped; confirmed-ok sorts before unknown;
  unknown is allowed (fail open); all denied -> missing_permissions naming
  each bot, missing permission, trace reason and fix. The reuse branch
  falls through when its token is denied.
- Bounded: discord_perm_check_concurrency at once, within
  discord_perm_check_budget_seconds; unanswered = unknown.
- Non-voice channel -> 400 bad_channel (not missing_permissions).
- systems/{id}.preferred_token_id is now read (plan finding 1), as a hint.
- Pool bots at discord_pool_bot_guild_cap are never offered as invites;
  pool_full when nothing else is left (owner Q3).
- handle_actual drops cached access on missing_permissions, channel_full,
  not_in_guild, bad_channel.
- New GET /discord/nodes/{node_id}/guilds/{guild_id}/voice-check (org
  member, names only) and GET /discord/guilds/{guild_id}/voice-check
  (service key or admin).
- PUT /tokens/{id}/prefer/{system_id}: org owners for their own systems
  and own BYO bots; shared systems and pool bots stay admin-only (owner Q2).
  Keeps both pointers single-valued; audited.
- Kill switch: DISCORD_PERM_CHECK_ENABLED=false.
- tests/conftest.py: autouse fixture so no test ever reaches discord.com.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 02:22:45 -04:00