diff --git a/gateway/delivery.py b/gateway/delivery.py index 0aac015a1c..23451454d8 100644 --- a/gateway/delivery.py +++ b/gateway/delivery.py @@ -2,7 +2,6 @@ platform home channel ("telegram"), origin (back to where the job was created), or local (files).""" import logging -import os import re from pathlib import Path from datetime import datetime @@ -221,10 +220,8 @@ class DeliveryRouter: return path def _filter_silence_narration_enabled(self) -> bool: - """``HERMES_FILTER_SILENCE_NARRATION`` env overrides the ``gateway.filter_silence_narration`` flag.""" - env = os.getenv("HERMES_FILTER_SILENCE_NARRATION") - return (bool(getattr(self.config, "filter_silence_narration", True)) if env is None - else env.strip().lower() in ("1", "true", "yes", "on")) + """filter silence narration based on gateway config without checking process env""" + return bool(getattr(self.config, "filter_silence_narration", True)) def _cap_oversized_output(self, adapter: Any, content: str, job_id: str) -> str: """Audit-save oversized cron output; truncate it for non-chunking adapters. Above MAX_PLATFORM_OUTPUT diff --git a/tests/gateway/test_delivery_silence_filter.py b/tests/gateway/test_delivery_silence_filter.py index 11b7ba3296..56c5fb8053 100644 --- a/tests/gateway/test_delivery_silence_filter.py +++ b/tests/gateway/test_delivery_silence_filter.py @@ -77,7 +77,6 @@ class RecordingAdapter: @pytest.mark.asyncio async def test_silence_narration_dropped_pre_send(tmp_path, monkeypatch): monkeypatch.setattr("gateway.delivery.get_hermes_home", lambda: tmp_path) - monkeypatch.delenv("HERMES_FILTER_SILENCE_NARRATION", raising=False) adapter = RecordingAdapter() router = DeliveryRouter(GatewayConfig(), adapters={Platform.DISCORD: adapter}) target = DeliveryTarget.parse("discord:99887766") @@ -95,7 +94,6 @@ async def test_silence_narration_dropped_pre_send(tmp_path, monkeypatch): @pytest.mark.asyncio async def test_config_opt_out_lets_silence_through(tmp_path, monkeypatch): monkeypatch.setattr("gateway.delivery.get_hermes_home", lambda: tmp_path) - monkeypatch.delenv("HERMES_FILTER_SILENCE_NARRATION", raising=False) adapter = RecordingAdapter() config = GatewayConfig(filter_silence_narration=False) router = DeliveryRouter(config, adapters={Platform.DISCORD: adapter}) @@ -109,19 +107,61 @@ async def test_config_opt_out_lets_silence_through(tmp_path, monkeypatch): @pytest.mark.asyncio -async def test_env_override_enables_filter_over_config(tmp_path, monkeypatch): +async def test_env_does_not_override_config_opt_out(tmp_path, monkeypatch): + # env shouldn't override config when filter is turned off monkeypatch.setattr("gateway.delivery.get_hermes_home", lambda: tmp_path) monkeypatch.setenv("HERMES_FILTER_SILENCE_NARRATION", "1") adapter = RecordingAdapter() - # Config says off, env override forces on. config = GatewayConfig(filter_silence_narration=False) router = DeliveryRouter(config, adapters={Platform.DISCORD: adapter}) target = DeliveryTarget.parse("discord:99887766") result = await router._deliver_to_platform(target, "*(silent)*", metadata=None) + assert len(adapter.calls) == 1 + assert adapter.calls[0]["content"] == "*(silent)*" + assert result == {"success": True} + + +@pytest.mark.asyncio +async def test_env_does_not_disable_filter_when_config_enabled(tmp_path, monkeypatch): + # env shouldn't disable filter when config has it on + monkeypatch.setattr("gateway.delivery.get_hermes_home", lambda: tmp_path) + monkeypatch.setenv("HERMES_FILTER_SILENCE_NARRATION", "0") + adapter = RecordingAdapter() + config = GatewayConfig(filter_silence_narration=True) + router = DeliveryRouter(config, adapters={Platform.DISCORD: adapter}) + target = DeliveryTarget.parse("discord:99887766") + + result = await router._deliver_to_platform(target, "*(silent)*", metadata=None) + assert adapter.calls == [] - assert result["filtered"] == "silence_narration" + assert result == { + "success": True, + "filtered": "silence_narration", + "delivered": False, + } + + +@pytest.mark.asyncio +async def test_multiplex_profiles_independent_silence_narration_filtering(tmp_path, monkeypatch): + # secondary profile keeps its own setting under multiplex regardless of process env + monkeypatch.setattr("gateway.delivery.get_hermes_home", lambda: tmp_path) + monkeypatch.setenv("HERMES_FILTER_SILENCE_NARRATION", "1") + adapter_a = RecordingAdapter() + adapter_b = RecordingAdapter() + router_a = DeliveryRouter(GatewayConfig(filter_silence_narration=True), adapters={Platform.DISCORD: adapter_a}) + router_b = DeliveryRouter(GatewayConfig(filter_silence_narration=False), adapters={Platform.DISCORD: adapter_b}) + target = DeliveryTarget.parse("discord:99887766") + + res_a = await router_a._deliver_to_platform(target, "*(silent)*", metadata=None) + res_b = await router_b._deliver_to_platform(target, "*(silent)*", metadata=None) + + assert adapter_a.calls == [] + assert res_a["filtered"] == "silence_narration" + assert len(adapter_b.calls) == 1 + assert adapter_b.calls[0]["content"] == "*(silent)*" + assert res_b == {"success": True} # --- Cron artifacts are exempt ---------------------------------------------- @@ -136,7 +176,6 @@ async def test_env_override_enables_filter_over_config(tmp_path, monkeypatch): @pytest.mark.asyncio async def test_cron_job_id_metadata_bypasses_the_filter(tmp_path, monkeypatch): monkeypatch.setattr("gateway.delivery.get_hermes_home", lambda: tmp_path) - monkeypatch.delenv("HERMES_FILTER_SILENCE_NARRATION", raising=False) adapter = RecordingAdapter() router = DeliveryRouter(GatewayConfig(), adapters={Platform.DISCORD: adapter}) target = DeliveryTarget.parse("discord:99887766") @@ -155,7 +194,6 @@ async def test_cron_job_id_metadata_bypasses_the_filter(tmp_path, monkeypatch): async def test_non_cron_metadata_still_filters(tmp_path, monkeypatch): """The exemption keys on job_id alone — everything else is unchanged.""" monkeypatch.setattr("gateway.delivery.get_hermes_home", lambda: tmp_path) - monkeypatch.delenv("HERMES_FILTER_SILENCE_NARRATION", raising=False) adapter = RecordingAdapter() router = DeliveryRouter(GatewayConfig(), adapters={Platform.DISCORD: adapter}) target = DeliveryTarget.parse("discord:99887766")