fix(discord): preserve channel session keys via channel_id fallbacks (#17622)

* fix(discord): preserve channel session keys via channel_id fallbacks

* docs(changelog): add discord session continuity note

* Tests: cover discord channel_id fallback

---------

Co-authored-by: Shadow <hi@shadowing.dev>
This commit is contained in:
Shakker
2026-02-16 02:30:17 +00:00
committed by GitHub
parent 39d5590230
commit 09566b1693
16 changed files with 235 additions and 49 deletions

View File

@@ -48,7 +48,11 @@ import {
resolveDiscordSystemLocation,
resolveTimestampMs,
} from "./format.js";
import { resolveDiscordChannelInfo, resolveDiscordMessageText } from "./message-utils.js";
import {
resolveDiscordChannelInfo,
resolveDiscordMessageChannelId,
resolveDiscordMessageText,
} from "./message-utils.js";
import { resolveDiscordSenderIdentity, resolveDiscordWebhookId } from "./sender-identity.js";
import { resolveDiscordSystemEvent } from "./system-events.js";
import { resolveDiscordThreadChannel, resolveDiscordThreadParentInfo } from "./threading.js";
@@ -67,6 +71,14 @@ export async function preflightDiscordMessage(
if (!author) {
return null;
}
const messageChannelId = resolveDiscordMessageChannelId({
message,
eventChannelId: params.data.channel_id,
});
if (!messageChannelId) {
logVerbose(`discord: drop message ${message.id} (missing channel id)`);
return null;
}
const allowBots = params.discordConfig?.allowBots ?? false;
if (params.botUserId && author.id === params.botUserId) {
@@ -102,11 +114,11 @@ export async function preflightDiscordMessage(
}
const isGuildMessage = Boolean(params.data.guild_id);
const channelInfo = await resolveDiscordChannelInfo(params.client, message.channelId);
const channelInfo = await resolveDiscordChannelInfo(params.client, messageChannelId);
const isDirectMessage = channelInfo?.type === ChannelType.DM;
const isGroupDm = channelInfo?.type === ChannelType.GroupDM;
logDebug(
`[discord-preflight] channelId=${message.channelId} guild_id=${params.data.guild_id} channelType=${channelInfo?.type} isGuild=${isGuildMessage} isDM=${isDirectMessage} isGroupDm=${isGroupDm}`,
`[discord-preflight] channelId=${messageChannelId} guild_id=${params.data.guild_id} channelType=${channelInfo?.type} isGuild=${isGuildMessage} isDM=${isDirectMessage} isGroupDm=${isGroupDm}`,
);
if (isGroupDm && !params.groupDmEnabled) {
@@ -208,6 +220,7 @@ export async function preflightDiscordMessage(
isGuildMessage,
message,
channelInfo,
messageChannelId,
});
let earlyThreadParentId: string | undefined;
let earlyThreadParentName: string | undefined;
@@ -235,7 +248,7 @@ export async function preflightDiscordMessage(
memberRoleIds,
peer: {
kind: isDirectMessage ? "direct" : isGroupDm ? "group" : "channel",
id: isDirectMessage ? author.id : message.channelId,
id: isDirectMessage ? author.id : messageChannelId,
},
// Pass parent peer for thread binding inheritance
parentPeer: earlyThreadParentId ? { kind: "channel", id: earlyThreadParentId } : undefined,
@@ -305,7 +318,7 @@ export async function preflightDiscordMessage(
const channelConfig = isGuildMessage
? resolveDiscordChannelConfigWithFallback({
guildInfo,
channelId: message.channelId,
channelId: messageChannelId,
channelName,
channelSlug: threadChannelSlug,
parentId: threadParentId ?? undefined,
@@ -320,13 +333,13 @@ export async function preflightDiscordMessage(
? `allowed=${channelConfig.allowed} enabled=${channelConfig.enabled ?? "unset"} requireMention=${channelConfig.requireMention ?? "unset"} matchKey=${channelConfig.matchKey ?? "none"} matchSource=${channelConfig.matchSource ?? "none"} users=${channelConfig.users?.length ?? 0} roles=${channelConfig.roles?.length ?? 0} skills=${channelConfig.skills?.length ?? 0}`
: "none";
logDebug(
`[discord-preflight] channelConfig=${channelConfigSummary} channelMatchMeta=${channelMatchMeta} channelId=${message.channelId}`,
`[discord-preflight] channelConfig=${channelConfigSummary} channelMatchMeta=${channelMatchMeta} channelId=${messageChannelId}`,
);
}
if (isGuildMessage && channelConfig?.enabled === false) {
logDebug(`[discord-preflight] drop: channel disabled`);
logVerbose(
`Blocked discord channel ${message.channelId} (channel disabled, ${channelMatchMeta})`,
`Blocked discord channel ${messageChannelId} (channel disabled, ${channelMatchMeta})`,
);
return null;
}
@@ -335,7 +348,7 @@ export async function preflightDiscordMessage(
isGroupDm &&
resolveGroupDmAllow({
channels: params.groupDmChannels,
channelId: message.channelId,
channelId: messageChannelId,
channelName: displayChannelName,
channelSlug: displayChannelSlug,
});
@@ -363,7 +376,7 @@ export async function preflightDiscordMessage(
);
} else {
logVerbose(
`Blocked discord channel ${message.channelId} not in guild channel allowlist (groupPolicy: allowlist, ${channelMatchMeta})`,
`Blocked discord channel ${messageChannelId} not in guild channel allowlist (groupPolicy: allowlist, ${channelMatchMeta})`,
);
}
return null;
@@ -372,13 +385,13 @@ export async function preflightDiscordMessage(
if (isGuildMessage && channelConfig?.allowed === false) {
logDebug(`[discord-preflight] drop: channelConfig.allowed===false`);
logVerbose(
`Blocked discord channel ${message.channelId} not in guild channel allowlist (${channelMatchMeta})`,
`Blocked discord channel ${messageChannelId} not in guild channel allowlist (${channelMatchMeta})`,
);
return null;
}
if (isGuildMessage) {
logDebug(`[discord-preflight] pass: channel allowed`);
logVerbose(`discord: allow channel ${message.channelId} (${channelMatchMeta})`);
logVerbose(`discord: allow channel ${messageChannelId} (${channelMatchMeta})`);
}
const textForHistory = resolveDiscordMessageText(message, {
@@ -467,7 +480,7 @@ export async function preflightDiscordMessage(
);
if (shouldLogVerbose()) {
logVerbose(
`discord: inbound id=${message.id} guild=${params.data.guild_id ?? "dm"} channel=${message.channelId} mention=${wasMentioned ? "yes" : "no"} type=${isDirectMessage ? "dm" : isGroupDm ? "group-dm" : "guild"} content=${messageText ? "yes" : "no"}`,
`discord: inbound id=${message.id} guild=${params.data.guild_id ?? "dm"} channel=${messageChannelId} mention=${wasMentioned ? "yes" : "no"} type=${isDirectMessage ? "dm" : isGroupDm ? "group-dm" : "guild"} content=${messageText ? "yes" : "no"}`,
);
}
@@ -542,14 +555,14 @@ export async function preflightDiscordMessage(
logVerbose(`discord: drop guild message (mention required, botId=${botId})`);
logger.info(
{
channelId: message.channelId,
channelId: messageChannelId,
reason: "no-mention",
},
"discord: skipping guild message",
);
recordPendingHistoryEntryIfEnabled({
historyMap: params.guildHistories,
historyKey: message.channelId,
historyKey: messageChannelId,
limit: params.historyLimit,
entry: historyEntry ?? null,
});
@@ -567,14 +580,14 @@ export async function preflightDiscordMessage(
isDirectMessage,
isGroupDm,
guild: params.data.guild ?? undefined,
channelName: channelName ?? message.channelId,
channelName: channelName ?? messageChannelId,
});
const systemText = resolveDiscordSystemEvent(message, systemLocation);
if (systemText) {
logDebug(`[discord-preflight] drop: system event`);
enqueueSystemEvent(systemText, {
sessionKey: route.sessionKey,
contextKey: `discord:system:${message.channelId}:${message.id}`,
contextKey: `discord:system:${messageChannelId}:${message.id}`,
});
return null;
}
@@ -603,6 +616,7 @@ export async function preflightDiscordMessage(
data: params.data,
client: params.client,
message,
messageChannelId,
author,
sender,
channelInfo,