Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

Slack DMs sync themselves, and Slack images reach the timeline and the agent

merged#2493CedarCopilot

CedarCopilot wants to merge 0 commits into staging from feat/channel-sync-two-tier

Live on prod, no production signal yetTimeline and evidence
  1. Opened
    Aug 15, 2026, 1:08 PM
  2. Merged
    Aug 15, 2026, 5:23 PM
  3. Live on staging
    Aug 15, 2026, 5:23 PM
  4. Live on prod
    Aug 15, 2026, 5:23 PM
  5. Observed 2 days
    Aug 15, 2026, 5:23 PM
  6. Pipelines steady after this deploy
    Aug 15, 2026, 5:23 PM
  7. Pipelines steady after this deploy
    Aug 15, 2026, 5:23 PM
  8. Unobserved

    Live on prod, no production signal yet

    Aug 18, 2026, 2:24 AM

Behaviors Libra is checking

Channel message streams and Slack thread views separate messages by the reader’s local calendar day with Today, Yesterday, and date labels.Inconclusivelow confidence

OTEL fallback found no prod spans matching ChannelMessageList since deploy.

prod, checked Aug 17, 2026, 8:46 PM
Opening a Slack channel loads a recent window first, then fetches older stored history on upward scroll and backfills from Slack only after local history is exhausted while preserving the reader’s scroll position.Inconclusivelow confidence

OTEL fallback found no prod spans matching inbox.slackChannelMessages and channels.backfill since deploy.

prod, checked Aug 17, 2026, 9:46 PM
Users can view, add, and toggle Slack reactions from channel streams and thread panels, with reaction chips updating immediately in both views.Inconclusivelow confidence

OTEL fallback found no prod spans matching useChannelReactions / crm.toggleReaction since deploy.

prod, checked Aug 17, 2026, 10:46 PM
Slack direct-message channels sync their messages automatically so their latest conversation is available without requiring a manual sync.Inconclusivelow confidence

Only 9 prod OTEL spans matching Slack DM channel sync reached Libra since the deploy, below the 20-span floor for calling a change verified. Nothing is failing; there is not yet enough traffic to confirm it.

prod, checked Aug 17, 2026, 11:46 PM
Images in Slack unfurls and Block Kit image blocks load through Cedar’s configured image proxy rather than directly exposing the reader to attacker-controlled image origins.Inconclusivelow confidence

OTEL fallback found no prod spans matching getProxiedImageUrl / SlackStructuredBody image rendering since deploy.

prod, checked Aug 18, 2026, 12:46 AM
Slack channel streams and thread panels render stored Block Kit content and link unfurls as structured headers, sections, cards, fields, and images instead of flattened duplicate text.Inconclusivelow confidence

OTEL fallback found no prod spans matching ChannelThreadView and SlackThreadPanel Slack message rendering since deploy.

prod, checked Aug 18, 2026, 1:46 AM

Failures attributed to this change

No prod customers are affected while this is only in staging. If promoted, customer impact is not proven from the retained evidence. 0 hits · 1 user · no retained trace sample.Introducedmedium confidence

single_user

staging, first seen Aug 15, 2026, 6:04 PM
No prod customers are affected while this is only in staging. If promoted, customer impact is not proven from the retained evidence. 0 hits · no retained affected-user count · no retained trace sample.Introducedmedium confidence

single_user

staging, first seen Aug 15, 2026, 6:04 PM

Libra has verdicts on 0 of 7 tracked behaviors on prod; 7 are still being checked. Libra checks hourly for 3 days after each deploy.

Slack and LinkedIn channel-sync work: DMs that sync themselves, Slack images that reach the timeline and the agent's eyes, and the OAuth scopes both depend on.

What was broken

Three things, each invisible in a different way.

