Skip to content

feat(review-desk): Let people act on Review items - #2462

Merged
dcramer merged 4 commits into
mainfrom
feat/review-item-actions
Oct 31, 2026
Merged

dcramer merged 4 commits into
mainfrom
feat/review-item-actions

Conversation

@sentry-junior

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

Copy link
Copy Markdown
Contributor

Part 2 of the review desk stack for #2401. Stacked on #2460.

Adds the review desk API and the person actions on Review items:

  • GET /api/review-items lists items with the Mine / Everyone / All views, the archived filter, a Conversation filter, and text search. GET /api/review-items/count returns the open items assigned to the viewer as a User (the nav count). GET /api/review-items/:id reads one item.
  • POST /api/review-items/:id/actions does take, submit, complete, or dismiss. The first close wins for every assignee and records who closed it. An action item needs an answer, so it cannot be completed. A retry of the same close succeeds and resends any missing messages.
  • A person action sends a web Message from that person to every open linked Conversation, so it has that person's authority. A Conversation that does not take web Messages gets an Event instead. An agent close (updateReviewItem) sends an Event to the other open linked Conversations, and the Event says it does not give user approval.
  • "Open" means the transcript is not purged. Archive is a per-viewer list state, so it does not stop messages.
  • acceptsWebMessages moves into web-input.ts so the dashboard append route and the review desk share one rule.

Tests: tests/integration/api/review-items/actions.test.ts (first-submit-wins, retry idempotency, take on Everyone, views, count) and the agent-close fan-out in review-item-tools.test.ts.

via David Cramer.

--

View Session [Sentry]

@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 31, 2026 2:35am UTC

Request Review

@blacksmith-sh

This comment has been minimized.

sentry-junior Bot and others added 4 commits October 31, 2026 02:35
Add the review desk API: list, count, read, and act on Review items.
A person can take, submit, complete, or dismiss an item. The first
close wins for every assignee. Each person action sends a web Message
from that person to every open linked Conversation. An agent close
sends an Event to the other linked Conversations.

Refs #2401

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

Co-Authored-By: David Cramer <david@sentry.io>
Co-Authored-By: David Cramer <david@sentry.io>
…ublic items

Co-Authored-By: David Cramer <david@sentry.io>
@dcramer
dcramer force-pushed the feat/review-item-actions branch from db5091c to 43eb5fd Compare October 31, 2026 02:35
@dcramer
dcramer marked this pull request as ready for review October 31, 2026 02:35
@github-actions github-actions Bot added the risk: high PR risk score: high label Oct 31, 2026
@github-actions

Copy link
Copy Markdown
Contributor

2 screenshot changes — 2 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

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 43eb5fd. Configure here.

@dcramer
dcramer merged commit e215da0 into main Oct 31, 2026
44 checks passed
@dcramer
dcramer deleted the feat/review-item-actions branch October 31, 2026 02:41
Comment on lines +128 to +145
if (acceptsWebMessages(args.conversationId, conversation?.destination)) {
// A person action comes from that person, like a reply in Slack.
await appendAndEnqueueWebMessage(
{
actor: webActorFromEmail(args.change.user.email, {
...(args.change.user.displayName
? { fullName: args.change.user.displayName }
: undefined),
}),
conversationId: args.conversationId,
idempotencyKey: key,
message: args.text,
},
{ nowMs: args.nowMs, queue: args.queue },
);
return;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Person review actions start credentialed web turns in conversations the actor never joined

Person take/submit/complete/dismiss posts a web Message as the actor into every linked conversation that accepts web input, with no participant check, so a public item assigned to a victim (always linked to the creating conversation) starts a Turn under the victim’s web actor and credentials there. Send non-participant linked conversations on the event path instead, and only use person-authored web Messages when the actor is a participant.

Evidence
  • sendOne() calls appendAndEnqueueWebMessage() with webActorFromEmail(change.user.email) for every open linked conversation where acceptsWebMessages() is true, including Slack and local:web destinations.
  • Unlike appendConversationMessageForViewer(), this path never checks isParticipant / conversation access for the acting user.
  • Web mailbox messages become Turns under that web actor; credentialContextForActor(actor) attaches that actor’s user token slot for tool auth.
  • Public review items may assign any user email, and addReviewItem always links the creating conversation, so a hostile public item makes the victim’s action enqueue a credentialed turn (and any submit answer text) into the attacker’s conversation.

Identified by Warden · security-review · UT4-ZXD

dcramer added a commit that referenced this pull request Oct 31, 2026
Part 3 of the review desk stack for #2401. Stacked on #2462.

- **Nav:** "Review desk" is the first nav item after Conversations. It
shows the count of open items assigned to the viewer as a User
(`/api/review-items/count`, refreshed every minute). Unassigned items do
not count.
- **Page (`/review`):** item list on the left, selected item on the
right (`?item=<id>`). Mine / Everyone / All views, an Open / Archived
filter that uses the same views, and search. The list groups items into
"Needs an answer", "Notices", and "Blocked Automations". Blocked
Automations come from the viewer's Automations with status `blocked`;
they are not stored as items. Unassigned items show only in All, with an
"Unassigned" label.
- **Selected item:** title, body, subject, linked Conversations, who
added it (Conversation and Automation), assignees, and the actions. An
assignee can take, submit, complete, or dismiss. An archived item shows
who closed it, when, and the answer.
- **Shared form:** the `requestUserInput` form moves from
`UserInputRequestCard` into `components/UserInputForm.tsx`. The
transcript card still sends the formatted answer as a message. The
review desk submits the structured answer. `ReviewItemActions` will also
back the transcript card and side panel in the next PR.

No new automated tests: the page is UI composition over the API that
#2462 tests. Visual QA follows on the top PR.

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

<!-- junior-session-footer:start -->
<!-- junior-conversation-id:slack%3AC0AHB7N2JCR%3A1793326028.695969 -->

--

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

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

---------

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

This branch was successfully deployed

1 active deployment
Preview – junior-docs — 43eb5fdd Deployed Oct 31, 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