feat: add main-session worktree mode for /specflow (#186)#187
Merged
Conversation
`/specflow` no longer hijacks the user's branch. When a change starts, prepare-change creates a dedicated git worktree at `.specflow/worktrees/<CHANGE_ID>/main/` (named after the change-id) from the user repo's current HEAD. The `<CHANGE_ID>` branch lives only inside that worktree; the user's repo stays on whatever branch they were on, with all staged/unstaged/untracked changes preserved. Highlights: - New capability `main-session-worktree` (path layout, base commit / branch capture, conflict fail-fast, reuse policy, push/PR semantics, cleanup gating, no legacy mode coexistence). - LocalRunState gains `base_commit`, `base_branch`, `cleanup_pending` fields with drift-guard test coverage. - Subagent worktrees re-parented under `.specflow/worktrees/<CHANGE_ID>/<RUN_ID>/<BUNDLE_ID>/`. Subagent base HEAD and patch-apply target are now the main-session worktree — `mainWorkspacePath` and `changeId` are mandatory in `WorktreeRuntime`. - `/specflow.approve` push and PR creation execute inside the worktree; PR base resolves from `base_commit` (single matching remote) → `base_branch` upstream → `base_branch` itself → repo default branch. - `/specflow.reject` operates inside the worktree and triggers terminal cleanup of `.specflow/worktrees/<CHANGE_ID>/`. - Terminal cleanup gate (`src/lib/terminal-worktree-cleanup.ts`) — removes the per-change worktree subtree only when the terminal action succeeded AND every worktree is clean; otherwise records `cleanup_pending = true` for retry on next terminal-phase invocation. - Legacy run-state guard refuses to resume `worktree_path == repo_path` records on prepare-change (synthetic runs exempt). Watcher fail-fasts on the same condition. - 992 tests pass, including new coverage for conflict paths, terminal cleanup defer/retry, legacy guard with synthetic exemption, and end-to- end invariants (C-1 through C-7). Accepted-risk (scope-limited follow-ups, see approval-summary.md): - R1-F04: `readRunState` backfills missing fields with defaults; the fail-fast policy is applied at mutating entry points (prepare-change) and the watcher, not at the read helper itself. - R2-F06 / R3-F08 / R3-F09: downstream phase CLIs (`specflow-review-*`, `specflow-challenge-proposal`, `specflow-generate-task-graph`) and the remaining slash-command templates still operate from caller's git root. The `worktree-resolver` foundation is in place; threading it through every CLI is a follow-up audit. Issue: #186
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.
Summary
/specflowno longer hijacks the user's branch. When a change starts, prepare-change creates a dedicated git worktree at.specflow/worktrees/<CHANGE_ID>/main/(named after the change-id) from the user repo's current HEAD. The<CHANGE_ID>branch lives only inside that worktree; the user's repo stays on whatever branch they were on, with all staged/unstaged/untracked changes preserved.main-session-worktreewith full lifecycle (create / reuse / fail-fast / cleanup).LocalRunStategainsbase_commit,base_branch,cleanup_pending(drift-guard updated)..specflow/worktrees/<CHANGE_ID>/<RUN_ID>/<BUNDLE_ID>/;WorktreeRuntime.{mainWorkspacePath,changeId}are mandatory and patches now land in the main-session worktree, never the user repo./specflow.approvepushes from the worktree; PR base resolves frombase_commit(single remote match) →base_branchupstream →base_branchitself → repo default branch./specflow.rejectruns inside the worktree and triggers terminal cleanup..specflow/worktrees/<CHANGE_ID>/only onsuccess_full ∧ tree_clean; otherwise recordscleanup_pending = trueand surfaces dirty paths for retry.worktree_path == repo_pathnon-synthetic records on prepare-change; watcher fail-fasts on the same condition.Accepted-risk follow-ups
readRunStatebackfills missing run-state fields with defaults (defense-in-depth fail-fast lives at the mutating entry points and the watcher, not the read helper).specflow-review-*,specflow-challenge-proposal,specflow-generate-task-graph) and most slash-command templates other thanapprove/rejectstill operate from caller's git root.src/lib/worktree-resolver.tsis the foundation for the audit; threading it through every CLI is a follow-up.Test plan
npm test— 992 tests pass./specflowfrom a feature branch, confirm user branch unchanged, worktree created, PR base = feature branch.git worktree listis clean after/specflow.approvesucceeds./specflowruns (if any) before merging.Issue
Closes #186