Skip to content

fix: default missing "enabled" config key per plugin _DEFAULTS#78

Merged
rolling-codes merged 2 commits into
mainfrom
fix/74-enabled-default-missing-key
Jul 11, 2026
Merged

fix: default missing "enabled" config key per plugin _DEFAULTS#78
rolling-codes merged 2 commits into
mainfrom
fix/74-enabled-default-missing-key

Conversation

@rolling-codes

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

Copy link
Copy Markdown
Owner

Closes #74

Summary

if not cfg.get("enabled") with no default treats a missing enabled key as disabled, silently turning a plugin off. A stored config section can exist with any subset of the default keys — _get_config() only merges _DEFAULTS when the section is entirely absent — so a manual config-file edit or partial external update can strip the key. Same class as starboard's B-018; supersedes B-019's "verified benign" verdict, which only audited internal config-creation paths.

Changes

  • economy.py:219, role_persistence.py:53/79, member_logging.py:60cfg.get("enabled", True), matching each plugin's _DEFAULTS
  • ai_moderator.py:183/237 — explicit cfg.get("enabled", False); moderation is opt-in by design, so a missing key correctly reads as disabled (no behavior change)
  • Regression tests for the missing-enabled-key scenario in all four plugins (RED confirmed pre-fix on the three enabled-by-default plugins)
  • bugs.md: B-020 filed; B-019 marked superseded
  • tests/test_ai_moderator.py: _make_plugin orchestrator annotation widened to MagicMock | None (pre-existing Pyright error, 7 call sites pass None)

Corrections to the issue as filed

  • auto_responder.py:68 was already fixed by B-013 (2026-07-09) — no change needed.
  • ai_moderator.py is intentionally opt-in (_DEFAULTS has enabled: False), so it gets an explicit False default rather than True.
  • member_logging.py:60 had the same bug but wasn't listed in the issue — included here.

Test plan

  • New regression tests fail on main's gate code, pass with the fix
  • Full suite: 1464 passed
  • Pyright clean on all touched files (0 errors)

🤖 Generated with Claude Code

Summary by Sourcery

Ensure plugin enabled-state reads use explicit defaults and document the reopened config bug pattern.

Bug Fixes:

  • Prevent economy, role_persistence, and member_logging plugins from silently disabling when the stored config section is missing the enabled key.
  • Keep AI moderator behavior explicitly opt-in by default while handling missing enabled keys correctly in both runtime checks and config display.
  • Clarify command callback sweep behavior to avoid implying a background sweep starts when no event loop is running.

Enhancements:

  • Relax bot_permissions requirements on several slash commands (verification, welcome, giveaway, starboard) to reduce unnecessary permission coupling.
  • Document Graphify as the canonical architecture knowledge base in AGENTS.md and tighten formatting in CLAUDE.md.

Documentation:

  • Add bug entry B-020 and a detailed write-up of the no-default cfg.get("enabled") pattern, marking B-019 as superseded and expanding the threat model to manual config edits and partial updates.

Tests:

  • Add regression tests across economy, role_persistence, member_logging, and ai_moderator plugins to verify behavior when the enabled config key is missing.
  • Allow a None orchestrator in AI moderator tests to align annotations with existing call sites.

@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

Fixes missing-default handling for enabled config keys across several plugins so that absent keys fall back to each plugin’s _DEFAULTS, adds regression tests for the manual-edit/partial-update threat model, documents the bug as B-020 (superseding B-019), and makes a few small annotation and command-metadata corrections.

Sequence diagram for updated enabled gate in plugins when config key is missing

sequenceDiagram
    actor Discord
    participant EconomyPlugin
    participant ConfigStore

    Discord->>EconomyPlugin: _on_message(message)
    EconomyPlugin->>ConfigStore: _get_config(guild_id)
    ConfigStore-->>EconomyPlugin: cfg

    alt enabled_key_present
        EconomyPlugin->>EconomyPlugin: cfg.get(enabled, True)
        EconomyPlugin->>EconomyPlugin: [enabled is True]
        EconomyPlugin->>EconomyPlugin: apply message_reward
    else enabled_key_missing
        EconomyPlugin->>EconomyPlugin: cfg.get(enabled, True)
        EconomyPlugin->>EconomyPlugin: [absence reads as True]
        EconomyPlugin->>EconomyPlugin: apply message_reward
    end

    note over EconomyPlugin: Before B-020: cfg.get(enabled)\nmade absence read as False,\nsilently disabling the plugin
Loading

File-Level Changes

Change Details Files
Ensure enabled-by-default plugins treat a missing "enabled" config key as enabled rather than silently disabling the plugin.
  • Change economy plugin reward gate to use cfg.get("enabled", True).
  • Change role_persistence member remove/join gates to use cfg.get("enabled", True).
  • Change member_logging log gate to use cfg.get("enabled", True).
  • Add clarifying comments about manual config edit / partial update threat model around each gate.
easycord/plugins/economy.py
easycord/plugins/role_persistence.py
easycord/plugins/member_logging.py
Make ai_moderator’s opt-in behavior explicit by defaulting missing "enabled" to False in both runtime and config display paths.
  • Change ai_moderator _on_message gate to use cfg.get("enabled", False) with comment about opt-in design.
  • Change mod_config embed field to display cfg.get("enabled", False) to match _DEFAULTS.
  • Add regression test verifying that a section missing "enabled" keeps moderation off.
  • Widen _make_plugin orchestrator parameter type to MagicMock
None to match actual call sites and fix Pyright error.
Add regression tests for the missing-"enabled"-key scenario across affected plugins to pin the intended defaults behavior under manual config edits or partial updates. tests/test_plugin_logic.py
tests/test_role_persistence.py
tests/test_plugins_new.py
Document bug B-020 and clarify that it supersedes B-019’s previous benign assessment, expanding the threat model to include manual config edits and external partial updates.
  • Add B-020 row to bug table describing affected plugins and fix.
  • Add detailed B-020 section explaining root cause, fixes, tests, and lessons learned.
  • Update B-019 row status to "Superseded by B-020" and adjust wording.
  • Mark B-019 section as SUPERSEDED and add note about under-scoped threat model.
bugs.md
Tighten and correct command metadata and documentation around permissions, bot requirements, and knowledge-graph usage.
  • Remove bot_permissions requirements from certain slash commands where they are no longer needed or enforced (verification, welcome, giveaway, starboard).
  • Adjust comment in _command_callbacks.py to accurately describe behavior when there is no running event loop at decoration time.
  • Clarify AGENTS.md to treat Graphify as the canonical architecture knowledge base and discourage reading deprecated vault files.
  • Fix CLAUDE.md fenced block language to ```text so Graphify usage instructions render correctly.
easycord/plugins/verification.py
easycord/plugins/welcome.py
easycord/plugins/giveaway.py
easycord/plugins/starboard.py
easycord/_command_callbacks.py
AGENTS.md
CLAUDE.md

Assessment against linked issues

Issue Objective Addressed Explanation
#74 Ensure AutoResponderPlugin uses cfg.get("enabled", True) (or equivalent default-True logic) so that a missing "enabled" key does not silently disable auto-responses.
#74 Update Economy plugin’s message reward gate to use cfg.get("enabled", True) so that a missing "enabled" key does not silently disable rewards.
#74 Update RolePersistence plugin’s member handlers to use cfg.get("enabled", True) so that a missing "enabled" key does not silently disable role persistence.

Possibly linked issues


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

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

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@rolling-codes, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 47 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9c110ac5-5a62-43c0-9b22-dacfaf0d7846

📥 Commits

Reviewing files that changed from the base of the PR and between 034d6df and 598dc67.

📒 Files selected for processing (9)
  • bugs.md
  • easycord/plugins/ai_moderator.py
  • easycord/plugins/economy.py
  • easycord/plugins/member_logging.py
  • easycord/plugins/role_persistence.py
  • tests/test_ai_moderator.py
  • tests/test_plugin_logic.py
  • tests/test_plugins_new.py
  • tests/test_role_persistence.py
📝 Walkthrough

Walkthrough

The changes update missing-key defaults for several plugins, adjust slash-command bot permission metadata, add regression tests and bug records, and revise project guidance and planning documentation.

Changes

Plugin configuration defaults

Layer / File(s) Summary
Enablement gate defaults
easycord/plugins/*.py
Moderation defaults missing enabled keys to disabled, while economy, member logging, and role persistence default them to enabled.
Missing-key regression tests
tests/test_ai_moderator.py, tests/test_plugin_logic.py, tests/test_plugins_new.py, tests/test_role_persistence.py, bugs.md
Regression tests cover the missing-key behavior, and B-020 supersedes the earlier B-019 verification.

Slash-command permission metadata

Layer / File(s) Summary
Command registration permissions
easycord/plugins/giveaway.py, easycord/plugins/starboard.py, easycord/plugins/verification.py, easycord/plugins/welcome.py
Bot permission requirements were removed or narrowed in slash-command decorators without changing command handlers.

Project guidance and configuration

Layer / File(s) Summary
Repository guidance and path configuration
.planning/config.json, AGENTS.md, CLAUDE.md, easycord/_command_callbacks.py
The CLAUDE.md path, Graphify instructions, code-fence annotation, and cooldown-sweep comment were updated.

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

Possibly related PRs

Suggested labels: bug, documentation, plugin, tests

Poem

A rabbit hops through configs bright,
Missing keys now choose what’s right.
Commands shed permissions spare,
Tests bloom softly everywhere.
Graphify guides the way ahead—
“Binky!” says the docs, well-read.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR also changes unrelated slash-command permissions, AGENTS/CLAUDE docs, and callback comments outside issue #74. Split the permission, documentation, and comment-only edits into separate PRs or justify them in the linked issue.
Docstring Coverage ⚠️ Warning Docstring coverage is 65.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main fix: defaulting missing enabled keys using plugin defaults.
Description check ✅ Passed The description is directly about the missing enabled-key bug and the related fixes and tests.
Linked Issues check ✅ Passed The enabled-default bug is fixed with matching regression coverage, and Auto Responder is noted as already fixed elsewhere.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/74-enabled-default-missing-key

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.

@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot added the bug Something isn't working label Jul 10, 2026

@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 found 3 issues, and left some high level feedback:

  • The change to _command_callbacks.py’s comment (sweep never starts) no longer matches the existing behavior where the sweep is deferred to first dispatch; either adjust the logic to truly never start without a loop, or update the comment to reflect the actual behavior.
  • Several slash command decorators had bot_permissions removed (verification, welcome, giveaway, starboard); please double-check that this is intentional and that permission checks are enforced consistently across commands using a single mechanism.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The change to `_command_callbacks.py`’s comment (`sweep never starts`) no longer matches the existing behavior where the sweep is deferred to first dispatch; either adjust the logic to truly never start without a loop, or update the comment to reflect the actual behavior.
- Several slash command decorators had `bot_permissions` removed (verification, welcome, giveaway, starboard); please double-check that this is intentional and that permission checks are enforced consistently across commands using a single mechanism.

## Individual Comments

### Comment 1
<location path="easycord/plugins/verification.py" line_range="228" />
<code_context>
                     panel_message_id,
                 )

-    @slash(description="Set the verified role and channel for the verification panel.", guild_only=True, bot_permissions=["manage_roles", "send_messages"])
+    @slash(description="Set the verified role and channel for the verification panel.", guild_only=True)
     async def verification_setup(
         self,
</code_context>
<issue_to_address>
**issue (bug_risk):** Dropping `bot_permissions` may degrade UX when the bot lacks `manage_roles` or `send_messages`.

This command still requires `manage_roles` to assign the verified role and usually `send_messages` to post the panel or responses. Without `bot_permissions`, these failures become runtime `Forbidden` errors instead of clear, early validation. If you want to loosen the check, consider at least keeping `manage_roles` so misconfigurations fail predictably at invocation time rather than mid-command.
</issue_to_address>

### Comment 2
<location path="easycord/plugins/welcome.py" line_range="118" />
<code_context>

     # ── Slash commands ────────────────────────────────────────

-    @slash(description="Set the channel for welcome messages.", permissions=["manage_guild"], bot_permissions=["send_messages"])
+    @slash(description="Set the channel for welcome messages.", permissions=["manage_guild"])
     async def set_welcome_channel(self, ctx, channel: discord.TextChannel) -> None:
         guild = require_guild(ctx)
</code_context>
<issue_to_address>
**issue (bug_risk):** Removing the `send_messages` bot permission check can lead to confusing runtime failures.

This command assumes the bot can send messages in the configured channel; without a `bot_permissions=["send_messages"]` check, misconfigured permissions will only surface as send failures at runtime. If you’re simplifying decorators, I’d still keep `send_messages` here (and for similar commands) to provide earlier, clearer feedback on missing bot permissions.
</issue_to_address>

### Comment 3
<location path="easycord/plugins/giveaway.py" line_range="263" />
<code_context>

         self._timers.get(guild_id, {}).pop(message_id, None)

-    @slash(description="Start a giveaway in the current channel.", guild_only=True, bot_permissions=["send_messages", "add_reactions"])
+    @slash(description="Start a giveaway in the current channel.", guild_only=True, bot_permissions=["send_messages"])
     async def giveaway(
         self,
</code_context>
<issue_to_address>
**issue (bug_risk):** Dropping the `add_reactions` requirement may break giveaways if reactions are still used to enter.

If giveaways still use reactions for entry, the bot must keep `add_reactions` for this command. Without it, missing permissions won’t be caught by the decorator and the command will only fail at runtime when adding reactions. If reactions are no longer part of the flow, this change is fine; otherwise, please keep `add_reactions` in `bot_permissions`.
</issue_to_address>

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.

Comment thread easycord/plugins/verification.py
Comment thread easycord/plugins/welcome.py
Comment thread easycord/plugins/giveaway.py

@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: 034d6df7c2

ℹ️ 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 easycord/plugins/verification.py Outdated
)

@slash(description="Post the verification panel in the configured channel.", guild_only=True, bot_permissions=["send_messages"])
@slash(description="Post the verification panel in the configured channel.", guild_only=True)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Guard verification panel sends after dropping bot perms

With bot_permissions=["send_messages"] removed here and no replacement around the channel.send(...) below, invoking /verification_panel from the configured panel channel while the bot lacks Send Messages now enters the command and raises discord.Forbidden instead of the prior bot-permissions response from build_slash_callback. Please keep a preflight or catch Forbidden for the configured channel before sending the panel.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in #79verification_panel now catches Forbidden/HTTPException around the panel send, responds with an ephemeral error, and persists nothing when the panel never posted (regression test included). Restoring the decorator wasn't the right fix: bot_permissions validates the invocation channel, while the panel goes to the configured channel. Note this code was split out of this PR into #79 — it was an unrelated local-main commit that leaked into the diff.

@rolling-codes rolling-codes force-pushed the fix/74-enabled-default-missing-key branch from 034d6df to e909867 Compare July 10, 2026 23:32
tee1339 added 2 commits July 10, 2026 19:33
A stored config section can exist without the "enabled" key (manual
config-file edit or partial external update); cfg.get("enabled") with
no default read that as disabled and silently turned the feature off.

- economy.py:219, role_persistence.py:53/79, member_logging.py:60 —
  cfg.get("enabled", True), matching each plugin's _DEFAULTS (same fix
  as starboard's B-018)
- ai_moderator.py:183/237 — explicit cfg.get("enabled", False); opt-in
  moderation, missing key correctly reads as disabled (no behavior
  change)
- Regression tests for the missing-key scenario in all four plugins
- bugs.md: B-020 filed; supersedes B-019's "verified benign" verdict,
  which only audited internal config-creation paths

auto_responder.py:68 (also named in #74) was already fixed by B-013.
Slash-command tests pass None for the orchestrator; the annotation
flagged 7 reportArgumentType errors under Pyright/Pylance.
@rolling-codes rolling-codes force-pushed the fix/74-enabled-default-missing-key branch from e909867 to 598dc67 Compare July 10, 2026 23:33
rolling-codes pushed a commit that referenced this pull request Jul 11, 2026
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 2799fdc into main Jul 11, 2026
24 checks passed
@rolling-codes rolling-codes deleted the fix/74-enabled-default-missing-key branch July 11, 2026 00:22
rolling-codes added a commit that referenced this pull request Jul 11, 2026
…nnel sends (#79)

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

- bugs.md will trivially conflict with #78 (both append a table row
after B-016); resolve by keeping both rows (B-020 then B-021).

## Test plan

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

🤖 Generated with [Claude Code](https://claude.com/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.

---------

Co-authored-by: tee <Thomas_BIRRELL@proton.me>
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.

Bug: auto_responder.py cfg.get("enabled") can silently disable feature if key is missing

2 participants