From 390ddfd0284e80dbdd095d99adefb4cee8214c86 Mon Sep 17 00:00:00 2001 From: wpeterr Date: Thu, 23 Jul 2026 08:03:04 -0700 Subject: [PATCH] =?UTF-8?q?fix(slack):=20quiet=20Slack=20display=20default?= =?UTF-8?q?s=20=E2=80=94=20no=20heartbeat/busy-ack=20breadcrumbs=20in=20ch?= =?UTF-8?q?annels?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Slack posts are durable workspace messages, not an ephemeral terminal status area. Default long_running_notifications and busy_ack_detail to off for Slack so long-running agent work does not leave permanent operational breadcrumbs like 'Working — 9 min — iteration 12/90' in channels. Both remain opt-in per platform via display.platforms.slack.*. Also covers the platform-generic shutdown-notification mute path with a regression test (gateway_restart_notification=false must suppress both the active-session interruption notice and the home-channel copy). Salvaged from #69028 (quiet-defaults half only). The PR's other half — the channel_session_scope_channels session-scoping feature — is a new config feature outside this log-noise cluster and overlaps the session scoping territory reworked by merged wave-1/2 Slack session work; it is deliberately not taken here. --- gateway/display_config.py | 7 ++++++- tests/gateway/test_display_config.py | 8 ++++++++ tests/gateway/test_restart_notification.py | 21 +++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/gateway/display_config.py b/gateway/display_config.py index 76466d521525..e58e6e82b22d 100644 --- a/gateway/display_config.py +++ b/gateway/display_config.py @@ -140,7 +140,12 @@ _PLATFORM_DEFAULTS: dict[str, dict[str, Any]] = { # Tier 2 — edit support, often customer/workspace channels # Slack: tool_progress off by default — Bolt posts cannot be edited like CLI; # "new"/"all" spam permanent lines in channels (hermes-agent#14663). - "slack": {**_TIER_MEDIUM, "tool_progress": "off"}, + "slack": { + **_TIER_MEDIUM, + "tool_progress": "off", + "long_running_notifications": False, + "busy_ack_detail": False, + }, "mattermost": _TIER_MEDIUM, "matrix": _TIER_MEDIUM, "feishu": _TIER_MEDIUM, diff --git a/tests/gateway/test_display_config.py b/tests/gateway/test_display_config.py index c45705bc4ab0..4d11f22db96c 100644 --- a/tests/gateway/test_display_config.py +++ b/tests/gateway/test_display_config.py @@ -328,6 +328,14 @@ class TestPlatformDefaults: assert resolve_display_setting({}, "discord", "long_running_notifications") is True assert resolve_display_setting({}, "discord", "busy_ack_detail") is True + def test_slack_workspace_chatter_defaults(self): + """Slack should not leave permanent heartbeat/debug breadcrumbs in channels.""" + from gateway.display_config import resolve_display_setting + + assert resolve_display_setting({}, "slack", "tool_progress") == "off" + assert resolve_display_setting({}, "slack", "long_running_notifications") is False + assert resolve_display_setting({}, "slack", "busy_ack_detail") is False + def test_telegram_mobile_chatter_can_opt_in(self): """Per-platform config can re-enable Telegram busy-ack detail and re-disable the kept-on defaults.""" diff --git a/tests/gateway/test_restart_notification.py b/tests/gateway/test_restart_notification.py index b090503c5b13..e110eb876e02 100644 --- a/tests/gateway/test_restart_notification.py +++ b/tests/gateway/test_restart_notification.py @@ -665,6 +665,27 @@ async def test_shutdown_notifications_use_cached_live_thread_source_when_origin_ ) +@pytest.mark.asyncio +async def test_shutdown_notifications_are_fully_muted_when_flag_disabled(): + runner, adapter = make_restart_runner() + source = make_restart_source(chat_id="active-42", chat_type="group", thread_id="topic-7") + session_key = build_session_key(source) + + runner.config.platforms[Platform.TELEGRAM].gateway_restart_notification = False + runner.config.platforms[Platform.TELEGRAM].home_channel = HomeChannel( + platform=Platform.TELEGRAM, + chat_id="home-42", + name="Ops Home", + ) + runner._running_agents[session_key] = object() + runner.session_store._entries[session_key] = MagicMock(origin=source) + adapter.send = AsyncMock() + + await runner._notify_active_sessions_of_shutdown() + + adapter.send.assert_not_awaited() + + @pytest.mark.asyncio async def test_restart_shutdown_notification_anchors_telegram_dm_topic(): runner, adapter = make_restart_runner()