Skip to content

fix: drop misleading bot_permissions preflights, guard configured-channel sends#79

Merged
rolling-codes merged 6 commits into
mainfrom
fix/command-perms-and-send-guards
Jul 11, 2026
Merged

fix: drop misleading bot_permissions preflights, guard configured-channel sends#79
rolling-codes merged 6 commits into
mainfrom
fix/command-perms-and-send-guards

Conversation

@rolling-codes

@rolling-codes rolling-codes commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Carries two commits split out of #78 (they were unpushed local-main commits that leaked into that PR's diff), plus the fix for the genuine review finding they surfaced.

Changes

Cherry-picked from local main:

  • 380e61a → drop bot_permissions from config-setter commands (welcome set_welcome_channel/set_auto_role, starboard_channel, verification_setup, verification_panel) and giveaway add_reactions (button-based flow, no reaction code). These preflights validated the invocation channel while the privileged operation targets a configured channel (or happens later on a different event) — wrong scope.
  • 5690a05 → CLAUDE.md/AGENTS.md planning-config sync.

New (B-021), addressing the Codex P2 review on #78:

  • verification_panel really does send at invocation — to the configured channel. Forbidden/HTTPException are now caught with an ephemeral error response, and nothing is persisted when the panel never posted.
  • Welcome/goodbye event-handler sends get except HTTPException: pass guards, matching the auto-role guard above them (same event-path class as B-014/B-015/B-016).
  • Regression tests for both paths; bugs.md B-021 filed.

