feat: add session-owned worktree cleanup audit and TTL enforcement (Closes #401)
Stale worktrees accumulate under branches/ when runs stop early, race a
sibling session, hit a validation failure, or lose cwd state, making later
workflow decisions harder and riskier.
Changes:
- worktree_cleanup_audit.py — ownership metadata, safety-first classifier
(active_open_pr, active_issue_work, dirty_local_worktree,
clean_stale_removable, detached_review_leftover, unsafe_unknown), TTL
expiry, per-worktree removal proof, and success-completion cleanup plan.
Only clean_stale_removable and detached_review_leftover are removable;
dirty/PR/leased/protected/unknown worktrees are never auto-deleted.
- gitea_audit_worktree_cleanup — read-only MCP tool that classifies every
branches/ entry, fetches live open-PR heads (fails closed if unavailable),
and returns counts, removable candidates, and git worktree list proof.
- work-issue.md 22A + review-merge-pr.md 28 — cleanup/TTL workflow rules.
- tests/test_worktree_cleanup_audit.py — 30 cases covering all nine
acceptance scenarios plus inference, metadata, TTL, and report accuracy.
Validation:
/Users/jasonwalker/Development/Gitea-Tools/venv/bin/python \
-m unittest tests.test_worktree_cleanup_audit tests.test_merged_cleanup_reconcile -q
38 passed.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
@@ -691,6 +691,39 @@ Do not update the main checkout unless the canonical workflow explicitly allows
|
||||
|
||||
Any cleanup is a mutation and must be reported.
|
||||
|
||||
### 22A. Session-owned worktree cleanup and TTL (#401)
|
||||
|
||||
Every session-owned worktree created under `branches/` has ownership metadata:
|
||||
path, workflow type, issue number, PR number, branch/head SHA, creator
|
||||
identity/profile, created timestamp, last-used timestamp, and cleanup
|
||||
eligibility.
|
||||
|
||||
Cleanup is classification-driven. `gitea_audit_worktree_cleanup` (read-only)
|
||||
classifies every `branches/` entry as exactly one of:
|
||||
|
||||
* `active_open_pr` — branch has an open PR; never auto-removed.
|
||||
* `active_issue_work` — active claim/lease or fresh issue worktree; never
|
||||
auto-removed.
|
||||
* `dirty_local_worktree` — uncommitted changes; never auto-removed.
|
||||
* `clean_stale_removable` — clean, no PR, no lease; removable.
|
||||
* `detached_review_leftover` — clean detached review/baseline/merge-simulation
|
||||
worktree; removable.
|
||||
* `unsafe_unknown` — protected base checkout or unknown workflow type; never
|
||||
auto-removed.
|
||||
|
||||
Only `clean_stale_removable` and `detached_review_leftover` may be removed, and
|
||||
only one-by-one after `git worktree list` proof plus per-worktree proof of:
|
||||
worktree path, branch/HEAD, clean/dirty status, no active PR/lease, and the
|
||||
removal result. Review, baseline, and merge-simulation worktrees are removed
|
||||
automatically at successful workflow completion; issue/conflict-fix worktrees
|
||||
are removed only after their TTL (`GITEA_WORKTREE_TTL_HOURS`, default 24h)
|
||||
expires and no lock/lease is held.
|
||||
|
||||
Dirty, active-PR, active-issue, and leased worktrees are never deleted
|
||||
automatically. If a removal fails, the final report must list the leftover
|
||||
worktree path and the reason. Include the `git worktree list` output as final
|
||||
cleanup verification.
|
||||
|
||||
## 23. Recovery handoff rules
|
||||
|
||||
If blocked, produce a recovery handoff with:
|
||||
|
||||
Reference in New Issue
Block a user