diff --git a/.changeset/plucky-wolves-dart.md b/.changeset/plucky-wolves-dart.md new file mode 100644 index 000000000..b011d5373 --- /dev/null +++ b/.changeset/plucky-wolves-dart.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 2727 +--- +**Refusing to run a phase from an executor worktree now tells you how to recover your work** — when GSD stopped because the session had drifted into an executor worktree, it only said to re-run from the orchestrator's worktree. If that worktree held commits or uncommitted changes, following that advice silently abandoned them. The refusal now lists the commits and files that exist only there, and gives the exact steps to integrate them before continuing. (#1856) diff --git a/CONTEXT.md b/CONTEXT.md index 949804165..8512928a4 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -122,7 +122,7 @@ Leaf module owning the **out-of-band** half of ADR-1411's "corrupt is not absent CJS Module owning worktree lifecycle safety policy for the GSD orchestration layer. Interface: `resolveWorktreeContext(cwd, deps) → WorktreeContext` (linked-worktree root mapping), `parseWorktreePorcelain(output) → WorktreeEntry[]` (porcelain parser, skips detached HEAD), `planWorktreePrune(repoRoot, opts, deps) → PrunePlan` (metadata-prune plan, never destructive by default), `executeWorktreePrunePlan(plan, deps) → PruneResult` (executes prune; degrades gracefully on git timeout), `listLinkedWorktreePaths(repoRoot, deps) → LinkedPathsResult`, `inspectWorktreeHealth(repoRoot, opts, deps) → HealthResult` (orphan + stale detection), `snapshotWorktreeInventory(repoRoot, opts, deps) → InventoryResult`, `planWorktreeWaveCleanup(repoRoot, manifest) → CleanupPlan` (manifest-scoped, fail-closed), `executeWorktreeWaveCleanupPlan(plan, deps) → CleanupResult`, `planWorktreeRecordAgent(manifestRaw, fields) → RecordAgentPlan` (write-strict per-agent manifest append; validates each field at write time via the same `normalizeCleanupManifestEntry` rules the reader enforces; fail-closed on a missing/garbled field or a duplicate `(worktree_path, branch)` the reader would dedup away), `cmdWorktreeRecordAgent(cwd, args, deps) → RecordAgentCmdResult` (thin deps-injectable IO wrapper for the `worktree record-agent` verb), `planWorktreeCreate(fields) → WorktreeCreatePlan` (write-strict `worktree create` planner — same missing-field-hint and `normalizeCleanupManifestEntry` validation as `planWorktreeRecordAgent`, pure/no-git), `executeWorktreeCreatePlan(plan, repoRoot, deps) → WorktreeCreateResult` (bounded `git rev-parse --verify` base check THEN `git worktree add -b `; fail-closed `base_unresolved`/`git_timeout`/`worktree_add_failed`; returns `cwd` — the working directory an executor spawn would use), `cmdWorktreeCreate(cwd, args, deps) → WorktreeCreateCmdResult` (CLI verb: plans, creates the worktree, then appends the manifest entry so it is immediately manageable by cleanup-wave/reap-orphans; dedupes by `(worktree_path, branch)`). #2584 ADR-1239 Codex-binding amendment, Phase 2: `worktree create` is the git-worktree-creation primitive for `dispatch.isolation: orchestrator-worktree` hosts — declared and testable but UNCONSUMED (no scheduler calls it yet; Phase 3 wires it). Source of truth: `gsd-core/bin/lib/worktree-safety.cjs`. Timeout path: all git subprocess calls are bounded; callers receive `ok:false, reason:'git_timed_out'` rather than a thrown exception. Test anchor: `tests/worktree-safety.test.cjs`. The `core.cjs` re-export spine was retired in epic #1267: this module absorbed the two thin compositional wrappers that squatted in Core — `resolveWorktreeRoot(cwd, deps)` (a projection over `resolveWorktreeContext`) and `pruneOrphanedWorktrees(...)` (sequences `planWorktreePrune` + `executeWorktreePrunePlan` with a timeout warning) — so callers reach this single worktree-lifecycle seam directly. `gitWorktreeInfoInternal` did NOT move here — worktree-info detection belongs to the Git Query Module. ### Worktree Lifecycle Module -Workflow contract seam covering agent worktree lifecycle orchestration rules. The `worktree_branch_check` block lives in one canonical fragment (`gsd-core/references/worktree-branch-check.md`) that `execute-phase.md`, `quick.md`, `diagnose-issues.md`, and `execute-plan.md` embed at dispatch. Key invariants: `worktree_branch_check` is **verify-only and fail-closed** — the orchestrator owns worktree lifecycle and base recovery, so the sub-agent holds no state-correction primitives; HEAD attachment verified via `git symbolic-ref`; positive allow-list `^worktree-agent-*` enforced; `git update-ref` on protected refs is prohibited; on base mismatch the sub-agent halts with `exit 42` and surfaces to the orchestrator (#48); the orchestrator runs a cwd-drift guard at `execute_waves` entry that resolves the worktree root and refuses drift into an agent worktree (#48); cleanup is manifest-scoped (`WAVE_WORKTREE_MANIFEST`) not global-discovery-based; worktree spawning is sequential (one `run_in_background` at a time to avoid `config.lock` contention). Test anchor: `tests/worktree.test.cjs`. +Workflow contract seam covering agent worktree lifecycle orchestration rules. The `worktree_branch_check` block lives in one canonical fragment (`gsd-core/references/worktree-branch-check.md`) that `execute-phase.md`, `quick.md`, `diagnose-issues.md`, and `execute-plan.md` embed at dispatch. Key invariants: `worktree_branch_check` is **verify-only and fail-closed** — the orchestrator owns worktree lifecycle and base recovery, so the sub-agent holds no state-correction primitives; HEAD attachment verified via `git symbolic-ref`; positive allow-list `^worktree-agent-*` enforced; `git update-ref` on protected refs is prohibited; on base mismatch the sub-agent halts with `exit 42` and surfaces to the orchestrator (#48); the orchestrator runs a cwd-drift guard at `execute_waves` entry that resolves the worktree root and refuses drift into an agent worktree (#48); #1856: that refusal now also reports what the agent worktree holds — commits ahead of the resolved base and uncommitted files, both with true counts plus a truncation notice — and the commit/switch/merge-or-cherry-pick sequence to integrate them, because `re-run from the orchestrator worktree` alone silently meant abandoning work that lives only on the agent branch. The refusal condition and exit code are unchanged, and every added command is diagnostic and `|| true`-guarded so a failure degrades to the plain refusal; cleanup is manifest-scoped (`WAVE_WORKTREE_MANIFEST`) not global-discovery-based; worktree spawning is sequential (one `run_in_background` at a time to avoid `config.lock` contention). Test anchor: `tests/worktree.test.cjs`. ### Worktree Root Resolution Adapter Module Adapter Module owning linked-worktree root mapping and metadata-prune policy (`git worktree prune` non-destructive default) for planning/workstream callers. diff --git a/gsd-core/workflows/execute-phase.md b/gsd-core/workflows/execute-phase.md index cd30bb8c3..7a4f17ad6 100644 --- a/gsd-core/workflows/execute-phase.md +++ b/gsd-core/workflows/execute-phase.md @@ -440,11 +440,56 @@ pin to `git worktree list`'s first entry — that is the main worktree, the wron when the orchestrator legitimately runs from a feature worktree. ```bash +# gsd:guard=orchestrator-cwd-drift ORCHESTRATOR_WT=$(git rev-parse --show-toplevel 2>/dev/null) || { echo "FATAL: execute_waves entry is not inside a git worktree (#48)." >&2; exit 1; } ORCH_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) if printf '%s' "$ORCH_BRANCH" | grep -Eq '^(worktree-)?agent-'; then echo "FATAL: orchestrator cwd is inside an agent worktree (branch '$ORCH_BRANCH', root '$ORCHESTRATOR_WT') — refusing to execute waves (#48). A prior isolation=\"worktree\" dispatch drifted the cwd; re-run from the orchestrator's own worktree." >&2 + # #1856 handoff: the refusal above is correct, but on its own it is a dead end — + # this worktree may hold committed fixes AND uncommitted work, and "re-run from + # the orchestrator's worktree" silently means abandoning them. Report exactly + # what is stranded and how to integrate it. Every command here is DIAGNOSTIC: + # each is `|| true`-guarded so a failure degrades to the plain refusal above + # rather than crashing before the message prints. + _WT_BASE="" + for _ref in "$(git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null || true)" \ + origin/next origin/main next main; do + [ -n "$_ref" ] || continue + if git rev-parse --verify --quiet "$_ref" >/dev/null 2>&1; then _WT_BASE="$_ref"; break; fi + done + _WT_AHEAD="" + [ -n "$_WT_BASE" ] && _WT_AHEAD=$(git rev-list --count "$_WT_BASE..HEAD" 2>/dev/null || true) + # Count BEFORE truncating, so a long list reports its true size rather than + # under-reporting what is stranded — which is the whole point of this report. + _WT_DIRTY_ALL=$(git status --porcelain 2>/dev/null || true) + _WT_DIRTY_N=0 + [ -n "$_WT_DIRTY_ALL" ] && _WT_DIRTY_N=$(printf '%s\n' "$_WT_DIRTY_ALL" | wc -l | tr -d ' ') + _WT_HAS_COMMITS=0 + [ -n "$_WT_AHEAD" ] && [ "$_WT_AHEAD" -gt 0 ] 2>/dev/null && _WT_HAS_COMMITS=1 + + echo "" >&2 + echo "── Handoff: what is in this worktree (#1856) ──" >&2 + if [ "$_WT_HAS_COMMITS" -eq 1 ]; then + echo " $_WT_AHEAD commit(s) on '$ORCH_BRANCH' not on '$_WT_BASE':" >&2 + git log --oneline --no-decorate "$_WT_BASE..HEAD" 2>/dev/null | head -20 | sed 's/^/ /' >&2 || true + [ "$_WT_AHEAD" -gt 20 ] 2>/dev/null && echo " … and $((_WT_AHEAD - 20)) more" >&2 + echo " These live ONLY on this branch. Switching away without integrating loses them." >&2 + fi + if [ -n "$_WT_DIRTY_ALL" ]; then + echo " $_WT_DIRTY_N uncommitted change(s) still in this worktree:" >&2 + printf '%s\n' "$_WT_DIRTY_ALL" | head -20 | sed 's/^/ /' >&2 + [ "$_WT_DIRTY_N" -gt 20 ] 2>/dev/null && echo " … and $((_WT_DIRTY_N - 20)) more" >&2 + fi + if [ "$_WT_HAS_COMMITS" -eq 1 ] || [ -n "$_WT_DIRTY_ALL" ]; then + echo "" >&2 + echo " To integrate before continuing:" >&2 + [ -n "$_WT_DIRTY_ALL" ] && echo " 1. git add -A && git commit -m 'wip: recover worktree state' # from THIS worktree" >&2 + echo " 2. cd # a checkout whose branch is NOT agent-*/worktree-agent-*" >&2 + echo " 3. git merge --no-ff $ORCH_BRANCH # or: git cherry-pick ... for selected commits" >&2 + echo " 4. re-run the phase from there" >&2 + echo " Verify with: git log --oneline ${_WT_BASE:-HEAD}..$ORCH_BRANCH" >&2 + fi exit 1 fi # Pin to the worktree root; each later orchestrator-side block re-pins the same way diff --git a/tests/execute-phase-worktree-guard.test.cjs b/tests/execute-phase-worktree-guard.test.cjs new file mode 100644 index 000000000..f0eab98b4 --- /dev/null +++ b/tests/execute-phase-worktree-guard.test.cjs @@ -0,0 +1,227 @@ +// allow-test-rule: runtime-contract-is-the-product see #1856 +// The orchestrator cwd-drift guard (#48) is shell EMBEDDED in execute-phase.md. +// The shipped text IS the runtime contract, so these tests extract the block and +// EXECUTE it against real git fixtures rather than asserting on its characters — +// the readFileSync here is extraction for execution, not a source-grep assertion. +'use strict'; + +const { test } = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const os = require('node:os'); +const path = require('node:path'); +const { execFileSync, spawnSync } = require('node:child_process'); +const { cleanup } = require('./helpers.cjs'); + +const ROOT = path.resolve(__dirname, '..'); +const WORKFLOW = path.join(ROOT, 'gsd-core', 'workflows', 'execute-phase.md'); +const GUARD_MARKER = 'gsd:guard=orchestrator-cwd-drift'; + +/** + * Pull the guard's bash block out of the workflow. Anchored on a stable marker + * comment rather than a line range so the test does not rot when the file moves. + */ +function guardScript() { + const md = fs.readFileSync(WORKFLOW, 'utf8'); + const fences = md.split('```'); + for (let i = 1; i < fences.length; i += 2) { + const body = fences[i].replace(/^bash\r?\n/, ''); + if (body.includes(GUARD_MARKER)) return body; + } + throw new Error( + `no fenced block carrying "${GUARD_MARKER}" in ${WORKFLOW} — the guard must be ` + + 'marked so this contract test can execute the shipped text.', + ); +} + +const git = (cwd, ...args) => + execFileSync('git', args, { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }); + +/** A real repo with a base branch and one commit. */ +function makeRepo() { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1856-')); + git(dir, 'init', '--quiet', '--initial-branch', 'next'); + git(dir, 'config', 'user.email', 'test@example.com'); + git(dir, 'config', 'user.name', 'Test'); + fs.writeFileSync(path.join(dir, 'base.txt'), 'base\n'); + git(dir, 'add', '-A'); + git(dir, 'commit', '--quiet', '-m', 'base'); + return dir; +} + +function commitFile(dir, name, msg) { + fs.writeFileSync(path.join(dir, name), `${name}\n`); + git(dir, 'add', '-A'); + git(dir, 'commit', '--quiet', '-m', msg); +} + +/** Run the extracted guard in `dir`. Never throws — returns the observed result. */ +function runGuard(dir) { + const res = spawnSync('bash', ['-c', guardScript()], { + cwd: dir, + encoding: 'utf8', + timeout: 30_000, + env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }, + }); + return { status: res.status, stdout: res.stdout || '', stderr: res.stderr || '' }; +} + +test('#1856: refusal names the stranded commits and the dirty tree', () => { + const dir = makeRepo(); + try { + git(dir, 'checkout', '--quiet', '-b', 'worktree-agent-36.12-05-090827'); + for (const m of ['wire roto toggle', 'preserve roto keys', 'simplify controls', + 'count semantics', 'bound regeneration']) { + commitFile(dir, m.replace(/\s/g, '-') + '.txt', `fix(36.12-05): ${m}`); + } + fs.writeFileSync(path.join(dir, 'uncommitted.txt'), 'work in progress\n'); + + const r = runGuard(dir); + assert.equal(r.status, 1, 'the guard must still REFUSE — #48 is load-bearing'); + assert.match(r.stderr, /worktree-agent-36\.12-05-090827/, 'names the branch'); + + // The whole point of #1856: the refusal must not be a dead end. + assert.match( + r.stderr, + /5\s+commit/i, + 'must report how many commits are stranded on the agent branch — without this the ' + + 'user cannot tell that switching away loses work (#1856)', + ); + assert.match( + r.stderr, + /uncommitted|dirty|unstaged/i, + 'must report that the worktree still has uncommitted changes (#1856)', + ); + assert.match( + r.stderr, + /cherry-pick|merge/i, + 'must give an integration command, not just "re-run from the orchestrator worktree"', + ); + } finally { + cleanup(dir); + } +}); + +test('#1856: the bare agent- namespace is handled identically', () => { + const dir = makeRepo(); + try { + git(dir, 'checkout', '--quiet', '-b', 'agent-a1b2c3'); + commitFile(dir, 'one.txt', 'feat: one'); + const r = runGuard(dir); + assert.equal(r.status, 1); + assert.match(r.stderr, /agent-a1b2c3/); + assert.match(r.stderr, /1\s+commit/i); + } finally { + cleanup(dir); + } +}); + +test('#1856: a clean agent worktree still refuses, without a wall of empty sections', () => { + const dir = makeRepo(); + try { + git(dir, 'checkout', '--quiet', '-b', 'agent-clean'); + const r = runGuard(dir); + assert.equal(r.status, 1, 'still refuses'); + // Nothing is stranded, so nothing must be claimed to be. + assert.doesNotMatch( + r.stderr, + /\b[1-9]\d*\s+commit/i, + 'a branch with no commits ahead must not report stranded commits', + ); + assert.doesNotMatch( + r.stderr, + /uncommitted changes/i, + 'a clean tree must not be reported as dirty', + ); + } finally { + cleanup(dir); + } +}); + +test('#1856: boundary — 1 and 2 commits ahead are both reported accurately', () => { + for (const n of [1, 2]) { + const dir = makeRepo(); + try { + git(dir, 'checkout', '--quiet', '-b', 'agent-count'); + for (let i = 0; i < n; i += 1) commitFile(dir, `c${i}.txt`, `feat: c${i}`); + const r = runGuard(dir); + assert.equal(r.status, 1); + assert.match(r.stderr, new RegExp(`\\b${n}\\s+commit`, 'i'), `${n} ahead reported`); + } finally { + cleanup(dir); + } + } +}); + +test('#1856: does not fire on an ordinary orchestrator branch', () => { + const dir = makeRepo(); + try { + const r = runGuard(dir); // still on `next` + assert.equal(r.status, 0, `guard must not fire on a normal branch: ${r.stderr}`); + assert.doesNotMatch(r.stderr, /refusing to execute waves/); + } finally { + cleanup(dir); + } +}); + +test('#1856: does not fire on a branch that merely starts with "agent"', () => { + const dir = makeRepo(); + try { + // The discriminator is the `agent-` NAMESPACE. `agentic-refactor` is an + // ordinary feature branch and must run. + git(dir, 'checkout', '--quiet', '-b', 'agentic-refactor'); + const r = runGuard(dir); + assert.equal(r.status, 0, `guard must not fire on agentic-refactor: ${r.stderr}`); + } finally { + cleanup(dir); + } +}); + +test('#1856: does not fire on a legitimate feature worktree', () => { + // Recorded constraint in the guard's own comment: the discriminator is the branch + // namespace, NOT the .claude/worktrees/ path — the orchestrator may legitimately + // run from a feature worktree there, and a path check would break that. + const dir = makeRepo(); + try { + const wt = path.join(dir, '.claude', 'worktrees', 'feature'); + fs.mkdirSync(path.dirname(wt), { recursive: true }); + git(dir, 'worktree', 'add', '--quiet', '-b', 'feat/legit', wt); + const r = runGuard(wt); + assert.equal(r.status, 0, `a feature worktree must run: ${r.stderr}`); + } finally { + cleanup(dir); + } +}); + +test('#1856: reporting degrades to the plain refusal when no base ref resolves', () => { + // No origin, no main/next to compare against — the guard must still refuse + // cleanly rather than crash or hang before printing. + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1856-nobase-')); + try { + git(dir, 'init', '--quiet', '--initial-branch', 'agent-orphan'); + git(dir, 'config', 'user.email', 'test@example.com'); + git(dir, 'config', 'user.name', 'Test'); + fs.writeFileSync(path.join(dir, 'a.txt'), 'a\n'); + git(dir, 'add', '-A'); + git(dir, 'commit', '--quiet', '-m', 'only'); + const r = runGuard(dir); + assert.equal(r.status, 1, 'still refuses with no resolvable base'); + assert.match(r.stderr, /refusing to execute waves/); + } finally { + cleanup(dir); + } +}); + +test('#1856: detached HEAD does not crash the guard', () => { + const dir = makeRepo(); + try { + const sha = git(dir, 'rev-parse', 'HEAD').trim(); + git(dir, 'checkout', '--quiet', '--detach', sha); + const r = runGuard(dir); + // `rev-parse --abbrev-ref HEAD` yields "HEAD" when detached — not an agent + // branch, so the guard must pass through without erroring. + assert.equal(r.status, 0, `detached HEAD must not crash the guard: ${r.stderr}`); + } finally { + cleanup(dir); + } +}); diff --git a/tests/fixtures/golden-install-parity/antigravity.json b/tests/fixtures/golden-install-parity/antigravity.json index 37b4f3c73..6c9828c6a 100644 --- a/tests/fixtures/golden-install-parity/antigravity.json +++ b/tests/fixtures/golden-install-parity/antigravity.json @@ -248,7 +248,7 @@ "gsd-core/workflows/docs-update.md": "53dd4148dd0f4c90", "gsd-core/workflows/edit-phase.md": "fc932e82ba1f585a", "gsd-core/workflows/eval-review.md": "610775f4968f7807", - "gsd-core/workflows/execute-phase.md": "8c0521b091bbc1b5", + "gsd-core/workflows/execute-phase.md": "a20deff10f1a9c7b", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "1832b97d0923fa67", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "0404bcd32f47715e", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/augment.json b/tests/fixtures/golden-install-parity/augment.json index 9e790165b..6ff89fdc9 100644 --- a/tests/fixtures/golden-install-parity/augment.json +++ b/tests/fixtures/golden-install-parity/augment.json @@ -319,7 +319,7 @@ "gsd-core/workflows/docs-update.md": "fba7329f525c9463", "gsd-core/workflows/edit-phase.md": "966a3eadd1bebc04", "gsd-core/workflows/eval-review.md": "c2933259ff7fb6ac", - "gsd-core/workflows/execute-phase.md": "fcc3181bc5593f8f", + "gsd-core/workflows/execute-phase.md": "d9ecf8b35ae4a771", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "f7782680c2b8ad6b", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "ab70374e44eb85cd", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/claude-local.json b/tests/fixtures/golden-install-parity/claude-local.json index 0cb522118..3e7f559e2 100644 --- a/tests/fixtures/golden-install-parity/claude-local.json +++ b/tests/fixtures/golden-install-parity/claude-local.json @@ -318,7 +318,7 @@ "gsd-core/workflows/docs-update.md": "dc44aa6aab38535d", "gsd-core/workflows/edit-phase.md": "dbbb6191f5a8b65e", "gsd-core/workflows/eval-review.md": "c0cf2d0c5dd9df36", - "gsd-core/workflows/execute-phase.md": "abebe1ef79aa5786", + "gsd-core/workflows/execute-phase.md": "3a1457523d8cf965", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "9a1f3deffb4dab14", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "ea0ebff5ac00fee6", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/claude.json b/tests/fixtures/golden-install-parity/claude.json index fccc728b2..97c7c736e 100644 --- a/tests/fixtures/golden-install-parity/claude.json +++ b/tests/fixtures/golden-install-parity/claude.json @@ -247,7 +247,7 @@ "gsd-core/workflows/docs-update.md": "7a0be3529a99b11f", "gsd-core/workflows/edit-phase.md": "8323bfe10faa0c0a", "gsd-core/workflows/eval-review.md": "02cefe2dbdd0af52", - "gsd-core/workflows/execute-phase.md": "f88215925dc01075", + "gsd-core/workflows/execute-phase.md": "4bc5300e8b3aa889", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "d2020c5e01c7bd7f", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "ab70374e44eb85cd", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/cline.json b/tests/fixtures/golden-install-parity/cline.json index 97c6f1701..cdd9d37f2 100644 --- a/tests/fixtures/golden-install-parity/cline.json +++ b/tests/fixtures/golden-install-parity/cline.json @@ -251,7 +251,7 @@ "gsd-core/workflows/docs-update.md": "5f953a0d4c0f3cad", "gsd-core/workflows/edit-phase.md": "9c9fadc047c61d74", "gsd-core/workflows/eval-review.md": "f67caf4dba0586d1", - "gsd-core/workflows/execute-phase.md": "769064cfeb1baf4a", + "gsd-core/workflows/execute-phase.md": "b8c122c15467a6d8", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "1b3558cb8f41b65a", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "e01459552d587863", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/codebuddy.json b/tests/fixtures/golden-install-parity/codebuddy.json index 1471d6f95..440cbf00b 100644 --- a/tests/fixtures/golden-install-parity/codebuddy.json +++ b/tests/fixtures/golden-install-parity/codebuddy.json @@ -319,7 +319,7 @@ "gsd-core/workflows/docs-update.md": "fba7329f525c9463", "gsd-core/workflows/edit-phase.md": "966a3eadd1bebc04", "gsd-core/workflows/eval-review.md": "c2933259ff7fb6ac", - "gsd-core/workflows/execute-phase.md": "79e703c637e2d7b1", + "gsd-core/workflows/execute-phase.md": "40765d7517891c09", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "f7782680c2b8ad6b", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "ab70374e44eb85cd", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/codex.json b/tests/fixtures/golden-install-parity/codex.json index 50e1ddcd7..92b672742 100644 --- a/tests/fixtures/golden-install-parity/codex.json +++ b/tests/fixtures/golden-install-parity/codex.json @@ -354,7 +354,7 @@ "gsd-core/workflows/docs-update.md": "2b0db5c092ac573d", "gsd-core/workflows/edit-phase.md": "e592a4d85ce5380f", "gsd-core/workflows/eval-review.md": "4d367d1e028629bd", - "gsd-core/workflows/execute-phase.md": "7bcc0a33f91336c7", + "gsd-core/workflows/execute-phase.md": "4d94ef7b8cf41b80", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "cd8678d082d6e191", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "ab70374e44eb85cd", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/copilot.json b/tests/fixtures/golden-install-parity/copilot.json index b0ad6343a..3816ab26b 100644 --- a/tests/fixtures/golden-install-parity/copilot.json +++ b/tests/fixtures/golden-install-parity/copilot.json @@ -249,7 +249,7 @@ "gsd-core/workflows/docs-update.md": "df1d2f6a653e0bb4", "gsd-core/workflows/edit-phase.md": "8667c28b22b1599f", "gsd-core/workflows/eval-review.md": "6fd7f2b0770b48f1", - "gsd-core/workflows/execute-phase.md": "d9ad04be8e897208", + "gsd-core/workflows/execute-phase.md": "261fb868e55c9289", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "ca37f91f7bd6f05c", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "e0ec3d9748a0fed9", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/cursor.json b/tests/fixtures/golden-install-parity/cursor.json index 1a8725513..666322185 100644 --- a/tests/fixtures/golden-install-parity/cursor.json +++ b/tests/fixtures/golden-install-parity/cursor.json @@ -319,7 +319,7 @@ "gsd-core/workflows/docs-update.md": "b4bf43f3005f2e45", "gsd-core/workflows/edit-phase.md": "8323bfe10faa0c0a", "gsd-core/workflows/eval-review.md": "e8a7646e1699a17d", - "gsd-core/workflows/execute-phase.md": "e8ddb24f9cdca5f0", + "gsd-core/workflows/execute-phase.md": "f33882f452e603d0", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "d2020c5e01c7bd7f", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "06b54ecd4015c64c", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/hermes.json b/tests/fixtures/golden-install-parity/hermes.json index c3f18bfe8..047049a87 100644 --- a/tests/fixtures/golden-install-parity/hermes.json +++ b/tests/fixtures/golden-install-parity/hermes.json @@ -248,7 +248,7 @@ "gsd-core/workflows/docs-update.md": "c017abde0209656e", "gsd-core/workflows/edit-phase.md": "7f27003f20e88fb8", "gsd-core/workflows/eval-review.md": "6d1c9c167f91b0f8", - "gsd-core/workflows/execute-phase.md": "fcf5f258a1e2aeea", + "gsd-core/workflows/execute-phase.md": "e66dfb357797ab51", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "9b2193de25506b3b", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "4dfefdd56d814d06", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "26ee34c543926402", diff --git a/tests/fixtures/golden-install-parity/kilo.json b/tests/fixtures/golden-install-parity/kilo.json index d09713679..8d740a30f 100644 --- a/tests/fixtures/golden-install-parity/kilo.json +++ b/tests/fixtures/golden-install-parity/kilo.json @@ -319,7 +319,7 @@ "gsd-core/workflows/docs-update.md": "4bbc9fcc8fea78a0", "gsd-core/workflows/edit-phase.md": "8323bfe10faa0c0a", "gsd-core/workflows/eval-review.md": "fb3b8244d66972ee", - "gsd-core/workflows/execute-phase.md": "e41ab56e1388afc8", + "gsd-core/workflows/execute-phase.md": "f0697801da646722", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "b1e6588cd32a6f08", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "ab70374e44eb85cd", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/kimi-code.json b/tests/fixtures/golden-install-parity/kimi-code.json index 2a4c9d688..6aa93cae2 100644 --- a/tests/fixtures/golden-install-parity/kimi-code.json +++ b/tests/fixtures/golden-install-parity/kimi-code.json @@ -277,7 +277,7 @@ "gsd-core/workflows/docs-update.md": "fba7329f525c9463", "gsd-core/workflows/edit-phase.md": "966a3eadd1bebc04", "gsd-core/workflows/eval-review.md": "c2933259ff7fb6ac", - "gsd-core/workflows/execute-phase.md": "6a663b8755ed216e", + "gsd-core/workflows/execute-phase.md": "87111d41f6498208", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "f7782680c2b8ad6b", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "ab70374e44eb85cd", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/kimi.json b/tests/fixtures/golden-install-parity/kimi.json index c13b9cae0..a16822f4a 100644 --- a/tests/fixtures/golden-install-parity/kimi.json +++ b/tests/fixtures/golden-install-parity/kimi.json @@ -313,7 +313,7 @@ "gsd-core/workflows/docs-update.md": "fba7329f525c9463", "gsd-core/workflows/edit-phase.md": "966a3eadd1bebc04", "gsd-core/workflows/eval-review.md": "c2933259ff7fb6ac", - "gsd-core/workflows/execute-phase.md": "df8c032fb91cedbd", + "gsd-core/workflows/execute-phase.md": "357e82b83fb4719d", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "f7782680c2b8ad6b", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "ab70374e44eb85cd", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/opencode.json b/tests/fixtures/golden-install-parity/opencode.json index 78d0d3fe0..efe764e86 100644 --- a/tests/fixtures/golden-install-parity/opencode.json +++ b/tests/fixtures/golden-install-parity/opencode.json @@ -319,7 +319,7 @@ "gsd-core/workflows/docs-update.md": "55cbaed5020bdd71", "gsd-core/workflows/edit-phase.md": "1876c855fb0a0a39", "gsd-core/workflows/eval-review.md": "4f932c3ea3eb807b", - "gsd-core/workflows/execute-phase.md": "78169e590b406fa8", + "gsd-core/workflows/execute-phase.md": "983551331e155e7d", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "a15993affd62f4bf", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "f74ce2de21b2d252", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/pi.json b/tests/fixtures/golden-install-parity/pi.json index 1e06343f3..0179ab3fd 100644 --- a/tests/fixtures/golden-install-parity/pi.json +++ b/tests/fixtures/golden-install-parity/pi.json @@ -215,7 +215,7 @@ "gsd-core/workflows/docs-update.md": "fba7329f525c9463", "gsd-core/workflows/edit-phase.md": "966a3eadd1bebc04", "gsd-core/workflows/eval-review.md": "c2933259ff7fb6ac", - "gsd-core/workflows/execute-phase.md": "4eddcc41c823db8b", + "gsd-core/workflows/execute-phase.md": "be00d0535fa8c720", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "f7782680c2b8ad6b", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "ab70374e44eb85cd", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/qwen.json b/tests/fixtures/golden-install-parity/qwen.json index cbedd6679..719896c53 100644 --- a/tests/fixtures/golden-install-parity/qwen.json +++ b/tests/fixtures/golden-install-parity/qwen.json @@ -248,7 +248,7 @@ "gsd-core/workflows/docs-update.md": "03599fe1d110e511", "gsd-core/workflows/edit-phase.md": "0fb5e0123cfc6f36", "gsd-core/workflows/eval-review.md": "57a5eaade256fee4", - "gsd-core/workflows/execute-phase.md": "da1e79f7407090a9", + "gsd-core/workflows/execute-phase.md": "5f70bb011fd5ca0d", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "0e0949db56deebeb", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "2ca3c7397d44613f", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/trae.json b/tests/fixtures/golden-install-parity/trae.json index fa0f506d9..60307b4b2 100644 --- a/tests/fixtures/golden-install-parity/trae.json +++ b/tests/fixtures/golden-install-parity/trae.json @@ -248,7 +248,7 @@ "gsd-core/workflows/docs-update.md": "78cd8efff2717c77", "gsd-core/workflows/edit-phase.md": "7facd0faa33c8cad", "gsd-core/workflows/eval-review.md": "263c8971520f632e", - "gsd-core/workflows/execute-phase.md": "67f3aaa7eae674e2", + "gsd-core/workflows/execute-phase.md": "695cf3c2b07e8920", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "296b812e8d0e9ce8", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "c1d6db937a51d433", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/windsurf.json b/tests/fixtures/golden-install-parity/windsurf.json index 378304a75..60b7431c4 100644 --- a/tests/fixtures/golden-install-parity/windsurf.json +++ b/tests/fixtures/golden-install-parity/windsurf.json @@ -248,7 +248,7 @@ "gsd-core/workflows/docs-update.md": "8fd49fe7a89da620", "gsd-core/workflows/edit-phase.md": "c0ae7d0063f3e789", "gsd-core/workflows/eval-review.md": "26051580110e6217", - "gsd-core/workflows/execute-phase.md": "043544b7a948cae5", + "gsd-core/workflows/execute-phase.md": "383836c8c1d0fa7e", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "3194ecd382690755", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "becb931701890353", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/fixtures/golden-install-parity/zcode.json b/tests/fixtures/golden-install-parity/zcode.json index 16a0dedc5..b65e677ed 100644 --- a/tests/fixtures/golden-install-parity/zcode.json +++ b/tests/fixtures/golden-install-parity/zcode.json @@ -319,7 +319,7 @@ "gsd-core/workflows/docs-update.md": "fba7329f525c9463", "gsd-core/workflows/edit-phase.md": "966a3eadd1bebc04", "gsd-core/workflows/eval-review.md": "c2933259ff7fb6ac", - "gsd-core/workflows/execute-phase.md": "1fb281c6e0511e2a", + "gsd-core/workflows/execute-phase.md": "3ffcd069e2aeb62b", "gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "f7782680c2b8ad6b", "gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md": "ab70374e44eb85cd", "gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028", diff --git a/tests/workflow-size-baseline.json b/tests/workflow-size-baseline.json index 000230c7e..300efa2f5 100644 --- a/tests/workflow-size-baseline.json +++ b/tests/workflow-size-baseline.json @@ -24,7 +24,7 @@ "docs-update.md": 56876, "edit-phase.md": 12927, "eval-review.md": 10316, - "execute-phase.md": 90143, + "execute-phase.md": 92874, "execute-plan.md": 35143, "explore.md": 11127, "extract-learnings.md": 13762,