CedarCopilot wants to merge 4 commits into staging from fix/slack-connect-workspace-scoping
Live on prod, no production signal yet
Strict CloudWatch fallback saw 913 success-shaped log lines matching pipeline, analytics, quota, aop, but no tied operation was present, so Libra is not calling this working.
Strict CloudWatch fallback found 10 prod failure log lines for [backfillSlackChannelHistory] Backfill failed (Superglue workflow failed: fetch failed), but this domain-wide failure family is not tied to this intent.
Strict CloudWatch fallback found 10 prod failure log lines for [backfillSlackChannelHistory] Backfill failed (Superglue workflow failed: fetch failed), but this domain-wide failure family is not tied to this intent.
Libra has verdicts on 0 of 3 tracked behaviors on prod; 3 are still being checked. Libra checks hourly for 3 days after each deploy.
Aspire's inbound-lead agent stopped firing at 12:22 UTC on 2026-08-26, the moment an external member joined #hot-lead-demo-request and made it a Slack Connect channel. Every delivery after that logged cross_workspace_drop and nothing ran:
17:51:22 cross_workspace_drop channel=C03GC5VHSKS workspace=T08AHSLJBTL
webhook=c80e3672… owner=<email>
The guard was approximating. It asked "does the row's owner hold a Slack connection to the workspace this event arrived under" as a stand-in for "is this the channel the row was registered against".
Inside one workspace those coincide. On a shared channel they don't: Slack delivers under one of the connected workspaces, which need not be the one the registration was made from. Verified in production , a message from an Aspire user arrived tagged with Cedar's workspace and was dropped.
Ask the real question. source_workspace_id records where a row was registered; resolveChannelTeams reads the channel's own host + connected team set, which is the one identity reported identically from every side. A row fires when both it and the incoming delivery appear in that set.
| Situation | Result |
|---|---|
| Aspire registered, event arrives under Cedar | fires |
| Colliding channel id, unrelated workspace | nothing fires |
| Channel lookup fails | falls back to the owner check |
The tenancy boundary survives because the incoming workspace must also be in the set. Without that, the new proof degrades to "this row is on some shared channel" , which a colliding id also satisfies.
Nothing new fires. A registration only exists if someone created one: findSlackChannelSources returns only rows with a matching source_ref, and dispatchPlaybookWebhookMessage then bails at playbook-webhook.ts:182 unless the playbook carries a <trigger type="webhook" id="…"> for that exact id. Cedar's org has zero slack_channel registrations and no such trigger block, so on this channel today the change makes exactly one thing fire: Aspire's. Two orgs both firing requires two deliberate acts by the second org.
fetchSlackChannelTeams calls conversations.info directly rather than through the slack-get-channel-info Superglue workflow, whose projection omits the sharing fields and is defined outside this repo.The route dedupes by event_id, which covers Slack retrying one envelope. It does not cover one message reaching Cedar through two installations, which would carry two distinct ids and fire every matching row twice. claimSourceEvent keys on the message ts, stable however many envelopes carry it. Fails open, matching the rate limiter.
Best-effort, not a guarantee. The read and write are separate KV operations, so concurrent envelopes can both claim. KVStore offers no compare-and-set, so an exact claim needs a different store; checkRateLimit accepts the same race for the same reason. What it
Libra has not measured any production surfaces for this change yet.