feat(workdir): hard-release worktree on branch mismatch (B12) #439
No reviewers
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
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks!439
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "dev/428"
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?
Fixes the silent-stall pattern where three back-to-back rebase dispatches all blocked because
acquireWorktreethrew instead of recovering from a branch mismatch.acquireWorktreenow hard-releases a mismatched worktree: if dirty, changes are committed toworktree-recovery/<sha>in the cache clone before the force-remove; the worktree is then re-created on the target branch. A 60 s overall timeout surfaces asWorktreeAcquireTimeout. The sweeper GCs recovery branches older than 24 h on startup and every 6 h.Test plan
acquireWorktreeforce-removes + re-adds, no recovery branch createdworktree-recovery/<sha>branch created in cache clone, warning logged, worktree ends up on target branchWorktreeAcquireTimeoutthrown after injected 200 ms deadline (real constant stays 60 s)gcAllWorktreeRecoveryBranchesspans all cache clonesCloses #428
All four AC groups verified against implementation and tests; CI green.
Hard release —
hardReleaseWorktreecorrectly sequences: dirty-stash (plumbingwrite-tree+commit-tree+git branch worktree-recovery/<sha>in cache clone),git worktree remove --force, belt-and-suspendersremovePath, thenaddWorktreeon target. Log line matches spec.Timeout —
Promise.race([_doAcquireWorktree, timeoutPromise])with 60 s default, injectable viaacquireTimeoutMs. Lock cleanup and unhandled-rejection guard (.catch(()=>{})onfinallychain) handled correctly.GC —
gcWorktreeRecoveryBranchesuses%(creatordate:unix)for stable age-checking;gcAllWorktreeRecoveryBranchesspans allrepos/*/cache clones; wired into sweeper Phase 5 with error isolation.Tests — all four spec test cases present as real git integration tests against local bare repos.
acquireTimeoutMs: 200keeps the timeout test fast without touching the real constant.Nit (not blocking):
worktree-recovery/<headSha>is shared across agents for the same repo. Two agents simultaneously dirty-releasing from the same HEAD SHA will race ongit branch; the loser logs a warning and loses its stash. This follows the spec's naming convention — just worth tracking if multi-agent concurrent hard-releases become common.