Skip to content

Add block list, live panel state, and admin-override audit logging - #14

Merged
diese-tech merged 3 commits into
mainfrom
claude/ponytail-audit-ui-review-eavl1k
Jul 19, 2026
Merged

Add block list, live panel state, and admin-override audit logging#14
diese-tech merged 3 commits into
mainfrom
claude/ponytail-audit-ui-review-eavl1k

Conversation

@diese-tech

Copy link
Copy Markdown
Owner

Summary

Third batch from the ongoing audit — remaining QoL items plus operational visibility, coordinated alongside the independent test/CI suite in #13 (disjoint files, no overlap).

  • Block list — the counterpart to the existing Permit list. /yap block user:, /yap unblock user:, and a new panel Block button. A block applies a persistent per-member deny overwrite (view_channel/connect both False) that survives the member leaving and holds regardless of the room's lock/hide state — Discord resolves per-member overwrites ahead of role/@everyone overwrites, so no bot-side join handling is needed for enforcement. Blocking disconnects the member if currently present. Block and Permit are mutually exclusive per member — applying one clears the other, mirroring how Kick already clears a permit. Blocked members now also appear in /yap room, alongside the existing Permitted list.

  • Live panel state — the persistent room panel embed previously only reflected the owner (and only after PR Fix room permission bypass and stale panel embed after ownership change #12's fix for that). It now shows live locked/hidden state and the current permit list too. refresh_panel_message was redesigned to re-derive the owner and state from the channel/DB itself rather than requiring every caller to pass them in — this let it get wired into apply_lock/apply_unlock/apply_hide/apply_unhide/apply_permit/apply_unpermit (previously only apply_transfer/apply_claim refreshed it) with no extra bookkeeping at each call site. The reconcile-time backfill for rooms that predate panel_message_id (added in Fix room permission bypass and stale panel embed after ownership change #12) now also posts with the room's actual current state instead of always defaulting to unlocked/visible/no-permits.

  • Admin-override audit logging — every admin-override room action (a non-owner Manage Channels admin acting on someone else's room, now gated on presence since Fix room permission bypass and stale panel embed after ownership change #12) is logged to the console, and optionally posted to a configurable channel via the new /yap modlog command (shown in /yap config). This gives server owners visibility into moderation actions taken on rooms they don't own.

  • Deduped has_manage_channelsservices/ownership.py previously carried a byte-for-byte copy of services/permissions.py::require_manage_channels. It now imports the canonical implementation under its existing local name, so no call sites changed.

Changes

  • schema.sql, storage.py: new temp_channel_blocks table (mirrors temp_channel_permits, purged with the room) and guild_configs.mod_log_channel_id column, both via the established guarded-migration pattern; new add_block/remove_block/list_blocks/set_mod_log_channel.
  • services/permissions.py: new deny_member_access (Block's counterpart to the existing grant_member_access).
  • services/room_actions.py: apply_block/apply_unblock, blocked_members; apply_permit/apply_block cross-clear each other; build_room_info_embed gains a blocked field; apply_unlock/apply_unhide gain a bot parameter (needed for the refresh call).
  • services/panel.py: build_panel_embed/send_room_panel/refresh_panel_message take/derive lock/hide/permit state; new Block button + select (row 2); lock/unlock/hide/unhide/permit/unpermit now trigger a refresh.
  • services/ownership.py: _log_admin_override, called from _authorize_channel right after the presence check passes; dedupe of has_manage_channels.
  • services/temp_channels.py: reconcile backfill posts real current state.
  • commands/setup.py, commands/owner_controls.py: /yap block, /yap unblock, /yap modlog; help/config text updated.

Test plan

  • py_compile clean; circular-import hazard re-verified in both orders after the new services.panelservices.room_actions surface area grew
  • Full command tree builds with yap block/yap unblock/yap modlog present (22 commands total); panel is persistent with 11 buttons across 3 rows
  • Block storage round-trip, idempotent add, purge-on-room-close
  • apply_block: overwrite applied, stored, clears any existing permit, disconnects a present target, self-block rejected; apply_unblock clears the record; apply_permit clears any existing block (mutual exclusivity both directions)
  • mod_log_channel_id setter round-trip, including auto-creating the guild config row when it doesn't exist yet
  • Migration verified against a simulated legacy database missing panel_message_id, mod_log_channel_id, and the blocks table all at once — all three added, existing rows preserved, immediately usable; double-init idempotent
  • refresh_panel_message reflects live locked/hidden state and the permit list; no-ops cleanly if the current owner has left the guild
  • _authorize_channel admin-override path: posts to the configured mod-log channel with the correct content; no-ops cleanly when unconfigured; never fires for an owner's own action
  • apply_lock/apply_unlock/apply_hide/apply_unhide each call refresh_panel_message(bot, channel) exactly once
  • Manual verification against a live Discord guild (no bot token in this environment)

Generated by Claude Code

claude added 2 commits July 19, 2026 21:00
- Block list: /yap block, /yap unblock, and a panel Block button. A
  block applies a persistent per-member deny overwrite (survives leaving,
  works regardless of lock/hide state) and disconnects the member if
  present. Block and Permit are mutually exclusive per member -- applying
  one clears the other. Blocked members now also show in /yap room,
  mirroring the existing Permitted list.

- Live panel state: the persistent room panel embed now shows live
  locked/hidden state and the current permit list, not just the owner.
  refresh_panel_message re-derives owner and state from the channel
  itself rather than requiring callers to pass them, so it's now wired
  into lock/unlock/hide/unhide/permit/unpermit (previously only
  transfer/claim refreshed it). The reconcile-time panel backfill for
  pre-migration rooms now also reflects actual state instead of posting
  with default values.

- Admin-override audit logging: every admin-override room action (a
  non-owner Manage Channels admin acting on someone else's room) is now
  logged to the console, and optionally to a configurable channel via
  the new /yap modlog command, shown in /yap config.

- Deduped has_manage_channels: services/ownership.py now imports the
  canonical implementation from services/permissions.py instead of
  keeping an identical copy.
Not project content -- excluding it the same way .vscode/ already is.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 69511d38b7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread services/room_actions.py
Comment thread services/ownership.py Outdated
…ries

- Departure cleanup (cleanup_temp_channel) was calling
  revoke_member_overwrites for a blocked member disconnected by
  apply_block, immediately clearing the deny overwrite that was just
  applied -- the block database record stayed but the actual Discord
  permission was wiped, letting the member see/rejoin right away. Blocked
  IDs are now exempted from that revocation, same as owner/permitted IDs.

- Admin-override logging moved from authorization time to actual
  execution time. Panel actions that open a modal or select (Rename,
  Limit, Transfer, Kick, Permit, Block) authorize twice per logical
  action -- once opening the UI, again on submit -- so logging inside
  _authorize_channel produced two log entries per completed action, plus
  phantom entries when an admin cancelled or picked an invalid target.
  log_admin_action is now called explicitly at the end of each apply_*
  function's success path instead. apply_transfer captures the
  pre-transfer owner record before mutating, since a post-mutation
  re-fetch would compare the actor against the *new* owner and wrongly
  flag an ordinary owner-initiated transfer as an admin override.
@diese-tech
diese-tech merged commit 61e6f94 into main Jul 19, 2026
@diese-tech
diese-tech deleted the claude/ponytail-audit-ui-review-eavl1k branch July 19, 2026 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants