Phase 1e of docs/DESIGN.md section 9: Slack as an output-delivery destination.
What's in it
SlackDeliveryDestination:
Pickers. It offers contingent pickers that run as the current user: first the workspace, from the user's own ACTIVE connections; then "Direct message to me", or a channel the user is a member of. Other tenants' workspaces never appear.
Authorization and delivery. It re-authorizes the owner on validate and on deliver, then queues through the outbox with the delivery template and the delivery idempotency key.
Status lookup.lookup(key) maps outbox status to delivery status: SENT→DELIVERED, DEAD_LETTER→FAILED, FAILED_AUTH→UNAUTHORIZED, and queued or retrying→QUEUED.
Limits. It declares maxClassification CONFIDENTIAL, REFUSE above that, 50 MB attachments and no bearer links.
FILE messages.
They use Slack's external upload flow: files.getUploadURLExternal, then a streamed upload from core storage with no temp files, then files.completeUploadExternal.
A message whose lease expired is reconciled through files.list and a title marker, so it never uploads twice.
The files:read scope is added to the manifest and the design.
Core types are stand-ins for now. Core output delivery (qqq#1205) isn't released, so the destination builds against minimal stand-in copies of the core types, marked STAND-IN(core=QRun-IO/qqq#1205, removeBy=4.1.0-RC.8). Switching is an import change once an RC ships #1205.
SlackApi.applySessionKeys(session, allAccess): hosts (kof22#222) stop calling the internal SlackSecurity.
Tests
verify passes locally with 150 tests (90.8% instructions, 97.3% classes). They cover:
Phase 1e of `docs/DESIGN.md` section 9: Slack as an output-delivery destination.
## What's in it
- **`SlackDeliveryDestination`:**
- **Pickers.** It offers contingent pickers that run as the current user: first the workspace, from the user's own ACTIVE connections; then "Direct message to me", or a channel the user is a member of. Other tenants' workspaces never appear.
- **Authorization and delivery.** It re-authorizes the owner on validate and on deliver, then queues through the outbox with the `delivery` template and the delivery idempotency key.
- **Status lookup.** `lookup(key)` maps outbox status to delivery status: SENT→DELIVERED, DEAD_LETTER→FAILED, FAILED_AUTH→UNAUTHORIZED, and queued or retrying→QUEUED.
- **Limits.** It declares `maxClassification` CONFIDENTIAL, REFUSE above that, 50 MB attachments and no bearer links.
- **FILE messages.**
- They use Slack's external upload flow: `files.getUploadURLExternal`, then a streamed upload from core storage with no temp files, then `files.completeUploadExternal`.
- A message whose lease expired is reconciled through `files.list` and a title marker, so it never uploads twice.
- The `files:read` scope is added to the manifest and the design.
- **Core types are stand-ins for now.** Core output delivery (qqq#1205) isn't released, so the destination builds against minimal stand-in copies of the core types, marked `STAND-IN(core=QRun-IO/qqq#1205, removeBy=4.1.0-RC.8)`. Switching is an import change once an RC ships #1205.
- **`SlackApi.applySessionKeys(session, allAccess)`:** hosts (kof22#222) stop calling the internal `SlackSecurity`.
## Tests
`verify` passes locally with 150 tests (90.8% instructions, 97.3% classes). They cover:
- picker isolation;
- DM and channel delivery;
- the exact bytes of a file upload;
- file reconcile with no re-upload;
- deduplication of repeated keys;
- lookup mapping;
- UNAUTHORIZED with no Slack request;
- a PHI canary in the summary, which is refused.
Codex implemented this; I reviewed it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Phase 1e of
docs/DESIGN.mdsection 9: Slack as an output-delivery destination.What's in it
SlackDeliveryDestination:deliverytemplate and the delivery idempotency key.lookup(key)maps outbox status to delivery status: SENT→DELIVERED, DEAD_LETTER→FAILED, FAILED_AUTH→UNAUTHORIZED, and queued or retrying→QUEUED.maxClassificationCONFIDENTIAL, REFUSE above that, 50 MB attachments and no bearer links.files.getUploadURLExternal, then a streamed upload from core storage with no temp files, thenfiles.completeUploadExternal.files.listand a title marker, so it never uploads twice.files:readscope is added to the manifest and the design.STAND-IN(core=QRun-IO/qqq#1205, removeBy=4.1.0-RC.8). Switching is an import change once an RC ships #1205.SlackApi.applySessionKeys(session, allAccess): hosts (kof22#222) stop calling the internalSlackSecurity.Tests
verifypasses locally with 150 tests (90.8% instructions, 97.3% classes). They cover:Codex implemented this; I reviewed it.
🤖 Generated with Claude Code