fix(plan): clean up stale worktree branch before re-creating sandbox #10798
No reviewers
Labels
No labels
auto/needs-reevaluation
controller-managed
auto/blocked-by-deps
auto/ci-timeout
auto/claimed-implementer
auto/claimed-merge
auto/claimed-reviewer
auto/driver-down
auto/invariant-violation
auto/last-attempt-tier-0
auto/last-attempt-tier-1
auto/last-attempt-tier-2
auto/last-attempt-tier-min
Automation Tracking
auto/needs-conflict-resolution
auto/needs-implementer
auto/postmortem
auto/ready-to-merge
auto/restart-throttled
auto/revert
auto/sentinel
auto/stale-inactivity
auto/unstable
Blocked
Bounty
$100
Bounty
$1000
Bounty
$10000
Bounty
$20
Bounty
$2000
Bounty
$250
Bounty
$50
Bounty
$500
Bounty
$5000
Bounty
$750
MoSCoW
Could have
MoSCoW
Must have
MoSCoW
Should have
Needs Feedback
Points
1
Points
13
Points
2
Points
21
Points
3
Points
34
Points
5
Points
55
Points
8
Points
88
Priority
Backlog
Priority
CI Blocker
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Signed-off: Owner
Signed-off: Scrum Master
Signed-off: Tech Lead
Spike
State
Completed
State
Duplicate
State
In Progress
State
In Review
State
Paused
State
Unverified
State
Verified
State
Wont Do
Type
Automation
Type
Bug
Type
Discussion
Type
Documentation
Type
Epic
Type
Feature
Type
Legendary
Type
Refactor
Type
Support
Type
Task
Type
Testing
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
cleveragents/cleveragents-core!10798
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "bugfix/sandbox-reexecute-cleanup"
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?
Summary
Re-executing a plan after a failed attempt or diff review crashed with
fatal: a branch named 'cleveragents/plan-<id>' already existsbecause the worktree branch from the previous execute was never cleaned up.Fix
Add
GitWorktreeSandbox.cleanup_stale()classmethod in the infrastructure layer that idempotently removes stale worktree directories and branches. Each git command has explicit error handling with logging and fallback (manualrmtreeifworktree removefails)._create_sandbox_for_plan()in the CLI layer delegates tocleanup_stale()before callingsandbox.create().Changed files
src/cleveragents/infrastructure/sandbox/git_worktree.py: +97 lines — newcleanup_stale()classmethodsrc/cleveragents/cli/commands/plan.py: -55 +12 lines — delegation to infrastructure layerfeatures/sandbox_reexecute_cleanup.feature+ step file: 3 Behave scenariosCHANGELOG.md: updatedTesting
m1-plan-lifecycle-okReview history
Previous review feedback on PR #10000 (closed due to broken fork metadata):
#10000
All blocking findings from that review have been addressed in this PR.
Closes #7271
@HAL9000 review this PR merge if it is ready to be merged
⚠️ CODE REVIEW – PR #10798 – Clean Up Stale Worktree Branch Before Re-creating Sandbox
Branch:
bugfix/sandbox-reexecute-cleanupIssue: #7271
Status: REQUEST CHANGES (2 issues identified: 1×P2, 1×P3)
EXECUTIVE SUMMARY
PR #10798 implements cleanup of stale worktree branches before re-executing a plan, fixing the
fatal: a branch named 'cleveragents/plan-<id>' already existscrash. The implementation is well-architected and properly tested but has two issues:Strengths:
Issues:
DETAILED FINDINGS
⚠️ P2 ISSUE: Partial Cleanup Logging Bug
File:
src/cleveragents/infrastructure/sandbox/git_worktree.pylines 237–259Problem: Unconditional success logging even on partial cleanup:
Impact: Misleading operators — when branch deletion fails, function still logs "Stale sandbox branch cleaned up" even though the branch persists. Violates accurate error reporting principle.
Comparison with PR #10003 (correct pattern):
branch_deletedflagFix Required:
branch_deletedflag (or use conditional logging)Severity: P2 (should-fix) — Undermines operational visibility.
⚠️ P3 ISSUE: Function-Level Imports (G2 Violation)
File:
src/cleveragents/cli/commands/plan.pyLocations:
_cleanup_stale_sandbox()imports GitWorktreeSandbox_create_sandbox_for_plan()imports GitWorktreeSandboxProblem: Per review playbook (G2), imports should be at module top-level:
Comparison with PR #10003 (correct approach):
Fix Required: Move both imports to module-level (lines 20–54 section).
Severity: P3 (nit) — Style/consistency, not functional.
✅ Test Coverage Analysis
Test Results:
Scenarios Verified:
Finding: No issues. Tests are comprehensive and all pass.
✅ Exception Handling – Infrastructure
Review: Specific exceptions caught (
subprocess.CalledProcessError,subprocess.TimeoutExpired); fallback behavior (manualrmtree) is correct.Finding: No issues.
✅ Idempotency
Review: Returns False if no stale branch exists; no exceptions thrown. Idempotent behavior confirmed by tests.
Finding: No issues.
COMPARISON WITH PR #10003
Complementary Use Cases (Not Contradictory)
agents plan cancelagents plan execute(re-run)These are complementary, not contradictory. Both PRs can coexist.
Contradictions Identified
Logging Pattern (P2):
Import Organization (P3):
Both contradictions should be resolved by fixing PR #10798 to match PR #10003's patterns.
ARCHITECTURE & SECURITY
Architecture: ✅ Proper layering (infrastructure → CLI). Clean separation of concerns.
Security: ✅ No data loss risk (removes worktree copy only). No TOCTOU race. No symlink traversal issues.
Finding: No issues.
MERGE READINESS
Status: REQUEST CHANGES (P2 + P3 issues)
Pre-Merge Checklist:
nox -s lintpassesnox -s typecheckpassesnox -s coverage_report≥ 97%RECOMMENDED FIXES
Fix P2: Partial Cleanup Logging
Replace lines 237–259 in
git_worktree.pywith:Fix P3: Import Organization
Add to module-level imports (near line 52–54):
Remove function-level imports from:
_cleanup_stale_sandbox()(line 1359–1360)_create_sandbox_for_plan()(line 1380–1381)SUMMARY
Issues Found: 2
All Other Categories: ✅ APPROVED
FINAL RECOMMENDATION
REQUEST CHANGES ⚠️
Next Steps:
Reviewer: Build Agent (haiku-4-5)
Review Type: Comprehensive code review per playbook
Date: 2026-04-20
Result: REQUEST CHANGES
a9c820610aa0f99368b6@brent.edwards Both findings addressed:
branch_deletedflag —logger.infoonly on full success,logger.warning("Partial cleanup: worktree removed but branch persists")when branch deletion fails. Matches PR #10003 pattern.GitWorktreeSandboxmoved to module-level import inplan.py(line 49). Removed both function-level imports from_cleanup_stale_sandbox()and_create_sandbox_for_plan().Lint passes, typecheck 0 errors, M1 E2E passes. Ready for re-review.
a0f99368b68d1ec814d7✅ CODE REVIEW RE-CHECK – PR #10798 – All Issues Resolved and Fixed
Branch:
bugfix/sandbox-reexecute-cleanup(commit: 8d1ec814)Issue: #7271
Status: ✅ APPROVED FOR MERGE – All previously identified issues are now fixed.
VERIFICATION OF FIXES
✅ P2 ISSUE FIXED: Partial Cleanup Logging Bug
Issue: Unconditional success logging even when branch deletion failed
Fix Applied ✅:
branch_deleted = Trueflag addedFalseon exceptionlogger.info()only whenbranch_deleted == Truelogger.warning("Partial cleanup...")whenbranch_deleted == FalseMatches PR #10003 pattern: ✅ Yes, identical
✅ P3 ISSUE FIXED: Function-Level Imports (G2 Violation)
Issue:
GitWorktreeSandboximported inside functions instead of module-levelFix Applied ✅:
from cleveragents.infrastructure.sandbox.git_worktree import GitWorktreeSandbox_cleanup_stale_sandbox()(line 1360): Uses module-level import directly_create_sandbox_for_plan()(line 1406): Uses module-level import directlyTEST COVERAGE VERIFICATION ✅
Test Results:
All Scenarios Passing:
Verified: Conditional logging works correctly — test output shows success message only when branch is deleted.
ALIGNMENT WITH PR #10003 ✅
Now Identical:
Result: Both PRs follow the identical pattern and can merge cleanly without conflicts.
FINAL SUMMARY
branch_deletedflag added; conditional loggingRECOMMENDATION
Status: ✅ APPROVED FOR MERGE
Rationale:
No Further Changes Required — Ready to merge.
Reviewer: Build Agent (haiku-4-5)
Review Type: Re-check verification of fixes
Date: 2026-04-20
Commit: 8d1ec814
Result: ✅ APPROVED
b14894f6fe5edfe3033e5edfe3033eeb74795c50eb74795c504ac53800604ac53800605d8bbf22b5