A Slack DM with a customer never synced itself. Both admission routes in bufferSlackMessageEvent are keyed on a channel NAME, and a D… has none , conversations.info returns no name, so the pattern branch continues before it can match. A DM was not unlikely to be admitted; it was structurally unable to be. Measured: 10 DM containers against 811 channels, 8 of the 10 link rows manual, and not one in any connection's selectedChannelIds. Every DM in Cedar got there because a person linked it by hand , while the eight carrying an external counterparty are Slack Connect DMs with meow.com, numeralhq.com, unifygtm.com, warp.dev, evervault.com, juicebox.ai, constructor.io and frontmatter.io.

No Slack image had ever been stored. 41,794 messages, 1,196 flagged has_attachments, 0 with a stored ref. Everything downstream was already built , S3 put, the refs column, the presign, a SlackAttachments component rendering images inline. The pipeline was complete and starved from its first step, because files:read was in neither scope list and Slack answers an unauthorized url_private fetch with 200 and an HTML login page rather than a 401, so the existing guard skipped every file in silence.

An agent could not see any of it. No Slack attachment tool existed, and the vision path was fed only from the user's own chat uploads.

What this does

  • DM auto-sync , a third admission rung: resolve the DM's participants, subtract owner domains and free mail, admit when anything external remains. Admission is not a link; the container lands pending and the ladder decides the deal, which it can do on the first message because participants are already recorded. Internal DMs are refused at admission, so Cedar never holds a copy of a rep's DMs with colleagues.
  • Scopes , files:read/files:write on both lists (the download and upload paths act as the user first), plus groups:write and conversations.connect:write bot-only for external deal channels.
  • Images to the agent , inbound only, images only, newest few, bounded and logged. Shared with the chat surface through one content-part builder.
  • read-slack-attachment , reaches PDFs/CSVs/spreadsheets, with the discovery surface that makes it reachable at all.
  • Operator CLI , slack-images scopes | status | inspect | backfill, and slack-manifest to generate the app manifest from the scope constants.

Proof

pnpm --filter @zero/server slack-images-probe

Generates a PNG of four colour bars in a random order, seeds it onto a real message, resolves it through the same code the orchestrator uses, hands it to the real orchestrator agent, and asserts the model names the colours in order , then deletes everything it created.

secret=[redacted] → blue → red → orange
[1] resolveConversationSlackImages → 1 image(s)
[2] buildUserMessageWithMedia → parts: image, text
    model said: "Green, Blue, Red, Orange"
✅ PASS

Green on every run since. 294 tests pass; typecheck shows 24 errors, all pre-existing in untouched files; deps:check clean.

Two oracles that failed, and why that mattered

The first two probes rendered a six-digit code and asked the model to read it back: 408121 against 484121, then 331122 against 375171. Right length, wrong digits , which looks exactly like a broken pipeline. It wasn't: asked open-endedly, the model accurately described the picture. It had the image and couldn't OCR synthetic glyphs. Colour-bar ordering is reliable; a flaky oracle reports a working pipeline as broken, which is the ambiguity a probe exists to remove.

Before this can do anything

files:read cannot be granted headlessly. Confirmed against the live grant via Slack's `x

Show production surfaces and changed-file mapping

Production surfaces

Libra has not measured any production surfaces for this change yet.

