Before submitting
Area
apps/web
Steps to reproduce
- Start a thread with a dedicated worktree.
- Let the agent create/switch to its own branch inside that worktree (it usually renames off the generated
t3code/<slug> branch).
- Open a PR for that branch.
- Look at the thread row in the sidebar.
Expected behavior
The PR number/badge shows on the thread row.
Actual behavior
No badge. The server finds the PR fine — the client discards it.
#4460 removed the dedicated-worktree bypass in resolveThreadPr, so every row now requires gitStatus.refName === thread.branch. But nothing ever writes the worktree's new HEAD back to projection_threads.branch (no branch-update event exists anywhere in apps/server/src), so the stored branch goes stale the moment the agent switches branches — and the badge disappears permanently.
Roughly half of my active worktree threads are in this state. Concrete shape: thread branch stays t3code/<slug>, worktree HEAD is fix/<something-the-agent-named>, and that branch has an open PR. gitStatus.pr contains it; resolveThreadPr returns null.
Not covered by #4752 / #4755 — that fix retains only merged/closed PRs and only for local checkouts ("worktree threads clear their snapshot on branch mismatch"). It restores zero badges in this case.
Impact
Minor bug or occasional failure
Version or commit
0.0.31-nightly.20260729.942 (regression from #4460, 7248877)
Environment
Linux, server started via npx t3@nightly server, web UI
Notes
A plain revert of #4460 would reintroduce the stacked-PR mislabel it fixed. The fix that satisfies both is to keep the stored branch in sync with the worktree's live HEAD, so the equality check passes legitimately and the label and PR always describe the same branch. That does mean a worktree parked on a stacked head branch would show that branch's PR — arguably correct, but a maintainer call.
Agent prompt to fix
In pingdotgg/t3code: a thread's stored branch (`projection_threads.branch`) goes stale
when an agent switches branches inside the thread's dedicated worktree. Since #4460
(commit 724887717), `resolveThreadPr` in apps/web/src/components/ThreadStatusIndicators.tsx
requires `gitStatus.refName === thread.branch`, so those threads permanently lose their
PR badge even though the server returns the PR in `gitStatus.pr`.
Fix by syncing the stored branch, not by reverting the check:
1. Find where thread git state is refreshed after a turn — start at
apps/server/src/orchestration/Layers/CheckpointReactor.ts, which already refreshes
local git status, and apps/server/src/vcs/VcsStatusBroadcaster.ts, which owns the
per-cwd status stream.
2. When a thread has `worktreePath !== null` and the observed HEAD ref for that worktree
differs from the thread's stored branch, persist the observed ref as the thread's
branch. Follow the existing orchestration event + projection pattern used for other
projection_threads columns (grep for how `worktree_path` and `settled_at` are written)
rather than writing SQL directly.
3. Only sync for dedicated worktrees. Threads on a shared local checkout must keep their
stored branch — the shared HEAD is not owned by the thread.
4. Ignore detached HEAD (`rev-parse --abbrev-ref HEAD` returning "HEAD") and leave the
stored branch alone.
5. Leave `resolveThreadPr` as-is. #4460's intent (label and PR must describe the same
branch) stays satisfied once the stored branch tracks the live one.
Tests: extend apps/server/src/orchestration/Layers/CheckpointReactor.test.ts (or the
broadcaster tests) with cases for drifted worktree branch, shared-checkout thread that
must NOT sync, and detached HEAD. Run `vp check` and the focused server test files.
Before submitting
Area
apps/web
Steps to reproduce
t3code/<slug>branch).Expected behavior
The PR number/badge shows on the thread row.
Actual behavior
No badge. The server finds the PR fine — the client discards it.
#4460 removed the dedicated-worktree bypass in
resolveThreadPr, so every row now requiresgitStatus.refName === thread.branch. But nothing ever writes the worktree's new HEAD back toprojection_threads.branch(no branch-update event exists anywhere inapps/server/src), so the stored branch goes stale the moment the agent switches branches — and the badge disappears permanently.Roughly half of my active worktree threads are in this state. Concrete shape: thread branch stays
t3code/<slug>, worktree HEAD isfix/<something-the-agent-named>, and that branch has an open PR.gitStatus.prcontains it;resolveThreadPrreturnsnull.Not covered by #4752 / #4755 — that fix retains only merged/closed PRs and only for local checkouts ("worktree threads clear their snapshot on branch mismatch"). It restores zero badges in this case.
Impact
Minor bug or occasional failure
Version or commit
0.0.31-nightly.20260729.942 (regression from #4460, 7248877)
Environment
Linux, server started via
npx t3@nightly server, web UINotes
A plain revert of #4460 would reintroduce the stacked-PR mislabel it fixed. The fix that satisfies both is to keep the stored branch in sync with the worktree's live HEAD, so the equality check passes legitimately and the label and PR always describe the same branch. That does mean a worktree parked on a stacked head branch would show that branch's PR — arguably correct, but a maintainer call.
Agent prompt to fix