diff --git a/src/adapters/discord_bot/views/task_modals.py b/src/adapters/discord_bot/views/task_modals.py index cfbb8ad..bac361f 100644 --- a/src/adapters/discord_bot/views/task_modals.py +++ b/src/adapters/discord_bot/views/task_modals.py @@ -71,9 +71,12 @@ async def on_submit(self, interaction: discord.Interaction) -> None: keep_archived = (task.status == TaskStatus.COMPLETED or task.is_archived) if task else False async with unarchive_thread_if_needed(thread, keep_archived=keep_archived): await interaction.response.send_message( - f"✅ Note added to **{self.short_id}** by <@{interaction.user.id}>:\n> {note_text}", - ephemeral=False, + f"✅ Note added to **{self.short_id}**.", + ephemeral=True, ) + from src.adapters.discord_bot.menu_manager import menu_manager + + menu_manager.schedule_toast_dismissal(interaction, delay=6.0) except Exception as e: await send_interaction_error( interaction, e, f"adding note to task '{self.short_id}'", logger, ephemeral=True diff --git a/tests/test_discord_thread_lifecycle.py b/tests/test_discord_thread_lifecycle.py index f651611..909aeae 100644 --- a/tests/test_discord_thread_lifecycle.py +++ b/tests/test_discord_thread_lifecycle.py @@ -465,6 +465,49 @@ async def test_task_note_modal_completed_archived_thread(services): interaction.response.send_message.assert_awaited_once() +@pytest.mark.asyncio +async def test_task_note_modal_responds_ephemerally_to_prevent_duplicate_activity(services, monkeypatch): + """Verify TaskNoteModal acknowledges ephemerally so thread does not get duplicate public messages.""" + from src.adapters.discord_bot.menu_manager import menu_manager + from src.adapters.discord_bot.views.task_modals import TaskNoteModal + + scheduled = [] + monkeypatch.setattr(menu_manager, "schedule_toast_dismissal", lambda target, delay=6.0: scheduled.append(target)) + + proj_srv = services["project"] + task_srv = services["task"] + guild_id = 11224455 + + project = await proj_srv.create_project(guild_id=guild_id, name="Notes Single Post Test", prefix="NOT2") + task = await task_srv.create_task( + guild_id=guild_id, + title="Task for Single Note Post", + creator_discord_id=1001, + project_id=project.id, + ) + + modal = TaskNoteModal( + task_id=task.id, + short_id=task.short_id, + task_service=task_srv, + ) + modal.note_input._value = "Checking single activity log." + + interaction = MagicMock(spec=discord.Interaction) + interaction.user = MagicMock() + interaction.user.id = 1001 + interaction.channel = MagicMock(spec=discord.Thread) + interaction.response = MagicMock() + interaction.response.send_message = AsyncMock() + + await modal.on_submit(interaction) + + interaction.response.send_message.assert_awaited_once() + assert interaction.response.send_message.call_args.kwargs.get("ephemeral") is True + assert len(scheduled) == 1 + assert scheduled[0] is interaction + + @pytest.mark.asyncio async def test_task_edit_modal_completed_archived_thread(services): """Verify editing details of a completed/archived task unarchives then re-archives thread."""