Eight Slack actions had _scopes that didn't match what the Slack Web API actually requires per docs.slack.dev. Six come from QA's Failed verdicts in [QA TESTING] Action To Scope Mapping.xlsx → WIPSlack; two were caught by an automated cross-check across the slack/ codebase and verified end-to-end against the current docs pages.
The sheet is WIP (work-in-progress), not yet finalized. Out of 158 rows, QA marked 7 as Failed across 6 unique actions — fixed in this PR. Plus 2 sheet-missed bugs the codebase sweep caught (also fixed).
archive_a_slack_conversation and unarchive_channel each call two Slack endpoints:
/api/conversations.archive (or .unarchive) — needs channels:write, groups:write, im:write, or mpim:write/api/admin.conversations.archive (or .unarchive) — needs admin.conversations:writeMercury only listed the regular-user scopes, so an admin-token user holding admin.conversations:write couldn't pass Mercury's gate. Fix: add admin.conversations:write to the existing any_of as an alternative. Purely additive — original 4 scopes preserved.
get_audit_action_types calls GET /audit/v1/actions. Per Slack docs this endpoint is unauthenticated. Mercury required auditlogs:read. Fix: _scopes = [].
list_canvases calls GET /api/files.list. Per docs this needs only files:read. Fix: drop canvases:read.
retrieve_a_user_s_identity_details calls GET /users.identity. Requires identity.basic per docs; Mercury was empty. Fix: add identity.basic.
files:read OR files:write to require writeupload_or_create_a_file_in_slack calls files.getUploadURLExternal and files.completeUploadExternal. Both require files:write. Mercury allowed files:read OR files:write, so a user with only files:read would 403 mid-upload. Fix: keep only files:write.
find_user_by_email_address.pyCalls GET /users.lookupByEmail. Per docs, the only required scope is users:read.email (applies to both bot and user tokens). Mercury required both users:read AND users:read.email (multi-clause all_of). A user holding only the documented required scope would FAIL Mercury's gate.
Fix: simplify to single any_of with only users:read.email.
get_canvas.pyCalls GET /files.info. Per docs, this method accepts only files:read. Mercury allowed canvases:read OR files:read. The canvases:read scope is for canvas-section endpoints (canvases.sections.lookup), not the generic files API. A user with only canvases:read would pass Mercury's gate then 403 at runtime.
Fix: drop canvases:read, keep files:read.
MERCURY_AUTOLOAD=true. Mercury's validate_scopes accepts every new _scopes block.ruff format + ruff check pass on all 8 files.tests/test_attrs/test_action_scopes.py all 5 tests pass.The community Slack OpenAPI spec at slack-api-specs/web-api/slack_web_openapi_v2.json still lists deprecated granular scope names (chat:write:bot, chat:write:user, files:write:user) that Slack has since unified into the simpler chat:write and files:write. Verified against current docs — Mercury's modern names are correct, the spec is outdated.
Affected actions (no fix needed): delete_a_comment_on_a_file, delete_a_file_by_id, delete_a_scheduled_message_in_a_chat, deletes_a_message_from_a_chat, enable_public_sharing_of_a_file, revoke_public_sharing_access_for_a_file, schedule_message, send_ephemeral_message, send_message, share_a_me_message_in_a_channel, updates_a_slack_message.
Recommendation: any future automated audit shouldn't trust the OpenAPI spec as the source of truth for Slack — docs.slack.dev pages are the authoritative source.
These call newer endpoints not yet in the community spec — canvas operations, SCIM, audit logs, RTM, search. Not flagged as bugs (Mercury's scopes look reasonable), but couldn't be auto-verified.
assistant_search_context, assistant_search_info, create_canvas, delete_canvas, edit_canvas, get_audit_action_types, get_audit_schemas, list_auth_teams, lookup_canvas_sections, read_audit_logs, rtm_start, search_all, slack_scim_get_config, upload_or_create_a_file_in_slack.
http_request)Actions calling Slack via the bolt-python SDK or a helper rather than direct http_request. Manual review needed.
admin_conversations_search, get_workspace_connections_for_channel, list_pending_workspace_invite_requests, restrict_app_installation, set_workspace_icon, set_workspace_owner, set_workspaces_for_channel, slack_admin_apps_approved_list.
Several sheet rows have status ✗ MISSING SCOPE but QA marked them Pass — those reflect Slack-specific quirks the spreadsheet's per-row check can't capture:
files.remote.add) where there's no user-token scope — Mercury correctly leaves _scopes empty for user-token flows.chat.scheduledMessages.list, chat.getPermalink, api.test) where Slack requires no token — Mercury's empty _scopes is correct.Worth noting: the binary status column doesn't reflect bot/user-token distinction or no-auth.
upload_or_create_a_file_in_slack: a user holding only files:read should now be blocked by Mercury's gate (used to pass and 403 mid-upload).find_user_by_email_address: a user with only users:read.email should now pass Mercury's gate (was previously rejected because users:read was also required).admin.conversations:write as an any_of alternative is the right shape for archive/unarchive — vs separating into its own clause.🤖 Generated with Claude Code