diff --git a/.changeset/quick-birds-run.md b/.changeset/quick-birds-run.md new file mode 100644 index 000000000..c1d3260be --- /dev/null +++ b/.changeset/quick-birds-run.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 2905 +--- +**`/gsd-code-review --fix` now honors `workflow.use_worktrees`** — when the setting is `false`, the fixer edits and commits in the main checkout instead of creating a git worktree (matching the other writer workflows), and the spec forbids `rm -rf` on a possible Windows reparse point so an improvised worktree teardown can no longer delete the real `node_modules`. The REVIEW-FIX report also records where verification ran. diff --git a/agents/gsd-code-fixer.md b/agents/gsd-code-fixer.md index f4394d2a2..4126a6157 100644 --- a/agents/gsd-code-fixer.md +++ b/agents/gsd-code-fixer.md @@ -216,9 +216,36 @@ If a finding references multiple files (in Fix section or Issue section): This agent runs as a background process that makes commits. Operating on the main working tree would race the foreground session (shared index, HEAD, and on-disk files). Instead, every instance runs in its own isolated worktree. +**#2825: honor `workflow.use_worktrees`.** This is the ONLY writer that hand-rolls a git worktree +inside the agent prompt; every other writer path (`/gsd:execute-phase`, `/gsd:execute-plan`, +`/gsd:quick`, `/gsd:diagnose-issues`) reads `workflow.use_worktrees` and skips isolation when it is +`false`. Read the same flag here and, when it is `false`, edit and commit in the main checkout +directly (set `wt="."`, no `reviewfix_branch`, no recovery sentinel, no `git worktree add`, and skip +the cleanup tail — there is no worktree to remove). When the flag is not `false`, the transactional +worktree path below runs unchanged. A user who explicitly opted out of worktrees must never have a +worktree created; the hand-rolled worktree also cannot run the project's gates safely (no +`node_modules`), so the opt-out is also the safe path. + The cleanup tail (commit fixes -> remove worktree -> drop recovery sentinel) MUST be **transactional**: either all of (worktree, branch advance, sentinel) end in a clean state, or — if the process is interrupted (system restart, OOM kill) between the last commit and `git worktree remove` — a discoverable recovery sentinel is left behind so a future run, `/gsd:resume-work`, or `/gsd:progress` can complete the cleanup. The bug fixed by #2839 was that the cleanup tail was non-transactional and silently left orphan worktrees + unmerged branches with no resume marker. ```bash +# #2825: honor workflow.use_worktrees — the documented opt-out. When false, +# edit/commit in the main checkout (wt=".", no temp branch, no sentinel, no +# cleanup tail). Read the flag the same way the four sibling writer workflows +# do. NOTE: this read parses .planning/config.json directly via `node` rather +# than the gsd-tools CLI, because setup_worktree runs BEFORE the canonical +# launcher preamble is sourced — invoking the CLI here would be undefined at +# runtime and violates the runtime-launcher-parity preamble-ordering rule. +# Once the preamble is sourced (later steps), the CLI is available. +USE_WORKTREES=$(node -e ' + try { + const fs = require("fs"); + const p = (process.env.GSD_PROJECT_DIR || process.cwd()) + "/.planning/config.json"; + const cfg = JSON.parse(fs.readFileSync(p, "utf8")); + process.stdout.write(String((cfg.workflow && cfg.workflow.use_worktrees) ?? true)); + } catch { process.stdout.write("true"); } +') + # Derive worktree path from padded_phase (parsed from config in next step, # but the shell snippet below is illustrative — adapt once config is parsed). # In practice: parse padded_phase from config first, then run: @@ -264,34 +291,47 @@ if [ -f "$sentinel" ]; then rm -f "$sentinel" fi -wt=$(mktemp -d "/tmp/sv-${padded_phase}-reviewfix-XXXXXX") +# #2825: when the user opted out of worktrees, edit/commit in the main +# checkout directly — no temp branch, no sentinel, no cleanup tail. This is +# the safe path: the hand-rolled worktree has no node_modules, so it cannot +# run the project's gates, and an improvised teardown can destroy the real +# node_modules on Windows (a junction followed by rm -rf). wt="." means every +# downstream read/edit/commit lands in the main working tree, and the cleanup +# tail below is a no-op (nothing to fast-forward, no worktree to remove). +if [ "$USE_WORKTREES" = "false" ]; then + wt="." + reviewfix_branch="$branch" + echo "workflow.use_worktrees=false — editing/committing in the main checkout (no worktree)." +else + wt=$(mktemp -d "/tmp/sv-${padded_phase}-reviewfix-XXXXXX") -# Create a temp branch from the current branch tip so the worktree -# attaches to that NEW branch rather than the user's currently-checked-out -# branch (#2990: git refuses to check out the same branch in two -# worktrees by default; the original `git worktree add "$wt" "$branch"` -# failed before the agent could do any work). The temp branch shares -# history with $branch up to the moment of creation, so commits made -# inside the worktree fast-forward $branch on cleanup. -reviewfix_branch="gsd-reviewfix/${padded_phase}-$$" -git worktree add -b "$reviewfix_branch" "$wt" "$branch" + # Create a temp branch from the current branch tip so the worktree + # attaches to that NEW branch rather than the user's currently-checked-out + # branch (#2990: git refuses to check out the same branch in two + # worktrees by default; the original `git worktree add "$wt" "$branch"` + # failed before the agent could do any work). The temp branch shares + # history with $branch up to the moment of creation, so commits made + # inside the worktree fast-forward $branch on cleanup. + reviewfix_branch="gsd-reviewfix/${padded_phase}-$$" + git worktree add -b "$reviewfix_branch" "$wt" "$branch" -# Write the recovery sentinel ONLY AFTER `git worktree add` succeeds. -# Writing it before would leave a sentinel pointing at a worktree that does -# not exist if `git worktree add` itself failed. -node -e ' - const fs = require("fs"); - const [sentinelPath, worktree_path, branch, reviewfix_branch, padded_phase] = process.argv.slice(1); - fs.writeFileSync(sentinelPath, JSON.stringify({ - worktree_path, - branch, - reviewfix_branch, - padded_phase, - started_at: new Date().toISOString() - }, null, 2)); -' "$sentinel" "$wt" "$branch" "$reviewfix_branch" "$padded_phase" + # Write the recovery sentinel ONLY AFTER `git worktree add` succeeds. + # Writing it before would leave a sentinel pointing at a worktree that does + # not exist if `git worktree add` itself failed. + node -e ' + const fs = require("fs"); + const [sentinelPath, worktree_path, branch, reviewfix_branch, padded_phase] = process.argv.slice(1); + fs.writeFileSync(sentinelPath, JSON.stringify({ + worktree_path, + branch, + reviewfix_branch, + padded_phase, + started_at: new Date().toISOString() + }, null, 2)); + ' "$sentinel" "$wt" "$branch" "$reviewfix_branch" "$padded_phase" -cd "$wt" + cd "$wt" +fi ``` Concrete steps: @@ -305,9 +345,18 @@ Concrete steps: **If `git worktree add` fails**, surface the error and exit — do not force-remove the path, as another concurrent run may be holding it. Do not write the sentinel (the worktree does not exist). Do not delete `$reviewfix_branch` either; if `-b` failed, no temp branch was created. -**Cleanup tail (transactional, ALWAYS — even on failure):** After writing REVIEW-FIX.md and before returning to the orchestrator, run the cleanup in this exact order: +**Cleanup tail (transactional, ALWAYS — even on failure — when a worktree was created):** After writing REVIEW-FIX.md and before returning to the orchestrator, run the cleanup in this exact order. (When `workflow.use_worktrees` is `false`, no worktree was created — the cleanup is a no-op and the bash below early-exits.) ```bash +# #2825: when worktrees were disabled, there is nothing to clean up — the +# agent edited/committed on $branch directly in the main checkout (wt=".", +# reviewfix_branch==$branch, no sentinel, no temp worktree). Skip the whole +# tail; the four steps below are all no-ops or harmful (e.g. `git worktree +# remove "."` ) in that mode. +if [ "$USE_WORKTREES" = "false" ]; then + exit 0 +fi + # Step 1 (#2990): fast-forward $branch to capture the commits the agent # made on $reviewfix_branch. Run from the main repo (not $wt) — the user's # checkout owns $branch. --ff-only ensures we never silently drop or @@ -354,7 +403,7 @@ fi rm -f "$sentinel" ``` -This cleanup is unconditional — register it mentally as a finally-block obligation. If the agent exits early (config error, no findings, etc.), still run the cleanup tail in order (fast-forward → worktree remove → temp branch delete → sentinel rm) before exit. The sentinel must NEVER be removed before `git worktree remove` succeeds. The temp branch must NEVER be deleted while the fast-forward is in a diverged state. +This cleanup is unconditional when a worktree was created — register it mentally as a finally-block obligation. If the agent exits early (config error, no findings, etc.), still run the cleanup tail in order (fast-forward → worktree remove → temp branch delete → sentinel rm) before exit. (When `workflow.use_worktrees` is `false`, no worktree exists and the bash above early-exits before these steps.) The sentinel must NEVER be removed before `git worktree remove` succeeds. The temp branch must NEVER be deleted while the fast-forward is in a diverged state. @@ -587,9 +636,33 @@ _Iteration: {N}_ -**ALWAYS run inside the isolated worktree** — set up via `branch=$(git branch --show-current)` + `wt=$(mktemp -d "/tmp/sv-${padded_phase}-reviewfix-XXXXXX")` + `git worktree add -b "$reviewfix_branch" "$wt" "$branch"` at the very start (see `setup_worktree` step). Using `mktemp` ensures concurrent runs do not collide. Attaching to a NEW branch `$reviewfix_branch` (not `$branch` directly) is required because git refuses to check out the same branch in two worktrees by default — `$branch` is already checked out in the user's main repo (#2990). Commits advance `$reviewfix_branch`; the cleanup tail fast-forwards `$branch` to `$reviewfix_branch` so the user's branch ends up with the agent's commits. Every file read, edit, and commit must happen inside `$wt`. Run the four-step cleanup tail unconditionally when done (treat it as a finally block). If `git worktree add` fails, exit with an error rather than force-removing a path another run may hold. This prevents racing the foreground session on the shared main working tree (#2686). +**ALWAYS run inside the isolated worktree** — set up via `branch=$(git branch --show-current)` + `wt=$(mktemp -d "/tmp/sv-${padded_phase}-reviewfix-XXXXXX")` + `git worktree add -b "$reviewfix_branch" "$wt" "$branch"` at the very start (see `setup_worktree` step). Using `mktemp` ensures concurrent runs do not collide. Attaching to a NEW branch `$reviewfix_branch` (not `$branch` directly) is required because git refuses to check out the same branch in two worktrees by default — `$branch` is already checked out in the user's main repo (#2990). Commits advance `$reviewfix_branch`; the cleanup tail fast-forwards `$branch` to `$reviewfix_branch` so the user's branch ends up with the agent's commits. Every file read, edit, and commit must happen inside `$wt`. Run the four-step cleanup tail when done (treat it as a finally block) — but only when a worktree was actually created; when `workflow.use_worktrees` is `false` the cleanup early-exits (no worktree to remove). If `git worktree add` fails, exit with an error rather than force-removing a path another run may hold. This prevents racing the foreground session on the shared main working tree (#2686). -**ALWAYS run the transactional cleanup tail in order** (#2839, #2990): the cleanup is four steps with strict ordering. (1) `git -C "$main_repo" merge --ff-only "$reviewfix_branch"` — fast-forward the user's branch to capture the agent's commits; on divergence, fail loudly and preserve the temp branch. (2) `git worktree remove "$wt" --force`. (3) `git -C "$main_repo" branch -D "$reviewfix_branch"` ONLY if the fast-forward succeeded; otherwise leave the temp branch for manual merge. (4) `rm -f "$sentinel"` (the recovery sentinel at `${phase_dir}/.review-fix-recovery-pending.json`). The sentinel is written AFTER `git worktree add` succeeds and removed only AFTER `git worktree remove` returns successfully. The temp branch is deleted only when the fast-forward succeeded. This ordering is what makes the cleanup tail transactional — an interruption between commits and `git worktree remove` leaves the sentinel behind (with `reviewfix_branch` recorded) so a future run, `/gsd:resume-work`, or `/gsd:progress` can detect and complete the recovery. Reversing the order recreates the orphan-worktree bug. +**#2825 — honor `workflow.use_worktrees`.** Before creating a worktree, read the +`workflow.use_worktrees` config flag (the documented opt-out — same key the four sibling writer +workflows honor). `setup_worktree` reads it via `node` directly from `.planning/config.json` +(because that step runs BEFORE the canonical gsd_run launcher preamble is sourced; later steps may +use `gsd_run query config-get workflow.use_worktrees`). When it is `false`, do NOT create a worktree +— edit and commit in the main checkout directly (`wt="."`, no temp branch, no sentinel, no cleanup +tail). A user who opted out of worktrees must +never have one created. See the `setup_worktree` step for the gated bash. + +**NEVER `rm -rf` a possible reparse point** (#2825). On Windows, `node_modules` inside the worktree +may be a junction/reparse point whose target is the REAL `node_modules` in the main checkout — and +`rm -rf` follows the link and deletes the target's contents (silent, misdiagnosable data loss). Do +NOT improvise a `node_modules` teardown. The worktree has no `node_modules` by design; if you need +the project's gates, run them in the main checkout after the fast-forward, OR leave the worktree's +dependency handling to `git worktree remove` (which does not recurse into a separately-managed +link). Never use `rm -rf` (or `2>/dev/null || rm -rf || true`) as a fallback for removing a path +that might be a reparse point — on failure, STOP and surface the error rather than falling through +to a destructive remove. + +**Record where verification ran** (#2825). The REVIEW-FIX.md verification section must state whether +the gates ran in the main checkout or the isolated worktree, so a reader can tell whether the numbers +are reproducible from the tree they are looking at (a worktree-env run is not reproducible from the +main checkout after teardown). + +**ALWAYS run the transactional cleanup tail in order when a worktree was created** (#2839, #2990; skipped — bash early-exits — when `workflow.use_worktrees` is `false`): the cleanup is four steps with strict ordering. (1) `git -C "$main_repo" merge --ff-only "$reviewfix_branch"` — fast-forward the user's branch to capture the agent's commits; on divergence, fail loudly and preserve the temp branch. (2) `git worktree remove "$wt" --force`. (3) `git -C "$main_repo" branch -D "$reviewfix_branch"` ONLY if the fast-forward succeeded; otherwise leave the temp branch for manual merge. (4) `rm -f "$sentinel"` (the recovery sentinel at `${phase_dir}/.review-fix-recovery-pending.json`). The sentinel is written AFTER `git worktree add` succeeds and removed only AFTER `git worktree remove` returns successfully. The temp branch is deleted only when the fast-forward succeeded. This ordering is what makes the cleanup tail transactional — an interruption between commits and `git worktree remove` leaves the sentinel behind (with `reviewfix_branch` recorded) so a future run, `/gsd:resume-work`, or `/gsd:progress` can detect and complete the recovery. Reversing the order recreates the orphan-worktree bug. **ALWAYS use the Write tool to create files** — never use `Bash(cat << 'EOF')` or heredoc commands for file creation. diff --git a/tests/code-review.test.cjs b/tests/code-review.test.cjs index cd4f554b8..0e2940949 100644 --- a/tests/code-review.test.cjs +++ b/tests/code-review.test.cjs @@ -260,6 +260,39 @@ describe('CR-AGENT: code review agent frontmatter', () => { assert.ok(content.includes('files_reviewed_list'), 'gsd-code-reviewer REVIEW.md frontmatter spec must include files_reviewed_list for --auto scope persistence'); }); + + // #2825: gsd-code-fixer is the only writer that hand-rolls a git worktree; it + // must honor workflow.use_worktrees (the documented opt-out) like its four + // sibling writer workflows, and never rm -rf a possible Windows reparse point. + test('#2825 gsd-code-fixer.md reads workflow.use_worktrees and gates git worktree add on it', () => { + const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-fixer.md'), 'utf-8'); + assert.ok( + content.includes('workflow.use_worktrees'), + 'gsd-code-fixer setup_worktree must read the workflow.use_worktrees config flag (#2825)', + ); + // The git worktree add must be CONDITIONAL on the flag, not unconditional. + // Locate the worktree-add line and confirm a USE_WORKTREES gate precedes it. + assert.ok( + /USE_WORKTREES=.false./.test(content) || content.includes('if [ "$USE_WORKTREES" = "false" ]'), + 'gsd-code-fixer must gate worktree creation on USE_WORKTREES=false (skip when opted out) (#2825)', + ); + }); + + test('#2825 gsd-code-fixer.md forbids rm -rf on a possible reparse point (Windows junction safety)', () => { + const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-fixer.md'), 'utf-8'); + assert.ok( + /rm -rf.*reparse point|reparse point.*rm -rf|NEVER .rm -rf.|never use .rm -rf/i.test(content), + 'gsd-code-fixer must forbid rm -rf on a possible reparse point/junction (#2825) — on Windows that is the delete-the-target path', + ); + }); + + test('#2825 gsd-code-fixer.md records where verification ran (main checkout vs worktree)', () => { + const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-fixer.md'), 'utf-8'); + assert.ok( + /verification[\s\S]*(main checkout|worktree)|(main checkout|worktree)[\s\S]*verification/i.test(content), + 'gsd-code-fixer REVIEW-FIX.md must record where verification ran (main checkout vs worktree) so a reader knows if the numbers are reproducible (#2825)', + ); + }); }); // --- CR-CMD: code review command structure --- diff --git a/tests/emitted-drift-ack.json b/tests/emitted-drift-ack.json index 5ca42ea3a..1284ce27d 100644 --- a/tests/emitted-drift-ack.json +++ b/tests/emitted-drift-ack.json @@ -1,119 +1,39 @@ { "version": 1, "paths": { - "plan-phase.md": { - "reason": "#2770: decision-coverage gate recomputes CONTEXT_PATH in-block + guards the empty-glob case (handler now fails closed on empty arg). Net growth kept under the ADR-857 size cap by condensing adjacent \u00a713a prose/JSON; the residual +89 bytes are the irreducible glob+guard logic." - }, - "discuss-phase-assumptions.md": { - "reason": "#2772: re-synced to the parent canonical block (had drifted \u2014 lost the 'Other' empty-text branch) + fixed the auto_advance\u2192confirm_creation circularity (end the workflow). discuss-phase.md is net -11 (condensed); auto.md shrank -4650 (removed a dead MAX_PASSES resolver shim)." - }, - "autonomous.md": { - "reason": "#2800 \u2014 the hand-enumerated reviewer-flag list is replaced by a loop over `gsd_run review-lane flags`, and the whole CONVERGENCE_ARGS construction is relocated below the runtime-launcher preamble because it now calls gsd_run and each bash fence is its own shell. Growth is the explanatory comments carrying that constraint plus the loop body, against nine deleted flag literals. Deliberate: the byte delta is the cost of the flags no longer being hand-maintained in three places that had drifted apart." - }, - "next.md": { - "reason": "#2800 \u2014 same derived-flag-loop change as autonomous.md. next.md needed no relocation (its launcher preamble already precedes the loop), so the growth here is only the loop plus the comment recording that --all and --text stay literal because they are convergence controls, not reviewer lanes." - }, - "agents/gsd-advisor-researcher.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-ai-researcher.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-assumptions-analyzer.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-code-fixer.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-code-reviewer.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-codebase-mapper.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-debug-session-manager.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-debugger.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-doc-classifier.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-doc-synthesizer.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-doc-verifier.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-doc-writer.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-domain-researcher.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-eval-auditor.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-eval-planner.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-executor.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-framework-selector.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-integration-checker.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-intel-updater.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-mempalace-curator.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-nyquist-auditor.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-pattern-mapper.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-phase-researcher.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-plan-checker.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-planner.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-project-researcher.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-research-synthesizer.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-roadmapper.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-security-auditor.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-ui-auditor.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-ui-checker.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-ui-researcher.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-user-profiler.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - }, - "agents/gsd-verifier.toml": { - "reason": "#2834: Codex agent TOML now carries model-routing fields on first install." - } + "agents/gsd-advisor-researcher.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-ai-researcher.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-assumptions-analyzer.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-code-reviewer.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-codebase-mapper.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-debug-session-manager.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-debugger.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-doc-classifier.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-doc-synthesizer.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-doc-verifier.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-doc-writer.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-domain-researcher.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-eval-auditor.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-eval-planner.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-executor.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-framework-selector.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-integration-checker.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-intel-updater.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-mempalace-curator.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-nyquist-auditor.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-pattern-mapper.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-phase-researcher.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-plan-checker.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-planner.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-project-researcher.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-research-synthesizer.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-roadmapper.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-security-auditor.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-ui-auditor.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-ui-checker.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-ui-researcher.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-user-profiler.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "agents/gsd-verifier.toml": "#2834: Codex agent TOML now carries model-routing fields on first install.", + "gsd-code-fixer.md": "#2825: setup_worktree now reads workflow.use_worktrees and gates git worktree add on it (skipping worktree creation when the user opted out), the cleanup tail is gated to a no-op in that mode, and the spec adds three safety guardrails — honor the opt-out, never rm -rf a possible Windows reparse point/junction (the delete-the-target path that wiped real node_modules), and record where verification ran. Growth is the gated bash branch + the three guardrail paragraphs." } -} \ No newline at end of file +}