Skip to content

[Bug]: watch_pull_request misses "checks passed" after a push on Bitbucket because the head SHA is never reported #16301

Description

@bman654

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Related but different: #15362 (fixed by #15804) covers a new required check that first appears already passed on the same head. Here the check name stays the same and a new commit is pushed.

Area

apps/server

Steps to reproduce

Seen on a Bitbucket Cloud pull request in a private repository. It has one required check, a Bitbucket Pipelines run that takes about 47 s.

Timeline (UTC, 2026-10-05):

Time Event
16:47:56 PR opened. The pipeline for the first commit started at 16:47:59 and passed after ~47 s.
~16:48–16:49 Agent called watch_pull_request while that run was still IN_PROGRESS. Soon after, the wake "All 1 check passed." arrived. ✅
~16:57 A reviewer approved and posted 7 comments. A wake listing them arrived. ✅
~17:03 The agent pushed a new commit to the source branch. Its pipeline started at 17:03:22 and passed after ~47 s (~17:04:09). ❌ No wake.
later (time unknown) The agent's session restarted.
01:46 (next day) The user noticed the PR and prompted the agent manually. Until then the PR sat open, approved and green.

Minimal repro:

  1. On a Bitbucket PR, call watch_pull_request and wait for the "checks passed" wake.
  2. Push a commit whose required pipeline finishes in less than one sweep interval.
  3. No "checks passed" wake arrives for the new commit.

Expected behavior

The tool description says T3 Code "wakes you with a message when a check fails, the required checks pass, someone else comments or reviews, or the branch starts to conflict with its base." After a push, the agent should be woken again when the required checks pass for the new commit. As far as I can tell from the code, that is what happens on hosts that report a head SHA.

Actual behavior

No wake arrived, and the watch didn't end (the PR stayed open and readable). The PR sat ready to merge and unattended for about 8.7 hours.

Likely cause (from reading the source; not confirmed with logs because the server traces for that window had rotated out):

  • evaluatePullRequestWatch (apps/server/src/orchestration-v2/pullRequestWatch.ts) resets passed only when the head moves (headMoved = headSha !== watch.headSha). After that, a second checks-passed needs passedNow && !passed, or on main the new gateGrew condition from fix(server): PR watch reports a required check that first appears already passed #15804.
  • The Bitbucket provider never reports headSha. RawBranchSchema in apps/server/src/pullRequest/bitbucketPullRequestJson.ts decodes only source.branch.name and source.repository, not source.commit.hash. toPullRequest and getChangeRequest don't set headSha either. ProviderChangeRequestDetail.headSha is optional ("where the host's detail read reports it").
  • So for Bitbucket, headSha is null on every pass and headMoved is always false. After the first "checks passed" wake, the watch only wakes again if some pass happens to see a required check pending or failed. A ~47 s run between 1-minute sweeps can easily go unseen. Main now sweeps every 2 minutes (fix(server): PR watches stop burning GitHub's rate limit and giving up #16208), which makes the window wider. gateGrew doesn't help because the check name doesn't change.
  • Unverified: if /pullrequests/{id}/statuses also returns the previous commit's status under the same key, the "later one wins" dedupe in decodeStatusesJson could hide the pending run even when a sweep does land during it.

Before reading the code, there were three candidate explanations: (1) the polling interval missed the in-progress state, (2) the wake was lost across the agent session restart, or (3) green → green isn't treated as a transition. The code points to (3) for Bitbucket specifically, with (1) explaining why the pending state wasn't seen. I can't rule out (2), but it isn't needed to explain this.

Asks:

  • Populate headSha for Bitbucket from the pull request's source.commit.hash, so a push resets the watch the same way it does for hosts that report the head. Any other provider without headSha would have the same gap.
  • Clarify in the watch_pull_request description whether "the required checks pass" wakes once per commit or only when the overall verdict changes, and that per-commit behavior depends on the host reporting the head commit.
  • Make sure wakes generated while the agent session is restarting are delivered afterwards, if that isn't already guaranteed.
  • To confirm: on Bitbucket, push a commit during a watch whose CI runs well beyond the sweep interval. If a green wake arrives, the pending state was observed, which fits the analysis above. If no wake arrives, the statuses dedupe is also involved.

Impact

Major degradation or frequent failure

Version or commit

macOS desktop nightly, a 0.0.46 build older than 0.0.46-nightly.20261005.2676; the updater was offering .2676 throughout the incident. The code references above are against current main. The headMoved reset and the Bitbucket decoder are the same in the code from #15057 that was running at the time.

Environment

macOS desktop app, Claude agent, Bitbucket Cloud PR (private repository) with a single required Bitbucket Pipelines check.

Logs or stack traces

No response (server traces covering the incident window had already rotated out.)

Screenshots, recordings, or supporting files

No response

Workaround

The reporter's agent skill now uses the PR watch only for comments, reviews and PR state, and watches CI results itself.

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 is broken or behaving incorrectly.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