worktree finish crashes on its own untracked .cc-os symlink #525
Labels
No labels
P0
P1
P2
P3
bug
create
delete
enhancement
filed-by/agent
filed-by/user
frozen
lint-rule
needs-info
needs-triage
next
plugin/cc-architect
plugin/os
plugin/os-adr
plugin/os-aidd-lint
plugin/os-backlog
plugin/os-context
plugin/os-doc-hygiene
plugin/os-sdlc
plugin/os-vault
project/cc-os
ready-for-agent
ready-for-human
recurring
review
update
waiting
wayfinder:grilling
wayfinder:map
wayfinder:map
wayfinder:research
wayfinder:task
wayfinder:task
wontfix
worklist/deviations
worklist/lint-rule
worklist/new-implement-build
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
jared/cc-os#525
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Context
plugins/os/bin/worktree start ticket-19printedlinked: .cc-os, .sdlc/pipeline.db(it creates a.cc-ossymlink in the worktree, untracked). After all commits were merged,plugins/os/bin/worktree finish ticket-19merged fine ("Already up to date") but then raised fromplugins/os/lib/worktree_cli_finish.rb:118remove_worktree:git worktree removefailed with "contains modified or untracked files, use --force to delete it"; the only untracked entry was.cc-os, i.e. the symlink start created. Exit code was 0 despite the crash.Expected behavior
finish removes its own linked entries (or passes --force when the only untracked paths are the ones it linked) and exits non-zero on failure.
Workaround
git worktree remove --force+git branch -dby hand.Discoverer: hyperthrive-websites, session 01WczDUXXTYSuFuZNRQQLf49, 2026-09-03. worktree start/finish lifecycle bug preventing normal cleanup.
Agent Brief
Category: bug
Summary:
worktree finishmust remove the entriesworktree startlinked, sogit worktree removesucceeds without--force.Current behavior:
worktree startsymlinks.cc-osand.sdlc/pipeline.db(plus anyworktree-symlinksconfig entries) into the new worktree. It keeps the linked list only in memory and prints it once. The root.gitignoreignores.cc-os/as a directory. The worktree entry is a symlink, so git reports it as untracked.worktree finishmerges, then callsgit worktree removewithout--forceand without removing the links. Git refuses with "contains modified or untracked files". TheRuntimeErrorfromsystem(..., exception: true)propagates uncaught through Thor. A direct run exits 1 with a Ruby backtrace. The ticket's report of exit 0 came through a wrapper and did not reproduce in a direct run.Desired behavior:
Before it removes the worktree,
finishremoves exactly the entries thatstartlinked. It then runsgit worktree removewithout--force. If untracked paths remain thatstartdid not create,finishrefuses with a message that names those paths and exits non-zero. It never passes--forceand never deletes user files. A failure ingit worktree removeproduces a one-line error, not a backtrace, and a non-zero exit.Key interfaces:
Worktree::StartCommand(or its successor) records the linked entries somewherefinishcan read back: a small manifest inside the worktree's own gitignored state, or a deterministic recomputation from the same configstartused. Either is acceptable; choose one and use it for both.cc-os,.sdlc/pipeline.db, and config extras.Worktree::FinishCommand#remove_worktree(or its successor) unlinks the recorded entries, then removes the worktree.finishcommand maps a removal failure to a clean error message and a non-zero exit code.Acceptance criteria:
startwith the default links, when all commits are merged andfinishruns, then the worktree and branch are gone and exit is 0.startlinked, whenfinishruns, then it does not pass--forceto git.finishruns, then it refuses, names the file, leaves the worktree in place, and exits non-zero.git worktree removefails for any reason, whenfinishruns, then stderr has one error line with no Ruby backtrace and exit is non-zero..cc-ossymlink case.Out of scope:
.gitignorepattern for.cc-os/(a symlink-aware pattern would hide the symptom, not fix cleanup).require_relativeline. That is a separate ticket.Governing ADRs: ADR-0143 (symlink owning state), ADR-0151 (Thor worktree CLI), ADR-0157 (CLI sole creator and destroyer).
Work started via /os-sdlc:implement on branch
ticket-525(worktree at .claude/worktrees/ticket-525), 2026-09-08.Resolution
Done: worktree finish now removes the entries start linked and exits 4 with a one-line error when other untracked files remain. LinkedEntries names the linked set for both commands. Five new finish scenario tests plus an entry file.
Evidence: Branch ticket-525 commit
e377c22, driven by /os-sdlc:implement (implementation 2, four behavioral increments, all gates green). Full os suite: 18 runs, 0 failures. Merge to main follows via worktree finish.Follow-ups: #534 runner brief ignores implementation target (hot-patched for this run, restored). #535 diff-test gate loops on scenario-split tests (entry file added as workaround). #533 start test files lack require_relative. The ticket's exit-0 claim did not reproduce in a direct run; dropped.
Live-verified after merge: the pre-merge finish (old code) crashed on the .cc-os symlink; the re-run with the merged code removed the worktree and branch cleanly. The reported exit 0 is explained: the crash exits 1, but a pipe such as
worktree finish x 2>&1 | tailreports the last command's status. Run it unpiped or read pipestatus.