workdir: PR-dispatch derives branch from pr.number, conflicts with actual PR head branch #119
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks#119
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
User story
As the operator, I want agent dispatches on a PR to use the PR's actual head branch for worktree acquisition, so that repeated address-review / merge dispatches on the same PR don't trip the "worktree on wrong branch — release first" error and get stuck.
What happens today
buildAgentRequest(agent, repo, pr.number, task)stuffsissue_number: pr.numberinto theTaskRequest. Downstream:But PR #115's actual head branch is
boss/26(the issue it closes). So:acquireWorktreecreates a new local branchboss/115at HEAD, in directory.../boss-default/charles__claude-hooks__boss%2F115.origin/boss/26inside the worktree, pushes toboss/26— work lands correctly.boss%2F115but branchboss/26.acquireWorktreecomputes path=boss%2F115, expected branch=boss/115, finds the existing worktree — current branch isboss/26, raises[workdir] worktree at X is on branch boss/26, expected boss/115 — release first.Hit live on PR #115 today (2026-04-20). Multiple address-review and the final
handleApproved→dispatchMergedispatch failed with this error:I unstuck by deleting the stale worktree and manually merging via
merge_pull_request. But the underlying bug will trip every subsequent multi-round PR.Root cause
Two data models fighting:
implementskill pushes to<prefix>/<issue_number>, soboss/26is the branch for issue #26's work. The PR is a separate numeric space (#115).handleReviewRequested/handleChangesRequested/handleApprovedall passpr.numberasissue_numberthroughbuildAgentRequest, which then feedsderiveIssueBranchandworktreePath.The mismatch is harmless on the first dispatch (creates a throwaway branch at HEAD), becomes load-bearing after the first successful run (worktree's actual branch is now
boss/26, notboss/<pr.number>).Fix options
A — Fetch PR head.ref at dispatch time
Each PR-scoped handler already calls
getPullRequest(repo, pr.number, token)in some paths. ExtendbuildAgentRequestto accept an optionalbranchoverride, and passprDetail.head.refwhen known. Fall back toderiveIssueBranchfor issue-scoped dispatches.Cleanest, but touches every PR-scoped handler.
B — Make
acquireWorktreerecover from branch-mismatchIf the existing worktree is on a different branch, treat that as the authoritative state (it's what git reflects) and use that branch instead of erroring. Log the discrepancy.
Simplest code change; trades strictness for resilience. Risk: masks legitimate bugs (e.g. two agents fighting over the same path).
C — Key the worktree path on issue number, not branch name
If
worktreePathencoded<agent>__<repo>__issue-<number>instead of<agent>__<repo>__<branch>, PR dispatches on #115 would land inissue-115/regardless of what branch got checked out inside. Single-branch-per-worktree would still be git's problem, but we'd stop making it worse with our own mismatched-path-derivation.Broader refactor; changes the on-disk layout.
Acceptance criteria
handleChangesRequested/handleApprovedon the same PR twice in a row must not produce the "is on branch X, expected Y — release first" error.acquireWorktreeeither reconciles or errors with a clearer actionable message.issue_number=115 → branch=boss/26 via PR head.refor similar) so operators can diagnose fromjournalctlnext time.Out of scope
git worktree removeworks; one-shot script is nice-to-have).References
src/workdir.ts:388— theworktree at X is on branch Y, expected Z — release firsterror.src/webhook-handlers.ts:159—buildAgentRequestthat stuffspr.numberasissue_number.src/agent-runner.ts:481—deriveIssueBranch(config.branch_prefix, task.issue_number).9d0f1a1d,536f0df0,a258fe62all failed with this error).Dependencies
main.