Skip to content

Retain a recoverable checkout until unregister succeeds - #4459

Open
max-sixty wants to merge 50 commits into
mainfrom
codex/removal-recovery
Open

max-sixty wants to merge 50 commits into
mainfrom
codex/removal-recovery

Conversation

@max-sixty

@max-sixty max-sixty commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

Keep a removed checkout recoverable until its complete Git registration has been atomically moved out of the registry. If unregister fails, restore the checkout; if a new occupant blocks restoration, preserve both payloads and report the Git repair command.

Only committed removals enter disposal. Transaction containers live under wt/removing/, separately from recovery checkout roots under wt/retained/. User-owned directories named registration cannot authorize disposal. State inspection, explicit clearing, and deferred preparation share that inventory, while actual deletion uses the existing locked trash drain. Recoverable containers are excluded. Exclusive moves preserve existing destinations during both disposal preparation and rollback.

Includes the registration-identity guards from #4454, which should land first. The combined design preserves tolerant ordinary inventory and strict destructive-boundary ownership. Ambiguous registrations refuse unregister; recovery restores the checkout without deleting its contents or branch. Fixing only the ambiguity permits the same removal to succeed.

Validation: 337 focused repository, held-reference, recovery, disposal, and removal tests pass. The combined full project gate passes: 5,486 tests, one skipped, plus formatting, Clippy, docs, doctests, and lockfile checks. Independent review of both parents and their automatic merges found no remaining issues and ran the ambiguity/refusal/recovery contrast through the CLI. Current-head required and advisory tests pass on Linux, macOS, and Windows; lint, docs, features, coverage workflow, and Codecov project also pass. Codecov patch remains a merge gate: 95.70% against a 98.62% target. The current review job completed normally, found no new actionable issue, and confirmed the earlier recovery finding resolved. It retained the existing maintainer decision hold instead of posting a duplicate review.

This was written by Codex on behalf of max-sixty

…ntity

# Conflicts:
#	src/git/repository/tests.rs
#	src/git/test.rs
…ntity

# Conflicts:
#	src/git/repository/tests.rs
Atomically move unregistered metadata into wt/trash and use one complete disposal inventory. Restore the state table and snapshots to main, remove the extra metadata prefix/root and payload rename reservation machinery, and trim their duplicate fixtures.

Keep cancellation at the transaction mutation boundary and document preserved-removal errors. Keep git worktree repair of the retained checkout: moving it blindly back can touch a concurrent original-path occupant. Extend the existing recovery contrast to cover that occupant.

Fallback fixtures now block the initial retained move, rather than later trash promotion. Source-only repair; no runtime validation. The ENOTEMPTY-only remaining-directory diagnostic and contrast are unchanged.
…t-registration-identity

# Conflicts:
#	src/git/repository/tests.rs
…t-registration-identity

# Conflicts:
#	src/git/repository/tests.rs

@worktrunk-bot worktrunk-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every fast-path removal now runs create_dir_all on .git/wt/retained/, and nothing removes that directory afterward, so each repo that has used wt remove ends up with a new permanent directory. AGENTS.md (Data Safety) names the FAQ's "What files does Worktrunk create?" table as the inventory, but it still lists only .git/wt/trash/<name>-<timestamp> under .git/wt/. A retained/ row would cover two cases: a checkout held for git worktree repair after a failed unregister, and a checkout left there after an interrupted removal. The row should also say that wt config state clear does not touch it. The table is in docs/src/content/docs/faq.md, mirrored in skills/worktrunk/reference/faq.md.

Comment thread src/git/remove.rs Resolved

@worktrunk-bot worktrunk-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stage_worktree_removal now returns an error after the unregister has already committed, so wt remove can report a removal that actually happened as a failure. Details inline.

Comment thread src/git/remove.rs Resolved

@worktrunk-bot worktrunk-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Holding the approval for a maintainer's decision instead of approving. This PR changes what Worktrunk deletes: disposal_entries now lets the stale-trash sweep and wt config state clear delete committed containers under .git/wt/retained/removing/, and wt remove's rm -rf now runs only after prepare_disposal succeeds. The repo's review guidance (.claude/skills/running-tend/references/review-pr.md, Data-Loss Surface: Hold for Human Review) reserves changes like that for a human decision. I have no open findings.

@max-sixty
max-sixty changed the base branch from main to codex/git-native-paths October 13, 2026 01:45
Base automatically changed from codex/git-native-paths to main October 13, 2026 02:28
…n-identity

# Conflicts:
#	src/git/repository/tests.rs
#	src/git/repository/working_tree.rs
#	src/git/repository/worktrees.rs
#	src/git/test.rs
# Conflicts:
#	src/commands/process.rs
#	src/git/repository/tests.rs
#	src/git/repository/working_tree.rs
#	src/git/test.rs
#	src/output/handlers.rs
#	tests/integration_tests/remove.rs

@worktrunk-bot worktrunk-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The revised disposal namespace can classify a recoverable checkout as committed disposal; details inline. @max-sixty, please review this deletion boundary before merge.

Comment thread src/git/repository/disposal.rs Resolved

This branch has not been deployed

No deployments
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.

2 participants