fix: tolerate season-reset payloads in /sq-info and stop duplicate error embeds

obtain_clan_new_points treated a missing `astat` or `member_ratings` block as
"squadron unavailable or deleted". After a season reset the game API omits those
blocks for inactive/unranked squadrons even though the clan and its roster still
exist, so /sq-info wrongly reported real squadrons (e.g. DSPL, 513th) as
nonexistent. Require a `members` roster to consider the payload valid (genuinely
deleted clans return CLAN_IS_NOT_EXISTS JSON handled upstream) and default both
stat blocks to zero, so the squadron renders at 0 points instead of erroring.

permission_fail was invoked twice per error because discord.py dispatches to
both the command-local `@cmd.error` handler and the global `@tree.error`
handler. Combined with a public defer, this produced a duplicated error message
(one public, one ephemeral). Guard on interaction.extras so the embed is sent
at most once per interaction.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
deploy
2026-07-01 12:28:22 +00:00
parent 3af950b464
commit 61236a8267
2 changed files with 23 additions and 2 deletions
+9
View File
@@ -598,6 +598,15 @@ def gate_entitle(required_tier: str):
async def permission_fail(interaction: discord.Interaction, error):
"""Handle permission-related errors with appropriate embeds."""
# discord.py dispatches a command error to BOTH the command's local
# `@cmd.error` handler and the global `@tree.error` handler (see
# app_commands/tree.py). Since both route here, guard against sending the
# error embed twice for the same interaction — the second send would land
# as a separate (and, after a public defer, differently-scoped) message.
if interaction.extras.get("_permission_fail_handled"):
return
interaction.extras["_permission_fail_handled"] = True
lang = await guild_lang(interaction.guild_id) if interaction.guild_id else "en"
if isinstance(error, BlacklistCheckFailure):
reason = getattr(error, "reason", None)