Skip to content

Preserve pull request status across branch checkouts - #5407

Open
juliusmarminge wants to merge 2 commits into
mainfrom
t3code/0b776cce
Open

Preserve pull request status across branch checkouts#5407
juliusmarminge wants to merge 2 commits into
mainfrom
t3code/0b776cce

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Aug 5, 2026

Copy link
Copy Markdown
Member

What Changed

  • Added branch-specific pull request lookup through the VCS workflow and WebSocket RPC layers.
  • Preserved thread and branch PR indicators when the working tree checkout changes.
  • Serialized local and remote VCS refreshes to prevent stale status from overwriting current checkout data.
  • Updated branch selectors, sidebar indicators, chat, and Git actions to resolve PR status from the thread’s recorded branch.
  • Simplified terminal font inheritance so terminal surfaces use the configured code font unless explicitly overridden.
  • Added coverage for checkout changes, refresh ordering, and remote status recovery.

Why

PR status was derived from the current checkout, causing thread badges and PR actions to show stale or incorrect information after switching branches. Branch-keyed lookups keep each thread associated with its own PR while preserving fast stream-fed status for the active checkout. Refresh serialization prevents slow remote lookups from publishing results for a previous branch.

The typography cleanup keeps monospace surfaces consistent and removes unused advanced-font preference logic.

UI Changes

The sidebar, chat, branch selector, and Git actions now continue to display and act on the correct PR after switching checkouts. No visual layout changes were made, so before/after screenshots are not applicable.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Medium Risk
Touches VCS caching, concurrency, and checkout/switch RPC ordering where stale or mismatched PR/ref data could briefly surface; changes are localized to git status/PR resolution with added test coverage.

Overview
PR indicators and thread badges now follow each thread’s recorded branch, not whatever is checked out in the repo. A new vcs.branchPr RPC (and cached client query) resolves PR/MR state from git branch config and upstream tracking, reusing the same lookupStatusPr path as live status.

Web and mobile replace checkout-only resolveThreadPr with useThreadPr / selectBranchPr: streamed status wins when refName matches the thread branch (including “no PR”), otherwise the branch-keyed query keeps the badge. Sidebar, chat, and the branch toolbar use this; resolveBranchToolbarPrBranch is removed. Git actions stay gated on checkout status only.

VcsStatusBroadcaster gets per-cwd local/remote semaphores, drops cached remote data on refName change, discards superseded in-flight remote reads, and publishes a local-only snapshot (remote: null) on checkout change before async remote refresh. vcsSwitchRef triggers refreshLocalStatus before the full refresh so clients don’t see the old branch after await.

Contracts add VcsBranchPrInput / VcsBranchPrResult; tests cover refresh races and branch PR selection.

Reviewed by Cursor Bugbot for commit 4a42ee1. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Preserve pull request status by branch across checkout changes

  • Adds a vcs.branchPr RPC endpoint that resolves a PR for any branch (not necessarily checked out) by reading git config to infer upstream and default branch, without requiring an active checkout.
  • Introduces selectBranchPr and useThreadPr utilities that prefer live git status when it matches the thread's branch, but fall back to the branch-keyed vcs.branchPr query when the checkout has moved away.
  • Updates PR badges in the sidebar rows, chat view, and branch toolbar to use useThreadPr instead of the removed resolveThreadPr function, so badges persist after a checkout change.
  • Fixes VcsStatusBroadcaster to prevent stale remote or local status from overriding newer state during concurrent refreshes; remote halves are cleared on ref changes and repopulated asynchronously.
  • Behavioral Change: switching refs now triggers an immediate local status publish before the full refresh, so clients see the new ref name sooner in the status stream.

Macroscope summarized 4a42ee1.

- Add branch-keyed PR lookup RPC and client query
- Serialize VCS refreshes to prevent stale status races
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 366c55e3-c521-4f3c-9fa5-ebf0a7adbba8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 5, 2026
Comment thread apps/web/src/components/GitActionsControl.tsx Outdated
Comment thread apps/server/src/vcs/VcsStatusBroadcaster.ts
Comment thread apps/web/src/components/ThreadStatusIndicators.tsx Outdated
@macroscopeapp

macroscopeapp Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. This PR introduces a new feature for preserving PR status across branch checkouts, including a new RPC endpoint, concurrency controls, and caching changes across multiple layers. Two open review comments identify potential race conditions and badge flickering bugs in the new logic that warrant human review.

You can customize Macroscope's approvability policy. Learn more.

- Reconcile VCS refreshes after mid-refresh checkouts
- Use branch-keyed PR lookups for thread indicators
- Keep git actions tied to the active checkout
// When the status describes the thread's own branch it is authoritative
// about that branch's PR — including when it reports none, so this must not
// fall through to a warm branch lookup that would resurrect a stale badge.
if (status !== null && thread.branch !== null && status.refName === thread.branch) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium state/use-thread-pr.ts:49

When the VCS status stream reports a matching refName with pr: null before the remote PR lookup resolves, useThreadPr returns null instead of falling through to the already-subscribed branchPr result. This causes the PR badge to flicker off immediately after checkout and can leave it permanently absent if that remote refresh later fails. The guard at line 49 treats any matching status as authoritative, including the transient state where the PR field is still pending, so the branch-keyed fallback is never reached. Consider distinguishing a status that has confirmed no PR from one whose PR field is still pending before short-circuiting.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/mobile/src/state/use-thread-pr.ts around line 49:

When the VCS status stream reports a matching `refName` with `pr: null` before the remote PR lookup resolves, `useThreadPr` returns `null` instead of falling through to the already-subscribed `branchPr` result. This causes the PR badge to flicker off immediately after checkout and can leave it permanently absent if that remote refresh later fails. The guard at line 49 treats any matching status as authoritative, including the transient state where the PR field is still pending, so the branch-keyed fallback is never reached. Consider distinguishing a status that has confirmed no PR from one whose PR field is still pending before short-circuiting.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but a cloud agent failed to start.

Reviewed by Cursor Bugbot for commit 4a42ee1. Configure here.

return mergeGitStatusParts(
cached?.local?.value ?? local,
cached?.remote ? cached.remote.value : remote,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale remote paired after checkout

Medium Severity

refreshStatusCore prefers cached local status after a mid-refresh checkout, but when that checkout cleared the cached remote half it falls back to the in-flight remote value. A checkout that lands after refreshRemoteStatus succeeds but before getCachedStatus can therefore return the new refName merged with the previous branch’s ahead/behind and PR data, even though the cache itself already dropped that remote half.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4a42ee1. Configure here.

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

Labels

size:L 100-499 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant