* 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>
This commit is contained in:
@@ -1232,8 +1232,12 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
||||
worktreeSafety.cmdWorktreeCleanupWave(cwd, args.slice(2));
|
||||
} else if (subcommand === 'reap-orphans') {
|
||||
worktreeSafety.cmdWorktreeReapOrphans(cwd);
|
||||
} else if (subcommand === 'base-check') {
|
||||
require('./lib/worktree-base-ref.cjs').cmdWorktreeBaseCheck(cwd, args.slice(2));
|
||||
} else if (subcommand === 'set-baseref') {
|
||||
require('./lib/worktree-base-ref.cjs').cmdWorktreeSetBaseRef(cwd, args.slice(2));
|
||||
} else {
|
||||
error('Unknown worktree subcommand. Available: cleanup-wave, reap-orphans', ERROR_REASON.SDK_UNKNOWN_COMMAND);
|
||||
error('Unknown worktree subcommand. Available: cleanup-wave, reap-orphans, base-check, set-baseref', ERROR_REASON.SDK_UNKNOWN_COMMAND);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ Configuration options for `.planning/` directory behavior.
|
||||
| `git.phase_branch_template` | `"gsd/phase-{phase}-{slug}"` | Branch template for phase strategy |
|
||||
| `git.milestone_branch_template` | `"gsd/{milestone}-{slug}"` | Branch template for milestone strategy |
|
||||
| `git.quick_branch_template` | `null` | Optional branch template for quick-task runs |
|
||||
| `workflow.use_worktrees` | `true` | Whether executor agents run in isolated git worktrees. Set to `false` to disable worktrees — agents execute sequentially on the main working tree instead. Recommended for solo developers or when worktree merges cause issues. |
|
||||
| `workflow.use_worktrees` | `true` | Whether executor agents run in isolated git worktrees. Set to `false` to disable worktrees — agents execute sequentially on the main working tree instead. Recommended for solo developers or when worktree merges cause issues. Note: if your branch is ahead of `origin/HEAD` (a diverged milestone or feature branch), GSD auto-degrades to sequential and prints a warning; set `worktree.baseRef:"head"` in `.claude/settings.local.json` to restore parallel execution. See the branch-divergence note below. |
|
||||
| `workflow.subagent_timeout` | `300000` | Timeout in milliseconds for parallel subagent tasks (e.g. codebase mapping). Increase for large codebases or slower models. Default: 300000 (5 minutes). |
|
||||
| `workflow.inline_plan_threshold` | `2` | Plans with this many tasks or fewer execute inline (Pattern C) instead of spawning a subagent. Avoids ~14K token spawn overhead for small plans. Set to `0` to always spawn subagents. |
|
||||
| `manager.flags.discuss` | `""` | Flags passed to `/gsd:discuss-phase` when dispatched from manager (e.g. `"--auto --analyze"`) |
|
||||
@@ -385,6 +385,8 @@ Several config fields affect each other or trigger special behavior:
|
||||
|
||||
8. **`sub_repos` auto-sync** -- On every config load, GSD scans for child directories with `.git` and updates the `sub_repos` array if the filesystem has changed. Legacy `multiRepo: true` is automatically migrated to a detected `sub_repos` array.
|
||||
|
||||
9. **`workflow.use_worktrees` and branch divergence** -- When `use_worktrees` is `true` (default), executor worktrees are forked from `origin/HEAD` by the Claude Code harness. If your current branch has commits that `origin/HEAD` does not (for example an unmerged milestone or feature branch), GSD automatically degrades to sequential execution for that run and prints a one-line `⚠ Worktree base mismatch` warning. To restore parallel execution permanently, set `worktree.baseRef:"head"` in `.claude/settings.local.json` (run `node gsd-tools.cjs worktree set-baseref`). This makes the harness fork worktrees from the live HEAD instead of `origin/HEAD`. Both fresh installs and upgrades of GSD Core set this automatically (no-clobber) when `use_worktrees` is enabled; you can also run the command manually at any time. Setting `workflow.use_worktrees: false` is the alternative if worktrees are not needed at all.
|
||||
|
||||
---
|
||||
|
||||
## Example Configurations
|
||||
|
||||
@@ -92,6 +92,16 @@ if [ "$RUNTIME" = "codex" ] && [ "$USE_WORKTREES" != "false" ]; then
|
||||
fi
|
||||
# Sweep orphaned locked worktrees from prior crashed sessions before spawning executors (#3707).
|
||||
[ "$USE_WORKTREES" != "false" ] && gsd_run query worktree.reap-orphans 2>/dev/null || true
|
||||
# Auto-degrade to sequential if HEAD has diverged from the worktree fork base (#683).
|
||||
# Only applies to Claude Code (isolation="worktree" is Claude-Code-specific).
|
||||
if [ "$RUNTIME" = "claude" ] && [ "$USE_WORKTREES" != "false" ]; then
|
||||
_SHOULD_DEGRADE=$(gsd_run query worktree.base-check --pick shouldDegrade 2>/dev/null || true)
|
||||
if [ "$_SHOULD_DEGRADE" = "true" ]; then
|
||||
_DEGRADE_MSG=$(gsd_run query worktree.base-check --pick message 2>/dev/null || true)
|
||||
[ -n "$_DEGRADE_MSG" ] && printf '%s\n' "$_DEGRADE_MSG" >&2
|
||||
USE_WORKTREES=false
|
||||
fi
|
||||
fi
|
||||
```
|
||||
Codex maps subagents to `spawn_agent`, which has no direct Codex mapping for Claude Code's `isolation="worktree"` parameter. Failing closed prevents main-checkout edits while the workflow believes agents are isolated.
|
||||
|
||||
@@ -111,6 +121,8 @@ fi
|
||||
|
||||
When `USE_WORKTREES` (project-level) is `false`, all executor agents run without `isolation="worktree"` — they execute sequentially on the main working tree instead of in parallel worktrees. The per-plan decision below has no effect when worktrees are project-disabled.
|
||||
|
||||
`USE_WORKTREES` is also automatically set to `false` for the duration of a run when `worktree base-check` detects that the orchestrator HEAD has diverged from the worktree fork base (the #683 condition — e.g. an unmerged milestone or feature branch). This check runs only when `RUNTIME=claude` because `isolation="worktree"` is a Claude Code-specific feature; other runtimes do not use it. The auto-degrade prints a one-line warning to stderr and falls through to the sequential path so executors do not hit the exit-42 worktree-branch-check halt. To restore parallel worktree execution, set `worktree.baseRef:"head"` in `.claude/settings.local.json` (or run `gsd-tools worktree set-baseref`) — this makes the fork base track the live HEAD instead of a fixed remote ref. The `worktree-branch-check` exit-42 guard inside each executor remains in place as a backstop.
|
||||
|
||||
Read context window size for adaptive prompt enrichment:
|
||||
|
||||
```bash
|
||||
|
||||
Reference in New Issue
Block a user