Skip to content

fix(worker): remove PR worktrees before releasing the PR lock - #2564

Merged
integry merged 2 commits into
mainfrom
fix/worktree-cleanup-before-lock-release
Sep 26, 2026
Merged

integry merged 2 commits into
mainfrom
fix/worktree-cleanup-before-lock-release

Conversation

@integry

@integry integry commented Sep 26, 2026

Copy link
Copy Markdown
Owner

Problem

Follow-ups on #2555 failed twice with Cannot create worktree: branch '…' is locked by another worktree. The worker logs show a race:

Time Event
22:36:00.001 Previous follow-up releases the PR lock, then starts removing its worktree
22:36:07.045 Next follow-up takes the lock; worktree add fails: branch "already used by worktree" (the one being removed); worktree remove --force then fails with validation failed … .git does not exist
22:36:07.784 Old worktree removal finishes

cleanupJob (src/jobs/prCommentJobUtils.ts) and the merge job's releaseMergeJobResources both released the lock before removing the worktree, which keeps the PR branch checked out until removal completes. The 22:43 failure was the same race against the merge job's worktree.

Fix

  • Order: both jobs remove their worktree first and release the PR lock afterwards (the lock has a 1h TTL, so holding it for a few seconds more is safe).
  • Safety net (packages/core/src/git/worktreeCreation.ts): when the forced removal of the conflicting worktree fails, removeStaleWorktreeRegistration drops only that worktree's registration, and only if git worktree list --porcelain reports it as prunable, then retries. A global git worktree prune stays avoided, as cleanupWorktree notes it races other tasks. This also recovers from registrations left behind by a worker crash.

Tests

  • test/staleWorktreeRegistration.test.ts (real git): reproduces the exact production errors (already used by worktree, then validation failed on forced remove) and shows the branch is freed; live worktrees and other stale registrations are left alone.
  • test/prCommentCleanupOrder.test.ts: cleanupJob removes the worktree before releasing the lock.
  • test/processMergeConflictJob.test.ts: the lock is still held while the merge job's worktree is removed.
  • New tests fail on the previous code; related suites pass (318 tests, 0 failures); typecheck and lint clean.

🤖 Generated with Claude Code

