Repository navigation
[Bug]: watch_pull_request misses "checks passed" after a push on Bitbucket because the head SHA is never reported #16301
Description
Activity
Note
Grok responding on behalf of Julius.
Triage
Thanks @bman654 for tracing this all the way into the source. Your diagnosis of the missing head SHA holds up, and it looks distinct from what #15362 / #15804 addressed.
What I found
evaluatePullRequestWatchtreats a new head as a new check run:headMovedclearspassed, so a later all-green result can wake again.PullRequestServiceonly copiesheadShawhen the provider sets it.- Bitbucket never sets it.
RawBranchSchemadecodessource.branch.nameandsource.repository, notsource.commit.hash, andtoChangeRequestdoesn't setheadSha. Every Bitbucket read hasheadSha === null, soheadMovedis always false and the watch stays in the "already passed" state. - That fits your timeline. The first wake came from a real pending-to-passed transition because the watch started while the pipeline was
IN_PROGRESS. The second commit's ~47s pipeline finished between sweeps, so the sweep only sawSUCCESSFULunder the same name and stayed silent. No lost wake or session restart is needed to explain the hours of silence; a produced wake is dispatched withqueue_after_active, so a restart wouldn't drop it. - Two side notes that don't change the diagnosis: Bitbucket checks are never marked
required(the "All 1 check passed." wording is the non-required path), sogateGrewfrom fix(server): PR watch reports a required check that first appears already passed #15804 can't fire here. And the statuses "later one wins" dedupe isn't needed to explain this incident, though the decoder does dropcreated_onand the commit link. - Current
mainsweeps every two minutes (fix(server): PR watches stop burning GitHub's rate limit and giving up #16208), which makes short pipelines easier to miss than on your build. - The same missing
headShaappears on GitLab (sha/diff_refs.head_sha) and Forgejo (head.sha). Azure DevOps also omits it, and its detail read currently returnschecks: [].
Likely fix area
- One option is mapping Bitbucket's
source.commit.hashonto the detailheadSha(optional, so payloads without it still decode), with watch tests covering a green-to-green push with a null head versus a changed head. - GitLab and Forgejo could get the same field.
- The
watch_pull_requestdescription could then say "checks passed" fires once per head commit, when the host reports the head.
A maintainer will decide on the fix direction.
- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.via-triageFiled through npx t3 triageFiled through npx t3 triage
on Oct 6, 2026 A second data point, from another Bitbucket Cloud pull request in the same private repository, on the same day and the same T3 Code build:
- The watch started while the PR's checks were already green on its first commit.
- The agent then pushed a new commit. That commit's pipeline sat PENDING for ~15s, then IN_PROGRESS, and finished SUCCESSFUL. From creation to completion it took about 62s, against ~47s for the run whose wake was missed.
- This time a "All 1 check passed" wake did arrive for the new commit.
That fits the reading in the issue. With no head SHA from the Bitbucket provider, the "checks passed" state only resets when a poll happens to see the run in a non-green state. Here a poll most likely landed while the run was pending or in progress, which cleared the passed state, so the next green produced a wake. In the original case the run was shorter than the poll interval and no poll saw it in progress, so the state stayed passed and no wake fired.
So a missed green wake after a push depends on whether a poll lands during the run. Populating the head SHA for Bitbucket would make it deterministic.
Before submitting
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):
watch_pull_requestwhile that run was stillIN_PROGRESS. Soon after, the wake "All 1 check passed." arrived. ✅Minimal repro:
watch_pull_requestand wait for the "checks passed" wake.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) resetspassedonly when the head moves (headMoved = headSha !== watch.headSha). After that, a secondchecks-passedneedspassedNow && !passed, or on main the newgateGrewcondition from fix(server): PR watch reports a required check that first appears already passed #15804.headSha.RawBranchSchemainapps/server/src/pullRequest/bitbucketPullRequestJson.tsdecodes onlysource.branch.nameandsource.repository, notsource.commit.hash.toPullRequestandgetChangeRequestdon't setheadShaeither.ProviderChangeRequestDetail.headShais optional ("where the host's detail read reports it").headShaisnullon every pass andheadMovedis 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.gateGrewdoesn't help because the check name doesn't change./pullrequests/{id}/statusesalso returns the previous commit's status under the same key, the "later one wins" dedupe indecodeStatusesJsoncould 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:
headShafor Bitbucket from the pull request'ssource.commit.hash, so a push resets the watch the same way it does for hosts that report the head. Any other provider withoutheadShawould have the same gap.watch_pull_requestdescription 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.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.2676throughout the incident. The code references above are against currentmain. TheheadMovedreset 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.