Skip to content

fix(conversations): Refresh destination visibility only from live signals - #2440

Merged
dcramer merged 1 commit into
mainfrom
fix/destination-visibility-live-signal
Oct 30, 2026
Merged

dcramer merged 1 commit into
mainfrom
fix/destination-visibility-live-signal

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

Refs #2431 (follow-up from the read-only audit).

Scheduled and event automation runs wrote the visibility saved when the Automation was created back to the shared junior_destinations row on every run. enqueueAgentDispatch passed destinationVisibility to recordActivity, and the Slack dispatch turn let that saved value win over the live channel type for every Turn summary and checkpoint. upsertDestination treats any passed visibility as a live signal and replaces the row. So when a channel went from public to private after an Automation was created, each run set it back to public. Dashboard privacy checks, message search, Briefs, and retention all read that row. The reverse case also caused harm: a saved private value hid a channel that is now public and put it on the shorter private retention window.

Now only a live Slack channel type (from the event or conversations.info) refreshes the row:

  • Dispatch enqueue and the blocked-dispatch summary no longer pass visibility. DispatchTurnContext.destinationVisibility is removed because nothing reads it now.
  • The Slack turn persists only the live channel type. The saved/stored fallback still sets the Slack Source visibility for a normal Turn, but the turn does not write it back.
  • Slack resume no longer reads the stored Conversation visibility and replays it as a new signal. A long resumed run could otherwise overwrite a newer live value.

The dispatch's saved visibility still sets the run's own thread scope (channelVisibility). That scope is separate from what this PR changes.

Existing rows. Rows can already be wrong for channels that changed visibility after an Automation was created there and had a run after the change. The next live Slack event that Junior handles in that channel corrects the row. Channels that only get automation runs stay wrong until such an event arrives. A one-time repair would call conversations.info for each Slack Destination that has Automations and update visibility. I did not run anything against production.

A dispatch into a channel with no Destination row now stores unknown, which readers treat as private, until the first live event. Before, it stored the dispatch's saved value.

Relation to #2382. This PR does not touch sql/store.ts, the schema, or upsertConversation, so it should not conflict with the root-Conversation visibility work in #2382. After both land, dispatch Conversations get no signal, so under #2382's rule they take the known Destination value and not the Automation's saved one. That also covers the "one public dispatch into a DM" case that #2382 describes.

The regression coverage extends the production-routing scenario in agent-dispatch-work.test.ts. A live event records the channel as private, a dispatch that carries public runs, and the Destination stays private. That scenario fails on main.

via David Cramer.

--

View Session [Sentry]

…nals

Automation runs saved the visibility captured when the Automation was
created and wrote it back to the shared Destination row on every run.
A channel that changed from public to private became public again in
the dashboard after each run.

Dispatch enqueue, dispatch turns, and resumed turns no longer pass a
saved visibility. Only a live Slack channel type refreshes the row.

Refs #2431

Co-Authored-By: David Cramer <david@sentry.io>
@vercel

vercel Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
junior-docs Ready Ready Preview Oct 30, 2026 4:14pm UTC

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

3 screenshot changes — 3 changed · 0 added · 0 removed

Review screenshots in Frameshift

Conversation Child Agent Drawer · Desktop
Conversation Child Agent Drawer · Desktop
Changed
Conversation Child Agent Drawer · Mobile
Conversation Child Agent Drawer · Mobile
Changed
Conversation Share Details · Desktop
Conversation Share Details · Desktop
Changed

@dcramer
dcramer merged commit 15ee5c1 into main Oct 30, 2026
45 checks passed
@dcramer
dcramer deleted the fix/destination-visibility-live-signal branch October 30, 2026 16:33
dcramer pushed a commit that referenced this pull request Oct 30, 2026
Since #2440 (`15ee5c130`), an automation run no longer writes its saved
visibility to the Destination row. Only a live Slack signal does. A run
into a channel with no row stores `unknown`, and readers treat it as
private.

In production, the Slack thread where a person created the Automation
records the channel. The eval fixture inserted Automations without that
thread, so their channels stayed `unknown`. The fixture reads results as
`WEB_VIEWER_EMAIL`, who is not a participant. So
`readConversationAccessFromSql` returned `canViewPrivateContent: false`,
and the reporting API hid tool payloads for every scheduled and event
automation run. Tool calls came back with no input and no output
(`result null [4B]` on every tool). `finishAutomationRun` results and
tool arguments were empty. This broke these cases on unrelated branches
(#2435, #2442, fix/flaky-behavioral-evals, chore/remove-slash-command):

- Integration: `Event automation delivery` (no-match silence ×2, blocked
automation) and `Scheduled Delivery` (no message outcome)
- Behavioral: `Scheduled Delivery` (post in this channel, provider that
Junior does not have) and `Sentry Skill Workflows` (creator-bound
scheduled Sentry work)

There is no product change. Fail-closed `unknown` is intended (#2440).
Automations are created from a live Slack turn in their channel, so
production channels have a known visibility.

## Fix

`packages/junior-evals/src/fixture/insert.ts`:
`insertScheduledAutomation` and `insertEventAutomation` now store the
creation thread through the Conversation store with `visibility:
"public"`, as the live Slack event would. No assertions, cases, or
timeouts change.

## Checks

- `pnpm lint`, `pnpm typecheck`, `pnpm --filter @sentry/junior-evals
test` pass.
- A throwaway harness check (not committed) used the real insert
functions. A dispatch-shaped write into a bare `slackChannel()` was
redacted (`unknown`). Channels from either insert function were readable
(`public`).
- The 7 affected eval cases did not run locally: the sandbox has no
`cloudflared` for eval egress. CI must confirm them.

<!-- junior-request-attribution:start -->
via **David Cramer**.
<!-- junior-request-attribution:end -->

<!-- junior-session-footer:start -->
<!-- junior-conversation-id:agent%3A5d3914babce549420a1ad7b950c41799 -->

--

[View
Session](https://junior-prod.sentry.dev/conversations/agent%3A5d3914babce549420a1ad7b950c41799)
[[Sentry]](https://sentry.sentry.io/explore/conversations/agent%3A5d3914babce549420a1ad7b950c41799/?project=4510944073809921)

<!-- junior-session-footer:end -->

---------

Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>

This branch was successfully deployed

1 active deployment
Preview – junior-docs — f90fff47 Deployed Oct 30, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: high PR risk score: high

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant