ts values and edit stamps, one-level threads with the rollups they leave on their parent, reactions, members, DMs and scheduled messages that post when the sandbox is advanced. The conformance suite pins Slack’s own slack_sdk and drives the container through the sequence an integration comes up in.
Slug: slack
Application failures are HTTP 200
This is the defining behaviour of the provider, and the one thing a caller cannot work around. Slack does not use status codes for application errors: a missing token, a bad token, a missing scope, an unknown channel and a method it does not have all come backHTTP 200 with {"ok": false, "error": "…"}. slack_sdk raises SlackApiError off that body, so a twin answering 401 would make the caller’s except land somewhere else than it does in production. 429 is the single exception.
One container is one workspace
The team, the bot user and the bot id are constants of the image —T024TW1NBAY, U024TW1NB0T, B024TW1NB0T — which is what makes auth.test assertable. They are three different things and callers key on each of them for different reasons.
What it models
Advancing the sandbox does one thing, because one thing in Slack ages: a scheduled message whose
post_at has passed becomes a real message. Messages do not expire and channels do not close.
Membership has two failure modes
A public channel the app is not in isnot_in_channel on a read — and postable anyway when chat:write.public is granted, which is what a live workspace does. A private channel the app is not in is channel_not_found on every method and absent from the list: invisible rather than forbidden.
Scenarios
busy-workspace, rate-limited, narrow-scopes, uninstalled-app.
Not modelled
Socket Mode, the Events API and webhooks, incoming webhooks, slash commands and interactivity, the OAuth v2 install flow, Block Kit rendering and modals, file uploads, Enterprise Grid andadmin.*, Canvases, huddles, workflows, multi-person DMs, user tokens beyond refusing them, and search.messages, which needs a user token.
Slack’s Web API carries no version anywhere, so the twin’s behaviour is pinned to the SDK version and to the date it was read off a live workspace. Two things it deliberately does not reproduce: msg_too_long, which never fired — Slack splits long text instead of refusing it — and unknown_method for a method-shaped name it has not modelled, where it answers a string Slack never sends rather than falsely claim Slack retired the method. The twin’s own README explains both.