diff --git a/plugins/platforms/slack/adapter.py b/plugins/platforms/slack/adapter.py index cd848c4bc5..7debfb6616 100644 --- a/plugins/platforms/slack/adapter.py +++ b/plugins/platforms/slack/adapter.py @@ -5959,12 +5959,20 @@ class SlackAdapter(BasePlatformAdapter): started (the sequential-suppression case) is left untouched. """ _ts = str((event or {}).get("ts") or "") - _was_claimed = bool(_ts) and _ts in self._processed_message_ts + # getattr: bare test doubles (object.__new__) may lack the map. + _claims = getattr(self, "_processed_message_ts", None) + _was_claimed = bool(_ts) and _claims is not None and _ts in _claims try: return await self._handle_slack_message_impl(event, payload) except BaseException: - if _ts and not _was_claimed and _ts in self._processed_message_ts: - self._processed_message_ts.pop(_ts, None) + _claims = getattr(self, "_processed_message_ts", None) + if ( + _ts + and not _was_claimed + and _claims is not None + and _ts in _claims + ): + _claims.pop(_ts, None) logger.warning( "[%s] handler failed after claiming ts=%s; claim released " "so a retry or edit can re-drive the turn", diff --git a/tests/gateway/test_slack_mention.py b/tests/gateway/test_slack_mention.py index a3d3aed0b8..2a52eea832 100644 --- a/tests/gateway/test_slack_mention.py +++ b/tests/gateway/test_slack_mention.py @@ -263,7 +263,9 @@ def test_reaction_guard_pinned_to_production_expression(): (back to ``is_dm or is_mentioned``, which reacts to unmentioned MPIMs) fails here instead of silently passing a self-referential lambda. """ - src = inspect.getsource(SlackAdapter._handle_slack_message) + # The public method is a thin claim-release guard; the production + # expression lives in the impl. + src = inspect.getsource(SlackAdapter._handle_slack_message_impl) assert "(is_one_to_one_dm or is_mentioned)" in src, ( "reaction guard no longer keys off is_one_to_one_dm — an unmentioned " "MPIM would react again (regression of the group-DM fix)"