worktree finish --keep exits 1 silently when the worktree fast-forward fails; route it through Checkout #849

Open
opened 2026-09-30 17:22:36 +00:00 by jared · 1 comment
Owner

Problem

FinishCommand#keep_aligned (plugins/os/lib/worktree/finish_command.rb:59) runs git merge --ff-only <base> in the kept worktree through an inline Git.new(worktree_path). When the fast-forward fails, for example because the worktree has uncommitted changes that it would overwrite, finish returns exit 1 and prints nothing. By then the branch is already merged into base.

The os:worktree skill maps exit 1 to "Merge conflicts. The CLI prints the files. Resolve them, then run step 3 again." An agent would run finish again against a branch that is already merged. plugins/os/invariants.md item 20 says every non-zero exit prints its reason.

The inline Git.new also bypasses Checkout, which #844 made the owner of worktree-side git actions (checkout.rb:7, bring_up_to at checkout.rb:29-35). Removal and ConflictScan receive their git through a keyword with a default; keep_aligned has no seam.

Observed

Contract-auditor GAP line, #844 implementation 9, dispatch 75: "FinishCommand#keep_aligned returns EXIT_CONFLICTS when the worktree ff-only fails and prints no message (finish_command.rb:59). The ticket does not specify this case."

Lens challenge of the same dispatch's P2 line (2026-09-30), verdict "code defect found": "An object that obeys P2 already exists. Checkout ... FinishCommand#keep_aligned is the one worktree-side action that stayed behind."

Reproduce

  1. Create a worktree on branch p with a commit not on base, and leave an uncommitted change in p to a file that base also changes.
  2. Run worktree finish p --keep from the main checkout.
  3. Observe: exit 1, no output about the failed fast-forward; base already contains p.

Origin

  • Trigger: /os-sdlc:implement 844 contract audit and lens challenge
  • Improvised this session: none
  • Chain: silent exit 1 ← keep_aligned builds its own git and has no failure message ← #844 did not specify the case
  • Root candidate: this ticket
  • Where: plugins/os/lib/worktree/finish_command.rb (keep_aligned); plugins/os/lib/worktree/checkout.rb
  • Session: f531ed01-125b-49b4-b35a-43528beff19e
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/f531ed01-125b-49b4-b35a-43528beff19e.jsonl

VERDICT: CREATE — defect shipped in #844; breaks invariants.md item 20 (ticket-skeptic, 2026-09-30).

## Problem `FinishCommand#keep_aligned` (`plugins/os/lib/worktree/finish_command.rb:59`) runs `git merge --ff-only <base>` in the kept worktree through an inline `Git.new(worktree_path)`. When the fast-forward fails, for example because the worktree has uncommitted changes that it would overwrite, finish returns exit 1 and prints nothing. By then the branch is already merged into base. The `os:worktree` skill maps exit 1 to "Merge conflicts. The CLI prints the files. Resolve them, then run step 3 again." An agent would run finish again against a branch that is already merged. `plugins/os/invariants.md` item 20 says every non-zero exit prints its reason. The inline `Git.new` also bypasses `Checkout`, which #844 made the owner of worktree-side git actions (`checkout.rb:7`, `bring_up_to` at `checkout.rb:29-35`). `Removal` and `ConflictScan` receive their git through a keyword with a default; `keep_aligned` has no seam. ## Observed Contract-auditor GAP line, #844 implementation 9, dispatch 75: "FinishCommand#keep_aligned returns EXIT_CONFLICTS when the worktree ff-only fails and prints no message (finish_command.rb:59). The ticket does not specify this case." Lens challenge of the same dispatch's P2 line (2026-09-30), verdict "code defect found": "An object that obeys P2 already exists. Checkout ... FinishCommand#keep_aligned is the one worktree-side action that stayed behind." ## Reproduce 1. Create a worktree on branch `p` with a commit not on base, and leave an uncommitted change in `p` to a file that base also changes. 2. Run `worktree finish p --keep` from the main checkout. 3. Observe: exit 1, no output about the failed fast-forward; base already contains `p`. ## Origin - Trigger: `/os-sdlc:implement 844` contract audit and lens challenge - Improvised this session: none - Chain: silent exit 1 ← `keep_aligned` builds its own git and has no failure message ← #844 did not specify the case - Root candidate: this ticket - Where: plugins/os/lib/worktree/finish_command.rb (`keep_aligned`); plugins/os/lib/worktree/checkout.rb - Session: f531ed01-125b-49b4-b35a-43528beff19e - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/f531ed01-125b-49b4-b35a-43528beff19e.jsonl VERDICT: CREATE — defect shipped in #844; breaks invariants.md item 20 (ticket-skeptic, 2026-09-30).
Author
Owner

From #1589 port check: FIXED. Keep path now goes through Integration#align (plugins/os-git/lib/os_git/integration.rb:268-271), which raises MergeConflict on a failed ff-only. Finish#keep_aligned rescues it (plugins/os-git/lib/os_git/worktree/finish.rb:45-50) and Outcome.keep_failed prints the message (plugins/os-git/lib/os_git/worktree/finish/outcome.rb:39). Exit is 1 with a printed reason. No inline Git.new remains. Not closed.

From #1589 port check: FIXED. Keep path now goes through Integration#align (plugins/os-git/lib/os_git/integration.rb:268-271), which raises MergeConflict on a failed ff-only. Finish#keep_aligned rescues it (plugins/os-git/lib/os_git/worktree/finish.rb:45-50) and Outcome.keep_failed prints the message (plugins/os-git/lib/os_git/worktree/finish/outcome.rb:39). Exit is 1 with a printed reason. No inline Git.new remains. Not closed.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#849
No description provided.