Changed files → surfaces

  • apps/mail/app/(routes)/playground/initial-sync.tsxno production surface mapped
  • apps/mail/components/ui/day-divider.tsxno production surface mapped
  • apps/mail/docs/url-driven-layout.mdno production surface mapped
  • apps/mail/lib/proxy-image.tsno production surface mapped
  • apps/mail/modules/conversations/components/timeline/SlackStructuredBody.test.tsxno production surface mapped
  • apps/mail/modules/conversations/components/timeline/SlackStructuredBody.tsxno production surface mapped
  • apps/mail/modules/conversations/components/timeline/SlackTimeline.tsxno production surface mapped
  • apps/mail/modules/conversations/components/timeline/UniversalComposer.tsxno production surface mapped
  • apps/mail/modules/inbox/components/ChannelMessageList.tsxno production surface mapped
  • apps/mail/modules/inbox/components/ChannelThreadView.tsxno production surface mapped
  • apps/mail/modules/inbox/components/SlackThreadPanel.tsxno production surface mapped
  • apps/mail/modules/inbox/hooks/use-channel-reactions.tsno production surface mapped
  • apps/mail/modules/inbox/hooks/use-open-channel-item.tsno production surface mapped
  • apps/mail/modules/threads/common/utils/email-utils.client.tsxno production surface mapped
  • apps/mail/modules/threads/mail.tsxno production surface mapped
  • apps/mail/modules/ux/layout/LayoutUrlSync.tsxno production surface mapped
  • apps/mail/tests/modules/inbox/channelReactions.test.tsxno production surface mapped
  • apps/mail/tests/modules/inbox/openChannelItem.test.tsxno production surface mapped
  • apps/mail/tests/modules/inbox/scrollAnchor.test.tsno production surface mapped
  • apps/mail/tests/modules/ux/layout/slackUrlSync.test.tsxno production surface mapped
  • apps/server/docs/channel-sync-architecture.mdno production surface mapped
  • apps/server/docs/dm-auto-sync.mdno production surface mapped
  • apps/server/docs/slack-images.mdno production surface mapped
  • apps/server/docs/slack-parity.mdno production surface mapped
  • apps/server/docs/unknown-removal.mdno production surface mapped
  • apps/server/docs/wiki/README.mdno production surface mapped
  • apps/server/docs/wiki/slack-images-and-agent-vision.mdno production surface mapped
  • apps/server/docs/wiki/slack-parity.mdno production surface mapped
  • apps/server/package.jsonno production surface mapped
  • apps/server/scripts/headless-dev-start.shno production surface mapped
  • apps/server/src/cli/channels.tsno production surface mapped
  • apps/server/src/cli/index.tsno production surface mapped
  • apps/server/src/db/crm-schema.tsno production surface mapped
  • apps/server/src/db/integration-schemas.tsno production surface mapped
  • apps/server/src/db/migrations/channel_container_history_cursor.sqlno production surface mapped
  • apps/server/src/db/migrations/slack_message_rich_payload.sqlno production surface mapped
  • apps/server/src/db/migrations/unknown_conversation_removal.sqlno production surface mapped
  • apps/server/src/db/outbound-schema.tsno production surface mapped
  • apps/server/src/docs/thread-sync-architecture.mdno production surface mapped
  • apps/server/src/lib/testing/__tests__/secret-png.test.tsno production surface mapped
  • apps/server/src/lib/testing/secret-png.tsno production surface mapped
  • apps/server/src/mastra/index.tsno production surface mapped
  • apps/server/src/mastra/skills/crm/domain-identification.tsno production surface mapped
  • apps/server/src/mastra/tools/event-execution/__tests__/unattributed-event.test.tsno production surface mapped
  • apps/server/src/mastra/tools/event-execution/assignEventToConversationTool.tsno production surface mapped
  • apps/server/src/mastra/tools/pipeline-agent-tools.tsno production surface mapped
  • apps/server/src/mastra/tools/slack/__tests__/readSlackAttachmentTool.test.tsno production surface mapped
  • apps/server/src/mastra/tools/slack/readSlackAttachmentTool.tsno production surface mapped
  • apps/server/src/mastra/tools/subagent-tool-allowlists.tsno production surface mapped
  • apps/server/src/mastra/tools/tool-names.tsno production surface mapped
  • apps/server/src/mastra/utils/__tests__/model-image-parts.test.tsno production surface mapped
  • apps/server/src/mastra/utils/context-formatting/__tests__/slack-attachments-context.test.tsno production surface mapped
  • apps/server/src/mastra/utils/context-formatting/conversation-context.tsno production surface mapped
  • apps/server/src/mastra/utils/context-formatting/event-context.tsno production surface mapped
  • apps/server/src/mastra/utils/model-image-parts.tsno production surface mapped
  • apps/server/src/mastra/workflows/chat/chat-workflow.tsno production surface mapped
  • apps/server/src/mastra/workflows/event-execution/on-event-agent-execution-workflow.tsno production surface mapped
  • apps/server/src/scripts/__tests__/slack-manifest.test.tsno production surface mapped
  • apps/server/src/scripts/slack-images-probe.tsno production surface mapped
  • apps/server/src/scripts/slack-images.tsno production surface mapped
  • apps/server/src/scripts/slack-manifest.tsno production surface mapped
  • apps/server/src/services/channels/__test__/link-store.test.tsno production surface mapped
  • apps/server/src/services/channels/adapters/index.tsno production surface mapped
  • apps/server/src/services/channels/containers.tsno production surface mapped
  • apps/server/src/services/channels/health.tsno production surface mapped
  • apps/server/src/services/channels/history.tsno production surface mapped
  • apps/server/src/services/channels/inspect.tsno production surface mapped
  • apps/server/src/services/crm/__test__/channel-deal-binding.test.tsno production surface mapped
  • apps/server/src/services/crm/__test__/channel-message-events.test.tsno production surface mapped
  • apps/server/src/services/crm/__test__/linkedin-linking.test.tsno production surface mapped
  • apps/server/src/services/crm/__tests__/slack-events.ingest.test.tsno production surface mapped
  • apps/server/src/services/crm/channel-message-events.tsno production surface mapped
  • apps/server/src/services/crm/conversation-slack-images.tsno production surface mapped
  • apps/server/src/services/crm/conversations.tsno production surface mapped
  • apps/server/src/services/crm/external-crm-events.tsno production surface mapped
  • apps/server/src/services/crm/slack-events.tsno production surface mapped
  • apps/server/src/services/inbox/slack-messages.tsno production surface mapped
  • apps/server/src/services/inbox/slack-thread.tsno production surface mapped
  • apps/server/src/services/integrations/linkedin/__test__/messaging.test.tsno production surface mapped
  • apps/server/src/services/integrations/linkedin/messaging.tsno production surface mapped
  • apps/server/src/services/integrations/slack/__tests__/slack-attachment-read.test.tsno production surface mapped
  • apps/server/src/services/integrations/slack/__tests__/slack-block-extraction.test.tsno production surface mapped
  • apps/server/src/services/integrations/slack/__tests__/slack-dm-admit.test.tsno production surface mapped
  • apps/server/src/services/integrations/slack/__tests__/slack-files-inbound.test.tsno production surface mapped
  • apps/server/src/services/integrations/slack/__tests__/slack-scope-drift.test.tsno production surface mapped
  • apps/server/src/services/integrations/slack/slack-api.tsno production surface mapped
  • apps/server/src/services/integrations/slack/slack-attachment-read.tsno production surface mapped
  • apps/server/src/services/integrations/slack/slack-dm-admit.tsno production surface mapped
  • apps/server/src/services/integrations/slack/slack-events-webhook.tsno production surface mapped
  • apps/server/src/services/integrations/slack/slack-files.tsno production surface mapped
  • apps/server/src/services/integrations/slack/slack-sync.tsno production surface mapped
  • apps/server/src/services/integrations/slack/slack.tsno production surface mapped
  • apps/server/src/services/integrations/whatsapp/index.tsno production surface mapped
  • apps/server/src/services/mail/initial-sync/handlers.tsno production surface mapped
  • apps/server/src/trpc/routes/admin.tsno production surface mapped
  • apps/server/src/trpc/routes/channels.tsno production surface mapped
  • apps/server/src/trpc/routes/inbox.tsno production surface mapped
  • apps/server/src/trpc/routes/integrations.tsno production surface mapped
  • apps/server/src/workflows/__tests__/conversation-sync-kv-flow.test.tsno production surface mapped
  • apps/server/src/workflows/step-registry/conversation-sync/finalize-steps.tsno production surface mapped