Adds SLACK_MESSAGE_REACTION_REMOVED, the secure variant of the deprecated
SLACK_REACTION_REMOVED trigger, mirroring the existing MessageReactionAdded
template:
apps/slack/triggers/message_reaction_removed.py with class
MessageReactionRemoved (event reaction_removed,
display_name = "Message Reaction Removed").
MessageReactionRemovedConfig) with optional
channel_id + emoji_name filtering.provider_registration_type = ProviderRegistrationType.APP_LEVEL.resolve_event_identity() returns EventIdentity(authz_required=True)
(per-user authz, since Slack reaction events carry no channel_type).setup() validates channel (conversations.info) and team (team.info)
via http_request and returns SetupResult(authz_ref=self._get_authz_user_id(auth))._transform output schema matches MessageReactionAdded's payload
(user, reaction, message_user, message_channel, message_ts,
event_ts, team_id).apps/slack/tool.py (import + triggers() list, alphabetical).reaction_removed.py docstring to
DEPRECATED: use SLACK_MESSAGE_REACTION_REMOVED instead.tests/test_apps/test_slack/test_message_reaction_removed.py
(match filtering, payload transform, authz-required identity, metadata).ruff format / ruff check clean on all changed files.mypy --config-file config/mypy.ini clean on the new/changed trigger files
(only pre-existing, unrelated mercury/tools/files.py errors surface, which
CI's diff-mode skips).test_slackbot_find_channels, test_slackbot_search_messages,
test_slackbot_explicit_actions) are environment-only — they fail identically
without this change because the generated apps/slack/config.json is absent
locally — and are unrelated to triggers.Swept every trigger marked DEPRECATED under apps/**/triggers/*.py. For each,
verified whether a non-deprecated, authz-aware replacement covering the same
provider event actually exists. No gaps found — every deprecated trigger has a
live replacement, and every replacement slug promised in a docstring exists.
apps/slack/triggers/)| Deprecated trigger | Provider event | Promised replacement | Replacement exists? | Authz-aware? |
|---|---|---|---|---|
reaction_added.py (ReactionAdded) | reaction_added | SLACK_MESSAGE_REACTION_ADDED | ✅ message_reaction_added.py | ✅ authz_required=True |
reaction_removed.py (ReactionRemoved) | reaction_removed | SLACK_MESSAGE_REACTION_REMOVED | ✅ added in this PR (message_reaction_removed.py) | ✅ authz_required=True |
receive_message.py (ReceiveMessage) | message | SLACK_CHANNEL_MESSAGE_RECEIVED | ✅ channel_message_received.py | ✅ (authz for group/mpim) |
receive_group_message.py (ReceiveGroupMessage) | message | SLACK_CHANNEL_MESSAGE_RECEIVED + channel_type="group" | ✅ (config field present) | ✅ |
receive_mpim_message.py (ReceiveMpimMessage) | message | SLACK_CHANNEL_MESSAGE_RECEIVED + channel_type="mpim" | ✅ (config field present) | ✅ |
receive_bot_message.py (ReceiveBotMessage) | message | SLACK_CHANNEL_MESSAGE_RECEIVED + is_bot_message=true | ✅ (is_bot_message config field present) | ✅ |
receive_thread_reply.py (ReceiveThreadReply) | message | SLACK_CHANNEL_MESSAGE_RECEIVED + is_thread_reply=true | ✅ (is_thread_reply config field present) | ✅ |
receive_direct_message.py (ReceiveDirectMessage) | message | SLACK_DIRECT_MESSAGE_RECEIVED |
All promised replacement config knobs (channel_type, is_bot_message,
is_thread_reply) were confirmed to exist on ChannelMessageReceivedConfig.
| Deprecated trigger | Note | Promised replacement | Replacement exists? |
|---|---|---|---|
apps/googlecalendar/triggers/event_changes.py (GoogleCalendarEventChangeTrigger) | Marked "SOON TO BE DEPRECATED" (webhook → polling migration, not an authz migration) | "Calendar Event Sync (polling trigger)" | ✅ event_sync.py (GoogleCalendarEventSyncTrigger, display_name "Calendar Event Sync") |
None. Every deprecated trigger has an existing replacement, and no docstring
promises a replacement slug that is missing. The only non-Slack hit
(googlecalendar event_changes) is a webhook→polling migration whose target
(event_sync) already ships.
🤖 Generated with Claude Code
✅ direct_message_received.py |
✅ authz_required=True |
private_message_posted.py (PrivateMessagePosted) | message | SLACK_CHANNEL_MESSAGE_RECEIVED + channel_type group/mpim | ✅ (config field present) | ✅ |