fix: make land-* post-merge cleanup worktree-aware#206
Merged
Conversation
Rework land-pr steps 5-6 and Success criteria to branch on worktree context: state-based merge verification, canonical is_linked_worktree predicate, base resolved from the PR, a three-leaf cleanup tree, and teardown deferred to gc_worktrees with both coverage caveats. Classic single-tree path is unchanged. Also materializes the join-keyed plan doc for #182. Closes #183
…worktree gc note Reuse the canonical is_linked_worktree predicate (byte-identical to land-pr) in land-docs and land-plan-docs: make setup and cleanup context-aware (no checkout of a held default from a linked worktree; git fetch + defer teardown to gc), and repair land-plan-docs's half-converted BASE handling. Add a companion note to git-worktree cross-referencing the land-* teardown deferral and gc's coverage limits. Closes #184 Closes #185
Clarify that the held-in-another-worktree guard runs before any git branch -d, including Leaf A's, per the AC pre-check note.
… cleanup recipes Address /workflows-review findings on PR #206: - P1: land-docs/land-plan-docs green-path cleanup called is_linked_worktree from a separate Bash invocation (function out of scope -> exit 127 -> wrong else-branch checkout that fails in a worktree) and led with 'if' (breaks the unattended allowed-tools first-token contract, gotcha #3). Replace with land-pr-style separate git-leading leaves, predicate evaluated in prose. - P2: reframe land-pr step 6 as two paths + a shared pre-delete guard (Leaf C was a cross-cutting guard, not a mutually-exclusive leaf). - P3: land-pr Leaf C guard uses whole-line grep -qxF. Findings recorded in todos/005-008.
Merged
aagnone3
added a commit
that referenced
this pull request
Jul 19, 2026
…#3) (#208) The "detect an existing PR before branching" section led its decision with a standalone `if [ -n "$EXISTING" ] ...` block. Claude Code matches a skill's `allowed-tools` (Bash(gh *), Bash(git *), Read) by the pipeline's FIRST token, and `if` is not allow-listed — so an unattended run could stall on a permission prompt (the same class fixed for the cleanup recipes in PR #206 / issue #182, which predated this block). Fold the null-check into the `gh pr list --jq` with `// empty` so the recipe leads with `gh` (covered by Bash(gh *)), and evaluate the existence decision in prose — mirroring how PR #206 resolved the cleanup recipes (command-leading leaves, predicate evaluated in prose). allowed-tools unchanged. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
aagnone3
added a commit
that referenced
this pull request
Jul 19, 2026
Captures two learnings from PR #206: the worktree-aware merge-verify + cleanup pattern for land-* skills, and the shell-function-scope trap where a predicate defined in one fenced recipe block does not survive into another (each block is its own shell). Markdown only — no code. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
aagnone3
added a commit
that referenced
this pull request
Jul 19, 2026
…ly, not --repo (#210) `gh repo view --repo "$ORIGIN"` fails with "unknown flag: --repo" (gh has no -R/--repo on `repo view`; the repo is a positional arg — unlike gh pr/issue/api). It empties BASE and breaks BASE resolution in both land-docs and land-plan-docs. The wrong form originated in the land-plan-docs-gh-git-boundary-gotchas solution doc's own §2 "fix" recipe and was copied into both skills (land-docs in #206, land-plan-docs in #173). Correct all three to the positional form and teach the distinction in the gotchas doc. Discovered while running the compound data lane for #182. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #182
Summary
land-pr,land-docs,land-plan-docs) so they branch on worktree context instead of assuming the default branch can be checked out in the current tree. In the worktree-first workflow this plugin promotes, the default branch is held by the primary tree, sogit checkout <default>from a linked worktree fails and the documented success criteria were unreachable — thegit-worktreeandland-prskills contradicted each other on every merge.gh pr view --json state,mergedAt), documenting thatfatal: '<base>' is already used by worktreeafter a merge means local cleanup failed, not the merge — do not retry. Step 6 is a context-aware three-leaf decision tree (classic single-tree / current linked worktree / feature-branch-held-elsewhere) built on a canonicalis_linked_worktreepredicate, resolves the base from the PR (baseRefName, not repo default /origin/HEAD), and points local teardown atgc_worktreeswith both coverage caveats documented. Success criteria and the report step are forked by mode.gc, spelling out gc's two coverage limits (can't self-reap the active worktree; only reaps$GIT_ROOT/.worktrees/).is_linked_worktreepredicate (verified by hash across all three skills), and repairsland-plan-docs's half-converted BASE handling.Key decisions (from the plan)
.claude/worktrees/(harness worktrees, including this run) is outside gc's scope and needs a manualgit worktree remove.allowed-toolsunchanged; gc is referenced in prose only. Classic single-tree behavior is preserved verbatim.Testing
bun test— 513 pass / 0 fail (consistency + converter suites; confirms no count/slug/frontmatter regressions).bun run typecheck— clean.is_linked_worktreepredicate confirmed byte-identical (md5) across land-pr / land-docs / land-plan-docs.…/.git/worktrees/…) ≠ common-dir (…/.git) → returns true.acceptance-criteria-reviewerpre-check: PASS on all 11 criteria across land-pr post-merge cleanup breaks under the worktree-first workflow (checkout of held default branch) #182/fix(land-pr): worktree-safe merge-verify + post-merge cleanup #183/docs(git-worktree): companion note on land-* teardown deferral to gc #184/fix(land-docs,land-plan-docs): extend worktree-safe cleanup pattern #185, no P1s.Post-Deploy Monitoring & Validation
This is a docs-only change to skill markdown (prose + bash recipes) — no product code, no runtime service, no deploy surface.
git-worktree+land-prtogether lands a PR from a linked worktree with no false-failure retry and no unreachable success criterion; worktree-mode runs report deferred teardown (naming the worktree + branch left for gc / manual removal).git checkout <default>from a context where the default is held elsewhere, or reporting cleanup "done" while a worktree/branch remains. Trigger →git revertthe docs commits (pure markdown, no state to unwind).No additional operational monitoring required: docs-only change with no production/runtime impact.Before / After Screenshots
N/A — no UI changes (skill markdown only).