From 4bb846b67a0909b90656929b06207272eb392ef2 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Mon, 13 Jul 2026 00:21:46 -0400 Subject: [PATCH] fix(#2112): scope commit to --files pathspec, not entire index (#2148) * fix(2112): scope commit to --files pathspec, not entire index cmdCommit/cmdCommitToSubrepo/cmdPrSubrepo staged exactly the files named in --files but then ran a bare 'git commit' with no pathspec, absorbing anything else in the index into a commit whose message described only the named files (#2112). Fix: append '-- ...stagedPaths' to the commit args when the caller declared a scope. Three guards are load-bearing: - stagedPaths (not filesToStage) excludes skipped missing files (#2014) - explicitFiles gate keeps the default .planning/ path byte-identical - MERGE_HEAD check via 'git rev-parse' falls back to bare commit during merge - --amend is left without pathspec (different operation) cmdPrSubrepo pathspec uses changedFiles (old+new for renames) so the full rename is captured atomically. Also fixes workflow markdown in spec-phase.md and add-tests.md. All-files-missing now short-circuits to nothing_to_commit instead of absorbing the entire index under a message describing files that were not committed. * docs(changeset): backfill PR number (#2148) * test: update golden-install-parity fixtures for workflow markdown changes (#2112) * test: update golden fixtures + workflow baselines for #2112 changes - claude-local.json golden fixture (now generated via gen script) - workflow-size-baseline.json (add-tests.md +16, spec-phase.md +42 bytes) - Extended gen-golden-install-parity-zcode.cjs to also regenerate the claude local-layout fixture --- .changeset/2112-commit-files-pathspec.md | 5 + gsd-core/workflows/add-tests.md | 2 +- gsd-core/workflows/spec-phase.md | 2 +- scripts/gen-golden-install-parity-zcode.cjs | 19 ++ src/commands.cts | 52 +++++- tests/commit-files-pathspec.test.cjs | 176 ++++++++++++++++++ .../golden-install-parity/antigravity.json | 4 +- .../golden-install-parity/augment.json | 4 +- .../golden-install-parity/claude-local.json | 4 +- .../golden-install-parity/claude.json | 4 +- .../fixtures/golden-install-parity/cline.json | 4 +- .../golden-install-parity/codebuddy.json | 4 +- .../fixtures/golden-install-parity/codex.json | 4 +- .../golden-install-parity/copilot.json | 4 +- .../golden-install-parity/cursor.json | 4 +- .../golden-install-parity/hermes.json | 4 +- .../fixtures/golden-install-parity/kilo.json | 4 +- .../fixtures/golden-install-parity/kimi.json | 4 +- .../golden-install-parity/opencode.json | 4 +- tests/fixtures/golden-install-parity/pi.json | 4 +- .../fixtures/golden-install-parity/qwen.json | 4 +- .../fixtures/golden-install-parity/trae.json | 4 +- .../golden-install-parity/windsurf.json | 4 +- .../fixtures/golden-install-parity/zcode.json | 4 +- tests/workflow-size-baseline.json | 4 +- 25 files changed, 285 insertions(+), 47 deletions(-) create mode 100644 .changeset/2112-commit-files-pathspec.md create mode 100644 tests/commit-files-pathspec.test.cjs diff --git a/.changeset/2112-commit-files-pathspec.md b/.changeset/2112-commit-files-pathspec.md new file mode 100644 index 000000000..1e8a1118d --- /dev/null +++ b/.changeset/2112-commit-files-pathspec.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 2148 +--- +**`commit --files` now commits only the declared paths** — `gsd-tools commit --files A B` previously ran a bare `git commit` that absorbed the entire staged index, silently sweeping in unrelated files the caller never named. The commit now appends a pathspec (`-- `) so only the staged subset of `--files` lands in the commit; the no-`--files` default path is unchanged. Missing tracked files are still skipped (not committed as deletions, #2014), and when all declared files are missing the function short-circuits to `nothing_to_commit` instead of absorbing the index. (#2112) diff --git a/gsd-core/workflows/add-tests.md b/gsd-core/workflows/add-tests.md index bffc16bff..cc710178a 100644 --- a/gsd-core/workflows/add-tests.md +++ b/gsd-core/workflows/add-tests.md @@ -308,7 +308,7 @@ If there are passing tests to commit: ```bash git add {test files} -git commit -m "test(phase-${phase_number}): add unit and E2E tests from add-tests command" +git commit -m "test(phase-${phase_number}): add unit and E2E tests from add-tests command" -- {test files} ``` Present next steps: diff --git a/gsd-core/workflows/spec-phase.md b/gsd-core/workflows/spec-phase.md index 698b4bb1e..f25731292 100644 --- a/gsd-core/workflows/spec-phase.md +++ b/gsd-core/workflows/spec-phase.md @@ -456,7 +456,7 @@ Write to: `{phase_dir}/{padded_phase}-SPEC.md` ```bash git add "${phase_dir}/${padded_phase}-SPEC.md" -git commit -m "spec(phase-${phase_number}): add SPEC.md for ${phase_name} — ${requirement_count} requirements (#2213)" +git commit -m "spec(phase-${phase_number}): add SPEC.md for ${phase_name} — ${requirement_count} requirements (#2213)" -- "${phase_dir}/${padded_phase}-SPEC.md" ``` If `commit_docs` is false: Skip commit. Note that SPEC.md was written but not committed. diff --git a/scripts/gen-golden-install-parity-zcode.cjs b/scripts/gen-golden-install-parity-zcode.cjs index c20b4e1eb..7c500699f 100644 --- a/scripts/gen-golden-install-parity-zcode.cjs +++ b/scripts/gen-golden-install-parity-zcode.cjs @@ -69,12 +69,17 @@ function cleanup(root) { // With no args, regenerates ALL runtimes. With args, only the named runtimes. const targets = process.argv.slice(2).length > 0 ? process.argv.slice(2) : Object.keys(RUNTIME_META); fs.mkdirSync(FIXTURE_DIR, { recursive: true }); + +// Track the claude root so we can reuse it for the local layout fixture below. +let claudeRoot = null; + for (const runtime of targets) { if (!Object.prototype.hasOwnProperty.call(RUNTIME_META, runtime)) { process.stderr.write(`[gen] unknown runtime '${runtime}' (not in RUNTIME_META) — skipping\n`); continue; } const { configDir, root } = runMinimalInstall({ runtime, scope: 'global' }); + if (runtime === 'claude') claudeRoot = root; let actual; try { actual = buildParityManifest(configDir, root); @@ -85,3 +90,17 @@ for (const runtime of targets) { fs.writeFileSync(fixturePath, JSON.stringify(actual, null, 2) + '\n', 'utf8'); process.stdout.write(`[gen] ${runtime}: wrote ${Object.keys(actual).length} file hashes -> ${fixturePath}\n`); } + +// Also regenerate the claude LOCAL legacy-layout fixture (claude-local.json). +// This layout is distinct from the global install (commands/gsd-*.md + +// agents/gsd-*.md) and has its own parity assertion in the test harness. +const { configDir: localConfigDir, root: localRoot } = runMinimalInstall({ runtime: 'claude', scope: 'local' }); +let localActual; +try { + localActual = buildParityManifest(localConfigDir, localRoot); +} finally { + cleanup(localRoot); +} +const localFixturePath = path.join(FIXTURE_DIR, 'claude-local.json'); +fs.writeFileSync(localFixturePath, JSON.stringify(localActual, null, 2) + '\n', 'utf8'); +process.stdout.write(`[gen] claude-local: wrote ${Object.keys(localActual).length} file hashes -> ${localFixturePath}\n`); diff --git a/src/commands.cts b/src/commands.cts index 7f2704197..1dd767081 100644 --- a/src/commands.cts +++ b/src/commands.cts @@ -694,6 +694,7 @@ function cmdCommit(cwd: string, message: string | undefined, files: string[] | u // Stage files const explicitFiles = files && files.length > 0; const filesToStage = explicitFiles ? files : ['.planning/']; + const stagedPaths: string[] = []; for (const file of filesToStage) { const fullPath = path.join(cwd, file); if (!fs.existsSync(fullPath)) { @@ -708,12 +709,32 @@ function cmdCommit(cwd: string, message: string | undefined, files: string[] | u execGit(['rm', '--cached', '--ignore-unmatch', file], { cwd }); } else { execGit(['add', file], { cwd }); + stagedPaths.push(file); } } - // Commit (--no-verify skips pre-commit hooks, used by parallel executor agents) - const commitArgs = amend ? ['commit', '--amend', '--no-edit'] : ['commit', '-m', sanitizedMessage as string]; + // Commit — when the caller declared a scope (--files), append a pathspec so + // only the declared files land in the commit, not the entire index (#2112). + // The pathspec uses stagedPaths (not filesToStage) so skipped missing files + // are excluded — otherwise git would record them as deletions (#2014). + // During a merge, git refuses partial commits — fall back to a bare commit. + // --amend is left without a pathspec: amending with -- is a different + // operation that rewrites the tip with only those paths. + if (explicitFiles && stagedPaths.length === 0 && !amend) { + const result = { committed: false, hash: null, reason: 'nothing_to_commit' }; + output(result, raw, 'nothing'); + return; + } + const isMergeInProgress = execGit(['rev-parse', '-q', '--verify', 'MERGE_HEAD'], { cwd }).exitCode === 0; + const canScope = explicitFiles && stagedPaths.length > 0 && !amend + && !isMergeInProgress; + const commitArgs = amend + ? ['commit', '--amend', '--no-edit'] + : ['commit', '-m', sanitizedMessage as string]; if (noVerify) commitArgs.push('--no-verify'); + if (canScope) { + commitArgs.push('--', ...stagedPaths); + } const commitResult = execGit(commitArgs, { cwd }); if (commitResult.exitCode !== 0) { if (commitResult.stdout.includes('nothing to commit') || commitResult.stderr.includes('nothing to commit')) { @@ -817,13 +838,22 @@ function cmdCommitToSubrepo(cwd: string, message: string | undefined, files: str const repoCwd = path.join(cwd, repo); // Stage files (strip sub-repo prefix for paths relative to that repo) + const stagedRelPaths: string[] = []; for (const file of repoFiles) { const relativePath = file.slice(repo.length + 1); - execGit(['add', relativePath], { cwd: repoCwd }); + const addResult = execGit(['add', relativePath], { cwd: repoCwd }); + if (addResult.exitCode === 0) { + stagedRelPaths.push(relativePath); + } } - // Commit - const commitResult = execGit(['commit', '-m', message as string], { cwd: repoCwd }); + // Commit — pathspec limits the commit to the staged files only (#2112) + const isMergeInProgressSub = execGit(['rev-parse', '-q', '--verify', 'MERGE_HEAD'], { cwd: repoCwd }).exitCode === 0; + const canScopeSub = stagedRelPaths.length > 0 && !isMergeInProgressSub; + const commitArgs = canScopeSub + ? ['commit', '-m', message as string, '--', ...stagedRelPaths] + : ['commit', '-m', message as string]; + const commitResult = execGit(commitArgs, { cwd: repoCwd }); if (commitResult.exitCode !== 0) { if (commitResult.stdout.includes('nothing to commit') || commitResult.stderr.includes('nothing to commit')) { repos[repo] = { committed: false, hash: null, files: repoFiles, reason: 'nothing_to_commit' }; @@ -969,8 +999,16 @@ function cmdPrSubrepo( } } - // 5. Commit - const commitResult = execGit(['commit', '-m', commitMessage as string], { cwd: repoCwd }); + // 5. Commit — pathspec limits the commit to the staged files only (#2112). + // changedFiles includes both old and new paths for renames so the full + // rename is captured atomically (pathspec on newPath alone would leave the + // deletion of oldPath stranded in the index). + const isMergeInProgressPr = execGit(['rev-parse', '-q', '--verify', 'MERGE_HEAD'], { cwd: repoCwd }).exitCode === 0; + const canScopePr = changedFiles.length > 0 && !isMergeInProgressPr; + const commitArgs = canScopePr + ? ['commit', '-m', commitMessage as string, '--', ...changedFiles] + : ['commit', '-m', commitMessage as string]; + const commitResult = execGit(commitArgs, { cwd: repoCwd }); if (commitResult.exitCode !== 0) { rollback(); error(`Failed to commit in ${repo}: ${commitResult.stderr}`); diff --git a/tests/commit-files-pathspec.test.cjs b/tests/commit-files-pathspec.test.cjs new file mode 100644 index 000000000..488934209 --- /dev/null +++ b/tests/commit-files-pathspec.test.cjs @@ -0,0 +1,176 @@ +/** + * Regression test for #2112: gsd-tools commit --files commits the entire + * index, not the declared paths. + * + * `cmdCommit` staged exactly the files named in --files but then ran a bare + * `git commit` with no pathspec, absorbing anything else that happened to be + * staged into a commit whose message described only the named files. + * + * The fix adds `'--', ...stagedPaths` to the commit args **only when** the + * caller declared a scope (explicitFiles), and only for paths that were + * actually staged (skipped missing files are excluded to avoid #2014). + */ + +const { describe, test, beforeEach, afterEach } = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('fs'); +const path = require('path'); +const { execSync } = require('child_process'); + +const { createTempGitProject, cleanup, runGsdTools } = require('./helpers.cjs'); + +describe('commit --files: pathspec honors declared scope (#2112)', () => { + let tmpDir; + + beforeEach(() => { + tmpDir = createTempGitProject(); + }); + + afterEach(() => { + cleanup(tmpDir); + }); + + test('commit --files does not absorb unrelated staged files', () => { + // Developer stages a WIP file via git add (not via --files). + fs.writeFileSync(path.join(tmpDir, 'src-wip.txt'), 'work in progress\n'); + execSync('git add src-wip.txt', { cwd: tmpDir, stdio: 'pipe' }); + + // GSD writes and commits a planning artifact, naming ONLY that file. + fs.writeFileSync(path.join(tmpDir, '.planning', 'PLAN.md'), '# Plan\n'); + runGsdTools( + ['commit', 'docs(01): add PLAN.md', '--files', '.planning/PLAN.md'], + tmpDir, + ); + + // The commit must contain ONLY .planning/PLAN.md. + const diffOutput = execSync('git diff HEAD~1 HEAD --name-only', { + cwd: tmpDir, + encoding: 'utf-8', + }).trim(); + assert.strictEqual( + diffOutput, + '.planning/PLAN.md', + 'commit --files must contain only the named files, got:\n' + diffOutput, + ); + + // The WIP file must still be staged, not committed. + const statusOutput = execSync('git status --porcelain', { + cwd: tmpDir, + encoding: 'utf-8', + }).trim(); + assert.ok( + statusOutput.includes('A src-wip.txt') || statusOutput.includes('A\tsrc-wip.txt'), + 'src-wip.txt should remain staged, not committed. Status:\n' + statusOutput, + ); + }); + + test('commit --files with two files commits exactly those two', () => { + fs.writeFileSync(path.join(tmpDir, '.planning', 'PLAN.md'), '# Plan\n'); + fs.writeFileSync(path.join(tmpDir, '.planning', 'RESEARCH.md'), '# Research\n'); + + runGsdTools( + ['commit', 'docs: artifacts', '--files', '.planning/PLAN.md', '.planning/RESEARCH.md'], + tmpDir, + ); + + const diffOutput = execSync('git diff HEAD~1 HEAD --name-only', { + cwd: tmpDir, + encoding: 'utf-8', + }); + const files = diffOutput.trim().split('\n').sort(); + assert.deepEqual( + files, + ['.planning/PLAN.md', '.planning/RESEARCH.md'], + 'commit should contain exactly the two named files', + ); + }); + + test('commit without --files still commits the entire .planning/ index (default path)', () => { + // Write a planning artifact and stage it. + fs.writeFileSync(path.join(tmpDir, '.planning', 'PLAN.md'), '# Plan\n'); + execSync('git add .planning/PLAN.md', { cwd: tmpDir, stdio: 'pipe' }); + + // Also stage an unrelated file. + fs.writeFileSync(path.join(tmpDir, 'extra.txt'), 'extra\n'); + execSync('git add extra.txt', { cwd: tmpDir, stdio: 'pipe' }); + + runGsdTools(['commit', 'docs: default commit'], tmpDir); + + // Default path (no --files) commits everything staged. + const diffOutput = execSync('git diff HEAD~1 HEAD --name-only', { + cwd: tmpDir, + encoding: 'utf-8', + }); + const files = diffOutput.trim().split('\n').sort(); + assert.ok( + files.includes('.planning/PLAN.md') && files.includes('extra.txt'), + 'default commit (no --files) should commit everything staged, got:\n' + files, + ); + }); + + test('missing tracked file in --files is still not committed as deletion (#2014 guard)', () => { + // Create and commit STATE.md, then remove it from disk. + fs.writeFileSync(path.join(tmpDir, '.planning', 'STATE.md'), '# State\n'); + execSync('git add .planning/STATE.md', { cwd: tmpDir, stdio: 'pipe' }); + execSync('git commit -m "add STATE.md"', { cwd: tmpDir, stdio: 'pipe' }); + fs.unlinkSync(path.join(tmpDir, '.planning', 'STATE.md')); + + // Also create a valid file to commit. + fs.writeFileSync(path.join(tmpDir, '.planning', 'PLAN.md'), '# Plan\n'); + + runGsdTools( + ['commit', 'docs: add plan', '--files', '.planning/PLAN.md', '.planning/STATE.md'], + tmpDir, + ); + + const diffOutput = execSync('git diff HEAD~1 HEAD --name-status', { + cwd: tmpDir, + encoding: 'utf-8', + }); + assert.ok( + !diffOutput.includes('D\t.planning/STATE.md'), + 'missing tracked file must not appear as a deletion, diff was:\n' + diffOutput, + ); + assert.ok( + diffOutput.includes('.planning/PLAN.md'), + 'PLAN.md should be committed', + ); + }); + + test('commit --files with only missing files returns nothing_to_commit', () => { + // Create and commit STATE.md, then remove it from disk. + fs.writeFileSync(path.join(tmpDir, '.planning', 'STATE.md'), '# State\n'); + execSync('git add .planning/STATE.md', { cwd: tmpDir, stdio: 'pipe' }); + execSync('git commit -m "add STATE.md"', { cwd: tmpDir, stdio: 'pipe' }); + fs.unlinkSync(path.join(tmpDir, '.planning', 'STATE.md')); + + // Stage an unrelated file so the index is non-empty. + fs.writeFileSync(path.join(tmpDir, 'extra.txt'), 'extra\n'); + execSync('git add extra.txt', { cwd: tmpDir, stdio: 'pipe' }); + + const result = runGsdTools( + ['commit', 'docs: try', '--files', '.planning/STATE.md'], + tmpDir, + ); + + const parsed = JSON.parse(result.output); + assert.strictEqual( + parsed.committed, false, + 'should not commit when all --files are missing', + ); + assert.strictEqual( + parsed.reason, 'nothing_to_commit', + 'should report nothing_to_commit, not absorb the index', + ); + + // The unrelated staged file must still be staged, not committed. + const statusOutput = execSync('git status --porcelain', { + cwd: tmpDir, + encoding: 'utf-8', + }).trim(); + assert.ok( + statusOutput.includes('extra.txt'), + 'extra.txt should remain staged, not absorbed into a commit', + ); + }); +}); diff --git a/tests/fixtures/golden-install-parity/antigravity.json b/tests/fixtures/golden-install-parity/antigravity.json index 6ff09f85e..29f737cda 100644 --- a/tests/fixtures/golden-install-parity/antigravity.json +++ b/tests/fixtures/golden-install-parity/antigravity.json @@ -198,7 +198,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "8cc2e884a021b79b", "gsd-core/workflows/add-phase.md": "f82afa2f93be19fa", - "gsd-core/workflows/add-tests.md": "f695210f67d2635e", + "gsd-core/workflows/add-tests.md": "ad6d49634e04ca7c", "gsd-core/workflows/add-todo.md": "de1ac76acfcc0133", "gsd-core/workflows/ai-integration-phase.md": "22f5466085c47c00", "gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c", @@ -296,7 +296,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "0f842a609851a401", "gsd-core/workflows/sketch.md": "314b7d323c6b57eb", "gsd-core/workflows/smart-entry.md": "3ce5b6228238fdb6", - "gsd-core/workflows/spec-phase.md": "11c9e6b01bd2880a", + "gsd-core/workflows/spec-phase.md": "978462218855c213", "gsd-core/workflows/spike-wrap-up.md": "8db41edc87cb7886", "gsd-core/workflows/spike.md": "dd8d139947a8fb31", "gsd-core/workflows/stats.md": "b64bda5c0a1a06fb", diff --git a/tests/fixtures/golden-install-parity/augment.json b/tests/fixtures/golden-install-parity/augment.json index 765321b6d..b0b96d3f7 100644 --- a/tests/fixtures/golden-install-parity/augment.json +++ b/tests/fixtures/golden-install-parity/augment.json @@ -269,7 +269,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "1bc7377b105194fc", "gsd-core/workflows/add-phase.md": "46e0551ffdd8ce1a", - "gsd-core/workflows/add-tests.md": "2c1da65d41dc12d2", + "gsd-core/workflows/add-tests.md": "24b0d8157a9ccb8b", "gsd-core/workflows/add-todo.md": "cc0efe270004c8fb", "gsd-core/workflows/ai-integration-phase.md": "40c217869a06981f", "gsd-core/workflows/analyze-dependencies.md": "52942af10f140717", @@ -367,7 +367,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "5f5ebb6a80d610c6", "gsd-core/workflows/sketch.md": "8319cedf3f93fc35", "gsd-core/workflows/smart-entry.md": "449238eb94abe187", - "gsd-core/workflows/spec-phase.md": "8c480bd91f3cef6f", + "gsd-core/workflows/spec-phase.md": "fa8669b75392cf6c", "gsd-core/workflows/spike-wrap-up.md": "8467dadf2af758e6", "gsd-core/workflows/spike.md": "7727c07bb221c8cc", "gsd-core/workflows/stats.md": "76a42cbeaf6007c2", diff --git a/tests/fixtures/golden-install-parity/claude-local.json b/tests/fixtures/golden-install-parity/claude-local.json index c9acaf61f..97dce43f5 100644 --- a/tests/fixtures/golden-install-parity/claude-local.json +++ b/tests/fixtures/golden-install-parity/claude-local.json @@ -268,7 +268,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "8d05775f367d1e48", "gsd-core/workflows/add-phase.md": "7285e6e8894a41c5", - "gsd-core/workflows/add-tests.md": "8012263b2d27b83e", + "gsd-core/workflows/add-tests.md": "ffbaf55a25f455a2", "gsd-core/workflows/add-todo.md": "1fc850476cd8340d", "gsd-core/workflows/ai-integration-phase.md": "3503f52a7356caf0", "gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c", @@ -366,7 +366,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "d52a5462bafda830", "gsd-core/workflows/sketch.md": "dbe6acc4d976060c", "gsd-core/workflows/smart-entry.md": "1850447c045f36d8", - "gsd-core/workflows/spec-phase.md": "e03fa9f1a44613dc", + "gsd-core/workflows/spec-phase.md": "ec4d7e4e83bb001d", "gsd-core/workflows/spike-wrap-up.md": "4bdfaf9d05c63e7c", "gsd-core/workflows/spike.md": "1571a05457beea8d", "gsd-core/workflows/stats.md": "3953356f476b5053", diff --git a/tests/fixtures/golden-install-parity/claude.json b/tests/fixtures/golden-install-parity/claude.json index cfd2a3b7f..7b8d9c988 100644 --- a/tests/fixtures/golden-install-parity/claude.json +++ b/tests/fixtures/golden-install-parity/claude.json @@ -197,7 +197,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "485c4b6673ddf832", "gsd-core/workflows/add-phase.md": "0d90083e9c17bec1", - "gsd-core/workflows/add-tests.md": "330b3e7d969fc2d1", + "gsd-core/workflows/add-tests.md": "c4b133a102d36a27", "gsd-core/workflows/add-todo.md": "8488f10f56ac24ca", "gsd-core/workflows/ai-integration-phase.md": "a898d99b8d844215", "gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c", @@ -295,7 +295,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "121ed4b8127abf04", "gsd-core/workflows/sketch.md": "737c0492686fea2d", "gsd-core/workflows/smart-entry.md": "ad20cf74ae2e8291", - "gsd-core/workflows/spec-phase.md": "82150c52a9077602", + "gsd-core/workflows/spec-phase.md": "d935df4ab9dd4f7c", "gsd-core/workflows/spike-wrap-up.md": "e2704024992b3fee", "gsd-core/workflows/spike.md": "6dce83a2c5e7e49c", "gsd-core/workflows/stats.md": "e7852c5d8f2b05a9", diff --git a/tests/fixtures/golden-install-parity/cline.json b/tests/fixtures/golden-install-parity/cline.json index fd422bb06..cd803c896 100644 --- a/tests/fixtures/golden-install-parity/cline.json +++ b/tests/fixtures/golden-install-parity/cline.json @@ -201,7 +201,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "6c4393113fa9d209", "gsd-core/workflows/add-phase.md": "cac9b86f66ab26f5", - "gsd-core/workflows/add-tests.md": "dd80832a428afb45", + "gsd-core/workflows/add-tests.md": "0354376bffdc0080", "gsd-core/workflows/add-todo.md": "b71e80304fe484eb", "gsd-core/workflows/ai-integration-phase.md": "5159c6bdf102f74b", "gsd-core/workflows/analyze-dependencies.md": "52942af10f140717", @@ -299,7 +299,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "1f44789553180d84", "gsd-core/workflows/sketch.md": "2226779b6003a71c", "gsd-core/workflows/smart-entry.md": "9a64f43927641ca4", - "gsd-core/workflows/spec-phase.md": "55d727dbf400ed9a", + "gsd-core/workflows/spec-phase.md": "641208ed90684364", "gsd-core/workflows/spike-wrap-up.md": "846958e0012a0899", "gsd-core/workflows/spike.md": "868b15cdf229cc43", "gsd-core/workflows/stats.md": "f9241bb65770c5a4", diff --git a/tests/fixtures/golden-install-parity/codebuddy.json b/tests/fixtures/golden-install-parity/codebuddy.json index bf52365d7..b2dec1387 100644 --- a/tests/fixtures/golden-install-parity/codebuddy.json +++ b/tests/fixtures/golden-install-parity/codebuddy.json @@ -269,7 +269,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "1bc7377b105194fc", "gsd-core/workflows/add-phase.md": "46e0551ffdd8ce1a", - "gsd-core/workflows/add-tests.md": "2c1da65d41dc12d2", + "gsd-core/workflows/add-tests.md": "24b0d8157a9ccb8b", "gsd-core/workflows/add-todo.md": "cc0efe270004c8fb", "gsd-core/workflows/ai-integration-phase.md": "40c217869a06981f", "gsd-core/workflows/analyze-dependencies.md": "52942af10f140717", @@ -367,7 +367,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "2aba89ecd8f41a0d", "gsd-core/workflows/sketch.md": "5eedd93f9a5b49d5", "gsd-core/workflows/smart-entry.md": "449238eb94abe187", - "gsd-core/workflows/spec-phase.md": "8c480bd91f3cef6f", + "gsd-core/workflows/spec-phase.md": "fa8669b75392cf6c", "gsd-core/workflows/spike-wrap-up.md": "2b004744c52e565c", "gsd-core/workflows/spike.md": "24a0fee1447b6f0a", "gsd-core/workflows/stats.md": "76a42cbeaf6007c2", diff --git a/tests/fixtures/golden-install-parity/codex.json b/tests/fixtures/golden-install-parity/codex.json index 0c21c5a99..847fe6493 100644 --- a/tests/fixtures/golden-install-parity/codex.json +++ b/tests/fixtures/golden-install-parity/codex.json @@ -304,7 +304,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "62431b27424ff1ff", "gsd-core/workflows/add-phase.md": "27f282bf5b8af59d", - "gsd-core/workflows/add-tests.md": "995918665fc78d39", + "gsd-core/workflows/add-tests.md": "5cdb15508c4b6075", "gsd-core/workflows/add-todo.md": "097e171f797737df", "gsd-core/workflows/ai-integration-phase.md": "1dfa15d8f28c022d", "gsd-core/workflows/analyze-dependencies.md": "f799abc00907377f", @@ -402,7 +402,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "07724a390fbb43f6", "gsd-core/workflows/sketch.md": "576f300dfdde1b7d", "gsd-core/workflows/smart-entry.md": "6f686195ae531b03", - "gsd-core/workflows/spec-phase.md": "deaec2464a6560ec", + "gsd-core/workflows/spec-phase.md": "3dd8ae6137492d80", "gsd-core/workflows/spike-wrap-up.md": "ace265c114298376", "gsd-core/workflows/spike.md": "f42a9983eb9c89a1", "gsd-core/workflows/stats.md": "6dfc500555849d74", diff --git a/tests/fixtures/golden-install-parity/copilot.json b/tests/fixtures/golden-install-parity/copilot.json index 965eaf83c..a18cc11ee 100644 --- a/tests/fixtures/golden-install-parity/copilot.json +++ b/tests/fixtures/golden-install-parity/copilot.json @@ -199,7 +199,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "98f2dbb7c7cc93c2", "gsd-core/workflows/add-phase.md": "34e6dd38c25b5b61", - "gsd-core/workflows/add-tests.md": "e88bc8bc3416bfdd", + "gsd-core/workflows/add-tests.md": "7f5da4d2a9fa8a1a", "gsd-core/workflows/add-todo.md": "10253591112b7d06", "gsd-core/workflows/ai-integration-phase.md": "ef0c2474cee76b00", "gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c", @@ -297,7 +297,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "f2590cb6ddbfad94", "gsd-core/workflows/sketch.md": "e2063966439af8c1", "gsd-core/workflows/smart-entry.md": "6c707b959a41900b", - "gsd-core/workflows/spec-phase.md": "858184a1966d4d79", + "gsd-core/workflows/spec-phase.md": "44bd9c50b42e73fb", "gsd-core/workflows/spike-wrap-up.md": "a34d1e9ec15ae904", "gsd-core/workflows/spike.md": "89f299c07ac0edd2", "gsd-core/workflows/stats.md": "1db01bd96aa570fe", diff --git a/tests/fixtures/golden-install-parity/cursor.json b/tests/fixtures/golden-install-parity/cursor.json index e97487dc7..a3f0a49f0 100644 --- a/tests/fixtures/golden-install-parity/cursor.json +++ b/tests/fixtures/golden-install-parity/cursor.json @@ -269,7 +269,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "2926457ed07b4500", "gsd-core/workflows/add-phase.md": "0d90083e9c17bec1", - "gsd-core/workflows/add-tests.md": "1837b9d2affa6913", + "gsd-core/workflows/add-tests.md": "37f031c4b3236a32", "gsd-core/workflows/add-todo.md": "d483ebe8edcf193a", "gsd-core/workflows/ai-integration-phase.md": "b79f320d59a68773", "gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c", @@ -367,7 +367,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "5be73b7bdf96b539", "gsd-core/workflows/sketch.md": "373bc0d83368a411", "gsd-core/workflows/smart-entry.md": "c8fc316358cdcd7b", - "gsd-core/workflows/spec-phase.md": "d6e23579376c9e91", + "gsd-core/workflows/spec-phase.md": "239b6e6cbddaf8c2", "gsd-core/workflows/spike-wrap-up.md": "4a3bf1058691e55d", "gsd-core/workflows/spike.md": "f741bead24d5669a", "gsd-core/workflows/stats.md": "e7852c5d8f2b05a9", diff --git a/tests/fixtures/golden-install-parity/hermes.json b/tests/fixtures/golden-install-parity/hermes.json index c3d0421b6..85281cc08 100644 --- a/tests/fixtures/golden-install-parity/hermes.json +++ b/tests/fixtures/golden-install-parity/hermes.json @@ -198,7 +198,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "79a453a2270483fb", "gsd-core/workflows/add-phase.md": "b4c4b32c111a116a", - "gsd-core/workflows/add-tests.md": "63390575b418e270", + "gsd-core/workflows/add-tests.md": "02f9e11ad2371c00", "gsd-core/workflows/add-todo.md": "5fe3ddc3227e0e22", "gsd-core/workflows/ai-integration-phase.md": "ddab2912d025db65", "gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c", @@ -296,7 +296,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "f1ece50ac65ea281", "gsd-core/workflows/sketch.md": "d5887983e62b574a", "gsd-core/workflows/smart-entry.md": "47f5c5e8608e5f7a", - "gsd-core/workflows/spec-phase.md": "6c8835fc65ea1cb8", + "gsd-core/workflows/spec-phase.md": "6ace28390408475f", "gsd-core/workflows/spike-wrap-up.md": "367325e6d567b904", "gsd-core/workflows/spike.md": "cdacb2887a321e11", "gsd-core/workflows/stats.md": "49a991d0d3905a56", diff --git a/tests/fixtures/golden-install-parity/kilo.json b/tests/fixtures/golden-install-parity/kilo.json index 91af4ccfc..3b5f4959c 100644 --- a/tests/fixtures/golden-install-parity/kilo.json +++ b/tests/fixtures/golden-install-parity/kilo.json @@ -269,7 +269,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "485c4b6673ddf832", "gsd-core/workflows/add-phase.md": "0d90083e9c17bec1", - "gsd-core/workflows/add-tests.md": "ecb959f321820e5e", + "gsd-core/workflows/add-tests.md": "6e54f3d71a202671", "gsd-core/workflows/add-todo.md": "5082510bf0449204", "gsd-core/workflows/ai-integration-phase.md": "c85c6afdc64f0da6", "gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c", @@ -367,7 +367,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "888c0548e63197b3", "gsd-core/workflows/sketch.md": "34a0c10fa56af7ea", "gsd-core/workflows/smart-entry.md": "7ffe4fdb93935400", - "gsd-core/workflows/spec-phase.md": "c231f8eb723e7604", + "gsd-core/workflows/spec-phase.md": "a5f3de15eeb7ce72", "gsd-core/workflows/spike-wrap-up.md": "458230d4d7c44b09", "gsd-core/workflows/spike.md": "8e63427fc146b45c", "gsd-core/workflows/stats.md": "e7852c5d8f2b05a9", diff --git a/tests/fixtures/golden-install-parity/kimi.json b/tests/fixtures/golden-install-parity/kimi.json index 0163d2a0e..427d2c300 100644 --- a/tests/fixtures/golden-install-parity/kimi.json +++ b/tests/fixtures/golden-install-parity/kimi.json @@ -262,7 +262,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "1bc7377b105194fc", "gsd-core/workflows/add-phase.md": "46e0551ffdd8ce1a", - "gsd-core/workflows/add-tests.md": "2c1da65d41dc12d2", + "gsd-core/workflows/add-tests.md": "24b0d8157a9ccb8b", "gsd-core/workflows/add-todo.md": "cc0efe270004c8fb", "gsd-core/workflows/ai-integration-phase.md": "40c217869a06981f", "gsd-core/workflows/analyze-dependencies.md": "52942af10f140717", @@ -360,7 +360,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "b767a1d3db129a8a", "gsd-core/workflows/sketch.md": "88cfdf4edcf222ab", "gsd-core/workflows/smart-entry.md": "449238eb94abe187", - "gsd-core/workflows/spec-phase.md": "8c480bd91f3cef6f", + "gsd-core/workflows/spec-phase.md": "fa8669b75392cf6c", "gsd-core/workflows/spike-wrap-up.md": "da0dcb252c54fa82", "gsd-core/workflows/spike.md": "7813e120577282d4", "gsd-core/workflows/stats.md": "76a42cbeaf6007c2", diff --git a/tests/fixtures/golden-install-parity/opencode.json b/tests/fixtures/golden-install-parity/opencode.json index d9c557dff..75bec1848 100644 --- a/tests/fixtures/golden-install-parity/opencode.json +++ b/tests/fixtures/golden-install-parity/opencode.json @@ -269,7 +269,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "08289088a88d410f", "gsd-core/workflows/add-phase.md": "5154a5fb3e0d4370", - "gsd-core/workflows/add-tests.md": "81d0a836878e1a10", + "gsd-core/workflows/add-tests.md": "b4deb88c74d491c7", "gsd-core/workflows/add-todo.md": "72fcef9fd0cafda5", "gsd-core/workflows/ai-integration-phase.md": "90e5f97018715b18", "gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c", @@ -367,7 +367,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "681800323681c5c6", "gsd-core/workflows/sketch.md": "fcb7af914159ef7b", "gsd-core/workflows/smart-entry.md": "2a253fe437496eea", - "gsd-core/workflows/spec-phase.md": "cb6cbe6eac816b0a", + "gsd-core/workflows/spec-phase.md": "5c4a3001095ca722", "gsd-core/workflows/spike-wrap-up.md": "30a73aa19a1db271", "gsd-core/workflows/spike.md": "f8b07d411473560a", "gsd-core/workflows/stats.md": "846cd2808461ccdc", diff --git a/tests/fixtures/golden-install-parity/pi.json b/tests/fixtures/golden-install-parity/pi.json index 77cf8f726..438874363 100644 --- a/tests/fixtures/golden-install-parity/pi.json +++ b/tests/fixtures/golden-install-parity/pi.json @@ -165,7 +165,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "1bc7377b105194fc", "gsd-core/workflows/add-phase.md": "46e0551ffdd8ce1a", - "gsd-core/workflows/add-tests.md": "2c1da65d41dc12d2", + "gsd-core/workflows/add-tests.md": "24b0d8157a9ccb8b", "gsd-core/workflows/add-todo.md": "cc0efe270004c8fb", "gsd-core/workflows/ai-integration-phase.md": "40c217869a06981f", "gsd-core/workflows/analyze-dependencies.md": "52942af10f140717", @@ -263,7 +263,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "838c701bd072ae73", "gsd-core/workflows/sketch.md": "c7725562b3efd311", "gsd-core/workflows/smart-entry.md": "449238eb94abe187", - "gsd-core/workflows/spec-phase.md": "8c480bd91f3cef6f", + "gsd-core/workflows/spec-phase.md": "fa8669b75392cf6c", "gsd-core/workflows/spike-wrap-up.md": "0b24057c340a8a17", "gsd-core/workflows/spike.md": "9134cdc3b75282c9", "gsd-core/workflows/stats.md": "76a42cbeaf6007c2", diff --git a/tests/fixtures/golden-install-parity/qwen.json b/tests/fixtures/golden-install-parity/qwen.json index 32a131972..c549ba993 100644 --- a/tests/fixtures/golden-install-parity/qwen.json +++ b/tests/fixtures/golden-install-parity/qwen.json @@ -198,7 +198,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "cee41d5fc52d4e37", "gsd-core/workflows/add-phase.md": "cc63a3e108c9a065", - "gsd-core/workflows/add-tests.md": "b62585823e5636bb", + "gsd-core/workflows/add-tests.md": "7cd945118e83246e", "gsd-core/workflows/add-todo.md": "5e037b444e657557", "gsd-core/workflows/ai-integration-phase.md": "afdc7c15f03a95fc", "gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c", @@ -296,7 +296,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "89e0eab2af946b04", "gsd-core/workflows/sketch.md": "483387542d6fc3af", "gsd-core/workflows/smart-entry.md": "d309710bcabd4675", - "gsd-core/workflows/spec-phase.md": "0d888493bde5146b", + "gsd-core/workflows/spec-phase.md": "546b3a8eb1a97013", "gsd-core/workflows/spike-wrap-up.md": "fe04cb3d30dcbc6c", "gsd-core/workflows/spike.md": "fad28f2ecf2dac52", "gsd-core/workflows/stats.md": "89a08155b92f4a2d", diff --git a/tests/fixtures/golden-install-parity/trae.json b/tests/fixtures/golden-install-parity/trae.json index a8dc5060c..14b49c301 100644 --- a/tests/fixtures/golden-install-parity/trae.json +++ b/tests/fixtures/golden-install-parity/trae.json @@ -198,7 +198,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "1851e97996d445d5", "gsd-core/workflows/add-phase.md": "09bdebbc62f3310e", - "gsd-core/workflows/add-tests.md": "ff3a598cdbc5aa6e", + "gsd-core/workflows/add-tests.md": "8ad08d29415f8f43", "gsd-core/workflows/add-todo.md": "0fe07cbd29ec252b", "gsd-core/workflows/ai-integration-phase.md": "d469eb120e52de0f", "gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c", @@ -296,7 +296,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "dbec602d104cb951", "gsd-core/workflows/sketch.md": "44ff275150b6d045", "gsd-core/workflows/smart-entry.md": "d8018578571f08d5", - "gsd-core/workflows/spec-phase.md": "ab8fad8038b14cad", + "gsd-core/workflows/spec-phase.md": "7b8873b0cd3eb9d7", "gsd-core/workflows/spike-wrap-up.md": "6fe876cb87603bc3", "gsd-core/workflows/spike.md": "c042a437baaf10ad", "gsd-core/workflows/stats.md": "e4f84542fb5721ef", diff --git a/tests/fixtures/golden-install-parity/windsurf.json b/tests/fixtures/golden-install-parity/windsurf.json index 6e81b5413..6a8fe3225 100644 --- a/tests/fixtures/golden-install-parity/windsurf.json +++ b/tests/fixtures/golden-install-parity/windsurf.json @@ -198,7 +198,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "61169973a10b1321", "gsd-core/workflows/add-phase.md": "f9b1f7cc229b57f8", - "gsd-core/workflows/add-tests.md": "b5e03955cb29d7d8", + "gsd-core/workflows/add-tests.md": "d51e69bb433535a4", "gsd-core/workflows/add-todo.md": "cab0d8215579fbdd", "gsd-core/workflows/ai-integration-phase.md": "8948988717506320", "gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c", @@ -296,7 +296,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "10063f56c2c7f141", "gsd-core/workflows/sketch.md": "25c1f8f7acfb1da9", "gsd-core/workflows/smart-entry.md": "bd81482cb6a7ac53", - "gsd-core/workflows/spec-phase.md": "c05348d644f9d77a", + "gsd-core/workflows/spec-phase.md": "744faedd273da0f7", "gsd-core/workflows/spike-wrap-up.md": "8029ca4effb5b716", "gsd-core/workflows/spike.md": "a94af5171bb9d2ce", "gsd-core/workflows/stats.md": "d58325fc3fb8d1b6", diff --git a/tests/fixtures/golden-install-parity/zcode.json b/tests/fixtures/golden-install-parity/zcode.json index 5180a9cd9..5d1665ac8 100644 --- a/tests/fixtures/golden-install-parity/zcode.json +++ b/tests/fixtures/golden-install-parity/zcode.json @@ -269,7 +269,7 @@ "gsd-core/workflows/_runtime-launcher.snippet.sh": "bf2dd5d1debd5335", "gsd-core/workflows/add-backlog.md": "1bc7377b105194fc", "gsd-core/workflows/add-phase.md": "46e0551ffdd8ce1a", - "gsd-core/workflows/add-tests.md": "2c1da65d41dc12d2", + "gsd-core/workflows/add-tests.md": "24b0d8157a9ccb8b", "gsd-core/workflows/add-todo.md": "cc0efe270004c8fb", "gsd-core/workflows/ai-integration-phase.md": "40c217869a06981f", "gsd-core/workflows/analyze-dependencies.md": "52942af10f140717", @@ -367,7 +367,7 @@ "gsd-core/workflows/sketch-wrap-up.md": "86db87b16548117e", "gsd-core/workflows/sketch.md": "e96f1866d3e60cab", "gsd-core/workflows/smart-entry.md": "449238eb94abe187", - "gsd-core/workflows/spec-phase.md": "8c480bd91f3cef6f", + "gsd-core/workflows/spec-phase.md": "fa8669b75392cf6c", "gsd-core/workflows/spike-wrap-up.md": "d643447e16e95753", "gsd-core/workflows/spike.md": "265e5c5a13ea0deb", "gsd-core/workflows/stats.md": "76a42cbeaf6007c2", diff --git a/tests/workflow-size-baseline.json b/tests/workflow-size-baseline.json index 7ba2a99d9..6a4cd4e5b 100644 --- a/tests/workflow-size-baseline.json +++ b/tests/workflow-size-baseline.json @@ -1,7 +1,7 @@ { "add-backlog.md": 7176, "add-phase.md": 7247, - "add-tests.md": 16945, + "add-tests.md": 16961, "add-todo.md": 8996, "ai-integration-phase.md": 14805, "analyze-dependencies.md": 3887, @@ -75,7 +75,7 @@ "sketch-wrap-up.md": 14267, "sketch.md": 20004, "smart-entry.md": 11124, - "spec-phase.md": 31945, + "spec-phase.md": 31987, "spike-wrap-up.md": 15136, "spike.md": 24561, "stats.md": 6762,