Skip to content

refactor: consolidate CoS worktree ownership - #4286

Merged
atomantic merged 2 commits into
mainfrom
claim/issue-4241
Aug 15, 2026
Merged

refactor: consolidate CoS worktree ownership#4286
atomantic merged 2 commits into
mainfrom
claim/issue-4241

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

Consolidates the "which worktrees may PortOS touch" and "what branch does this task target" logic that was independently duplicated across worktreeManager.js, branchReconcile.js, agentWorkspacePrep.js, agentWorktreeCleanup.js, agentManagement.js, and cosTaskStore.js into two pure, unit-tested modules:

  • server/lib/worktreeOwnership.jsworktreeOwnershipReason() is the single ownership gate for destructive worktree operations (adopt/reap/cleanup), taking explicit options for the differences that are intentional (a reaper may include .claude/worktrees/; stale /claim worktrees may be reclaimed only by branch reconciliation; liveness requirements differ by caller).
  • server/lib/taskTargetBranch.jsresolveTaskTargetBranch() / shouldStripTaskTargetBranch() is the single reader/writer contract for a task's existingBranch (retry) vs reviewLoopPRBranch (review-loop follow-up) pointer, closing a gap where three call sites read metadata.existingBranch raw and so weren't healed the same way agentWorkspacePrep.js's resolver already was.

Also collapses prepareAgentWorkspace's two-step "try create, then discover the holder on failure" flow into resolving the branch holder once up front (pointer if still valid, else discovery), giving a resume retry the same safe worktree-takeover behavior a review-loop follow-up already had, and retiring the branchStillClaimed fail-open.

Follow-up from #4239's review; addresses #4241.

Also includes a /simplify pass: dropped worktreeOwnershipReason's unused allowLocked option and the unexercised bare-string root form (no caller ever used either), and parallelized prepareAgentWorkspace's independent base-branch-detection and branch-holder-resolution I/O instead of awaiting them serially.

One deferred cleanup filed as #4284 (out of scope here — touches an externally-asserted test vocabulary): reapMergedWorktrees's inline remap from the shared module's canonical worktree-* skip-reason codes back to a private legacy vocabulary.

Test plan

  • cd server && NODE_ENV=test npx vitest run lib/worktreeOwnership.test.js lib/taskTargetBranch.test.js services/agentManagement.test.js services/agentWorkspacePrep.test.js services/branchReconcile.test.js services/cleanupAgentWorktree.test.js services/cosTaskStore.test.js services/worktreeManager.test.js — 624 tests passing
  • Manually traced isAbandonedAgentWorktree, worktreeProtectionReason, and resolveLiveOwnerReason against their pre-refactor implementations to confirm the shared predicate preserves each of their previously-intentional differences (locked handling, stale-claim reclaim, liveness-unknown fail-closed behavior)
  • Manually traced spawnReviewLoopFollowUp to confirm reviewLoopFollowUp/reviewLoopPRBranch are still both stamped so resolveTaskTargetBranch's fallback still resolves a follow-up's branch after the existingBranch write was removed

…prep I/O

/simplify pass on #4241's worktree-ownership consolidation:
- worktreeOwnershipReason() drops allowLocked (no caller ever passed
  true) and the unexercised bare-string root form in normalizedRoots().
- prepareAgentWorkspace() now resolves the base-branch lookup and the
  branch-holder takeover concurrently instead of serially — they're
  independent reads and neither depends on the other's result.

Deferred: the legacy skip-reason remap in reapMergedWorktrees (filed as
#4284, out of scope here — it touches an externally-asserted vocabulary).
@atomantic
atomantic merged commit 50fe903 into main Aug 15, 2026
6 checks passed
@atomantic
atomantic deleted the claim/issue-4241 branch August 15, 2026 14:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant