Skip to main content
A Slack workspace over the Web API a bot integration actually uses: conversations public and private, messages with server-minted 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 back HTTP 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 is not_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 and admin.*, 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.