Review findings dispositions (from #78 bots)

  • Codex P2 (verification_panel unguarded send) — fixed here; restoring the decorator would have checked the wrong channel.
  • Sourcery: verification_setup needs manage_roles — declined: pure config write; role assignment happens at button click, which already handles Forbidden.
  • Sourcery: welcome setters need perms — declined for the setters (config-only, runtime paths guarded); the genuinely unguarded welcome/goodbye sends are fixed here.
  • Sourcery: giveaway needs add_reactions — declined: giveaway entry is fully button-based; no reaction code exists.

Notes

Test plan

  • New regression tests fail without the guards, pass with them
  • Full suite: 1462 passed
  • Pyright: 0 errors on touched files

🤖 Generated with Claude Code

Summary by Sourcery

Guard configured-channel sends in verification and welcome flows while removing misleading bot_permissions preflights.

Bug Fixes:

  • Handle permission and HTTP errors when posting the verification panel so failures respond ephemerally and do not persist panel state.
  • Prevent welcome and goodbye message send failures from escaping event handlers when the bot lacks permissions in configured channels.

Enhancements:

  • Remove bot_permissions preflights from config-only slash commands and giveaways where they checked the wrong channel or unused permissions.
  • Clarify command callback sweep behavior comment and update internal guidance/docs for graph-based planning and Graphify usage.

Documentation:

  • Document bug B-021, its root cause, fixes, and lessons learned in bugs.md, and sync CLAUDE/AGENTS guidance on using the knowledge graph.

Tests:

  • Add regression tests to ensure verification_panel handles Forbidden sends with an ephemeral error and that welcome send failures do not raise out of the join handler.

tee1339 added 3 commits July 10, 2026 19:35
…veaway add_reactions

Config-setter commands (welcome set_welcome_channel/set_auto_role, starboard_channel,
verification_setup, verification_panel) store data then respond ephemeral — they never
perform the privileged Discord op at invocation, so bot_permissions checked the wrong
scope. Dropped from all five.

giveaway: removed add_reactions (button-based flow, reactions never called).
_command_callbacks: corrected misleading comment — sweep is not rescheduled at first
dispatch if get_running_loop raises at decoration time.
…l (B-021)

The dropped bot_permissions preflight only ever checked the invocation
channel; these sends target a *configured* channel and were never
actually covered:

- verification_panel: Forbidden/HTTPException now respond with an
  ephemeral error instead of escaping the command; nothing persisted
  when the panel never posted (Codex P2 on PR #78)
- welcome/goodbye event sends: except HTTPException pass, matching the
  auto-role guard — event path must not raise into the dispatcher
  (same class as B-014/B-015/B-016)

Regression tests for both; bugs.md B-021 filed.
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@sourcery-ai

sourcery-ai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Reviewer's Guide

Removes misleading decorator-level bot_permissions checks for configuration-only commands and adds direct guards around sends to configured channels, especially for the verification panel and welcome/goodbye handlers, with regression tests and documentation updates.

Sequence diagram for guarded verification_panel send to configured channel

sequenceDiagram
    actor User
    participant VerificationPlugin as VerificationPlugin
    participant Context as Context
    participant ConfiguredChannel as ConfiguredChannel

    User->>VerificationPlugin: verification_panel(ctx)
    VerificationPlugin->>VerificationPlugin: _get_guild_config(guild_id)
    VerificationPlugin->>ConfiguredChannel: channel.send(embed, view)
    alt discord.Forbidden
        VerificationPlugin->>VerificationPlugin: logger.error(...)
        VerificationPlugin->>Context: respond(ephemeral error, ephemeral=True)
        VerificationPlugin-->>User: ephemeral error shown
    else discord.HTTPException
        VerificationPlugin->>VerificationPlugin: logger.error(...)
        VerificationPlugin->>Context: respond(generic failure, ephemeral=True)
        VerificationPlugin-->>User: ephemeral error shown
    else success
        VerificationPlugin->>VerificationPlugin: bot.add_view(view, message_id)
        VerificationPlugin-->>User: verification panel posted
    end
Loading

File-Level Changes

Change Details Files
Guard verification panel sends to the configured channel and remove misplaced bot_permissions preflights.
  • Removed bot_permissions preflight from verification_setup and verification_panel slash commands so permissions are not checked on the invocation channel.
  • Wrapped the verification_panel send to the configured channel in Forbidden/HTTPException handlers, returning ephemeral error responses and avoiding persisting panel state on failure.
  • Added a regression test that simulates a Forbidden send and asserts an ephemeral error response and no saved panel_message_id.
  • Documented bug B-021 for verification_panel in bugs.md.
easycord/plugins/verification.py
tests/test_verification.py
bugs.md
Ensure welcome/goodbye event handler sends do not raise out of the dispatcher and align their behavior with other guarded event paths.
  • Wrapped welcome and goodbye channel.send calls in HTTPException guards to prevent errors from escaping member_join/member_remove handlers.
  • Kept configuration-only welcome/goodbye/auto-role setters but removed their bot_permissions requirements, relying on runtime guards in event paths instead.
  • Added a regression test that a Forbidden welcome send does not escape _on_member_join and still attempts a single send.
  • Documented the welcome/goodbye part of bug B-021 in bugs.md.
easycord/plugins/welcome.py
tests/test_plugin_commands.py
bugs.md
Clean up bot_permissions usage for configuration commands and giveaway, ensuring checks align with the actual execution channel and behavior.
  • Removed bot_permissions send_messages/add_reactions from the giveaway slash command because the flow is button-based and does not use reactions.
  • Removed bot_permissions send_messages from the starboard_channel config setter, since it only writes configuration for a separate runtime path.
  • Kept only relevant permissions for commands that actually act immediately in the invocation channel.
easycord/plugins/giveaway.py
easycord/plugins/starboard.py
Align internal documentation and planning configuration with the updated workflow and graphify usage.
  • Updated AGENTS.md to clarify that the pre-built knowledge graph is the primary architecture reference and added concrete graphify command examples.
  • Adjusted CLAUDE.md graphify usage block to be typed as text and consistent with AGENTS.md.
  • Updated .planning/config.json to sync planning configuration with the new guidance.
AGENTS.md
CLAUDE.md
.planning/config.json
Clarify behavior of the sweep task registration in command callbacks.
  • Updated the comment on the RuntimeError handler for sweep_task scheduling to reflect that the sweep never starts when there is no running event loop at decoration time.
easycord/_command_callbacks.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Improved reliability when sending verification, welcome, and goodbye messages to channels where the bot lacks access.
    • Failed verification-panel sends now provide a clear private error response without saving an invalid panel.
    • Auto-role assignment failures are now logged for easier diagnosis.
  • Improvements

    • Reduced unnecessary permission requirements for giveaway, starboard, verification, and welcome commands.
    • Added regression coverage for Discord permission and messaging failures.

Walkthrough

The change adds a shared send_safe helper for Discord message delivery, applies it to verification and welcome flows, adds failure-handling tests, removes selected command permission declarations, and updates project guidance and configuration references.

Changes

Guarded Discord delivery

Layer / File(s) Summary
Safe-send helper and coverage
easycord/helpers/channel.py, easycord/helpers/__init__.py, tests/test_helpers.py
Adds and exports send_safe, which returns sent messages, logs Discord send failures, and returns None on exceptions with regression tests.
Verification panel failure handling
easycord/plugins/verification.py, tests/test_verification.py
Uses guarded panel sending, responds ephemerally on failure, avoids persisting failed panel messages, and removes decorator-level bot permission requirements.
Welcome and goodbye delivery
easycord/plugins/welcome.py, tests/test_plugin_commands.py
Guards welcome and goodbye sends, logs auto-role HTTP failures, removes related command permission declarations, and tests non-propagating send failures.
Command metadata and repository guidance
easycord/plugins/giveaway.py, easycord/plugins/starboard.py, .planning/config.json, AGENTS.md, CLAUDE.md, bugs.md, easycord/_command_callbacks.py
Adjusts command permissions, updates project guidance and configuration paths, records bug B-021, and clarifies cooldown-sweep behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant VerificationPlugin
  participant send_safe
  participant DiscordChannel
  participant CommandInvoker
  participant PanelStore
  VerificationPlugin->>send_safe: Send verification embed and view
  send_safe->>DiscordChannel: channel.send(...)
  DiscordChannel-->>send_safe: Message or Discord exception
  send_safe-->>VerificationPlugin: Message or None
  alt send succeeds
    VerificationPlugin->>PanelStore: Persist panel_message_id
  else send fails
    VerificationPlugin->>CommandInvoker: Send ephemeral error response
  end
Loading

Possibly related PRs

Poem

I’m a bunny with safer sends,
No lost messages, no loose ends.
Panels warn when channels say “no,”
Welcome notes handle errors slow.
Hop, hop—tests now watch the flow!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.83% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the main changes: removing misleading permission preflights and guarding configured-channel sends.
Description check ✅ Passed The description directly matches the changeset and explains the permission removals, guarded sends, tests, and docs updates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/command-perms-and-send-guards

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added bug Something isn't working documentation Improvements or additions to documentation plugin tests labels Jul 10, 2026
@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.32258% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
easycord/plugins/welcome.py 77.77% 2 Missing ⚠️
easycord/_command_callbacks.py 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@sourcery-ai sourcery-ai 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.

Hey - I've left some high level feedback:

  • In the welcome/goodbye event handlers, swallowing all discord.HTTPException without logging makes debugging real failures difficult; consider either narrowing this to Forbidden or at least emitting a debug log when the send fails.
  • You now have several places that implement the same "configured channel send with Forbidden/HTTPException handling" pattern (verification panel, welcome/goodbye, auto-role); consider extracting a small helper for this to keep the behavior consistent and reduce duplication.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the welcome/goodbye event handlers, swallowing all `discord.HTTPException` without logging makes debugging real failures difficult; consider either narrowing this to `Forbidden` or at least emitting a debug log when the send fails.
- You now have several places that implement the same "configured channel send with Forbidden/HTTPException handling" pattern (verification panel, welcome/goodbye, auto-role); consider extracting a small helper for this to keep the behavior consistent and reduce duplication.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

tee1339 added 2 commits July 10, 2026 19:52
Covers the remaining B-021 guard branches flagged by codecov/patch.
Review feedback on the B-021 guards:

- send_safe() in helpers/channel.py sends to a configured channel,
  absorbs Forbidden/HTTPException with a logged warning, and returns
  the message or None; adopted by verification_panel and the
  welcome/goodbye event sends (previously except-pass with no log)
- welcome auto-role failure now logs a warning instead of a silent
  pass (add_roles, so the send helper doesn't apply)
- unit tests for all three helper branches

member_logging._log_to_channel has the same shape but lives in PR #78's
diff; adopting it there is a post-merge follow-up.
@rolling-codes rolling-codes merged commit 58a021c into main Jul 11, 2026
12 checks passed
@rolling-codes rolling-codes deleted the fix/command-perms-and-send-guards branch July 11, 2026 17:13

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bugs.md`:
- Around line 27-28: Insert a blank line between the B-021 heading and the
following “Where” list item in bugs.md, leaving the heading text and list
content unchanged.

In `@easycord/plugins/welcome.py`:
- Around line 79-84: Extract the inline auto-role assignment handling near the
welcome event into a shared add_roles_safe-style helper, analogous to send_safe,
with the helper owning the Discord call, warning log, and HTTPException handling
so exceptions cannot escape the dispatcher. Route the auto-role path through
this helper and add a regression test asserting the warning is emitted on
assignment failure.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: abeee6ea-3776-4a18-95fc-e4b82e98512e

📥 Commits

Reviewing files that changed from the base of the PR and between 2799fdc and 9c9f5f3.

📒 Files selected for processing (14)
  • .planning/config.json
  • AGENTS.md
  • CLAUDE.md
  • bugs.md
  • easycord/_command_callbacks.py
  • easycord/helpers/__init__.py
  • easycord/helpers/channel.py
  • easycord/plugins/giveaway.py
  • easycord/plugins/starboard.py
  • easycord/plugins/verification.py
  • easycord/plugins/welcome.py
  • tests/test_helpers.py
  • tests/test_plugin_commands.py
  • tests/test_verification.py
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: CodeRabbit
🧰 Additional context used
📓 Path-based instructions (6)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: For questions about EasyCord architecture, module relationships, data flows, or cross-cutting patterns, query graphify-out/graph.json with /graphify before manually reading source files; do not rebuild the graph or read deprecated vault files.
The CI PR gate runs critical Ruff checks, advisory full Ruff, release metadata validation, plugin-test verification, and pytest across Python 3.10, 3.11, and 3.12 in that order.
Before making changes, verify repository state with git status --short --branch and git log --oneline -5 --decorate.

Files:

  • easycord/helpers/__init__.py
  • AGENTS.md
  • easycord/plugins/starboard.py
  • easycord/_command_callbacks.py
  • easycord/plugins/giveaway.py
  • CLAUDE.md
  • tests/test_helpers.py
  • bugs.md
  • easycord/helpers/channel.py
  • tests/test_verification.py
  • tests/test_plugin_commands.py
  • easycord/plugins/verification.py
  • easycord/plugins/welcome.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Install development dependencies with pip install -e ".[dev]".
Async tests use pytest-asyncio with asyncio_mode = "auto"; do not manually set up an event loop.
Build the distribution package with python -m build.

Files:

  • easycord/helpers/__init__.py
  • easycord/plugins/starboard.py
  • easycord/_command_callbacks.py
  • easycord/plugins/giveaway.py
  • tests/test_helpers.py
  • easycord/helpers/channel.py
  • tests/test_verification.py
  • tests/test_plugin_commands.py
  • easycord/plugins/verification.py
  • easycord/plugins/welcome.py
{easycord,tests}/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

The blocking lint gate runs ruff check easycord tests --select E9,F63,F7,F82 and python scripts/verify_plugin_tests.py.

Files:

  • easycord/helpers/__init__.py
  • easycord/plugins/starboard.py
  • easycord/_command_callbacks.py
  • easycord/plugins/giveaway.py
  • tests/test_helpers.py
  • easycord/helpers/channel.py
  • tests/test_verification.py
  • tests/test_plugin_commands.py
  • easycord/plugins/verification.py
  • easycord/plugins/welcome.py
easycord/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

easycord/**/*.py: Bot-level behavior must be added to the appropriate bot mixin file: _bot_commands.py, _bot_events.py, _bot_guild.py, or _bot_plugins.py; bot.py defines Bot through multiple inheritance.
Context functionality belongs in context.py or the relevant _context_channels.py, _context_moderation.py, or _context_ui.py mixin.
Route AI orchestration through orchestrator.py and provider adapters in plugins/_ai_providers.py; register tools with ToolRegistry, enforce ToolSafety, and await every ToolLimiter method.
Per-guild state must always go through the database layer and must not be stored directly on the Bot instance.
Look up localization keys through LocalizationManager; do not hardcode strings in plugin responses.
Use ctx.user or ctx.member; ctx.author does not exist.
Treat ctx.is_admin as a property and do not call it as ctx.is_admin().
Cooldown sentinels must default to float("-inf"), not 0.0, so first-message events pass on fresh runners.

easycord/**/*.py: Import public APIs from easycord; do not import internal _-prefixed modules directly.
Use ctx.user or ctx.member, never ctx.author; treat ctx.is_admin as a property and never call it.
Store per-guild plugin state in the database layer, not on the Plugin instance.
Never hardcode plugin response strings; look them up through ctx.t(...).
Always await asynchronous ToolLimiter methods such as check_limit, reset_user, and reset_tool.
Require an explicit ToolSafety annotation when registering an @ai_tool.
Narrow channel types with SENDABLE_CHANNEL_TYPES before calling .send() on a channel obtained from context or Discord.
Initialize LevelsPlugin._cooldowns sentinels with float("-inf"), not 0.0, so the first message passes.
Route every destructive action in event-path plugins through one governed method that owns rate limiting, channel narrowing, and Discord error handling; Discord exceptions must not escape the dispatc...

Files:

  • easycord/helpers/__init__.py
  • easycord/plugins/starboard.py
  • easycord/_command_callbacks.py
  • easycord/plugins/giveaway.py
  • easycord/helpers/channel.py
  • easycord/plugins/verification.py
  • easycord/plugins/welcome.py
**/*.{py,md}

📄 CodeRabbit inference engine (CLAUDE.md)

For questions about EasyCord architecture, module relationships, data flows, or cross-cutting patterns, query C:\Users\Tom\Code projects\EasyCord\graphify-out\graph.json before manually reading source files. Do not rebuild the graph or read deprecated vault files.

Files:

  • easycord/helpers/__init__.py
  • AGENTS.md
  • easycord/plugins/starboard.py
  • easycord/_command_callbacks.py
  • easycord/plugins/giveaway.py
  • CLAUDE.md
  • tests/test_helpers.py
  • bugs.md
  • easycord/helpers/channel.py
  • tests/test_verification.py
  • tests/test_plugin_commands.py
  • easycord/plugins/verification.py
  • easycord/plugins/welcome.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Run the test suite with pytest tests/; individual tests may be run with pytest node IDs.

tests/**/*.py: Use easycord.testing helpers such as invoke, FakeContextBuilder, and PluginTestSuite for command and plugin tests.
When constructing plugins in tests, use __new__, assign _bot, and then call Plugin.__init__; do not assign bot directly.

Files:

  • tests/test_helpers.py
  • tests/test_verification.py
  • tests/test_plugin_commands.py
🪛 markdownlint-cli2 (0.22.1)
bugs.md

[warning] 27-27: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🔇 Additional comments (13)
easycord/helpers/channel.py (1)

4-6: LGTM!

Also applies to: 16-40

easycord/helpers/__init__.py (1)

2-2: LGTM!

Also applies to: 16-16

tests/test_helpers.py (1)

1-10: LGTM!

Also applies to: 149-183

easycord/plugins/giveaway.py (1)

263-263: LGTM!

easycord/plugins/starboard.py (1)

262-262: LGTM!

.planning/config.json (1)

61-61: LGTM!

AGENTS.md (1)

5-17: LGTM!

CLAUDE.md (1)

9-9: LGTM!

easycord/_command_callbacks.py (1)

87-93: 🩺 Stability & Availability

Verify cooldown-sweep startup when no event loop is running.

This path permanently skips cleanup when build_slash_callback is constructed outside an active loop; first dispatch does not start the sweep. Confirm registration always occurs inside a running loop, or lazily create the sweep task on first invocation to prevent stale buckets from accumulating.

easycord/plugins/verification.py (1)

11-11: LGTM!

Also applies to: 228-228, 265-265, 299-311

tests/test_verification.py (1)

288-317: LGTM!

Also applies to: 318-341

easycord/plugins/welcome.py (1)

4-10: LGTM!

Also applies to: 20-21, 103-103, 122-126, 150-150

tests/test_plugin_commands.py (1)

279-303: LGTM!

Also applies to: 305-322

Comment thread bugs.md
Comment on lines +27 to +28
## B-021 — Unguarded sends in verification_panel and welcome event handlers
- **Where:** `easycord/plugins/verification.py` `verification_panel` (panel send to the

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a blank line after the B-021 heading.

markdownlint reports MD022 because the list starts immediately after ## B-021 ...; insert one blank line before - **Where:**.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 27-27: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bugs.md` around lines 27 - 28, Insert a blank line between the B-021 heading
and the following “Where” list item in bugs.md, leaving the heading text and
list content unchanged.

Source: Linters/SAST tools

Comment on lines +79 to +84
except discord.HTTPException as exc:
# bot may lack manage_roles or the role may be above its top role
logger.warning(
"Failed to assign auto-role %s in guild %s: %s",
role.id, member.guild.id, exc,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider a shared helper for role-assignment failures, mirroring send_safe.

Logging instead of silently swallowing is a good fix, but the auto-role assignment is still handled with an ad-hoc inline try/except, unlike the message sends in this same file which are now routed through the shared send_safe helper. This diverges from the pattern this PR just established for guarded Discord operations, and there's no dedicated test asserting the new warning-log behavior (only the send-failure paths gained regression tests).

Consider extracting an analogous add_roles_safe-style helper (owning the try/except + logging) for consistency and to make this path independently testable, and add a regression test for the auto-role failure log path.

As per path instructions, "Route every destructive action in event-path plugins through one governed method that owns rate limiting, channel narrowing, and Discord error handling; Discord exceptions must not escape the dispatcher."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@easycord/plugins/welcome.py` around lines 79 - 84, Extract the inline
auto-role assignment handling near the welcome event into a shared
add_roles_safe-style helper, analogous to send_safe, with the helper owning the
Discord call, warning log, and HTTPException handling so exceptions cannot
escape the dispatcher. Route the auto-role path through this helper and add a
regression test asserting the warning is emitted on assignment failure.

Source: Path instructions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation plugin tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants