From e2429a26e0d3d039e6c8fb49d93e21382d4ec72b Mon Sep 17 00:00:00 2001 From: novax635 Date: Fri, 24 Apr 2026 12:28:14 +0300 Subject: [PATCH] fix(gateway): avoid threadless mirror session contamination --- gateway/mirror.py | 2 ++ tests/gateway/test_mirror.py | 57 ++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/gateway/mirror.py b/gateway/mirror.py index 0312424f1..8e21b8d9a 100644 --- a/gateway/mirror.py +++ b/gateway/mirror.py @@ -94,6 +94,8 @@ def _find_session_id(platform: str, chat_id: str, thread_id: Optional[str] = Non origin_chat_id = str(origin.get("chat_id", "")) if origin_chat_id == str(chat_id): origin_thread_id = origin.get("thread_id") + if thread_id is None and origin_thread_id is not None: + continue if thread_id is not None and str(origin_thread_id or "") != str(thread_id): continue updated = entry.get("updated_at", "") diff --git a/tests/gateway/test_mirror.py b/tests/gateway/test_mirror.py index 427e720cd..074eca064 100644 --- a/tests/gateway/test_mirror.py +++ b/tests/gateway/test_mirror.py @@ -77,6 +77,46 @@ class TestFindSessionId: assert result == "sess_topic_a" + def test_threadless_lookup_skips_threaded_sessions(self, tmp_path): + sessions_dir, index_file = _setup_sessions(tmp_path, { + "topic_a": { + "session_id": "sess_topic_a", + "origin": {"platform": "telegram", "chat_id": "-1001", "thread_id": "10"}, + "updated_at": "2026-01-01T00:00:00", + }, + "topic_b": { + "session_id": "sess_topic_b", + "origin": {"platform": "telegram", "chat_id": "-1001", "thread_id": "11"}, + "updated_at": "2026-02-01T00:00:00", + }, + }) + + with patch.object(mirror_mod, "_SESSIONS_DIR", sessions_dir), \ + patch.object(mirror_mod, "_SESSIONS_INDEX", index_file): + result = _find_session_id("telegram", "-1001") + + assert result is None + + def test_threadless_lookup_can_match_non_thread_session(self, tmp_path): + sessions_dir, index_file = _setup_sessions(tmp_path, { + "group": { + "session_id": "sess_group", + "origin": {"platform": "telegram", "chat_id": "-1001"}, + "updated_at": "2026-01-01T00:00:00", + }, + "topic": { + "session_id": "sess_topic", + "origin": {"platform": "telegram", "chat_id": "-1001", "thread_id": "11"}, + "updated_at": "2026-02-01T00:00:00", + }, + }) + + with patch.object(mirror_mod, "_SESSIONS_DIR", sessions_dir), \ + patch.object(mirror_mod, "_SESSIONS_INDEX", index_file): + result = _find_session_id("telegram", "-1001") + + assert result == "sess_group" + def test_no_match_returns_none(self, tmp_path): sessions_dir, index_file = _setup_sessions(tmp_path, { "sess": { @@ -189,6 +229,23 @@ class TestMirrorToSession: assert (sessions_dir / "sess_topic_a.jsonl").exists() assert not (sessions_dir / "sess_topic_b.jsonl").exists() + def test_threadless_mirror_does_not_write_to_threaded_session(self, tmp_path): + sessions_dir, index_file = _setup_sessions(tmp_path, { + "topic": { + "session_id": "sess_topic", + "origin": {"platform": "telegram", "chat_id": "-1001", "thread_id": "10"}, + "updated_at": "2026-01-01T00:00:00", + }, + }) + + with patch.object(mirror_mod, "_SESSIONS_DIR", sessions_dir), \ + patch.object(mirror_mod, "_SESSIONS_INDEX", index_file), \ + patch("gateway.mirror._append_to_sqlite"): + result = mirror_to_session("telegram", "-1001", "Hello group!", source_label="cron") + + assert result is False + assert not (sessions_dir / "sess_topic.jsonl").exists() + def test_no_matching_session(self, tmp_path): sessions_dir, index_file = _setup_sessions(tmp_path, {})