From fc7a01b6cb04038d8d89bff2c2a23a6bcd4d4343 Mon Sep 17 00:00:00 2001 From: kshitijk4poor <82637225+kshitijk4poor@users.noreply.github.com> Date: Sun, 28 Jun 2026 12:15:13 +0530 Subject: [PATCH] test+harden: modernize salvaged Matrix path for current plugin layout Two follow-ups on top of the salvaged #46365 fix: 1. Tests: the salvaged tests injected the ephemeral MatrixAdapter via sys.modules["gateway.platforms.matrix"], but Matrix migrated to a plugin (#41112) and the fallback now imports from plugins.platforms.matrix.adapter. Point the three sys.modules patches at the current module path so the ephemeral-fallback tests actually exercise the injected fake adapter. 2. Harden the live-adapter lookup: split the gateway import guard from the adapter lookup and log (instead of silently swallowing) when a runner exists but adapters.get() raises. A silent fall-through there would re-introduce the per-send reconnect/OTK-exhaustion storm this fix exists to prevent (#46310). Documented that the live adapter is gateway-owned and must not be disconnected, and why the ephemeral finally never touches it. --- tests/tools/test_send_message_tool.py | 6 ++--- tools/send_message_tool.py | 36 +++++++++++++++++++++------ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/tests/tools/test_send_message_tool.py b/tests/tools/test_send_message_tool.py index 439e3032cc6..f535aeee5e6 100644 --- a/tests/tools/test_send_message_tool.py +++ b/tests/tools/test_send_message_tool.py @@ -943,7 +943,7 @@ class TestMatrixMediaLiveAdapterReuse: "gateway.run._gateway_runner_ref", return_value=fake_runner, ), patch.dict( - sys.modules, {"gateway.platforms.matrix": SimpleNamespace()} + sys.modules, {"plugins.platforms.matrix.adapter": SimpleNamespace()} ): result = asyncio.run( _send_matrix_via_adapter( @@ -993,7 +993,7 @@ class TestMatrixMediaLiveAdapterReuse: with patch( "gateway.run._gateway_runner_ref", return_value=None - ), patch.dict(sys.modules, {"gateway.platforms.matrix": fake_module}): + ), patch.dict(sys.modules, {"plugins.platforms.matrix.adapter": fake_module}): result = asyncio.run( _send_matrix_via_adapter( SimpleNamespace(enabled=True, token="tok", extra={}), @@ -1038,7 +1038,7 @@ class TestMatrixMediaLiveAdapterReuse: with patch( "gateway.run._gateway_runner_ref", return_value=fake_runner, - ), patch.dict(sys.modules, {"gateway.platforms.matrix": fake_module}): + ), patch.dict(sys.modules, {"plugins.platforms.matrix.adapter": fake_module}): result = asyncio.run( _send_matrix_via_adapter( SimpleNamespace(enabled=True, token="tok", extra={}), diff --git a/tools/send_message_tool.py b/tools/send_message_tool.py index 58021fd4ca5..8fcc51f23f0 100644 --- a/tools/send_message_tool.py +++ b/tools/send_message_tool.py @@ -1482,19 +1482,39 @@ async def _send_matrix_via_adapter(pconfig, chat_id, message, media_files=None, metadata = {"thread_id": thread_id} if thread_id else None # --- Try the live gateway adapter first (persistent E2EE session) --- + # Reusing the running gateway's already-connected adapter is the whole + # point of #46310: it avoids a per-send login + olm/megolm re-init + OTK + # claim that, under burst sends, exhausts recipient one-time keys and + # silently drops messages. The import is guarded narrowly (gateway code may + # be absent in some standalone contexts); a runner that *exists* but whose + # adapter lookup fails is logged rather than silently swallowed, because a + # silent fall-through here would re-introduce the exact reconnect storm + # this fix prevents. live_adapter = None + runner = None try: - from gateway.config import Platform from gateway.run import _gateway_runner_ref - runner = _gateway_runner_ref() - if runner is not None: - live_adapter = runner.adapters.get(Platform.MATRIX) except Exception: - live_adapter = None + runner = None + if runner is not None: + try: + from gateway.config import Platform + live_adapter = runner.adapters.get(Platform.MATRIX) + except Exception: + logger.warning( + "Matrix: live gateway adapter lookup failed; falling back to an " + "ephemeral connect (may re-init E2EE per send, see #46310)", + exc_info=True, + ) + live_adapter = None if live_adapter is not None: - return await _send_via_matrix_adapter( + # NOTE: the live adapter is owned by the gateway — we must NOT + # disconnect it. Correctness here depends on this branch returning + # before the ephemeral ``adapter`` is constructed below, so the + # ephemeral ``finally`` disconnect never touches the live session. + return await _matrix_send_core( live_adapter, chat_id, message, media_files, metadata ) @@ -1509,7 +1529,7 @@ async def _send_matrix_via_adapter(pconfig, chat_id, message, media_files=None, connected = await adapter.connect() if not connected: return _error("Matrix connect failed") - return await _send_via_matrix_adapter( + return await _matrix_send_core( adapter, chat_id, message, media_files, metadata ) except Exception as e: @@ -1521,7 +1541,7 @@ async def _send_matrix_via_adapter(pconfig, chat_id, message, media_files=None, pass -async def _send_via_matrix_adapter(adapter, chat_id, message, media_files, metadata): +async def _matrix_send_core(adapter, chat_id, message, media_files, metadata): """Core send logic shared by live and ephemeral Matrix adapters.""" last_result = None