Skip to content

fix(review-desk): Close Review items that no agent can act on - #2506

Merged
dcramer merged 2 commits into
mainfrom
fix/review-items-stay-open
Nov 1, 2026
Merged

dcramer merged 2 commits into
mainfrom
fix/review-items-stay-open

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Part of #2488

Some Review items stayed open forever, because no agent could act on them any more. Some questions also stayed open after a person answered in the thread.

  • Conversation purge. The purge now dismisses the open items that the purged Conversation tree added, with the reason "Conversation purged". The rows stay. This applies to every visibility, so it does not depend on fix(review-desk): Purge private Review items and add missing foreign keys #2477. fix(review-desk): Purge private Review items and add missing foreign keys #2477 deletes private items later in the same transaction, so the two can merge in either order. The purge also selects a tree that still has an open item, so the next run closes items that an older purge left open.
  • Automation items survive a purge. A recurring Automation refreshes its item by dedupe key, but the item keeps the Conversation of its first run. So the purge and the "tree still has open items" check skip items with an automation_id. An Automation delete closes those.
  • Automation delete. deleteAutomation only soft-deletes the row, so the set null foreign key never runs. It now dismisses the open items of the Automation in the same transaction, with the reason "Automation deleted". The dismiss runs only after the delete returns a row, so it runs under the Automation lock.
  • Reply in a subscribed thread. A reply without a mention in a thread that Junior follows can start a Turn, but Slack ingress returned before it closed the answered questions. It now closes them with the same rules as a mention: an open action item that this Conversation added, and the person is an assignee or there are no assignees. Passive messages skip the allowed domain check at ingress, so the close checks the domain. It checks only when an open item can match, so most replies need no Slack profile lookup. The dashboard message path already closed questions for every message.
  • Docs. The README and the updateReviewItem description said that an item never closes on its own. They now list every way an item closes on main today.

A purge or an Automation delete sends no message and does not change the Slack cards. A click on an old card tells the person that the item is closed.

retention.test.ts went over the 1,000-line limit, so the attachment retention tests move to retention-attachments.test.ts, with shared seed helpers in tests/fixtures/conversation-retention.ts. The tests do not change.

via David Cramer.

--

View Session [Sentry]

@vercel

vercel Bot commented Nov 1, 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 Nov 1, 2026 8:29pm UTC

Request Review

A recurring Automation refreshes its Review item by dedupe key, but the
item keeps the Conversation of its first run. Purge of that Conversation
closed the item while the Automation was still live. Purge now skips
Automation items, and an Automation delete closes them.

- Dismiss Automation items only after the delete returns a row, under
  the Automation lock.
- Check the allowed domain of a subscribed reply only when an open item
  can match, so most replies need no Slack profile lookup.
- Remove the plugin close path from the tool text and README. It does
  not exist yet.
- Split the attachment retention tests into their own file, with shared
  seed helpers, to keep retention.test.ts under the length limit.

Co-Authored-By: David Cramer <[email protected]>
@dcramer
dcramer merged commit 9455e0f into main Nov 1, 2026
45 checks passed
@dcramer
dcramer deleted the fix/review-items-stay-open branch November 1, 2026 21:15
sentry-junior Bot added a commit that referenced this pull request Nov 1, 2026
…vate items

A purge already leaves an open item of an Automation open, because a
later run can still change it (#2506). The private item delete did not
skip it, so a purge of the first run removed an item that the Automation
still updates. Skip open Automation items in the delete and in the purge
selection, so the next purge deletes the item after it closes.

Co-Authored-By: David Cramer <[email protected]>
dcramer added a commit that referenced this pull request Nov 2, 2026
…swers (#2525)

A person answers one Review item in a thread, and every other open item
for them in that thread closes too.

`closeReviewItemsAnsweredByReply` closed every open action item that the
replier could answer in the Conversation, and saved the same reply text
as the answer to each. Since #2506, a plain reply in a subscribed thread
runs this path too. So one typed reply cleared all open questions with
the wrong answers.

Now the decision model checks the reply before anything closes
(`review-items/reply-match.ts`). One `completeDecision` call (the same
decision model as the passive reply router, prompt
`junior.review_item_reply_match`) asks one `answers` / `unrelated`
question for each open item that the replier can answer. Only items with
`answers` at p >= 0.7 close. If the decision fails or takes more than 10
seconds, all items stay open and the agent still gets the reply. In
Slack, the match runs after the ingress lock is released, so a slow
decision does not block the thread. The `addReviewItem` / update tool
descriptions and `review-items/AGENTS.md` describe this.

The matcher calls `completeDecision` directly. No Slack or dashboard
service takes a review-item decision function.

**Tests and evals.** Which items a reply answers is a model choice, so
it is tested in evals, not with a fake:
- New `classifiers` eval suite (`evals/classifiers/**`, hard pass/fail,
own config, global setup, and `evals-classifiers.yml` workflow).
`review-item-replies.eval.ts` checks the exact set of items that a reply
answers with the real decision model: picks an option, acknowledgement,
follow-up question, one of two similar questions, both questions, a text
answer, and an unrelated message. The workflow runs when the suite, the
harness, `reply-match.ts`, or `pi/client.ts` changes.
- The Slack integration test has no model fake. It covers the rules that
need no model choice: a non-assignee or a Slack author outside the
allowed domains cannot close an item, and a retry of a reply that
already closed an item delivers it again (card update and the other
linked thread).

Card clicks and desk submits were not affected: they close only their
own item and do not use the reply path.

Remaining risk: each thread reply makes one decision-model call while
the replier has open items in that thread.

<!-- junior-request-attribution:start -->
via @dcramer.
<!-- junior-request-attribution:end -->

<!-- junior-session-footer:start -->
<!-- junior-conversation-id:slack%3AC0B595QDZLL%3A1793593475.449169 -->

--

[View
Session](https://junior-prod.sentry.dev/conversations/slack%3AC0B595QDZLL%3A1793593475.449169)
[[Sentry]](https://sentry.sentry.io/explore/conversations/slack%3AC0B595QDZLL%3A1793593475.449169/?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 <[email protected]>
Co-authored-by: David Cramer <[email protected]>

This branch was successfully deployed

1 active deployment
Preview – junior-docs — d648164f Deployed Nov 1, 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