CedarCopilot wants to merge 4 commits into staging from fix/slack-link-scope-v2
Live on prod since Wed, 2 of 7 behaviors working
Since the deploy, 301 prod OTEL spans matching linkSlackChannelOnly ran with 0 error spans. In the 59h before the deploy the same surface ran 361 OTEL spans with 0 error spans. Confidence is medium because the surface was already clean before the deploy, so this confirms no.
Post-deploy OTEL had 0 instrumented spans for the exact function, so verification relies on CloudWatch. The fallback warning appeared 93 times in prod after 2026-08-27T02:03:14Z, including workspace-listing failures with token_revoked and ratelimited. Concrete [SLACK_LINK].
Verification reached its 130s outer budget before the verifier returned. Libra is keeping this intent verifying until the next check.
Verification reached its 120s wall-clock budget before a tied verdict. Libra is keeping this intent verifying until the next check.
Unable to complete verification: the available telemetry shows repeated successful listUserSlackChannels logs, including multi-page runs, but the returned data is truncated and does not establish the full post-deploy success/error rate, latency, distinct-user count, or absence.
Unable to complete verification within the available telemetry loop; the retrieved CloudWatch results show linker activity before the deployment cutoff, but not yet a post-deploy invalid-config outcome or verdict.
Libra has verdicts on 2 of 7 tracked behaviors on prod; 5 are still being checked. Libra checks hourly for 3 days after each deploy.
Replaces #2596, which was branched off tool-surface/master-agent-families and carried three unrelated customer docs. Same two commits, cut from staging.
Linking selected candidates from listSlackChannels ā Slack's conversations.list, every channel in the workspace. Corgi names customer channels {company}-corgi, so endsWith: "-corgi" matched 445 workspace channels for a user who is a member of 16. Each candidate costs a members fetch plus a DB write at SLACK_SYNC_CONCURRENCY_LIMIT = 1, exhausting both the Step Functions 10-minute state timeout and the HTTP gateway timeout , while linking nothing.
An earlier hypothesis (a hung call missing Effect.timeout) was disproved by the logs: every batch emitted initial_sync_step_complete and there were zero initial_sync_slack_channel_error rows.
listUserSlackChannelsWithMetadata , intersects users.conversations (membership) with conversations.list (metadata). Membership decides which channels; the workspace listing supplies num_members.
Why the intersect rather than membership alone: users.conversations omits num_members (verified live). linkMatchingSlackChannelsForUser skips a channel as unchanged only when the count and updated both hold steady , and Slack's updated does not move on a member join (verified: channels created and invited-to the same day report updated === created). Membership-only would have pinned every count to 0 and silently stopped re-evaluating channels that become linkable because a customer joined. Both calls are cheap listings; the cost that timed out the sync was per-channel work, still bounded by the intersection.
Container bootstrap , linkSlackChannelOnly returned success:false whenever no channel_containers row existed, and containers were only ever created by message ingest. That made link-only sync structurally unable to onboard a new user: every channel is uningested by definition. Now bootstraps via the idempotent ensureContainerForMember. Verified this doesn't leak into the message-fetch cron, which requires cu.conversation_id IS NOT NULL.
Config-shape coercion , SlackConfigSchema.autoSelectPatterns now accepts a legacy bare object and normalises it to an array. Raw SQL bypasses the schema on write, so the read path is the only place that can guarantee the shape; a parse failure there rejected the entire config and read as "nothing configured". Six connections across five orgs (Greptile, Hamming Ć2, Invoicebutler, Listenlabs, Understudylabs) were silently linking zero channels. Genuinely unparseable values still fail loudly, and the failure is now a structured error counted as errors: 1.
Fixed the source , this repo's account-setup runbook documented the bare-object form in its own Phase 7 SQL, which is where these configs came from. Corrected, plus a rule recording the trap.
All 8 malformed connections normalised to the array form; 0 remain fleet-wide.
101 passing across the Slack suite (up from 94 pre-change). Typecheck clean for touched files , the 2 errors in phase2c-seed-playbook.ts are uncommitted WIP that predates this work. pnpm deps:check ā no violations.
Full report: docs/bugs/slack-channel-link-timeout-2026-08-26.md
š¤ Generated with Claude Code
The PR scopes Slack auto-link candidates to the installing user's channel memberships, normalizes legacy Slack pattern configuration, and bootstraps containers for link-only onboarding.
users.conversations membership with workspace metadata to bound per-channel work.autoSelectPatterns and structured configuration errors.Libra has not measured any production surfaces for this change yet.