Skip to content

pr-review re-reviews an escalated PR while needs-human-review is present, then removes the hold on fix-request #2090

Closed

Description

@don-petry

Problem

Once pr-review escalates a PR to a human (review cycle 3/3, needs-human-review added), it should stop until a person removes the label or @mentions the bot. review-one-pr.sh is meant to enforce this: when it sees an escalation marker and the label is still there, it emits noop human-escalated. On #1902 that didn't happen:

Time (UTC, 2026-10-09) Event
04:44:28 pr-review escalates #1902 at cycle 3/3 (human-escalation reset=04:44:28Z) and adds needs-human-review.
~04:44 Auto-rebase merges main into the branch. The head becomes f5303859; the PR's own code is unchanged.
05:03:22 dev-lead posts its hold notice for needs-human-review, so the label was present.
05:04:30 pr-review posts a full-cascade fix-requested, cycle 1/3 on f5303859.
05:10:49 pr-review posts a full-cascade fix-requested, cycle 2/3 on the same f5303859.
~05:11 needs-human-review has been removed. No person touched the PR. dev-lead's hold notice flips to "hold was lifted".

So a PR escalated to a human:

  • was reviewed twice more by the full multi-model cascade, the second time on a commit it had just reviewed;
  • had its human hold removed by automation, through clear_automated_hold_label in post-pr-review.sh on the fix-request path. Because the label was automation-set, the provenance check allows the removal.

This may be why needs-human-review has been seen vanishing from other PRs.

Why it matters

Hypotheses (not yet confirmed)

FORCE_REVIEW is only set by a repository_dispatch with force_review: true, which is the mention path. No mention was posted. Candidates:

  1. Ring version: consumers run pr-review/v1-next. Its review-one-pr.sh may predate the label-aware escalation block on main, or match a different escalation marker.
  2. Sweep: a sweep re-dispatch (sweep-stuck-reviews.sh, or the rate-limit sweep that feat(#1894): answer "why isn't this PR approved?" from the real pr-review gate chain (+ why-not-approved agent) #1902's 04:14 rate-limited … reset=05:14:19Z marker points at) may reach the cascade without going through the escalation no-op.
  3. Snapshot: the escalation check may have read a PR snapshot without the label.

The run logs for the 05:04 and 05:10 pr-review runs on #1902 will show which path ran: look for the noop:, re-engage: or force-review: line.

Acceptance criteria

  1. While needs-human-review is present after an escalation, no automated path (synchronize, sweep, rate-limit retry, auto-rebase) runs the cascade. Only a human removing the label or @mentioning the bot re-engages it.
  2. Automation never removes needs-human-review on a PR whose latest escalation is still in effect.
  3. pr-review never runs the full cascade twice on the same head SHA unless forced.
  4. A regression test reproduces the feat(#1894): answer "why isn't this PR approved?" from the real pr-review gate chain (+ why-not-approved agent) #1902 sequence: escalate, base merge moves the head, re-trigger, expect a no-op.

Activity

  1. github-actions commented on Oct 9, 2026

    @github-actions
    Contributor

    Thanks for the thorough write-up and timeline on #1902, which makes this much easier to dig into. To help us pin down which of your hypotheses applies, could you share the pr-review run logs for the 05:04 and 05:10 runs on #1902, specifically which noop:, re-engage: or force-review: line each one printed (or the trigger event if none did)?

  2. don-petry commented on Oct 9, 2026

    @don-petry
    CollaboratorAuthor

    Another data point: pr-review posted a third review on #1902 at 05:13:57Z (cycle 3/3, single-reviewer mode), again on the unchanged head f5303859. That makes three automated reviews of the same SHA in 10 minutes after a human escalation.

    The 04:14 marker on #1902 promised a re-review "after 2026-10-09T05:14:19Z", so this third run lands just before that reset time. That fits hypothesis 2: a sweep or rate-limit re-dispatch reaches the cascade without passing through the escalation no-op. The fix should guard every dispatch path on the escalation and label state, not only the synchronize path.


    Generated by Claude Code

  3. don-petry commented on Oct 9, 2026

    @don-petry
    CollaboratorAuthor

    Root cause confirmed from the run logs. It's hypothesis 1 (ring version), triggered by the pr-auto-review dispatch path.

    What the runs show. All three post-escalation reviews on #1902 were PR Review Agent — Trigger runs from a repository_dispatch:

    Time (UTC) Job Cycle
    04:41 113673082073 0
    05:06 113679198554 1
    05:07 113679322068 2

    Fix. #2078 (merged Oct 8) derives FORCE_REVIEW only from an explicit client_payload.force_review. v1-next has since moved to 6415eab, which includes it.

    What #2091 adds: regression tests (tests/test_review_one_pr_escalation_hold.bats) that replay the #1902 sequence against current code. Automated dispatches stay paused on the hold and never remove the label. A structural pin on the #2078 expression fails against the f34a765 workflow.

    Still exposed. Downstream consumers pin pr-review/v1-stable (776c958), which predates #2078. They keep the bypass until pr-review is promoted.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugBug reports

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions