Skip to content

fix(review): reject failed required checks before launching an agent #644

Description

@neubig

Problem

The GitHub PR reviewer launches an agent conversation even when GitHub already reports a required check as failed. On 2026-09-22, requesting all-hands-bot on OpenHands/OpenHands#17544 delivered the native review_requested webhook and created reviewer conversation f46343fd-9486-5943-a38f-fd8a279dd40f, although the required Validate PR description check was already failing and the repository workflow had already posted the specific remediation.

This spends an LLM slot on a PR that is deterministically not reviewable and contributes to host pressure. The reviewer should reserve agent work for PRs that pass cheap deterministic eligibility checks.

Desired behavior

Before creating a review conversation, the reviewer evaluates existing deterministic blockers for the current head. A known failing required check stops the run without starting an agent. Once the author pushes or edits the PR and the required checks pass, an explicit new review request can start the normal review.

Acceptance criteria

  • The reviewer checks current-head required-check state before creating an agent conversation.
  • A completed failing or cancelled required check prevents conversation creation and leaves a concise, non-duplicative explanation of what must be fixed when an equivalent repository workflow comment does not already exist.
  • Pending checks do not produce a false approval; the automation either waits within a bounded budget or exits with a clear retry condition without starting the reviewer agent prematurely.
  • Checks from an obsolete head do not block the current head.
  • A subsequent explicit all-hands-bot review request after the current head is green proceeds through the existing review flow.
  • Tests prove that a failing required check creates zero agent conversations and that a green current head creates exactly one.
  • Existing review verdict, maintainer-handoff, and profile/secret behavior remains unchanged.

Live evidence

  • PR: ci(docker): verify agent server version in image OpenHands#17544
  • Native webhook delivery was HTTP 200 and dispatched reviewer run b373576d-2934-4b9a-b41a-cb219de1d7b9.
  • The run created conversation f46343fd-9486-5943-a38f-fd8a279dd40f despite the existing failed Validate PR description check; the conversation was paused to free the slot.

OpenHands AI triage

The following comments and acceptance criteria were added by the OpenHands AI agent.

Triage

This is a bug report against the deterministic PR reviewer automation in this repository, not the Actions-based plugins/pr-review. Bounded scope: add a pre-dispatch eligibility gate to skills/github-pr-reviewer/scripts/worker.py (the catalog bundle entrypoint python3 worker.py) so PullRequestReviewer.run() evaluates the current head's check runs before calling dispatcher.deliver(...); extend the shared skills/github/scripts/github_client.py transport if a check-run read is needed; cover both the reviewer-request event path and the scheduled label scan; update skills/github-pr-reviewer/SKILL.md / README.md; and bump the automations/catalog/github-pr-reviewer/manifest.json bundle version because shipped files change.

The four design questions raised earlier are resolved by the maintainer's comment and are folded into the criteria below: every completed exact-head check run with failure, cancelled, or timed_out blocks unless its conclusion is neutral or skipped, with no dependence on ruleset/branch-protection visibility and no manually maintained check-name list; any queued or in-progress exact-head check exits without launching an agent and states that review is waiting on checks; remediation comments deduplicate through a stable machine-readable marker carrying the head SHA and gate category; and the gate applies to both event and scheduled modes.

Non-goals: no change to the review prompt, agent behavior, verdict parsing, or the existing maintainer handoff in scripts/maintainer_handoff.py; no change to profile or secret selection; no branch-protection or ruleset dependency; no configured check-name allowlist; no merge or auto-merge behavior; and no change to the Actions-based plugins/pr-review.

Actual Behavior

The reviewer creates a review conversation for a PR whose current head already has a deterministically failing required check. On 2026-09-22, requesting all-hands-bot on OpenHands/OpenHands#17544 delivered the native review_requested webhook (HTTP 200, reviewer run b373576d-2934-4b9a-b41a-cb219de1d7b9) and created conversation f46343fd-9486-5943-a38f-fd8a279dd40f even though the head's Validate PR description check was already failing; the conversation was paused to free the slot. As of this writing the head c49ff9c4350ebe26be4d196d15ecf6b7c34dec08 reports that check as COMPLETED / FAILURE.

Reproduce against the automation's own delivery tests from the repository root:

uv sync --group test
uv run pytest -q tests/test_github_reviewer_delivery.py

The existing cases assert that a trigger dispatches a review unconditionally, so the failing-check case has no coverage today.

Acceptance Criteria

  • Before any conversation is created, the reviewer reads the check runs reported for the PR's current head SHA and classifies each as blocking, non-blocking, or pending; this evaluation happens ahead of dispatcher.deliver(...) in PullRequestReviewer.run().
  • A completed check run on the current head with conclusion failure, cancelled, or timed_out prevents conversation creation, and no agent conversation is started for that trigger.
  • A completed check run with conclusion success, neutral, or skipped does not block the review.
  • If any check run for the current head is queued or in_progress, the run exits without launching an agent and reports that the review is waiting on checks, without holding a worker slot to poll.
  • A blocked or waiting run does not consume the trigger: a later explicit all-hands-bot review request, or the normal scheduled scan, starts the review once the current head's checks are non-blocking.
  • Check runs attributed to a different (obsolete) head SHA do not block the current head.
  • When a check blocks the review, the automation leaves exactly one concise explanation of what must be fixed, identified by a stable machine-readable marker that includes the head SHA and the gate category; on a later run for a different head the marked comment is updated or replaced rather than duplicated, and an already-present equivalent repository workflow comment is not duplicated.
  • The gate uses the check-run data reachable with the reviewer's existing token and does not require branch-protection or ruleset read access, and it does not depend on a manually maintained list of check names.
  • The gate applies identically in the reviewer-request event path and the scheduled label-scan path.
  • Automated tests prove that a blocking current-head check produces zero agent conversations and that a green current head produces exactly one, and that a pending check produces zero; uv run pytest -q passes.
  • Existing review verdict parsing, the maintainer handoff, and profile/secret selection are unchanged.
  • skills/github-pr-reviewer/SKILL.md and README.md describe the eligibility gate and the waiting-on-checks outcome, and automations/catalog/github-pr-reviewer/manifest.json carries a bumped bundle version with regenerated catalog artifacts.

Activity

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

    bugSomething isn't workingpriority:normalNormal priorityready-for-devScoped for contribution; managed by repository readiness checks.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions