Skip to content

PR watch says "All required checks passed" while a required GitHub check hasn't started yet #28183

Open

Description

@olschulz

What happened

A thread watched a GitHub PR with watch_pull_request. The base branch requires two checks: a quick lint job, and an aggregate E2E job that has needs: on several E2E runner jobs. Once the lint job passed, T3 woke the thread with "All 1 required check passed". The runners were still going, and the required aggregate job didn't exist on the commit yet, so the message was false.

The next sweep sends a second wake once the aggregate job appears, so the watch itself recovers. The problem is that first message: an agent that trusts it can report the PR as done, or merge it, before a required check has run.

Diagnosis

For GitHub, T3 learns which checks are required only from isRequired on the check contexts already on the commit (toCheckEntries in gitHubPullRequestJson.ts). A required check from branch protection or a ruleset that hasn't been created yet doesn't show up at all. So in evaluatePullRequestWatch (apps/server/src/orchestration-v2/pullRequestWatch.ts), required holds only the lint check, passedNow is true, and the thread gets a checks-passed wake with required: true.

GitHub only creates a job that has needs: when it starts. That means any workflow whose required check is an aggregate "all tests passed" job, a common setup, hits this.

The Forgejo provider already reads the branch's required checks (forgejoRequiredChecks.ts). GitHub could do the same: read the base branch's required checks (GraphQL baseRef.refUpdateRule.requiredStatusCheckContexts, or REST GET /repos/{owner}/{repo}/rules/branches/{branch}) and treat any that haven't been created yet as pending.

Steps to reproduce

  1. In a GitHub repo, protect the base branch with two required checks: a quick job A, and a job Done with needs: [slow], where slow runs for a few minutes.
  2. Open a PR and call watch_pull_request on it.
  3. Wait until A has passed while slow is still running.
  4. The next sweep wakes the thread with "All 1 required check passed", although Done is required and hasn't started.

Version

0.1.6-nightly.20261030.3940

Environment

Linux x64, desktop app with its local server, Claude agent, github.com, classic branch protection with two required checks.

Evidence

- About three minutes after the push, a sweep woke the thread with "All 1 required check passed" while the E2E runners were still going.
- The required aggregate job started about 30 seconds later, after the runners finished.
- The branch protection's required checks were the aggregate E2E job and the lint job.

Related issues

#23712 (fixed: missing final wake after an early required-check pass). This issue is about the early wake's message, not a missing wake.

Fix applied or workaround

After a "required checks passed" wake, look at the full check list and keep the watch on until every check on the head has finished.

Filed by

Triaged and drafted by Claude Opus 5.5 (claude-opus-5-5) in Claude Code inside T3 Code.

Activity

  1. BartWaardenburg commented on Nov 5, 2026

    @BartWaardenburg

    Another case: the ruleset requires CI and Action checks passed. Both are summary jobs with needs:. Action checks passed finished first, and T3 woke the thread with "All 1 required check passed" while CI did not exist yet. Auto-merge then merged 4 seconds after CI passed, before the next sweep. So the second wake never came, and with #25160 the thread saw nothing more. When the watch reads the required checks of the ruleset (GET /repos/{owner}/{repo}/rules/branches/{branch}), it fixes this case.

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

    via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions