fix(discord): delete obsolete slash commands before creating new ones#2
Open
infinitycrew39 wants to merge 4 commits into
Open
fix(discord): delete obsolete slash commands before creating new ones#2infinitycrew39 wants to merge 4 commits into
infinitycrew39 wants to merge 4 commits into
Conversation
Discord enforces a hard 100-command limit per app. The sync function was trying to create new commands before deleting obsolete ones, which could temporarily push the total over 100 and trigger error 30032, silently breaking all slash commands. This fix reorders the sync to: 1. Identify and delete obsolete commands first 2. Then create/update desired commands This ensures we always stay at or below the 100-command limit during sync.
Add a test to verify that _safe_sync_slash_commands deletes obsolete commands before creating new ones. This ensures we never temporarily exceed Discord's 100-command limit during sync, which would trigger error 30032 and break all slash commands. This test guards against the regression where sync could fail even though the registration cap was properly enforced.
infinitycrew39
pushed a commit
that referenced
this pull request
Jun 25, 2026
…eation snapshot (NousResearch#44585) An unpinned cron job follows the global default provider (config.yaml model.default + resolve_runtime_provider). If that global state is changed after the job is created — e.g. a temporary switch to a paid provider like nous/claude-fable-5 — the job silently inherits it on its next tick and spends real money. This is the reported $7.73 incident: a job created under a free/default provider later inherited a temporary paid switch. Fix (ask #1 only) preserves the legitimate "unpinned job should follow model.default" use case by detecting *drift* rather than freezing the model: - create_job (cron/jobs.py): for UNPINNED, agent-backed jobs (no explicit provider, not no_agent), snapshot the provider that resolution WOULD pick right now into a new optional `provider_snapshot` field, resolved via the same resolve_runtime_provider() path the ticker uses. Fail-open to None on any resolution error so job creation never breaks. - run_job (cron/scheduler.py): right after runtime resolution, if the job has a provider_snapshot AND is unpinned AND the currently-resolved provider DIFFERS from the snapshot, fail closed for that run — make no paid call and deliver a loud, actionable alert naming both providers and telling the user to pin explicitly (`cronjob action=update job_id=.. provider=..`). Back-compat: jobs with no snapshot (pre-existing jobs, no_agent jobs, or any job whose creation-time resolution failed) behave exactly as before — the guard only engages when a snapshot exists. Explicitly-pinned jobs (job.provider set) are unaffected since they don't drift with global state. Tests: tests/cron/test_cron_provider_pin.py covers snapshot-matches (runs), snapshot-differs (fail closed, no agent constructed), no-snapshot back-compat, None-snapshot back-compat, explicitly-pinned (runs regardless), plus create_job snapshot capture/skip/fail-open. The fail-closed case is load-bearing (fails without the guard). Issue NousResearch#44585 asks #2-4 (hard-stop a running job, gateway-stop containment, fail-closed on provider mutation) are out of scope for this change.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue
Discord enforces a hard 100-command limit per app. When syncing slash commands, if we try to create new commands before deleting obsolete ones, we can temporarily exceed this limit, triggering error 30032 which silently breaks ALL slash commands.
Root Cause
The
_safe_sync_slash_commands()function inplugins/platforms/discord/adapter.pywas iterating over desired commands and trying to create new ones BEFORE deleting obsolete ones. If Discord already had 100 commands and a new command needed to be added, this would exceed the limit momentarily.Solution
Reorder the sync operations to:
This ensures we always stay at or below the 100-command limit during sync.
Changes
_safe_sync_slash_commands()to delete before createTesting
The regression test
test_safe_sync_deletes_before_creating()verifies that:Fixes the "Cronjob ran without error and final message was created but still failed with runtime error" issue where error 30032 was breaking all Discord slash commands.