fix(server): threads launched without a branch record the checkout's#34051

open2
main
GitHub fork: pr/launch-branch
opened17h agobyRradomirml
View on GitHubTwo-way sync enabledPR last imported 1h ago

Problem

A thread launched over MCP (t3_thread_launch, or t3 thread start) in the project root or an existing worktree records no branch when the caller names none. The thread's folder can be on a branch, but the thread keeps branch: null. Threads made in the app do not have this problem, because the composer sends the checked-out branch.

As a result, a thread that a script or agent launched shows no branch in the sidebar. It also misses the pull request refresh after each turn, which needs the branch.

Reproduce:

  1. Check out a feature branch in a project folder.
  2. Run t3 thread start <project> "go" without --worktree.
  3. Run t3 thread show <id> --json. thread.branch is null.

Change

When the launch names no branch, ThreadLaunchService reads the branch checked out in the thread's folder and records it, as the composer does. It uses the worktree path if there is one, otherwise the project root. A folder that is not a Git checkout, or has a detached HEAD, still records no branch, because currentBranch returns null there and errors fall back to null. Reused worktrees are not touched, as before.

Scope and approval

This is a small fix for an obvious bug: the two launch paths record different metadata for the same folder. The change is one server function plus a test. It does not change any contract or client.

Verification

  • I added a case to apps/server/src/orchestration-v2/ThreadLaunchService.test.ts for a launch in an existing worktree and in the project root. Without the fix, both fail with expected null to equal 'task-branch' and expected null to equal 'main'. With the fix, all 48 tests in the file pass.
  • vp run check:changed passes: format, lint, knip, typecheck, and the tests next to the change.
  • Runtime check with vp run dev and the Replay (dev) provider, against a scratch repo checked out on feature/demo.

Before the fix:

1$ git -C demo-repo branch --show-current
2feature/demo
3$ t3 thread start --provider devReplay --model showcase demo-repo go
4mcp:7d09bf6c-968e-4133-b3d2-9c7b7341f406
5$ t3 thread show mcp:7d09bf6c-968e-4133-b3d2-9c7b7341f406 --json | jq '.thread | {branch, worktreePath}'
6{"branch":null,"worktreePath":null}

After the fix:

1$ git -C demo-repo branch --show-current
2feature/demo
3$ t3 thread start --provider devReplay --model showcase demo-repo go
4mcp:7cec2b91-6062-487f-a613-96a060ecda0b
5$ t3 thread show mcp:7cec2b91-6062-487f-a613-96a060ecda0b --json | jq '.thread | {branch, worktreePath}'
6{"branch":"feature/demo","worktreePath":null}

I did not check the sidebar in a client. The sidebar already renders thread.branch, and this change only fills that field.

Done with Claude Opus 5.5 in Claude Code (T3 Code).

Checks

21 successful · 10 skipped
All checks passed
7723365

Added 1 commit

  • fix(server): threads launched without a branch record the checkout's18d260a
Synced from GitHub

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — Launches without an explicit branch now record the checkout’s current branch instead of null, while preserving reused worktrees and explicit branches. This changes default thread metadata behavior and requires human confirmation.

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

Synced from GitHub

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

When a launch omits a branch, ThreadLaunchService now records the current branch from the worktree or project root. If the lookup fails, it records null. Tests cover both workspace types.

Changes: Launch branch metadata

Layer / File(s)Summary
Resolve branch during launch
apps/server/src/orchestration-v2/ThreadLaunchService.ts, apps/server/src/orchestration-v2/ThreadLaunchService.test.ts
For non-reused workspaces, launch preparation records the requested branch or looks up the current branch from the workspace path. A failed lookup records null. Tests check existing-worktree and root workspaces.

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

Change: Bug fix · Severity of issue fixed: Low

Possibly related issues

  • pingdotgg/t3code#31177: The issue reports missing branch metadata when a project-folder launch omits a branch. This change records the current branch from the project root.

Suggested reviewers: juliusmarminge

Merge Risk: External image Minimal · up to 77233

Launches record the checkout branch when available, with no established merge-blocking issue.

Pre-merge checks: Passed 4

Check nameStatusExplanation
Title checkPassedThe title identifies the main server fix: threads launched without an explicit branch record the checkout branch. It is concise and related to the changeset, although the possessive phrasing is slight…
Description checkPassedThe description includes all required sections. It explains the problem, change, scope justification, focused tests, runtime verification, limitations, and agent details. The verification results are …
Linked Issues checkPassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes checkPassedCheck skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title identifies the main server fix: threads launched without an explicit branch record the checkout branch. It is concise and related to the changeset, although the possessive phrasing is slightly incomplete.

Full details: Description check

Explanation

The description includes all required sections. It explains the problem, change, scope justification, focused tests, runtime verification, limitations, and agent details. The verification results are specific and relevant.

Finishing Touches

Generate unit tests (beta)

  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
External image Recent review info

External image Run configuration

External image Commits

Reviewing files that changed from the base of the PR and between 18d260a596bb2e35c43052c2e3217fa502e769a0 and 7723365d10ed3da15bfdfcbbc6c228f23c233fa3.

External image Files selected for processing: 2

  • apps/server/src/orchestration-v2/ThreadLaunchService.test.ts
  • apps/server/src/orchestration-v2/ThreadLaunchService.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Note

Written by gpt-6.1-sol on behalf of Maria

Verified in a real dev environment

verified exact head 18d260a596bb2e35c43052c2e3217fa502e769a0 on this linux boat vm. no code changes were needed.

reproduced on github/main (79bca436b2) in a separate worktree, then stopped main before starting the pr. used isolated dev state, a real git repository, real codex gpt-6.1-sol turns through the local proxy, and repo playwright with /usr/bin/google-chrome. projects and threads were created through real cli/mcp server paths without mocks or fixtures.

  • main: the provider returned feature/launch-proof, but the thread stored branch: null and the sidebar omitted the branch.
  • pr: the same root launch stored feature/launch-proof, and the web sidebar displayed it.
  • existing worktree: mcp launch stored feature/worktree-proof; the real provider ran there and returned that branch.
  • explicit branch: a new worktree retained feature/explicit-proof, matching the provider checkout.
  • detached head: an existing worktree retained branch: null; the provider confirmed detached head.
  • web client: approved real tool requests, switched threads, and sent a follow-up through the composer. it completed with branch metadata intact.

short runtime transcript from t3 thread show --json:

text
1main root: branch=null, provider reply=feature/launch-proof
2pr root: branch=feature/launch-proof, status=completed
3pr existing worktree: branch=feature/worktree-proof, status=completed
4pr explicit branch: branch=feature/explicit-proof, status=completed
5pr detached head: branch=null, status=completed
6pr root after web follow-up: branch=feature/launch-proof, runCount=2, status=completed

full command results

all 48 existing launch-service tests passed on blacksmith with vp test run apps/server/src/orchestration-v2/ThreadLaunchService.test.ts. inspected ci reported 32 successful checks, zero failing or pending.

before on main: completed real codex turn with no sidebar branch

after on pr: same repository and prompt with branch displayed in sidebar

real web approval, composer follow-up, and existing-worktree branch

inspected the captures and verified uploaded video playback and seeking in chrome.

Not verified

native ios/android, the electron shell, macos/windows, other providers, and remote/relay/tunnel connections were not exercised on this linux web run. automatic remote pull-request refresh was not exercised because the verification repository has no remote pr. non-git folders and git lookup failures were not exercised through a provider turn.

Added 1 commit

  • Merge remote-tracking branch 'origin/main' into pr/launch-branch7723365

Evidence

Create a Git project on feature/launch-proof, start a thread through the CLI without branch or worktree options, wait for its replay turn, and open the thread. Real Chromium web client, 1280×800, light theme, fresh synthetic data on each commit.

The project-root scenario fails on base and passes on head. The sidebar omits the branch before the fix and displays it afterward. Supplemental CLI reads confirm thread.branch changes from null to feature/launch-proof.

Passing proof scenario · Sanitized branch observations · Supplemental comparison driver · MCP launch helper

Limitation: the completed-turn existing-worktree repetition recorded feature/existing-proof on both commits, so that path did not reproduce the lasting failure.

AI-assisted; verified with the tests and tools listed above.

Not shown:

  • The existing_worktree path did not reproduce a lasting branch omission: after its initial replay turn, persisted metadata contained feature/existing-proof on both commits. Immediate idle-launch reads sometimes returned null, but were sensitive to asynchronous workspace preparation.
  • Detached HEAD and non-Git folder behavior were not exercised.
Bbinjamshidreviewed7h ago
Synced from GitHub

Recording the checked-out branch when the launch names none matches what the composer sends, and the fallback is safe: GitWorkflowService.currentBranch already returns null for non-repos and detached HEADs, and orElseSucceed covers the 5s timeout or other git errors without failing the launch. Reused worktrees and explicitly named branches are unchanged.

  1. low, apps/server/src/orchestration-v2/ThreadLaunchService.test.ts:1079: the mock returns "main" for any cwd other than /wt/task, so the project-root case would still pass if the code looked up the wrong folder (for example a stale worktreePath). Matching cwd === "/repo" (the harness's workspaceRoot) explicitly, and adding one case where currentBranch fails and the launch still records null, would pin down both the path choice and the error fallback.
Synced from GitHub

There is also a composer/UI route to the missing-branch case this PR addresses. The statement that threads made in the app cannot have this problem is too broad.

In a macOS Nightly recording supplied by a user, a Git project is checked out on master. With Git actions and Changes hidden in the thread-details menu, new current-checkout threads have no sidebar branch. Enabling Branch and pull request makes the details card show master, but the sidebar still has no branch. After Reset to default, another new thread shows master in the sidebar. Existing older threads in that project also show master.

Source inspection on main at f6433dba45 explains the dependency:

  • ThreadDetailsPanel.tsx mounts GitActionsControl only when Git actions or Changes is visible.
  • GitActionsControl.tsx owns the effect that calls resolveLiveThreadBranchUpdate and persists the live branch into the draft. Hiding both rows removes that effect.
  • BranchToolbarBranchSelector.tsx can display the current branch without saving it for a local/current-checkout draft; its automatic defaulting effect is restricted to worktree mode.
  • SidebarThreadRow.tsx renders the saved thread.branch; when it is null and there is no other metadata, the row collapses and moves the machine/provider icons beside the title, truncating more of it.

Suggested additional regression/verification case: start a current-checkout thread in a synthetic Git repo with Git actions and Changes both hidden, including with Branch and pull request visible. The resulting server thread should record the checkout's branch independently of those presentation settings. Repeat with Reset to default as the control.

The server fallback in this PR appears to cover that launch without depending on mounted UI controls. I inspected the patch, but have not run this UI scenario against the PR head, so that remains a verification request rather than a claimed passing result. I have not attached the user's recording because it contains private workspace information.

Investigation and comment by GPT-6.1 Sol in the Codex harness through T3 Code.