From 54e7220d06f7c59d653d0a666b3a3c4ae0712aba Mon Sep 17 00:00:00 2001 From: asepharyana Date: Wed, 26 Aug 2026 17:31:37 +0700 Subject: [PATCH] fix(auto-delete): prevent double-processing + improve error classification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two bugs causing 23 spurious 'error' logs after successful deletions: 1. batchProcessor switch missing 'completed' case: partitionBatchOutcome returns 'completed' for successful messages, but the switch only handled 'upload_pending' and 'api_failed'. Successful messages fell through to default → re-enqueued to individual fallback → re-analyzed → re-delete attempt → error (message already gone from Discord). Now explicitly skips 'completed' messages. 2. isAlreadyDeletedError only caught codes 10008/404. Discord also returns 10003 (Unknown Channel) and 50001 (Missing Access) when a message or channel is gone. Added these codes plus text-based fallback matching 'Unknown Message'/'Unknown Channel'. Impact: eliminates ~23 redundant error logs per day + stops wasted LLM calls re-analyzing already-processed messages. --- .../ai-moderation/autoDeleteManager.ts | 19 ++++++++++++++++++- .../modules/ai-moderation/batchProcessor.ts | 4 ++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/services/discord-gateway/src/modules/ai-moderation/autoDeleteManager.ts b/services/discord-gateway/src/modules/ai-moderation/autoDeleteManager.ts index cad3509a..23b637cc 100644 --- a/services/discord-gateway/src/modules/ai-moderation/autoDeleteManager.ts +++ b/services/discord-gateway/src/modules/ai-moderation/autoDeleteManager.ts @@ -130,7 +130,24 @@ function getErrorCode(error: unknown): number | string | undefined { function isAlreadyDeletedError(error: unknown): boolean { const code = getErrorCode(error); - return code === 10008 || code === 404 || code === "10008" || code === "404"; + // Discord REST error codes for "message not found": + // 10008 = Unknown Message, 10003 = Unknown Channel, + // 50001 = Missing Access (channel deleted/hidden), 404 = HTTP + if ( + code === 10008 || + code === 10003 || + code === 50001 || + code === 404 || + code === "10008" || + code === "10003" || + code === "50001" || + code === "404" + ) + return true; + // Fallback: check the message text for the Discord "Unknown Message" string + const msg = + error instanceof Error ? error.message : typeof error === "string" ? error : ""; + return msg.includes("Unknown Message") || msg.includes("Unknown Channel"); } function hasChannelMessagesApi(channel: unknown): channel is { diff --git a/services/discord-gateway/src/modules/ai-moderation/batchProcessor.ts b/services/discord-gateway/src/modules/ai-moderation/batchProcessor.ts index 145f750d..7e10ed37 100644 --- a/services/discord-gateway/src/modules/ai-moderation/batchProcessor.ts +++ b/services/discord-gateway/src/modules/ai-moderation/batchProcessor.ts @@ -233,6 +233,10 @@ export async function processBatch( // conversation cooldown instead of an immediate individual retry. apiFailedMessages.push(msg); break; + case "completed": + // Successfully analyzed — already broadcast + auto-delete scheduled + // above. Do NOT re-enqueue for individual fallback. + break; default: // incomplete / parse_failed / unexplained drops stay retryable via // the individual fallback queue (same semantics as before).