fix(#1857): test gates normalize to one-shot + bounded timeout (no watch-mode hang)

A GSD verification gate resolves a project's test command and runs it. vitest
defaults to WATCH mode in an interactive TTY — exactly where a user runs
`gsd-execute-phase` — so a resolved `npm test`/`pnpm test` backed by vitest never
exited and the orchestrator waited indefinitely. Recovery needed the user to
manually prompt "something blocking?".

Fix — one shared helper + a bounded, surfacing timeout on the test-command gates:
- New pure module src/normalize-test-command.cts + `gsd-tools query
  normalize-test-command` verb: rewrites a resolved command to a best-effort
  one-shot form (direct vitest → `vitest run`; jest `--watch` → `--watchAll=false`;
  a package-manager `test` script whose package.json runner is watch-vitest →
  `CI=true` prefix; handles `--dir`; already-one-shot commands unchanged —
  never double-flagged). Named `normalize-test-command` (not `test-*`) so the
  file does not match node --test's default `test-*` discovery glob.
- The three gates that HUNG or silently-continued route through that ONE helper
  and bound execution with `timeout $(config-get workflow.test_gate_timeout)`
  (new config key, default 600s): the regression gate (extracted to
  execute-phase/steps/regression-gate.md since execute-phase.md is size-frozen —
  it shrank 93528→93132; ABORTS on exit 124), the post-merge gate, and the
  audit-fix gate (previously an UNBOUNDED `eval`). All name watch/dev mode on 124.
- verify-phase's gate was ALREADY bounded (a fixed `timeout 300`, not a hang), so
  it only gains the normalizer (so a watch runner exits fast) + a watch-mode hint
  on 124, staying under its frozen 40960-byte tier cap.

Security hardening (review): the normalizer only rewrites a runner named as a
standalone command TOKEN (so `run-vitest.js`/`make test-vitest`/paths are never
mangled), is length-capped and uses only linear-time split-based scanning (no
super-linear backtracking on an adversarial `workflow.test_command`), and reads
package.json only when it is a regular file (never blocks on a FIFO via `--dir`).

Config key `workflow.test_gate_timeout` (seconds, default 600) registered in the
schema manifest + templates/config.json + docs/CONFIGURATION.md (mirrors
workflow.cross_ai_timeout). New module registered in .gitignore, eslint ignores,
inventory manifest/index. All 16 golden-install-parity fixtures + workflow size
baseline regenerated for the changed shipped files; bin/lib is excluded from the
parity manifest.

Tests: tests/normalize-test-command.test.cjs (normalizer units incl. security
hardening) and tests/test-gate-watch-mode.test.cjs (the three core gates route
through the shared helper + configured timeout + exit-124 watch-mode hint;
verify-phase asserted as normalize-only/already-bounded).
tests/execute-phase-active-flags.test.cjs repointed at the extracted step;
tests/planner-language-regression.test.cjs allowlist comment updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-07-07 11:07:48 -04:00
parent a3b9cbaeb8
commit 603593d41d
36 changed files with 677 additions and 155 deletions

View File

@@ -97,6 +97,9 @@ const path = require('path');
const EXECUTE_PHASE_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'execute-phase.md');
const VERIFY_PHASE_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'verify-phase.md');
const AUDIT_FIX_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'audit-fix.md');
// #1857: execute-phase's regression-gate test-command resolution was extracted
// to this step file (execute-phase.md is size-frozen — phase-6 capstone).
const REGRESSION_GATE_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'execute-phase', 'steps', 'regression-gate.md');
function assertMakefileCheckBeforeNpmTest(filePath, label) {
const content = fs.readFileSync(filePath, 'utf-8');
@@ -166,8 +169,8 @@ describe('bug-2396: Makefile test target must take priority over hardcoded comma
assert.ok(fs.existsSync(AUDIT_FIX_PATH), 'audit-fix.md should exist');
});
test('execute-phase.md: Makefile check precedes npm test (post-merge gate)', () => {
assertMakefileCheckBeforeNpmTest(EXECUTE_PHASE_PATH, 'execute-phase.md');
test('regression-gate step: Makefile check precedes npm test (#1857 — extracted from execute-phase.md)', () => {
assertMakefileCheckBeforeNpmTest(REGRESSION_GATE_PATH, 'regression-gate.md');
});
test('verify-phase.md: Makefile check precedes npm test', () => {
@@ -178,8 +181,8 @@ describe('bug-2396: Makefile test target must take priority over hardcoded comma
assertMakefileCheckBeforeNpmTest(AUDIT_FIX_PATH, 'audit-fix.md');
});
test('execute-phase.md: workflow.test_command config checked first (within bash block)', () => {
assertConfigGetBeforeMakefile(EXECUTE_PHASE_PATH, 'execute-phase.md');
test('regression-gate step: workflow.test_command config checked first (within bash block) (#1857)', () => {
assertConfigGetBeforeMakefile(REGRESSION_GATE_PATH, 'regression-gate.md');
});
test('verify-phase.md: workflow.test_command config checked first (within bash block)', () => {

View File

@@ -38,10 +38,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "ea841e2865248e74",
"gsd-core/bin/gsd-tools.cjs": "b518bc939b3e031e",
"gsd-core/bin/gsd-tools.cjs": "e8ccbbe8cefc2e9a",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "8bc541aabc2e143c",
@@ -162,7 +162,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "6c505bdf5af338c8",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "593d4e6d20fdde7c",
"gsd-core/templates/continue-here.md": "8b1dce4832c7922b",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -200,7 +200,7 @@
"gsd-core/workflows/add-todo.md": "de1ac76acfcc0133",
"gsd-core/workflows/ai-integration-phase.md": "22f5466085c47c00",
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
"gsd-core/workflows/audit-fix.md": "44e9b0a78eb79311",
"gsd-core/workflows/audit-fix.md": "3ecffffe78021e0a",
"gsd-core/workflows/audit-milestone.md": "77089ccd7b45c0f0",
"gsd-core/workflows/audit-uat.md": "ea8ddd910ed16ba4",
"gsd-core/workflows/autonomous.md": "603ce2019835f00e",
@@ -231,10 +231,11 @@
"gsd-core/workflows/docs-update.md": "8e986e26d0e6e1a0",
"gsd-core/workflows/edit-phase.md": "fc932e82ba1f585a",
"gsd-core/workflows/eval-review.md": "eb4040eaa5b8497f",
"gsd-core/workflows/execute-phase.md": "97453d3b8f49f27f",
"gsd-core/workflows/execute-phase.md": "82beafd82b24210c",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "55d0706e80a2554a",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "687513ef1010180e",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "9b7107b31b60a3b9",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "e0fa99178ae544f0",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "907af77eafc3d97b",
"gsd-core/workflows/explore.md": "934c00f9f216dbdb",
@@ -306,7 +307,7 @@
"gsd-core/workflows/undo.md": "6ab639d1fc7e0721",
"gsd-core/workflows/update.md": "2c58df5e21c41c31",
"gsd-core/workflows/validate-phase.md": "6c0ab739d15709fa",
"gsd-core/workflows/verify-phase.md": "8070a098ab538b33",
"gsd-core/workflows/verify-phase.md": "0eefbb6bb1b0bed6",
"gsd-core/workflows/verify-work.md": "be699ed7920f61b0",
"hooks/gsd-check-update-worker.js": "fa301e6366270d5f",
"hooks/gsd-check-update.js": "4617a98bf529e4c3",

View File

@@ -109,10 +109,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
@@ -233,7 +233,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "222997133232a6f5",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "69b01e7909ea3f66",
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -271,7 +271,7 @@
"gsd-core/workflows/add-todo.md": "cc0efe270004c8fb",
"gsd-core/workflows/ai-integration-phase.md": "40c217869a06981f",
"gsd-core/workflows/analyze-dependencies.md": "52942af10f140717",
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
"gsd-core/workflows/audit-milestone.md": "6866ce260980c21e",
"gsd-core/workflows/audit-uat.md": "fcfbec501620b564",
"gsd-core/workflows/autonomous.md": "7e5683728ef33707",
@@ -302,10 +302,11 @@
"gsd-core/workflows/docs-update.md": "f35922d15b7061c9",
"gsd-core/workflows/edit-phase.md": "966a3eadd1bebc04",
"gsd-core/workflows/eval-review.md": "f898936e2cfe4130",
"gsd-core/workflows/execute-phase.md": "346e443b260e4f38",
"gsd-core/workflows/execute-phase.md": "1b2d0b868f574e80",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "4e265392b3f2ba0e",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "2c412310dce31a0b",
"gsd-core/workflows/explore.md": "6c04f2e658d93261",
@@ -377,7 +378,7 @@
"gsd-core/workflows/undo.md": "96d2775f008b3a85",
"gsd-core/workflows/update.md": "fd160e13f8b7e83c",
"gsd-core/workflows/validate-phase.md": "2c6d7671fcaabcaa",
"gsd-core/workflows/verify-phase.md": "98a995046bdb6c3c",
"gsd-core/workflows/verify-phase.md": "22f18492581f1da5",
"gsd-core/workflows/verify-work.md": "34e980a6950cd83c",
"hooks/gsd-check-update-worker.js": "cc1ef5f840f9dfc9",
"hooks/gsd-check-update.js": "7b3a7983d5f1f5d3",

View File

@@ -37,10 +37,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
@@ -161,7 +161,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "222997133232a6f5",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "69b01e7909ea3f66",
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -199,7 +199,7 @@
"gsd-core/workflows/add-todo.md": "8488f10f56ac24ca",
"gsd-core/workflows/ai-integration-phase.md": "a898d99b8d844215",
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
"gsd-core/workflows/audit-milestone.md": "23c1e35f449933b8",
"gsd-core/workflows/audit-uat.md": "e11db0d74c2a7405",
"gsd-core/workflows/autonomous.md": "722397c04272dfaa",
@@ -230,10 +230,11 @@
"gsd-core/workflows/docs-update.md": "63082608d3ae92be",
"gsd-core/workflows/edit-phase.md": "8323bfe10faa0c0a",
"gsd-core/workflows/eval-review.md": "f59e8329dae1e528",
"gsd-core/workflows/execute-phase.md": "4aa452149551956b",
"gsd-core/workflows/execute-phase.md": "4aa35e8cb9d68cde",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "facb0e816d87a0c7",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "cce1a33fe9a0a32d",
"gsd-core/workflows/explore.md": "b9eea1bac358c9ce",
@@ -305,7 +306,7 @@
"gsd-core/workflows/undo.md": "791e0bf96d9a057f",
"gsd-core/workflows/update.md": "f9e7d8a760d0d3c8",
"gsd-core/workflows/validate-phase.md": "2ac231dc541441c2",
"gsd-core/workflows/verify-phase.md": "0d4ffabc1caa473a",
"gsd-core/workflows/verify-phase.md": "e0957e153788a222",
"gsd-core/workflows/verify-work.md": "efe57bdbbb3af03f",
"hooks/gsd-check-update-worker.js": "a530efdb5fdc0da3",
"hooks/gsd-check-update.js": "25cde66a12d6b886",

View File

@@ -41,10 +41,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "476aa24e8c4f03cf",
"gsd-core/bin/gsd-tools.cjs": "3dce0048d7aed8f4",
"gsd-core/bin/gsd-tools.cjs": "93273f4eda2750d2",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
@@ -165,7 +165,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "988307dc093216d1",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "69b01e7909ea3f66",
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -203,7 +203,7 @@
"gsd-core/workflows/add-todo.md": "b71e80304fe484eb",
"gsd-core/workflows/ai-integration-phase.md": "5159c6bdf102f74b",
"gsd-core/workflows/analyze-dependencies.md": "52942af10f140717",
"gsd-core/workflows/audit-fix.md": "47c29d04bab02b27",
"gsd-core/workflows/audit-fix.md": "9bb427cd3b4075d5",
"gsd-core/workflows/audit-milestone.md": "2266710d0ae48932",
"gsd-core/workflows/audit-uat.md": "1fb7b2ab9d587c8f",
"gsd-core/workflows/autonomous.md": "cc5217b1b2238a4c",
@@ -234,10 +234,11 @@
"gsd-core/workflows/docs-update.md": "39f288623a8f6f32",
"gsd-core/workflows/edit-phase.md": "9c9fadc047c61d74",
"gsd-core/workflows/eval-review.md": "3e1d7829ed2ed494",
"gsd-core/workflows/execute-phase.md": "5c56112513a04340",
"gsd-core/workflows/execute-phase.md": "ae12e044fb2f3b57",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "67ebc93f51968cb6",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "e3cb789a350dcadc",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "82e6cfe1e1b1ec0e",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "36b463d72d3e11c5",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "0c5551f99ee0a017",
"gsd-core/workflows/explore.md": "e83af8ceae314cf9",
@@ -309,7 +310,7 @@
"gsd-core/workflows/undo.md": "96d2775f008b3a85",
"gsd-core/workflows/update.md": "165beec33490bd28",
"gsd-core/workflows/validate-phase.md": "5b4ae14c87859bd2",
"gsd-core/workflows/verify-phase.md": "20e90407e1e531fc",
"gsd-core/workflows/verify-phase.md": "a4f918c92c927268",
"gsd-core/workflows/verify-work.md": "6fa216623778c541",
"scripts/changeset/README.md": "86ff89331dfd94b2",
"scripts/changeset/cli.cjs": "68f92a344b199271",

View File

@@ -109,10 +109,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
@@ -233,7 +233,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "222997133232a6f5",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "69b01e7909ea3f66",
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -271,7 +271,7 @@
"gsd-core/workflows/add-todo.md": "cc0efe270004c8fb",
"gsd-core/workflows/ai-integration-phase.md": "40c217869a06981f",
"gsd-core/workflows/analyze-dependencies.md": "52942af10f140717",
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
"gsd-core/workflows/audit-milestone.md": "6866ce260980c21e",
"gsd-core/workflows/audit-uat.md": "fcfbec501620b564",
"gsd-core/workflows/autonomous.md": "7e5683728ef33707",
@@ -302,10 +302,11 @@
"gsd-core/workflows/docs-update.md": "f35922d15b7061c9",
"gsd-core/workflows/edit-phase.md": "966a3eadd1bebc04",
"gsd-core/workflows/eval-review.md": "f898936e2cfe4130",
"gsd-core/workflows/execute-phase.md": "2f9b53aac81a8f27",
"gsd-core/workflows/execute-phase.md": "cf72b6db051f9189",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "4e265392b3f2ba0e",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "933d10547116794a",
"gsd-core/workflows/explore.md": "6c04f2e658d93261",
@@ -377,7 +378,7 @@
"gsd-core/workflows/undo.md": "96d2775f008b3a85",
"gsd-core/workflows/update.md": "5ff1f77222977648",
"gsd-core/workflows/validate-phase.md": "2c6d7671fcaabcaa",
"gsd-core/workflows/verify-phase.md": "98a995046bdb6c3c",
"gsd-core/workflows/verify-phase.md": "22f18492581f1da5",
"gsd-core/workflows/verify-work.md": "34e980a6950cd83c",
"hooks/gsd-check-update-worker.js": "bdc9324a2f080ddd",
"hooks/gsd-check-update.js": "b7669f605631e506",

View File

@@ -73,10 +73,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
@@ -197,7 +197,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "5b5dd37145241462",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "593d4e6d20fdde7c",
"gsd-core/templates/continue-here.md": "8b1dce4832c7922b",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -235,7 +235,7 @@
"gsd-core/workflows/add-todo.md": "097e171f797737df",
"gsd-core/workflows/ai-integration-phase.md": "1dfa15d8f28c022d",
"gsd-core/workflows/analyze-dependencies.md": "f799abc00907377f",
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
"gsd-core/workflows/audit-milestone.md": "46edd152d8b63bfc",
"gsd-core/workflows/audit-uat.md": "2564078edb15b5e9",
"gsd-core/workflows/autonomous.md": "92f08626d4aea668",
@@ -266,10 +266,11 @@
"gsd-core/workflows/docs-update.md": "e255317df939e302",
"gsd-core/workflows/edit-phase.md": "e592a4d85ce5380f",
"gsd-core/workflows/eval-review.md": "63d0d0670b54c244",
"gsd-core/workflows/execute-phase.md": "b6f4765843dc05f7",
"gsd-core/workflows/execute-phase.md": "e62b664cf4db4d55",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "f4cacd27d37bac65",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "ac1f1d9ada00a91e",
"gsd-core/workflows/explore.md": "2ef10d17c8864a04",
@@ -341,7 +342,7 @@
"gsd-core/workflows/undo.md": "5ff7d63b0a2f46d5",
"gsd-core/workflows/update.md": "5c35c0ec0f462ea6",
"gsd-core/workflows/validate-phase.md": "020201a41049679f",
"gsd-core/workflows/verify-phase.md": "b9f70235e777aa81",
"gsd-core/workflows/verify-phase.md": "2e12c3cb97a9122a",
"gsd-core/workflows/verify-work.md": "69e27f6f419d0bba",
"hooks/gsd-check-update.js": "ef48957eb6ac6a10",
"hooks/gsd-context-monitor.js": "76fecaaa2babd6c1",

View File

@@ -39,10 +39,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "ea841e2865248e74",
"gsd-core/bin/gsd-tools.cjs": "b518bc939b3e031e",
"gsd-core/bin/gsd-tools.cjs": "e8ccbbe8cefc2e9a",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "10226e9512dd44bf",
@@ -163,7 +163,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "27318be7b7c984e1",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "593d4e6d20fdde7c",
"gsd-core/templates/continue-here.md": "8b1dce4832c7922b",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -201,7 +201,7 @@
"gsd-core/workflows/add-todo.md": "10253591112b7d06",
"gsd-core/workflows/ai-integration-phase.md": "ef0c2474cee76b00",
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
"gsd-core/workflows/audit-fix.md": "d25431af0ecf6355",
"gsd-core/workflows/audit-fix.md": "9fdfe8a7fbcd1417",
"gsd-core/workflows/audit-milestone.md": "19e03e6d34d96f38",
"gsd-core/workflows/audit-uat.md": "5ea0e30548ed0933",
"gsd-core/workflows/autonomous.md": "dd972ddde9663295",
@@ -232,10 +232,11 @@
"gsd-core/workflows/docs-update.md": "9292cfa3c52c434e",
"gsd-core/workflows/edit-phase.md": "8667c28b22b1599f",
"gsd-core/workflows/eval-review.md": "81c8e72ba3862856",
"gsd-core/workflows/execute-phase.md": "bc0ec0e19ce96269",
"gsd-core/workflows/execute-phase.md": "6f7aa92705d3527e",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "63b712920f21a40f",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "15f872e83ad87196",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "1b73ab2fc47c9dbf",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "b26edeee455481a7",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "c5e9dae726db15cc",
"gsd-core/workflows/explore.md": "5fd91a8510e1114b",
@@ -307,7 +308,7 @@
"gsd-core/workflows/undo.md": "ba1ef7aa80bef6bd",
"gsd-core/workflows/update.md": "f444a7cfcd246cfb",
"gsd-core/workflows/validate-phase.md": "2f705775a4b76d42",
"gsd-core/workflows/verify-phase.md": "59d1046b3a2bc481",
"gsd-core/workflows/verify-phase.md": "5c72780e34214e27",
"gsd-core/workflows/verify-work.md": "58e9b1b16f773b53",
"hooks/gsd-session.json": "0a462834f2a28fee",
"scripts/changeset/README.md": "86ff89331dfd94b2",

View File

@@ -109,10 +109,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "2525f1ae8b086828",
"gsd-core/bin/gsd-tools.cjs": "7fd5fbaf1bbd9db5",
"gsd-core/bin/gsd-tools.cjs": "3fa86b509ea5c8fc",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
@@ -233,7 +233,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "762b16f9a6488474",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "69b01e7909ea3f66",
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -271,7 +271,7 @@
"gsd-core/workflows/add-todo.md": "d483ebe8edcf193a",
"gsd-core/workflows/ai-integration-phase.md": "b79f320d59a68773",
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
"gsd-core/workflows/audit-milestone.md": "23c1e35f449933b8",
"gsd-core/workflows/audit-uat.md": "e11db0d74c2a7405",
"gsd-core/workflows/autonomous.md": "4b20eda9a0b587ce",
@@ -302,10 +302,11 @@
"gsd-core/workflows/docs-update.md": "e86d7d7e2e3dac6d",
"gsd-core/workflows/edit-phase.md": "8323bfe10faa0c0a",
"gsd-core/workflows/eval-review.md": "a86279dd98dd5c03",
"gsd-core/workflows/execute-phase.md": "f9c628754cd74d0a",
"gsd-core/workflows/execute-phase.md": "cf1b15f505b519d8",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "facb0e816d87a0c7",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "83dc1bf7f73735c0",
"gsd-core/workflows/explore.md": "b9eea1bac358c9ce",
@@ -377,7 +378,7 @@
"gsd-core/workflows/undo.md": "18dec684fb1076f9",
"gsd-core/workflows/update.md": "23e294ba707c3580",
"gsd-core/workflows/validate-phase.md": "2df0c6e298a5f249",
"gsd-core/workflows/verify-phase.md": "0d4ffabc1caa473a",
"gsd-core/workflows/verify-phase.md": "e0957e153788a222",
"gsd-core/workflows/verify-work.md": "145596b2542c457a",
"hooks/gsd-cursor-post-tool.js": "019d503aee8b4a3f",
"hooks/gsd-cursor-session-start.js": "c6e04ed597ea7020",

View File

@@ -38,10 +38,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "3a3409215044af9f",
"gsd-core/bin/gsd-tools.cjs": "e666de93d4fd49fc",
"gsd-core/bin/gsd-tools.cjs": "e979f092ce2b15ee",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
@@ -162,7 +162,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "6f968b6bb6e1982f",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "69b01e7909ea3f66",
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -200,7 +200,7 @@
"gsd-core/workflows/add-todo.md": "5fe3ddc3227e0e22",
"gsd-core/workflows/ai-integration-phase.md": "ddab2912d025db65",
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
"gsd-core/workflows/audit-fix.md": "cc6270e912471cc2",
"gsd-core/workflows/audit-fix.md": "2eee4a0be82ef951",
"gsd-core/workflows/audit-milestone.md": "806d346ee5bfe9f8",
"gsd-core/workflows/audit-uat.md": "86d9131fccabf2ad",
"gsd-core/workflows/autonomous.md": "dd572ca89862e5ec",
@@ -231,10 +231,11 @@
"gsd-core/workflows/docs-update.md": "4d6c06e611d83b6d",
"gsd-core/workflows/edit-phase.md": "7f27003f20e88fb8",
"gsd-core/workflows/eval-review.md": "f510e5762212dc6f",
"gsd-core/workflows/execute-phase.md": "c449a87fcca14433",
"gsd-core/workflows/execute-phase.md": "f36c7b810285838c",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "ceb8758c22660c1a",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "3ab8bc8a07133068",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "c9ad17d6cc6dfe45",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "5a78d5dfea6a911a",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "4dbe9b6f0c976245",
"gsd-core/workflows/explore.md": "48770d68e8b9c132",
@@ -306,7 +307,7 @@
"gsd-core/workflows/undo.md": "791e0bf96d9a057f",
"gsd-core/workflows/update.md": "7499bb4cb2a3ce6f",
"gsd-core/workflows/validate-phase.md": "75e8971d3981d06b",
"gsd-core/workflows/verify-phase.md": "84e00bd685006870",
"gsd-core/workflows/verify-phase.md": "5c8d1305b47fbef4",
"gsd-core/workflows/verify-work.md": "e56e07475d5eb51e",
"hooks/gsd-check-update-worker.js": "7989cc2bedd1138d",
"hooks/gsd-check-update.js": "25f5ad726f76fc11",

View File

@@ -109,10 +109,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
@@ -233,7 +233,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "5b5dd37145241462",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "593d4e6d20fdde7c",
"gsd-core/templates/continue-here.md": "8b1dce4832c7922b",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -271,7 +271,7 @@
"gsd-core/workflows/add-todo.md": "5082510bf0449204",
"gsd-core/workflows/ai-integration-phase.md": "c85c6afdc64f0da6",
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
"gsd-core/workflows/audit-milestone.md": "23c1e35f449933b8",
"gsd-core/workflows/audit-uat.md": "e11db0d74c2a7405",
"gsd-core/workflows/autonomous.md": "73f429f7472c9949",
@@ -302,10 +302,11 @@
"gsd-core/workflows/docs-update.md": "79afaaf19fd527cc",
"gsd-core/workflows/edit-phase.md": "8323bfe10faa0c0a",
"gsd-core/workflows/eval-review.md": "926eda8bbee28b23",
"gsd-core/workflows/execute-phase.md": "17cf87593b833b6d",
"gsd-core/workflows/execute-phase.md": "ec448a1e25854abf",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "facb0e816d87a0c7",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "8dc89b35582407f7",
"gsd-core/workflows/explore.md": "14242d36d4822df6",
@@ -377,7 +378,7 @@
"gsd-core/workflows/undo.md": "7cd2153f8b15e30d",
"gsd-core/workflows/update.md": "07dc2fba78ad1865",
"gsd-core/workflows/validate-phase.md": "557e3251e3b9349a",
"gsd-core/workflows/verify-phase.md": "0d4ffabc1caa473a",
"gsd-core/workflows/verify-phase.md": "e0957e153788a222",
"gsd-core/workflows/verify-work.md": "b68ac37f6301a3b5",
"hooks/gsd-check-update-worker.js": "c992bbad91d0e994",
"hooks/gsd-check-update.js": "fdd77abe7ef26a2d",

View File

@@ -74,10 +74,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
@@ -198,7 +198,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "222997133232a6f5",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "69b01e7909ea3f66",
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -236,7 +236,7 @@
"gsd-core/workflows/add-todo.md": "cc0efe270004c8fb",
"gsd-core/workflows/ai-integration-phase.md": "40c217869a06981f",
"gsd-core/workflows/analyze-dependencies.md": "52942af10f140717",
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
"gsd-core/workflows/audit-milestone.md": "6866ce260980c21e",
"gsd-core/workflows/audit-uat.md": "fcfbec501620b564",
"gsd-core/workflows/autonomous.md": "7e5683728ef33707",
@@ -267,10 +267,11 @@
"gsd-core/workflows/docs-update.md": "f35922d15b7061c9",
"gsd-core/workflows/edit-phase.md": "966a3eadd1bebc04",
"gsd-core/workflows/eval-review.md": "f898936e2cfe4130",
"gsd-core/workflows/execute-phase.md": "5d3377bc8ebbae58",
"gsd-core/workflows/execute-phase.md": "91fe17be2d178f24",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "4e265392b3f2ba0e",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "c8502b7475d797a7",
"gsd-core/workflows/explore.md": "6c04f2e658d93261",
@@ -342,7 +343,7 @@
"gsd-core/workflows/undo.md": "96d2775f008b3a85",
"gsd-core/workflows/update.md": "6718e0632bba26ca",
"gsd-core/workflows/validate-phase.md": "2c6d7671fcaabcaa",
"gsd-core/workflows/verify-phase.md": "98a995046bdb6c3c",
"gsd-core/workflows/verify-phase.md": "22f18492581f1da5",
"gsd-core/workflows/verify-work.md": "34e980a6950cd83c",
"scripts/changeset/README.md": "86ff89331dfd94b2",
"scripts/changeset/cli.cjs": "68f92a344b199271",

View File

@@ -109,10 +109,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
@@ -233,7 +233,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "bb76f9538f2bc4e0",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "593d4e6d20fdde7c",
"gsd-core/templates/continue-here.md": "8b1dce4832c7922b",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -271,7 +271,7 @@
"gsd-core/workflows/add-todo.md": "72fcef9fd0cafda5",
"gsd-core/workflows/ai-integration-phase.md": "90e5f97018715b18",
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
"gsd-core/workflows/audit-fix.md": "497a33eb4ee38d47",
"gsd-core/workflows/audit-fix.md": "2871c5d0a4b671fa",
"gsd-core/workflows/audit-milestone.md": "7aa0db364a4b67e2",
"gsd-core/workflows/audit-uat.md": "c800099fab1e1c1b",
"gsd-core/workflows/autonomous.md": "6cb0c014f5f56965",
@@ -302,10 +302,11 @@
"gsd-core/workflows/docs-update.md": "850366c2ef8fb780",
"gsd-core/workflows/edit-phase.md": "1876c855fb0a0a39",
"gsd-core/workflows/eval-review.md": "5394694d29ad7543",
"gsd-core/workflows/execute-phase.md": "ec2ef02d93b17a24",
"gsd-core/workflows/execute-phase.md": "9026c312d564381f",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "1804215577f1ad35",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "647ec0d29a0d6365",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "baa2c401af10a80a",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "b86ca98268dd3705",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "e8de8ea661c1fe81",
"gsd-core/workflows/explore.md": "7f5f9231cfd3089b",
@@ -377,7 +378,7 @@
"gsd-core/workflows/undo.md": "0bba5e7f6196c894",
"gsd-core/workflows/update.md": "71b6cd852f38b4bc",
"gsd-core/workflows/validate-phase.md": "abcdbc1b56780565",
"gsd-core/workflows/verify-phase.md": "5bd04b040cd071dd",
"gsd-core/workflows/verify-phase.md": "126be1d026900102",
"gsd-core/workflows/verify-work.md": "f0d205568abfaf74",
"hooks/gsd-check-update-worker.js": "385fb7c67810baf6",
"hooks/gsd-check-update.js": "4549451414ffa7d7",

View File

@@ -38,10 +38,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "6e98d76e955e35a2",
"gsd-core/bin/gsd-tools.cjs": "1caaaac4e81c7105",
"gsd-core/bin/gsd-tools.cjs": "0341a6cf54b9acbe",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
@@ -162,7 +162,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "fe32daf7235d2a93",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "69b01e7909ea3f66",
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -200,7 +200,7 @@
"gsd-core/workflows/add-todo.md": "5e037b444e657557",
"gsd-core/workflows/ai-integration-phase.md": "afdc7c15f03a95fc",
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
"gsd-core/workflows/audit-fix.md": "da62236c7b3161a0",
"gsd-core/workflows/audit-fix.md": "aaa1b74e001322b6",
"gsd-core/workflows/audit-milestone.md": "b7617cf590d92a56",
"gsd-core/workflows/audit-uat.md": "97d441d07e7972b3",
"gsd-core/workflows/autonomous.md": "3014ff90115f0daf",
@@ -231,10 +231,11 @@
"gsd-core/workflows/docs-update.md": "45d2f0d173c84e07",
"gsd-core/workflows/edit-phase.md": "0fb5e0123cfc6f36",
"gsd-core/workflows/eval-review.md": "6dee8a1e40ececd4",
"gsd-core/workflows/execute-phase.md": "6bb6f3c6a33c4233",
"gsd-core/workflows/execute-phase.md": "60deeb0a791c3cd5",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "36af8d91e4ae8b9c",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "5c30e38cdc265e20",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "98db1ba4c39cd784",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "56fc78db4de210df",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "503b0ced0731dc38",
"gsd-core/workflows/explore.md": "e1a83a8982532e5b",
@@ -306,7 +307,7 @@
"gsd-core/workflows/undo.md": "791e0bf96d9a057f",
"gsd-core/workflows/update.md": "b34cb866152d4de3",
"gsd-core/workflows/validate-phase.md": "e989cbaa4228564c",
"gsd-core/workflows/verify-phase.md": "a8679ba1d84145c5",
"gsd-core/workflows/verify-phase.md": "0dc52b9e629a5f5a",
"gsd-core/workflows/verify-work.md": "b5afb65fdf311301",
"hooks/gsd-check-update-worker.js": "4bb354044e0dff91",
"hooks/gsd-check-update.js": "d2065cb3e725a42a",

View File

@@ -38,10 +38,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "de4627dff103d527",
"gsd-core/bin/gsd-tools.cjs": "172d8fce13b74b2d",
"gsd-core/bin/gsd-tools.cjs": "75bf5691ded4927b",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
@@ -162,7 +162,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "c9c5df7a8911bca9",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "69b01e7909ea3f66",
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -200,7 +200,7 @@
"gsd-core/workflows/add-todo.md": "0fe07cbd29ec252b",
"gsd-core/workflows/ai-integration-phase.md": "d469eb120e52de0f",
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
"gsd-core/workflows/audit-fix.md": "ac71c1179444fdc3",
"gsd-core/workflows/audit-fix.md": "76607add3257cb37",
"gsd-core/workflows/audit-milestone.md": "a379eda51d821bce",
"gsd-core/workflows/audit-uat.md": "6e768b1c208a787a",
"gsd-core/workflows/autonomous.md": "c482645c5d1ead46",
@@ -231,10 +231,11 @@
"gsd-core/workflows/docs-update.md": "f13571f08e083356",
"gsd-core/workflows/edit-phase.md": "7facd0faa33c8cad",
"gsd-core/workflows/eval-review.md": "37d545d4f0db4927",
"gsd-core/workflows/execute-phase.md": "0f90fb13e63cf2b2",
"gsd-core/workflows/execute-phase.md": "aa5abb8c77a00153",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "c985a30317a1aa6b",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "1e0cc4675bcf1496",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "0a9e915170c7121c",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "4b00ef3484a84954",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "4910f75bab2040ab",
"gsd-core/workflows/explore.md": "8a5437aa0c239c38",
@@ -306,7 +307,7 @@
"gsd-core/workflows/undo.md": "59b8baa54efc4110",
"gsd-core/workflows/update.md": "1f935251fca1f276",
"gsd-core/workflows/validate-phase.md": "1c0ebe56d96a14d1",
"gsd-core/workflows/verify-phase.md": "53cbdce394dcdac0",
"gsd-core/workflows/verify-phase.md": "a151ed36eb51813b",
"gsd-core/workflows/verify-work.md": "d3a0970205acc6a5",
"scripts/changeset/README.md": "86ff89331dfd94b2",
"scripts/changeset/cli.cjs": "68f92a344b199271",

View File

@@ -38,10 +38,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "5636ca0b726871b2",
"gsd-core/bin/gsd-tools.cjs": "d4fb7a7431f2b7d2",
"gsd-core/bin/gsd-tools.cjs": "dd746ae946645155",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
@@ -162,7 +162,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "f7e0345b72e84e6e",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "69b01e7909ea3f66",
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -200,7 +200,7 @@
"gsd-core/workflows/add-todo.md": "cab0d8215579fbdd",
"gsd-core/workflows/ai-integration-phase.md": "8948988717506320",
"gsd-core/workflows/analyze-dependencies.md": "77aff48f97fa6f1c",
"gsd-core/workflows/audit-fix.md": "babe6812b86cec8f",
"gsd-core/workflows/audit-fix.md": "aa052e15623d759d",
"gsd-core/workflows/audit-milestone.md": "ac2238ea6c11ae9e",
"gsd-core/workflows/audit-uat.md": "d496e39402e160de",
"gsd-core/workflows/autonomous.md": "fe7bb7c978f305a2",
@@ -231,10 +231,11 @@
"gsd-core/workflows/docs-update.md": "70f73cc8c27e0ca0",
"gsd-core/workflows/edit-phase.md": "c0ae7d0063f3e789",
"gsd-core/workflows/eval-review.md": "b28be79ef29f16fd",
"gsd-core/workflows/execute-phase.md": "7cf72d7c95491ece",
"gsd-core/workflows/execute-phase.md": "1dac1bdda0696dc0",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "47ae5482f8e64100",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "0f9ccd7edea1d6a9",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "15bca39a75c664be",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "02324a66cb42fae3",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "c8567fb4438b4404",
"gsd-core/workflows/explore.md": "04e461ff8159a24e",
@@ -306,7 +307,7 @@
"gsd-core/workflows/undo.md": "18dec684fb1076f9",
"gsd-core/workflows/update.md": "79aaf4b8f1f83045",
"gsd-core/workflows/validate-phase.md": "2db47bf5547d7b9d",
"gsd-core/workflows/verify-phase.md": "ea7f8a705b297e27",
"gsd-core/workflows/verify-phase.md": "f961cdb3ef03ff05",
"gsd-core/workflows/verify-work.md": "5ad63a5edfb6acac",
"scripts/changeset/README.md": "86ff89331dfd94b2",
"scripts/changeset/cli.cjs": "68f92a344b199271",

View File

@@ -109,10 +109,10 @@
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
"gsd-core/bin/gsd-tools.cjs": "2c08276ad3758a7d",
"gsd-core/bin/gsd-tools.cjs": "6a7616125440c8b1",
"gsd-core/bin/gsd_run": "62d9b647ede212e6",
"gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16",
"gsd-core/bin/shared/config-schema.manifest.json": "1318633d27964e7a",
"gsd-core/bin/shared/config-schema.manifest.json": "6bba2b9c9fa47cb8",
"gsd-core/bin/shared/model-catalog.json": "e554a288fcbc1b2e",
"gsd-core/bin/shared/runtime-aliases.manifest.json": "2df2c5ac1957911a",
"gsd-core/bin/verify-reapply-patches.cjs": "caec5dbce11e3904",
@@ -233,7 +233,7 @@
"gsd-core/templates/codebase/stack.md": "116e7e67dd87ddec",
"gsd-core/templates/codebase/structure.md": "222997133232a6f5",
"gsd-core/templates/codebase/testing.md": "76abff7f2050c9ea",
"gsd-core/templates/config.json": "1473dff11272d3c4",
"gsd-core/templates/config.json": "a4b783ef759a0f37",
"gsd-core/templates/context.md": "69b01e7909ea3f66",
"gsd-core/templates/continue-here.md": "f522a51b6895fba8",
"gsd-core/templates/copilot-instructions.md": "aea34bc52ff548ea",
@@ -271,7 +271,7 @@
"gsd-core/workflows/add-todo.md": "cc0efe270004c8fb",
"gsd-core/workflows/ai-integration-phase.md": "40c217869a06981f",
"gsd-core/workflows/analyze-dependencies.md": "52942af10f140717",
"gsd-core/workflows/audit-fix.md": "514d02c730349a35",
"gsd-core/workflows/audit-fix.md": "eedb2da4bffb7575",
"gsd-core/workflows/audit-milestone.md": "6866ce260980c21e",
"gsd-core/workflows/audit-uat.md": "fcfbec501620b564",
"gsd-core/workflows/autonomous.md": "7e5683728ef33707",
@@ -302,10 +302,11 @@
"gsd-core/workflows/docs-update.md": "f35922d15b7061c9",
"gsd-core/workflows/edit-phase.md": "966a3eadd1bebc04",
"gsd-core/workflows/eval-review.md": "f898936e2cfe4130",
"gsd-core/workflows/execute-phase.md": "49f793a605e4665e",
"gsd-core/workflows/execute-phase.md": "bb4f1120804c5a90",
"gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md": "4e265392b3f2ba0e",
"gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md": "7ebb7d1af6082028",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "fca31a68773b37da",
"gsd-core/workflows/execute-phase/steps/post-merge-gate.md": "811b6d8489571581",
"gsd-core/workflows/execute-phase/steps/regression-gate.md": "8ccc16a6c7cf6000",
"gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md": "be84efbd71e1513e",
"gsd-core/workflows/execute-plan.md": "ed874410972d32b7",
"gsd-core/workflows/explore.md": "6c04f2e658d93261",
@@ -377,7 +378,7 @@
"gsd-core/workflows/undo.md": "96d2775f008b3a85",
"gsd-core/workflows/update.md": "dc580dee13f881a6",
"gsd-core/workflows/validate-phase.md": "2c6d7671fcaabcaa",
"gsd-core/workflows/verify-phase.md": "98a995046bdb6c3c",
"gsd-core/workflows/verify-phase.md": "22f18492581f1da5",
"gsd-core/workflows/verify-work.md": "34e980a6950cd83c",
"hooks/gsd-check-update-worker.js": "6660bcf03ed849a0",
"hooks/gsd-check-update.js": "901ea3bd75fd5bbc",

View File

@@ -0,0 +1,158 @@
'use strict';
/**
* Regression tests for the test-command normalizer (#1857).
*
* A GSD test gate must not hang forever on a watch-mode runner. The normalizer
* rewrites a resolved test command to a best-effort one-shot form; the gate's
* wall-clock timeout is the ultimate guarantee (asserted separately as workflow
* content). These tests cover the two normalization acceptance criteria:
* (a) an already-one-shot command is invoked UNCHANGED (never double-flagged),
* (b) a watch-mode command is normalized to a one-shot form.
*/
const { test, describe, beforeEach, afterEach } = 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 { cleanup } = require('./helpers.cjs');
const normalizer = require('../gsd-core/bin/lib/normalize-test-command.cjs');
const { normalizeTestCommand, isAlreadyOneShot } = normalizer;
function tmpProject(testScript) {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1857-'));
fs.writeFileSync(
path.join(dir, 'package.json'),
JSON.stringify({ scripts: { test: testScript } }),
);
return dir;
}
describe('normalizeTestCommand: direct vitest (watch by default) → one-shot (#1857)', () => {
test('bare vitest gains "run"', () => {
assert.strictEqual(normalizeTestCommand('vitest', '/tmp'), 'vitest run');
});
test('npx vitest with flags gains "run" and keeps flags', () => {
assert.strictEqual(normalizeTestCommand('npx vitest --coverage', '/tmp'), 'npx vitest run --coverage');
});
test('vitest --watch is stripped and made one-shot', () => {
assert.strictEqual(normalizeTestCommand('vitest --watch', '/tmp'), 'vitest run');
});
});
describe('normalizeTestCommand: already one-shot is a no-op (#1857)', () => {
for (const cmd of ['vitest run', 'vitest --run', 'npx vitest run -t foo', 'jest --watchAll=false']) {
test(`"${cmd}" is recognised one-shot and returned unchanged`, () => {
assert.strictEqual(normalizeTestCommand(cmd, '/tmp'), cmd);
assert.ok(isAlreadyOneShot(cmd), `"${cmd}" should be recognised as one-shot`);
});
}
// jest is one-shot by default (no --watch); --runInBand doesn't disable watch,
// so it isn't a one-shot MARKER — but a jest command without a watch flag is
// still returned unchanged via the jest branch.
for (const cmd of ['jest', 'jest --runInBand']) {
test(`"${cmd}" (jest, no watch flag) is returned unchanged`, () => {
assert.strictEqual(normalizeTestCommand(cmd, '/tmp'), cmd);
});
}
});
describe('normalizeTestCommand: direct jest with watch flag → one-shot (#1857)', () => {
test('jest --watch → --watchAll=false', () => {
assert.strictEqual(normalizeTestCommand('jest --watch', '/tmp'), 'jest --watchAll=false');
});
test('jest --watchAll → --watchAll=false', () => {
assert.strictEqual(normalizeTestCommand('jest --watchAll', '/tmp'), 'jest --watchAll=false');
});
});
describe('normalizeTestCommand: package-manager script invocation inspects package.json (#1857)', () => {
let vitestDir; let vitestRunDir; let jestDir;
beforeEach(() => {
vitestDir = tmpProject('vitest'); // watches by default
vitestRunDir = tmpProject('vitest run'); // already one-shot
jestDir = tmpProject('jest'); // one-shot by default
});
afterEach(() => {
for (const d of [vitestDir, vitestRunDir, jestDir]) {
cleanup(d);
}
});
test('npm test whose script is watch-vitest → CI=true prefix', () => {
assert.strictEqual(normalizeTestCommand('npm test', vitestDir), 'CI=true npm test');
});
test('pnpm test whose script is watch-vitest → CI=true prefix', () => {
assert.strictEqual(normalizeTestCommand('pnpm test', vitestDir), 'CI=true pnpm test');
});
test('npm test whose script is already "vitest run" → unchanged', () => {
assert.strictEqual(normalizeTestCommand('npm test', vitestRunDir), 'npm test');
});
test('npm test whose script is jest (one-shot) → unchanged', () => {
assert.strictEqual(normalizeTestCommand('npm test', jestDir), 'npm test');
});
test('pnpm --dir <app> test inspects the target package.json (#1857 comment 5)', () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1857-root-'));
try {
fs.mkdirSync(path.join(root, 'app'));
fs.writeFileSync(path.join(root, 'app', 'package.json'), JSON.stringify({ scripts: { test: 'vitest' } }));
assert.strictEqual(normalizeTestCommand('pnpm --dir app test', root), 'CI=true pnpm --dir app test');
// An explicit --run the user already passed is respected (no-op); the
// gate timeout backstops a project that still watches despite --run.
assert.strictEqual(normalizeTestCommand('pnpm --dir app test -- --run', root), 'pnpm --dir app test -- --run');
} finally {
cleanup(root);
}
});
});
describe('normalizeTestCommand: non-JS / unknown runners are untouched (#1857)', () => {
for (const cmd of ['cargo test', 'go test ./...', 'make test', 'python -m pytest -q', 'true', '']) {
test(`"${cmd}" is returned unchanged`, () => {
assert.strictEqual(normalizeTestCommand(cmd, '/tmp'), cmd);
});
}
test('npm test with no package.json is left unchanged (cannot classify)', () => {
const empty = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1857-empty-'));
try {
assert.strictEqual(normalizeTestCommand('npm test', empty), 'npm test');
} finally {
cleanup(empty);
}
});
});
describe('normalizeTestCommand: security hardening (#1857 review)', () => {
// "vitest"/"jest" as a token that isn't the invoked binary must NOT be mangled.
for (const cmd of ['make test-vitest', 'node ./scripts/run-vitest.js', './bin/vitest-wrapper.sh', 'cat vitest.config.js', 'node jest-runner.js']) {
test(`"${cmd}" is not mangled (word-token, not substring)`, () => {
assert.strictEqual(normalizeTestCommand(cmd, '/tmp'), cmd);
});
}
test('an oversized command is returned unchanged and in linear time (no ReDoS)', () => {
// The blow-up input from the review: a long "npm " run with no `test` token.
const huge = 'npm '.repeat(200000); // ~800 KB
const start = Date.now();
const out = normalizeTestCommand(huge, '/tmp');
const elapsedMs = Date.now() - start;
assert.strictEqual(out, huge, 'oversized input must be returned unchanged');
assert.ok(elapsedMs < 250, `normalization must be fast even on adversarial input (took ${elapsedMs}ms)`);
});
test('a package.json that is not a regular file is ignored (no FIFO hang)', () => {
// resolvePackageDir would point here; a non-regular "package.json" must be skipped.
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1857-notfile-'));
try {
fs.mkdirSync(path.join(dir, 'package.json')); // a DIRECTORY named package.json
// Classified as "cannot determine runner" → command returned unchanged.
assert.strictEqual(normalizeTestCommand('npm test', dir), 'npm test');
} finally {
cleanup(dir);
}
});
});

View File

@@ -122,9 +122,9 @@ const ALLOWLIST = {
'review.md': ['time_sizing'],
// Fast uses "under 2 minutes wall time" as operational constraint
'fast.md': ['time_sizing'],
// Execute-phase uses "timeout: 5 minutes" for test runner
// Execute-phase uses a configurable test-gate timeout (workflow.test_gate_timeout, #1857)
'execute-phase.md': ['time_sizing'],
// Verify-phase uses "timeout: 5 minutes" for test runner
// Verify-phase uses a configurable test-gate timeout (workflow.test_gate_timeout, #1857)
'verify-phase.md': ['time_sizing'],
// Map-codebase documents subagent_timeout
'map-codebase.md': ['time_sizing'],

View File

@@ -0,0 +1,93 @@
// allow-test-rule: source-text-is-the-product #1857
// Workflow .md files — their text IS the deployed contract the orchestrator runs.
/**
* #1857: a GSD test gate must not hang forever on a watch-mode runner.
*
* Three gates were UNBOUNDED or silently-continued and are the core fix. They must:
* - route the resolved command through the shared `normalize-test-command`
* helper (defeats vitest/jest watch mode), so the paths cannot drift,
* - bound execution with `timeout` using the `workflow.test_gate_timeout`
* budget, and
* - surface a timeout (exit 124) with a watch-mode hint — the regression gate
* ABORTS, the others surface clearly (never silently ignored).
*
* verify-phase's gate was ALREADY bounded (a fixed `timeout 300`, not a hang), so
* it only needs the normalizer (so a watch runner exits fast) and keeps its own
* fixed 5-minute bound — asserted separately below.
*/
'use strict';
const { test, describe } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const ROOT = path.join(__dirname, '..');
const REGRESSION_GATE = path.join(ROOT, 'gsd-core', 'workflows', 'execute-phase', 'steps', 'regression-gate.md');
const POST_MERGE_GATE = path.join(ROOT, 'gsd-core', 'workflows', 'execute-phase', 'steps', 'post-merge-gate.md');
const AUDIT_FIX = path.join(ROOT, 'gsd-core', 'workflows', 'audit-fix.md');
const VERIFY_PHASE = path.join(ROOT, 'gsd-core', 'workflows', 'verify-phase.md');
const EXECUTE_PHASE = path.join(ROOT, 'gsd-core', 'workflows', 'execute-phase.md');
function read(p) { return fs.readFileSync(p, 'utf-8'); }
// The three gates that were unbounded/silently-continued: full normalize + configured timeout.
const FULL_GATES = [
['regression gate', REGRESSION_GATE],
['post-merge gate', POST_MERGE_GATE],
['audit-fix gate', AUDIT_FIX],
];
describe('#1857: test gates normalize to one-shot and bound with a timeout', () => {
for (const [label, file] of FULL_GATES) {
describe(label, () => {
test('routes the resolved command through the shared normalize-test-command helper', () => {
const c = read(file);
assert.match(c, /normalize-test-command/, `${label} must call the shared normalize-test-command helper`);
});
test('bounds execution with a timeout using the workflow.test_gate_timeout budget', () => {
const c = read(file);
assert.match(c, /workflow\.test_gate_timeout/, `${label} must read workflow.test_gate_timeout`);
assert.match(c, /timeout "\$TEST_GATE_TIMEOUT"/, `${label} must wrap the test command in a timeout with the configured budget`);
});
test('surfaces a timeout (exit 124) with a watch-mode hint — never a silent hang', () => {
const c = read(file);
assert.match(c, /-eq 124/, `${label} must handle the timeout exit code (124)`);
assert.match(c, /watch\/dev mode/, `${label} must name watch/dev mode as the likely cause on timeout`);
});
});
}
// verify-phase is already bounded (fixed `timeout 300`, not a hang); it only
// needs the normalizer so a watch runner exits fast, and names watch mode on 124.
describe('verify-phase gate (already bounded — normalize-only)', () => {
test('routes the resolved command through the shared normalize-test-command helper', () => {
assert.match(read(VERIFY_PHASE), /normalize-test-command/, 'verify-phase must call the shared normalize-test-command helper');
});
test('surfaces its fixed timeout (exit 124) naming watch/dev mode', () => {
const c = read(VERIFY_PHASE);
assert.match(c, /-eq 124/, 'verify-phase must handle the timeout exit code (124)');
assert.match(c, /watch\/dev mode/, 'verify-phase must name watch/dev mode as the likely cause on timeout');
});
});
test('the regression gate ABORTS (halts) on a watch-mode timeout', () => {
const c = read(REGRESSION_GATE);
assert.match(c, /REGRESSION GATE ABORTED/, 'regression gate must abort (not continue) on timeout');
});
test('execute-phase.md delegates the regression gate to the extracted step (size-frozen file stays lean)', () => {
const c = read(EXECUTE_PHASE);
assert.match(c, /steps\/regression-gate\.md/, 'execute-phase.md must reference the extracted regression-gate step');
});
test('the gates share ONE normalizer — the helper is a single source of truth', () => {
// The behaviour lives in src/normalize-test-command.cts; every gate invokes it
// by the same verb name, so a change to watch-defeat logic touches one place.
for (const file of [REGRESSION_GATE, POST_MERGE_GATE, AUDIT_FIX, VERIFY_PHASE]) {
assert.match(read(file), /gsd_run query normalize-test-command/);
}
});
});

View File

@@ -5,7 +5,7 @@
"add-todo.md": 8996,
"ai-integration-phase.md": 14805,
"analyze-dependencies.md": 3887,
"audit-fix.md": 11032,
"audit-fix.md": 11717,
"audit-milestone.md": 17681,
"audit-uat.md": 7469,
"autonomous.md": 42474,
@@ -24,7 +24,7 @@
"docs-update.md": 55706,
"edit-phase.md": 12927,
"eval-review.md": 9967,
"execute-phase.md": 93528,
"execute-phase.md": 93132,
"execute-plan.md": 32655,
"explore.md": 10541,
"extract-learnings.md": 12893,
@@ -88,6 +88,6 @@
"undo.md": 10431,
"update.md": 20914,
"validate-phase.md": 10789,
"verify-phase.md": 40772,
"verify-phase.md": 40923,
"verify-work.md": 38267
}