feat(bot): a self-diagnosing bot, a /record start that knows the session, and linking that names the way out (phase 5 lane B) #521
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/phase5b-bot-self-diagnosis"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #373, closes #393, closes #392. Phase 5 lane B of the v4.3.0 build order (#514). Five commits; every API change is additive (new endpoints, new defaulted fields), so no
BOT_CONTRACT_VERSIONbump. No migration.#373 self-diagnosis.
api_clientraisesQuestBoardApiError(status, detail)(a subclass ofhttpx.HTTPStatusError, so the startup handshake and existing handlers are untouched); cogs show the backend's own sentence for a 4xx or a 503 (the named acceptance case, "LLM endpoint not configured", is a 503 that always carries actionable prose) and the generic message for a 500 or network failure./next,/quests,/historydistinguish "no campaign is bound to this server" from "nothing scheduled" via a newGET /api/bot/guilds/{id}/campaigns, consulted only on the empty path./askgets an additivereason: "no_transcripts"rather than a null answer that would crash an older bot. NewHelpcog:/help(a test asserts it covers every registered command), anon_guild_joinwelcome with the three setup steps and the guild ID pasted in, a presence set in the constructor so it survives reconnects. Alsocommand_prefix=commands.when_mentioned, the one prefix discord.py exempts from the "message content intent is missing" warning seen on prod after v4.2.3, with a test.#393
/record start. Reconciled with #399, which is left intact: the audio was already rescued on restart, but everything needed to say so died with the process. The active recording is now written to Redis DB 0 (qb:bot:recording:<guild_id>, 7-day TTL, best-effort), andannounce_interrupted_recordingsruns after #399's recovery to report which of three things happened (recovered and being transcribed; kept but not yet submitted; nothing captured)./record start's session argument autocompletes against a newGET /api/bot/guilds/{id}/sessions/recordable; the slash path setssession_title(the "Unknown Session" bug) with the regression test nothing had; a definite 404 refuses the start while a timeout still starts, since capture cannot be redone;defer()precedes the metadata fetch;/record stopfulfils its interaction; failure strings are written for a hosted customer with the exception in the log and a retry link.#392 linking dead ends. Two small self-contained HTML pages replace the raw JSON 400/409, each naming the next step (
/linkagain vs sign in as the other account and/unlink)./auth/linkrecords the outcome and/api/bot/link-status/{token}gains an additivestate(pending|linked|expired|conflict), so the poller speaks as soon as the outcome is known and names/unlinkon a conflict. Closed DMs fall back to a self-deleting channel mention in both the linking poller and the pre-vote prompt. The vote reminder tells unlinked players to run/link;Profile.jsxnames the command. Review note: the backend'sSecurityHeadersMiddlewarenow emitsdefault-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'fortext/htmlresponses only (the pages contain no user-controlled text); JSON responses keep the strict policy verbatim, with a test.Bot 398 passed (+80), backend full 2378 passed / 13 skipped, frontend 514 passed, ruff and version-sync clean. One adjacent data-loss finding filed as #520 (raw tracks deleted on a mid-conversion failure).
🤖 Generated with Claude Code
822bea8ff4842c864ab8842c864ab8f3a0166759