Skip to content

fix(web): a branch switch no longer waits behind the previous PR lookup - #28576

Open
Yuruzuu wants to merge 1 commit into
pingdotgg:mainfrom
Yuruzuu:fix/branch-picker-open-blocks-switch
Open

Yuruzuu wants to merge 1 commit into
pingdotgg:mainfrom
Yuruzuu:fix/branch-picker-open-blocks-switch

Conversation

@Yuruzuu

@Yuruzuu Yuruzuu commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Problem

Picking a branch shortly after the previous switch can stall for seconds: the label stays dimmed and the picker is disabled. In a real client the trigger took up to 6.09 s to come back during rapid switching.

Change

Opening the picker sends a local status refresh (#22807) through vcsCommandScheduler, the serial per-checkout queue that vcs.switchRef also uses. On the server that refresh takes the remote write lock, so it waits for any running PR lookup. The checkout then waits behind the refresh, so an unrelated PR lookup holds up a local git checkout.

Now the picker uses refreshLocalStatusForPicker, the same RPC outside that queue. The refresh only reads status, so it has no reason to hold up a checkout. Other refreshStatus callers keep the queue.

Web and desktop share this picker. Mobile doesn't send this refresh when opening its picker, so it doesn't change. No contract or server changes.

Scope and approval

This qualifies for the small, focused bug-fix exception in CONTRIBUTING.md: 13 non-test lines that stop a read from blocking a checkout, with no feature, default or contract change.

Verification

Real web client (Chrome, 1280×800, fresh state, scratch clone of this repo with origin on GitHub). 8 picks per build, logged by a page observer. Captured on this commit before a rebase over one unrelated upstream commit.

Trigger enabled again, median / max Before After
Rapid switching 1.91 s / 6.09 s 0.105 s / 0.116 s
Waiting for each switch to settle 0.115 s / 5.42 s 0.122 s / 0.141 s

The median time between picks in the rapid runs was 2.54 s before and 0.91 s after, because the tool could pick again as soon as the trigger came back. Combined with #28575, the settled maximum goes from 4.95 s to 0.713 s.

Before recording (main), after recording (this branch), raw measurements.

vp test run src/state/vcs.test.ts (packages/client-runtime): 11/11. The new test checks that a checkout completes while the picker's refresh is still held, and it fails if the serial queue is restored. tsc --noEmit passes on apps/web and packages/client-runtime. check:changed: lint, knip and tests pass. Format flags only an untracked local file, and vp run typecheck can't start in my checkout because of a stale tsc shim.

These runs don't prove the server half of the cause directly; the unit test covers the queue. Flagging one thing seen nearby: in one exploratory run on this build, a PR badge appeared and vanished about 15 ms later, a few times on one switch. It didn't reproduce in the corrected runs. I reproduced a likely cause in a unit test on unmodified main: a local-only refresh that captured "no remote status" before waiting on the lock clears the PR the earlier read just published. So it looks pre-existing and isn't fixed here, though I haven't shown that this is what the run hit.

Not checked: native desktop, relay and tunnel.

Made with Claude Opus 5.5 via Claude Code in T3 Code. Real-client captures and measurements by GPT-6.1 Terra via Codex in T3 Code.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Nov 1, 2026
@macroscopeapp

macroscopeapp Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 530fb04

Macroscope's review found this PR approvable — The branch picker’s local status refresh now runs outside the shared command queue so it does not delay a subsequent branch switch. Mutating commands remain serialized, and existing server-side status locking is unchanged.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between b50d8a1 and 530fb04.

Files selected for processing: 3
  • apps/web/src/components/BranchToolbarBranchSelector.tsx
  • packages/client-runtime/src/state/vcs.test.ts
  • packages/client-runtime/src/state/vcs.ts

Limit details: You’ve used all 10 included reviews currently available.

Walkthrough

The branch picker now uses a local-only status refresh command without the serial scheduler or concurrency limit. A test verifies that a ref checkout can complete while the refresh is pending.

Changes: Branch picker refresh

Layer / File(s) Summary
Picker refresh and checkout
packages/client-runtime/src/state/vcs.ts, apps/web/src/components/BranchToolbarBranchSelector.tsx, packages/client-runtime/src/state/vcs.test.ts
The selector uses refreshLocalStatusForPicker when the picker first opens. The command invalidates cached refs when it settles and does not use the serial scheduler or concurrency limit. A test verifies that checkout succeeds while the refresh RPC is pending.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • Issue 27696 reports delays from shared command queue contention. This change addresses the picker refresh wait described in the issue, but does not change the reported polling volume.

Suggested reviewers: utkarshusername, juliusmarminge, t3dotgg

Merge Risk: Minimal · up to 530fb

The picker refresh no longer blocks checkout through the client queue. No merge-blocking risk was found.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main fix: branch switching no longer waits behind a previous PR lookup.
Description check Passed The description covers the problem, change, scope and approval rationale, verification results, limitations, and evidence. It is complete and directly related to the changes.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Finishing Touches
Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Usage-based review receipt

Note

This review was completed with usage-based billing: files reviewed beyond your plan's included limits are billed at $0.25/file. View usage-based billing.

@maria-rcks

maria-rcks commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

Note

Written by gpt-6.1-sol on behalf of Maria

Verified in a real dev environment

Verified unchanged head 530fb0431e0b0cba0ff969ae15caa7f03791c01a against github/main at 8760d063e9 on a disposable Linux VM. Used separate installs, one background dev server at a time, Playwright from the repo, and /usr/bin/google-chrome at 1280×800. Created the project and thread through the app, using a real clone with GitHub origin and real Codex gpt-6.1-sol turns. No mocks or seeded/demo data.

  • Reproduced the queue delay on main. Across 15 actual alternating branch checkouts per build, pick-to-enabled-trigger median/max was 2253/2731 ms on main, 849/1110 ms on this head. Excluded each run's initial already-current selection. Checked the actual git branch after every pick.
  • Observed real WebSocket traffic: main sent all 15 checkout requests after the picker refresh completed. This head sent all 14 fully paired checkout requests while that refresh was still pending; 10 completed before it. The last refresh response fell outside the capture. Example: a PR-head refresh took 1207 ms, while checkout was sent 231 ms into it and completed 131 ms later.
  • Search plus keyboard selection switched to verification-c. Searching another branch and pressing Escape preserved that checkout. A subsequent real Codex tool call returned verification-c, matching the client and git.
  • vp run check:changed HEAD^ passed through blacksmith-check: format, lint, both knip passes, seven affected package typechecks, 11 vcs tests, and the changed component's React compiler check. All 32 reported PR checks were successful.

Representative repeat captures as animated recordings, with elapsed time visible:

main: branch switches wait behind picker refresh

pr head: rapid branch switches bypass pending picker refresh

real codex tool call reports the branch selected through the picker

Not verified

Native Electron, iOS/Android, macOS/Windows, relay/tunnel connections, and other providers were not exercised. This verifies the local web checkout queue change, not the separate PR-badge race described in the PR body. Briefly stale branch metadata also appeared on main during rapid picks.

This branch has not been deployed

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

Labels

size:S 10-29 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants