* fix(#683): auto-degrade phase execution to sequential on worktree base mismatch Claude Code forks worktree-isolated executors off the repository default branch (origin/HEAD), not the orchestrator's HEAD. Running /gsd-execute-phase on a branch diverged from the default (unmerged milestone/feature branch) left every executor without the phase's plan files and tripped the worktree-branch-check guard with `exit 42` — 100% reproducible, all OSes. - New module src/worktree-base-ref.cts: HEAD-vs-fork-base drift detection (origin/HEAD with symbolic-ref fallback) and no-clobber worktree.baseRef management, exposed as `worktree base-check` / `worktree set-baseref`. - execute-phase.md: pre-dispatch, for Claude Code with worktrees enabled, auto-degrades the run to sequential on the main tree when a base mismatch is detected, recommending worktree.baseRef:"head". The exit-42 guard stays as a backstop. - Installer: fresh local Claude installs set worktree.baseRef:"head" in .claude/settings.local.json (no-clobber, respecting an explicit shared settings.json value); upgrades print an opt-in notice pointing at `gsd-tools worktree set-baseref`. - Docs: how-to guide, CLI/config reference, planning-config cross-ref. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#683): auto-apply worktree.baseRef on upgrade; gate fresh+upgrade on use_worktrees Per maintainer direction: on a local Claude Code UPGRADE, set worktree.baseRef:"head" automatically (no opt-in notice) when the project's workflow.use_worktrees is enabled, instead of merely printing a remediation notice. For consistency the FRESH path is now gated the same way: both paths compute worktrees-enabled once (bounded walk-up read of .planning/config.json, default enabled unless workflow.use_worktrees === false) and apply the no-clobber baseRef only when enabled — never overwriting an explicit value in settings.local.json or a shared settings.json. gsd-tools worktree set-baseref remains for manual use. Docs + changeset updated; tests hardened (file-exists assertions, fresh+disabled case, upgrade idempotency). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#683): measure workflow byte-budget on LF, fixing Windows-only CI failure The workflow-size-budget test failed only on Windows: git checks out the .md files as CRLF (no eol=lf in .gitattributes) and byteCount used fs.statSync().size (raw on-disk bytes), counting an extra \r per line. That inflated execute-phase.md — the XL high-water-mark file pinned near its ceiling by the tighten-only ratchet — from 88492 LF bytes to ~90245 on Windows, over the 90000 XL ceiling, while passing on the LF-checkout Mac/Linux runners. The ceilings are explicitly "calibrated against raw `wc -c`" on an LF checkout, so the measurement should be LF-based on every platform. byteCount now reads the file and counts Buffer.byteLength after stripping CR, making the budget platform-independent (a no-op on LF checkouts; verified statSync === normalized for all 88 workflow files). No ceilings changed. Added a regression test asserting CRLF and LF content of the same file count identically. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#683): make worktree-base-ref test path mocks Windows-safe (path.join) tests/worktree-base-ref.test.cjs keyed its injected readFile/writeFile mocks (and a few expected `file` values) with forward-slash template literals like `${claudeDir}/settings.local.json`. The module composes those paths with path.join(), which emits backslashes on Windows, so the mock keys never matched the module's lookup → readFile returned null → resolveEffectiveBaseRef / cmdWorktreeBaseCheck / cmdWorktreeSetBaseRef (and the JSONC variants) failed on the Windows full-test runner only (they passed on Mac/Linux, and the install tests passed because they use the real filesystem). The module is correct; only the test fixtures hardcoded '/'. All mock keys and path assertions now use path.join(base, ...) mirroring the module, so they match on every platform (no-op on POSIX). 19 path references across 16 lines. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
6.1 KiB
How to fix the worktree base-mismatch (exit 42) error
Goal: Understand why /gsd-execute-phase halts with FATAL: worktree base mismatch / exit 42 when your branch is ahead of the default branch, and choose the right fix to restore normal — or parallel — execution.
Prerequisites: GSD Core is installed and you have an active project. You have run /gsd-execute-phase and either seen the exit-42 error or the one-line ⚠ Worktree base mismatch warning.
What you will see
When you run /gsd-execute-phase on a branch that is ahead of the repository's default branch (for example, an unmerged milestone branch, a long-lived feature branch, or a branch with commits not yet in origin/HEAD), you may see one of two messages:
Automatic-degrade warning (phase still completes):
⚠ Worktree base mismatch: HEAD (abc12345) differs from origin/HEAD (def67890).
Running this phase sequentially on the main working tree.
To keep parallel worktrees, set worktree.baseRef:"head" in
.claude/settings.local.json (or run: gsd-tools worktree set-baseref). See #683.
The phase runs to completion sequentially; nothing is blocked. This is the runtime mitigation.
Exit-42 halt (older installs or misconfigured environments):
FATAL: worktree base mismatch
All worktree-isolated executors halt immediately. Zero progress is made.
Why this happens
Claude Code's isolation="worktree" forks executor worktrees from the repository's default branch (origin/HEAD), not from your current HEAD. When your branch contains commits that origin/HEAD does not have — plan files, new source files, anything added since the branch diverged — those files are absent inside each worktree. GSD's worktree-branch-check safety guard correctly refuses to act on a worktree that does not match the orchestrator's state, and exits with code 42.
This is the guard working as designed: it prevents silent data loss or phantom edits in the wrong tree. The error is a branch-state condition, not an OS-specific or hardware issue.
Option 1 — Do nothing (you are already unblocked)
If you saw the ⚠ Worktree base mismatch warning rather than an exit-42 halt, GSD has already automatically degraded to sequential execution on the main working tree for this run. The phase will complete. No action is required.
Use this option when:
- You are on a diverged branch temporarily
- You do not care about parallel execution for this phase
- You want to merge back to the default branch soon
Option 2 — Permanent fix: set worktree.baseRef: "head" (recommended)
This option restores parallel worktree execution on diverged branches. It tells Claude Code to fork executor worktrees from your current HEAD instead of origin/HEAD, so the plan files and branch-only commits are present in every worktree.
Run the convenience command from your project root:
node "$HOME/.claude/gsd-core/bin/gsd-tools.cjs" worktree set-baseref
This writes worktree.baseRef: "head" into .claude/settings.local.json in your project root. It is no-clobber: if you already have an explicit baseRef set to something else, it leaves your value in place and tells you.
To verify the result:
node "$HOME/.claude/gsd-core/bin/gsd-tools.cjs" worktree base-check
The output is JSON. When shouldDegrade is false and reason is "baseref-head", parallel worktrees will work on any branch.
Alternatively, set the value by hand in .claude/settings.local.json:
{
"worktree": {
"baseRef": "head"
}
}
Note: Fresh installs and upgrades of GSD Core both set worktree.baseRef:"head" automatically in .claude/settings.local.json (no-clobber) when workflow.use_worktrees is enabled (the default). You can also apply or re-apply it manually at any time with gsd-tools worktree set-baseref — for example, if you toggled worktrees on after the initial install.
Use this option when:
- You regularly work on long-lived or milestone branches
- You want parallel phase execution (faster, lower context-window pressure)
- You are a solo developer or team working on a feature branch for an extended period
Option 3 — Fallback: disable worktrees entirely
If worktrees are causing persistent problems beyond the base-mismatch (for example, your environment does not support them), disable them permanently for this project:
Add or edit .planning/config.json:
{
"workflow": {
"use_worktrees": false
}
}
All executor agents will then run sequentially on the main working tree for every phase. This is equivalent to what the automatic degrade does, but permanent.
Use this option when:
- Worktrees are consistently problematic in your environment
- You prefer sequential execution for auditability or tooling reasons
- You are on a platform or CI setup that does not support git worktrees
See also: workflow.use_worktrees in the configuration reference.
The exit-42 backstop
The worktree-branch-check guard (exit 42) remains active in all execution modes as a safety backstop. It fires only when an executor worktree's branch does not match the expected orchestrator state — a condition that should not arise once you have applied one of the options above. If you continue to see exit 42 after setting worktree.baseRef: "head", run /gsd-forensics to investigate.
Summary
| Situation | Recommended action |
|---|---|
| Saw the warning, phase completed | Nothing — degrade handled it automatically |
| Regularly on diverged branches, want parallel execution | worktree set-baseref (Option 2) |
| Worktrees consistently problematic | Set workflow.use_worktrees: false (Option 3) |
| Still seeing exit 42 after fixes | Run /gsd-forensics "exit 42 after fix" |