fix(discord): skip backfill for auto-created threads and update test fakes

When auto-threading kicked in, the broadened backfill gate ran on the
freshly-created thread — but the thread has no prior context to fetch,
and the parent-channel reference passed to _fetch_channel_context would
have leaked unrelated context (see #31467).

Skip backfill when auto_threaded_channel is set.  Also teach the
_FakeTextChannel / _FakeThreadChannel test doubles to expose a no-op
history() async generator so the broadened gate doesn't trip
AttributeError → discord.Forbidden (MagicMock) → TypeError in the
existing auto-thread tests.  Add a regression test that asserts
auto-threaded messages do not trigger backfill.
This commit is contained in:
teknium1 2026-05-28 03:56:01 -07:00 committed by Teknium
parent 68ddd6b338
commit b243afb68b
3 changed files with 39 additions and 1 deletions

View file

@ -4820,8 +4820,10 @@ class DiscordAdapter(BasePlatformAdapter):
# recovery)
# DMs skip entirely because every DM message triggers the bot,
# so the session transcript already has everything.
# Auto-threaded messages also skip — we just created the thread,
# there's nothing prior to backfill.
_has_mention_gap = require_mention and not is_free_channel and not in_bot_thread
if _has_mention_gap or is_thread:
if (_has_mention_gap or is_thread) and auto_threaded_channel is None:
_backfill_text = await self._fetch_channel_context(
message.channel, before=message,
)

View file

@ -905,3 +905,25 @@ async def test_discord_dm_does_not_backfill(adapter, monkeypatch):
assert event.channel_context is None
@pytest.mark.asyncio
async def test_discord_auto_thread_skips_backfill(adapter, monkeypatch):
"""Auto-created threads skip backfill — the thread is brand new with no prior context."""
monkeypatch.setenv("DISCORD_REQUIRE_MENTION", "true")
monkeypatch.setenv("DISCORD_AUTO_THREAD", "true")
monkeypatch.delenv("DISCORD_NO_THREAD_CHANNELS", raising=False)
monkeypatch.delenv("DISCORD_FREE_RESPONSE_CHANNELS", raising=False)
adapter.config.extra["history_backfill"] = True
fake_thread = FakeThread(channel_id=777, name="auto-thread")
adapter._auto_create_thread = AsyncMock(return_value=fake_thread)
adapter._fetch_channel_context = AsyncMock(return_value="[Recent channel messages]\n[Alice] noise")
bot_user = adapter._client.user
parent = FakeTextChannel(channel_id=200, name="general")
message = make_message(channel=parent, content="hello", mentions=[bot_user])
await adapter._handle_message(message)
adapter._auto_create_thread.assert_awaited_once()
adapter._fetch_channel_context.assert_not_awaited()

View file

@ -624,6 +624,13 @@ class _FakeTextChannel:
self.guild = SimpleNamespace(name=guild_name, id=1)
self.topic = None
def history(self, *args, **kwargs):
async def _empty():
return
yield # pragma: no cover — make this an async generator
return _empty()
class _FakeThreadChannel(_discord_mod.Thread):
"""isinstance(ch, discord.Thread) → True."""
@ -636,6 +643,13 @@ class _FakeThreadChannel(_discord_mod.Thread):
self.topic = None
self.parent = SimpleNamespace(id=parent_id, name="general", guild=SimpleNamespace(name=guild_name, id=1))
def history(self, *args, **kwargs):
async def _empty():
return
yield # pragma: no cover — make this an async generator
return _empty()
def _fake_message(channel, *, content="Hello", author_id=42, display_name="Jezza"):
return SimpleNamespace(