[DEVEX-1523] Make AI reviewer output deterministic and tighten safety gates#126
Conversation
Reworks the shared Claude AI review workflow so the AI cannot
directly approve PRs and produces a deterministic verdict that the
workflow translates into review actions and a Check Run status.
Key changes:
- Concurrency: cancel-in-progress per PR, killing stale runs against
older commits before they can post a late approval.
- Size gate moved out of the LLM into a deterministic shell step
using the Files API. Default lowered to 500 lines / 30 files and
test changes are excluded from the count.
- Claude no longer has access to gh pr review / gh pr comment.
It writes a constrained-schema verdict.json (approve | comment |
defer) plus reasoning. A follow-up step posts the formal review
based on the verdict and re-checks HEAD SHA and current size
before approving.
- Approval body always includes the AI's reasoning.
- Optional Slack notification on auto-approve (slack_channel input,
slack_bot_token secret).
- Publishes a dedicated AI Code Review Check Run with conclusion
derived deterministically from the verdict:
approve -> success, comment -> neutral, defer/size -> skipped.
- Adds checks: write permission for the Check Runs API.
Co-authored-by: Cursor <cursoragent@cursor.com>
PR SummaryMedium Risk Overview The Claude step is constrained to writing a structured Reviewed by Cursor Bugbot for commit 1242a30. Bugbot is set up for automated code reviews on this repo. Configure here. |
Cursor bugbot flagged that retaining Bash(gh api:*) lets the AI POST to /pulls/N/reviews with event=APPROVE, bypassing every safety gate the previous commit added. Closes the gap with three layers: 1. Tool-runner enforcement (primary): narrows the allowedTools glob from Bash(gh api:*) to Bash(gh api:repos/*/pulls/*/comments*) so any path other than the comments endpoint is denied before the command runs. This blocks gh api -X POST .../reviews directly. 2. Server-side defense-in-depth: a new "Dismiss unauthorized AI approvals" step runs before Apply verdict and dismisses any APPROVED review by the reviewer bot on the current HEAD SHA. Filters by commit_id == HEAD_SHA_AT_START so stale approvals on older commits (already obsolete in GitHub's eyes) are left alone. Bot identity is derived via gh api user so the shared workflow isn't coupled to a specific bot username. 3. Prompt hard rule: explicit forbid on gh api -X POST/PUT/PATCH/ DELETE/--method/-f/-F/--input, with note that any bypass will be dismissed by the workflow. Soft control, for documentation. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1242a30. Configure here.

Summary
Reworks the shared Claude AI review workflow so the AI's output drives review actions and check status through a constrained, machine-readable contract rather than direct tool calls. Addresses the recent incident on encodium/manage#7507 where a stale parallel run approved a PR that another concurrent run had just deferred as too large.
Why
The previous design let the LLM judge size, decide concurrency, and call
gh pr review --approvedirectly. Two runs on consecutive commits reached opposite conclusions on the same PR, and a stale--approvefrom the older run was attributed to the newer HEAD commit. Root causes: no concurrency control, LLM-judged size gate, no SHA pinning, and the LLM having direct approve authority.What changed
cancel-in-progressper PR — new pushes cancel in-flight runs.gh pr reviewandgh pr commentremoved from Claude's allowed tools. Claude writes a constrained-schemaverdict.json(approve|comment|defer) with required reasoning.slack_channel; on auto-approve, the workflow posts a link to the PR plus reasoning via the Slack API (slack_bot_tokensecret).AI Code Reviewpublished via the Check Runs API. Conclusion is deterministic from the verdict:approve → success,comment → neutral,defer/too-big/missing-verdict → skipped. Pinned to the head SHA at workflow start.checks: writefor the Check Runs API.Operator follow-ups (not in this PR)
rp-ai-reviewertoken (PAT or App installation)Checks: read & writeon consumer repos. Without it, the dedicatedAI Code Reviewcheck won't publish (workflow will log a warning, other functionality unaffected).AI_REVIEWER_SLACK_BOT_TOKENorg secret if any caller passesslack_channel. See the companion manage PR for the manage-side caller wiring and channel.AI Code Reviewto required status checks on protected branches for visibility.Test plan
--approvereview with reasoning, and the dedicatedAI Code Reviewcheck showssuccess.skipped, Claude action never runs (verify in logs).comment, apply step posts a--commentreview, dedicated check showsneutral.slack_channelset andslack_bot_tokenunset — confirm warning is logged and workflow completes without failure.Made with Cursor