Follow-up and merge-conflict jobs released the PR processing lock before
removing their git worktree. Removal takes seconds, and the worktree keeps
the PR branch checked out until it finishes, so a queued job that took the
lock in that window failed with "branch ... is locked by another worktree"
(twice on #2555). Both jobs now remove the worktree first.

As a safety net, when `git worktree remove --force` refuses a worktree
whose .git file is already gone, only that one registration is dropped
(and only when git reports it as prunable) before retrying. A global
`git worktree prune` stays avoided, since it can race other tasks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@integry integry added the AI label Sep 26, 2026
@integry

integry commented Sep 26, 2026

Copy link
Copy Markdown
Owner Author

/ultrafix

@propr-dev propr-dev Bot added the ultrafix label Sep 26, 2026
@propr-dev

propr-dev Bot commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

🔄 Ultrafix loop started (goal: 8/10, max cycles: 10)

First action: /review

💡 Tip: Remove the ultrafix label from this PR to stop further ultrafix cycles.

@propr-dev

propr-dev Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

✅ AI Code Review Complete requested by @integry

Posted 1 review:

View Task Details

@propr-dev

propr-dev Bot commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

CI failed: Full Test Suite Shard 3/4

Please investigate and fix this CI failure.

  • Check: Full Test Suite Shard 3/4
  • Result: failure
  • Commit: e7cefc14347d (e7cefc14347db2aa5a311f5b1683a102e44079cc)
  • Details: View CI failure

Failure evidence

.github:21
Process completed with exit code 1.

.github:18454
Process completed with exit code 1.

.github:2
Node.js 20 is deprecated. The following actions target Node.js 20 but are being forced to run on Node.js 24: actions/checkout@11d5960. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/

@propr-dev

propr-dev Bot commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

🔍 AI Code Review — codex:gpt-6-astra

Overall Evaluation

The PR addresses the reported race by awaiting worktree cleanup before releasing either job’s PR lock, with targeted recovery for stale Git registrations. Merge-ready within scope, conditional on the four pending test shards passing.

✅ Correct cleanup ordering — Both cleanup paths await worktree removal before releasing the lock, while preserving lock release after a caught cleanup failure.

✅ Targeted stale recovery — The fallback requires Git’s prunable marker and matches the target’s gitdir before deleting one registration, avoiding global pruning.

✅ Relevant regression coverage — The tests cover cleanup ordering and reproduce the missing-.git failure with real Git, including refusal to remove a live registration.

This was a static review of the supplied diff and context; no commands were run. The supplied current checks report no failures.

Merge blockers

No merge blockers.

Suggestions

These are optional follow-ups and are not sent to /fix.

S1: 🟢 Exercise the integrated recovery path

The real-Git tests call removeStaleWorktreeRegistration directly, so they do not cover its wiring through conflict-error parsing, failed forced removal, and the subsequent worktree-add retry in packages/core/src/git/worktreeCreation.ts. An integration test through createWorktreeFromExistingBranch would strengthen regression protection. This is optional because the supplied control flow correctly connects those steps and no defect was established.

Score

The change is focused, addresses the demonstrated ordering failure, and includes relevant regression tests. No merge-blocking defect was identified; four test shards remain pending.

Score: 9/10


🤖 Review Details

  • Model: GPT-6 Astra
  • Time: 32s
  • Tokens: 37,505 (36,737 in / 768 out)
  • Cost: $0.30

View Task


💡 Next step: Comment /fix to address F# merge blockers only.
F# IDs increment across review comments and remain permanent, so selectors such as /fix F3 F5 stay unambiguous across cycles. Suggestions require a separate ordinary follow-up request.

🤖 Review by ProPR

@propr-dev propr-dev Bot removed the ultrafix label Sep 26, 2026
@propr-dev

propr-dev Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

✅ Applied the requested follow-up changes in commit 209e8c3

Summary of Changes

Fixed the shard failure in test/staleWorktreeRegistration.test.ts: the assertion now accepts both Git error messages, including CI’s “already checked out at.”

Reproduced the failure before the fix; all three related test files pass afterward. The Node.js deprecation warning was unrelated.

No visual changes; no previews needed.


🤖 Implementation Details

  • Model: GPT-6 Astra (high)
  • Requested By: @propr-dev[bot]
  • Time: 2m 54s
  • Tokens: 296,366 (294,930 in / 1,436 out)
  • Cost: $0.77

Undo Changes • View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Implement fixes for issues found by /review /fix or /fix address the null check issue
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR
Processing comment ID: 5850956378✓

…test.ts`: the assertion now accepts both Git error messages, including CI’s “already checked out at.”

Fixed the shard failure in `test/staleWorktreeRegistration.test.ts`: the assertion now accepts both Git error messages, including CI’s “already checked out at.”

Reproduced the failure before the fix; all three related test files pass afterward. The Node.js deprecation warning was unrelated.

No visual changes; no previews needed.

PR: #2564
Comment by: @propr-dev[bot] (ID: 5850956378)
Model: gpt-6-astra
@integry
integry merged commit 2e35eff into main Sep 26, 2026
36 of 37 checks passed
@github-actions

Copy link
Copy Markdown

Full Test Suite Results

Validation failed during: Redis startup (shard 1), Shard coverage verification.

  • Docs site validation: skipped (classifier decision: false)
  • Shard coverage verification: failure
  • Hosted native Electron units: skipped (classifier decision: false)
  • Shard 1/4: failed during Redis startup on gitfix-rootless-4
  • Shard 2/4: passed in 490.5s on gitfix-rootless-4
  • Shard 3/4: passed in 469.7s on gitfix-rootless-2
  • Shard 4/4: passed in 295.8s on gitfix-rootless-1
View shard 1/4 output
Test output file not available.

View Workflow
View uploaded artifacts

@propr-dev

propr-dev Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

✅ Applied the requested follow-up changes in commit 2e0c5b7

Summary of Changes

Added bounded Redis startup and cleanup retries, preserving container ownership checks and reporting diagnostics before cleanup.

Shard coverage failed because shard 1 never ran; coverage enforcement remains unchanged.

Validation: 69 tests passed, including new regression cases; shell syntax and diff checks passed. Full CI wasn’t rerun locally because Docker is unavailable.

No visual changes.


🤖 Implementation Details

  • Model: GPT-6 Astra (high)
  • Requested By: @github-actions[bot]
  • Time: 4m 31s
  • Tokens: 375,042 (370,273 in / 4,769 out)
  • Cost: $1.13

Undo Changes • View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Implement fixes for issues found by /review /fix or /fix address the null check issue
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR
Processing comment ID: 5851292805✓

propr-dev Bot pushed a commit that referenced this pull request Sep 27, 2026
… container ownership checks and reporting diagnostics before cleanup.

Added bounded Redis startup and cleanup retries, preserving container ownership checks and reporting diagnostics before cleanup.

Shard coverage failed because shard 1 never ran; coverage enforcement remains unchanged.

Validation: 69 tests passed, including new regression cases; shell syntax and diff checks passed. Full CI wasn’t rerun locally because Docker is unavailable.

No visual changes.

PR: #2564
Comment by: @github-actions[bot] (ID: 5851292805)
Model: gpt-6-astra
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants