Discord: channel permission math for radio bots (#225 S1) #230

Merged
logan merged 2 commits from feat/225-s1-discord-perms into main 2026-10-05 02:03:28 -04:00
2 Commits
Author SHA1 Message Date
Logan CusanoandClaude Opus 5.5 9e850fedf0 Discord perms: partial guild payload is unknown, not a deny (#225 S1 review)
A guild without its @everyone role (or that role's permissions) was read
as base 0, a definite deny that would block a start. It now raises
ValueError, which S3 treats as unknown and lets the start go ahead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 01:57:15 -04:00
Logan CusanoandClaude Opus 5.5 09746c467b Discord: channel permission math for radio bots (#225 S1)
New pure module app/internal/discord_perms.py:
- effective_permissions(guild, member, channel) -> (bits, trace), in
  Discord's order: owner, base (@everyone | member roles), ADMINISTRATOR,
  @everyone overwrite, role overwrites (all denies then all allows),
  member overwrite, no View Channel = 0, no Connect drops voice perms
  (as discord.py does, so labels match the edge), timeout keeps only
  View + Read History.
- trace names what removed each radio permission, e.g. "denied by
  #dispatch's override for @Muted".
- check_voice(bits, channel, trace=None) -> {ok, is_voice, missing,
  reasons, user_limit, limit_bypass}; only type-2 channels count; labels
  match node-26#38's _join_refusal ("View Channel", "Connect", "Speak").
- Permission strings parsed with int (values above 2**53 tested);
  malformed values raise ValueError so callers treat them as unknown.

No caller yet; S3 wires it into pick_token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 01:53:44 -04:00