@opengsd/gsd-core 1.12.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (286) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +12 -0
  4. package/agents/gsd-executor.md +63 -35
  5. package/agents/gsd-plan-checker.md +76 -57
  6. package/agents/gsd-planner.md +14 -0
  7. package/agents/gsd-ui-checker.md +19 -3
  8. package/agents/gsd-ui-researcher.md +29 -0
  9. package/agents/gsd-verifier.md +23 -1
  10. package/bin/install.js +239 -67
  11. package/commands/gsd/execute-phase.md +1 -1
  12. package/commands/gsd/ns-workflow.md +2 -1
  13. package/commands/gsd/phase.md +1 -1
  14. package/commands/gsd/quick-batch.md +105 -0
  15. package/commands/gsd/surface.md +18 -8
  16. package/gsd-core/bin/gsd-tools.cjs +195 -50
  17. package/gsd-core/bin/lib/capability-activation.cjs +27 -0
  18. package/gsd-core/bin/lib/capability-registry.cjs +514 -114
  19. package/gsd-core/bin/lib/capability-state.cjs +7 -1
  20. package/gsd-core/bin/lib/capability-validator.cjs +120 -4
  21. package/gsd-core/bin/lib/capability-writer.cjs +14 -4
  22. package/gsd-core/bin/lib/check-command-router.cjs +85 -2
  23. package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
  24. package/gsd-core/bin/lib/clusters.cjs +1 -0
  25. package/gsd-core/bin/lib/command-aliases.cjs +16 -0
  26. package/gsd-core/bin/lib/commands.cjs +337 -13
  27. package/gsd-core/bin/lib/config-loader.cjs +3 -0
  28. package/gsd-core/bin/lib/core-utils.cjs +34 -7
  29. package/gsd-core/bin/lib/decisions.cjs +213 -1
  30. package/gsd-core/bin/lib/edge-probe.cjs +14 -1
  31. package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
  32. package/gsd-core/bin/lib/frontmatter.cjs +137 -23
  33. package/gsd-core/bin/lib/gap-checker.cjs +22 -13
  34. package/gsd-core/bin/lib/git-base-branch.cjs +10 -2
  35. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
  36. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +54 -11
  37. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +75 -22
  38. package/gsd-core/bin/lib/host-integration.cjs +57 -5
  39. package/gsd-core/bin/lib/init-command-router.cjs +14 -0
  40. package/gsd-core/bin/lib/init.cjs +132 -15
  41. package/gsd-core/bin/lib/install-engine.cjs +184 -12
  42. package/gsd-core/bin/lib/install-model-override-resolver.cjs +45 -0
  43. package/gsd-core/bin/lib/install-profiles.cjs +22 -14
  44. package/gsd-core/bin/lib/installer-migration-report.cjs +1 -0
  45. package/gsd-core/bin/lib/io.cjs +35 -0
  46. package/gsd-core/bin/lib/loop-resolver.cjs +14 -8
  47. package/gsd-core/bin/lib/markdown-table.cjs +123 -0
  48. package/gsd-core/bin/lib/milestone.cjs +22 -2
  49. package/gsd-core/bin/lib/phase-command-router.cjs +13 -6
  50. package/gsd-core/bin/lib/phase-id.cjs +251 -9
  51. package/gsd-core/bin/lib/phase.cjs +774 -35
  52. package/gsd-core/bin/lib/plan-document.cjs +10 -0
  53. package/gsd-core/bin/lib/planning-snapshot.cjs +147 -20
  54. package/gsd-core/bin/lib/planning-workspace.cjs +103 -28
  55. package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
  56. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
  57. package/gsd-core/bin/lib/quick-batch.cjs +840 -0
  58. package/gsd-core/bin/lib/review-lane-descriptor.cjs +53 -5
  59. package/gsd-core/bin/lib/review-lane-invocation.cjs +73 -1
  60. package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
  61. package/gsd-core/bin/lib/roadmap-parser.cjs +499 -26
  62. package/gsd-core/bin/lib/roadmap.cjs +187 -58
  63. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +233 -33
  64. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +16 -17
  65. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +286 -108
  66. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +215 -43
  67. package/gsd-core/bin/lib/shell-command-projection.cjs +4 -0
  68. package/gsd-core/bin/lib/smart-entry.cjs +7 -9
  69. package/gsd-core/bin/lib/state-document.cjs +30 -5
  70. package/gsd-core/bin/lib/state-md-schema.cjs +23 -13
  71. package/gsd-core/bin/lib/state-transition.cjs +333 -44
  72. package/gsd-core/bin/lib/state.cjs +684 -125
  73. package/gsd-core/bin/lib/surface.cjs +23 -8
  74. package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
  75. package/gsd-core/bin/lib/uat.cjs +1419 -515
  76. package/gsd-core/bin/lib/update-context.cjs +6 -2
  77. package/gsd-core/bin/lib/validate.cjs +230 -12
  78. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  79. package/gsd-core/bin/lib/verification.cjs +273 -12
  80. package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
  81. package/gsd-core/bin/lib/verify.cjs +346 -16
  82. package/gsd-core/bin/lib/workstream-inventory.cjs +20 -2
  83. package/gsd-core/bin/lib/worktree-safety.cjs +8 -0
  84. package/gsd-core/bin/shared/config-schema.manifest.json +8 -0
  85. package/gsd-core/bin/verify-reapply-patches.cjs +70 -3
  86. package/gsd-core/references/agent-contracts.md +3 -3
  87. package/gsd-core/references/edge-probe.md +17 -13
  88. package/gsd-core/references/execute-mvp-tdd.md +18 -16
  89. package/gsd-core/references/execute-phase-response-language.md +6 -0
  90. package/gsd-core/references/executor-examples.md +42 -0
  91. package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
  92. package/gsd-core/references/mvp-concepts.md +2 -2
  93. package/gsd-core/references/plan-checker-examples.md +41 -0
  94. package/gsd-core/references/planner-antipatterns.md +25 -0
  95. package/gsd-core/references/planner-chunked.md +5 -1
  96. package/gsd-core/references/planner-coupling.md +42 -0
  97. package/gsd-core/references/planner-quick-batch.md +71 -0
  98. package/gsd-core/references/planner-reviews.md +47 -0
  99. package/gsd-core/references/planner-revision.md +75 -2
  100. package/gsd-core/references/planning-config.md +2 -1
  101. package/gsd-core/references/response-language-directive.md +9 -0
  102. package/gsd-core/references/revision-loop.md +118 -11
  103. package/gsd-core/references/tdd.md +14 -9
  104. package/gsd-core/references/verifier-evidence-gate.md +160 -0
  105. package/gsd-core/templates/phase-prompt.md +4 -0
  106. package/gsd-core/templates/verification-report.md +5 -0
  107. package/gsd-core/workflows/add-backlog.md +2 -0
  108. package/gsd-core/workflows/add-phase.md +2 -0
  109. package/gsd-core/workflows/add-tests.md +1 -1
  110. package/gsd-core/workflows/add-todo.md +1 -1
  111. package/gsd-core/workflows/ai-integration-phase.md +1 -1
  112. package/gsd-core/workflows/analyze-dependencies.md +2 -0
  113. package/gsd-core/workflows/audit-fix.md +2 -0
  114. package/gsd-core/workflows/audit-milestone.md +2 -0
  115. package/gsd-core/workflows/audit-uat.md +2 -0
  116. package/gsd-core/workflows/autonomous.md +2 -0
  117. package/gsd-core/workflows/check-todos.md +1 -1
  118. package/gsd-core/workflows/cleanup.md +1 -1
  119. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +15 -13
  120. package/gsd-core/workflows/code-review-fix.md +2 -0
  121. package/gsd-core/workflows/code-review.md +73 -31
  122. package/gsd-core/workflows/complete-milestone.md +13 -4
  123. package/gsd-core/workflows/debug.md +1 -1
  124. package/gsd-core/workflows/diagnose-issues.md +5 -1
  125. package/gsd-core/workflows/discuss-phase/modes/advisor.md +2 -0
  126. package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
  127. package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
  128. package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
  129. package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
  130. package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -0
  131. package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
  132. package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
  133. package/gsd-core/workflows/discuss-phase/modes/text.md +2 -0
  134. package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
  135. package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
  136. package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
  137. package/gsd-core/workflows/discuss-phase-power.md +2 -0
  138. package/gsd-core/workflows/discuss-phase.md +1 -1
  139. package/gsd-core/workflows/do.md +43 -13
  140. package/gsd-core/workflows/docs-update.md +1 -1
  141. package/gsd-core/workflows/edit-phase.md +2 -0
  142. package/gsd-core/workflows/eval-review.md +1 -1
  143. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +2 -0
  144. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +17 -1
  145. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +8 -2
  146. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -0
  147. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
  148. package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
  149. package/gsd-core/workflows/execute-phase.md +32 -14
  150. package/gsd-core/workflows/execute-plan.md +8 -8
  151. package/gsd-core/workflows/explore.md +2 -0
  152. package/gsd-core/workflows/extract-learnings.md +2 -0
  153. package/gsd-core/workflows/fast.md +6 -0
  154. package/gsd-core/workflows/forensics.md +2 -0
  155. package/gsd-core/workflows/graduation.md +1 -1
  156. package/gsd-core/workflows/health.md +1 -1
  157. package/gsd-core/workflows/help/modes/brief.md +2 -0
  158. package/gsd-core/workflows/help/modes/default.md +2 -0
  159. package/gsd-core/workflows/help/modes/full.md +12 -0
  160. package/gsd-core/workflows/help/modes/topic.md +2 -0
  161. package/gsd-core/workflows/help.md +2 -0
  162. package/gsd-core/workflows/import.md +3 -3
  163. package/gsd-core/workflows/inbox.md +1 -1
  164. package/gsd-core/workflows/ingest-docs.md +1 -1
  165. package/gsd-core/workflows/insert-phase.md +2 -0
  166. package/gsd-core/workflows/list-phase-assumptions.md +2 -0
  167. package/gsd-core/workflows/list-seeds.md +2 -0
  168. package/gsd-core/workflows/list-workspaces.md +2 -0
  169. package/gsd-core/workflows/manager.md +3 -3
  170. package/gsd-core/workflows/map-codebase.md +2 -0
  171. package/gsd-core/workflows/milestone-summary.md +2 -0
  172. package/gsd-core/workflows/mvp-phase.md +1 -1
  173. package/gsd-core/workflows/new-milestone.md +1 -1
  174. package/gsd-core/workflows/new-project.md +5 -3
  175. package/gsd-core/workflows/new-workspace.md +1 -1
  176. package/gsd-core/workflows/next.md +2 -0
  177. package/gsd-core/workflows/node-repair.md +2 -0
  178. package/gsd-core/workflows/note.md +2 -0
  179. package/gsd-core/workflows/onboard.md +1 -1
  180. package/gsd-core/workflows/pause-work.md +19 -4
  181. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
  182. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -0
  183. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +9 -0
  184. package/gsd-core/workflows/plan-phase.md +130 -12
  185. package/gsd-core/workflows/plan-review-convergence.md +102 -10
  186. package/gsd-core/workflows/plant-seed.md +1 -1
  187. package/gsd-core/workflows/pr-branch.md +11 -3
  188. package/gsd-core/workflows/profile-user.md +1 -1
  189. package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
  190. package/gsd-core/workflows/progress.md +25 -3
  191. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +37 -2
  192. package/gsd-core/workflows/quick/steps/research-phase.md +3 -3
  193. package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
  194. package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
  195. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
  196. package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
  197. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
  198. package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
  199. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
  200. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
  201. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
  202. package/gsd-core/workflows/quick-batch.md +203 -0
  203. package/gsd-core/workflows/quick.md +13 -3
  204. package/gsd-core/workflows/reapply-patches.md +2 -0
  205. package/gsd-core/workflows/remove-phase.md +2 -0
  206. package/gsd-core/workflows/remove-workspace.md +1 -1
  207. package/gsd-core/workflows/resume-project.md +6 -2
  208. package/gsd-core/workflows/review.md +215 -10
  209. package/gsd-core/workflows/scan.md +2 -0
  210. package/gsd-core/workflows/section-manifest.json +12 -0
  211. package/gsd-core/workflows/secure-phase.md +1 -1
  212. package/gsd-core/workflows/session-report.md +2 -0
  213. package/gsd-core/workflows/settings-advanced.md +2 -0
  214. package/gsd-core/workflows/settings-integrations.md +9 -8
  215. package/gsd-core/workflows/settings.md +1 -1
  216. package/gsd-core/workflows/ship.md +10 -10
  217. package/gsd-core/workflows/sketch-wrap-up.md +2 -0
  218. package/gsd-core/workflows/sketch.md +1 -1
  219. package/gsd-core/workflows/smart-entry.md +1 -1
  220. package/gsd-core/workflows/spec-phase.md +24 -19
  221. package/gsd-core/workflows/spike-wrap-up.md +2 -0
  222. package/gsd-core/workflows/spike.md +1 -1
  223. package/gsd-core/workflows/stats.md +2 -0
  224. package/gsd-core/workflows/sync-skills.md +12 -4
  225. package/gsd-core/workflows/thread.md +2 -0
  226. package/gsd-core/workflows/transition.md +2 -0
  227. package/gsd-core/workflows/ui-phase.md +26 -5
  228. package/gsd-core/workflows/ui-review.md +1 -1
  229. package/gsd-core/workflows/ultraplan-phase.md +2 -0
  230. package/gsd-core/workflows/undo.md +1 -1
  231. package/gsd-core/workflows/update.md +41 -38
  232. package/gsd-core/workflows/validate-phase.md +1 -1
  233. package/gsd-core/workflows/verify-work.md +49 -3
  234. package/hooks/dist/gsd-check-update-worker.js +19 -2
  235. package/hooks/dist/gsd-context-monitor.js +283 -12
  236. package/hooks/dist/gsd-node-runner.sh +1 -0
  237. package/hooks/dist/gsd-prompt-guard.js +30 -5
  238. package/hooks/dist/gsd-read-guard.js +2 -0
  239. package/hooks/dist/gsd-read-injection-scanner.js +5 -5
  240. package/hooks/dist/gsd-secret-read-guard.js +1079 -0
  241. package/hooks/dist/gsd-statusline.js +7 -3
  242. package/hooks/dist/gsd-validate-commit.sh +444 -7
  243. package/hooks/dist/gsd-workflow-guard.js +2 -1
  244. package/hooks/dist/lib/git-cmd.js +210 -1
  245. package/hooks/dist/lib/injection-patterns.js +36 -6
  246. package/hooks/dist/managed-hooks-registry.cjs +1 -0
  247. package/hooks/gsd-check-update-worker.js +19 -2
  248. package/hooks/gsd-context-monitor.js +283 -12
  249. package/hooks/gsd-node-runner.sh +1 -0
  250. package/hooks/gsd-prompt-guard.js +30 -5
  251. package/hooks/gsd-read-guard.js +2 -0
  252. package/hooks/gsd-read-injection-scanner.js +5 -5
  253. package/hooks/gsd-secret-read-guard.js +1079 -0
  254. package/hooks/gsd-statusline.js +7 -3
  255. package/hooks/gsd-validate-commit.sh +444 -7
  256. package/hooks/gsd-workflow-guard.js +2 -1
  257. package/hooks/hooks.json +6 -0
  258. package/hooks/lib/git-cmd.js +210 -1
  259. package/hooks/lib/injection-patterns.js +36 -6
  260. package/hooks/managed-hooks-registry.cjs +1 -0
  261. package/package.json +5 -5
  262. package/scripts/build-hooks.js +11 -4
  263. package/scripts/ci-test-scope.cjs +7 -0
  264. package/scripts/docs-guard-registry.cjs +10 -0
  265. package/scripts/gen-loop-host-contract.cjs +67 -15
  266. package/scripts/lib/shellcheck-fetch.cjs +247 -0
  267. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
  268. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  269. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  270. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +5 -0
  271. package/scripts/lint-phase-enumeration-drift.cjs +24 -6
  272. package/scripts/lint-phase-id-drift.cjs +133 -8
  273. package/scripts/lint-portable-grep.cjs +176 -0
  274. package/scripts/lint-response-language-coverage.cjs +524 -0
  275. package/scripts/lint-test-file-count.allowlist.json +3 -1
  276. package/scripts/lint-workflow-shellcheck-baseline.json +1027 -0
  277. package/scripts/lint-workflow-shellcheck.cjs +614 -0
  278. package/scripts/npm-audit-baseline.cjs +376 -0
  279. package/scripts/prompt-injection-scan.sh +8 -0
  280. package/scripts/require-issue-link-policy.cjs +16 -1
  281. package/skills/gsd-execute-phase/SKILL.md +1 -1
  282. package/skills/gsd-ns-workflow/SKILL.md +1 -0
  283. package/skills/gsd-phase/SKILL.md +1 -1
  284. package/skills/gsd-quick-batch/SKILL.md +105 -0
  285. package/skills/gsd-surface/SKILL.md +18 -8
  286. package/vscode/package.json +1 -1
@@ -19,7 +19,7 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
19
19
 
20
20
  Extract from init JSON: `todo_count`, `todos`, `pending_dir`, `response_language`.
21
21
 
22
- **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
22
+ **If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
23
23
 
24
24
  If `todo_count` is 0:
25
25
  ```
@@ -19,7 +19,7 @@ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-pars
19
19
  RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --raw --default "" 2>/dev/null || echo "")
20
20
  ```
21
21
 
22
- **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
22
+ **If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
23
23
 
24
24
 
25
25
  <step name="identify_completed_milestones">
@@ -27,21 +27,23 @@ FALLOW_STDERR_TMP=$(mktemp)
27
27
  # Phase scope uses fallow's native changed-files scoping (--changed-since <base>).
28
28
  # Derive the phase base commit; if none is found, fall back to repo scope (fallow
29
29
  # auto-detects the base branch). #3191/#3503: the grep is the SAME anchored,
30
- # POSIX-portable conventional-commit-scope derivation the workflow's Tier-3
31
- # scope step uses (subject-line `type((phase-)?N(-plan)?):`, padded or unpadded
32
- # phase spelling). Free prose in commit bodies — "deferred to Phase N per
33
- # D-09", "### Phase N" format examples — never captures the base, and a bare
34
- # digit substring matches version strings, dates, and other phases; the oldest
35
- # such false match would silently widen --changed-since far past the phase.
30
+ # Phase-directory-anchor derivation, lockstep with the workflow's Tier-3
31
+ # scope step (#3191/#3995): base = the parent of the first commit that added
32
+ # anything under the phase's own directory. Commit subjects carry no milestone
33
+ # bound — a same-numbered phase in a previous milestone used to win the grep.
36
34
  FALLOW_SCOPE_ARGS=()
37
35
  if [ \"$FALLOW_SCOPE\" = \"phase\" ]; then
38
- PHASE_SCOPE_NUM=\"${PADDED_PHASE}\"
39
- case \"$PADDED_PHASE\" in
40
- 0[0-9]*) PHASE_SCOPE_NUM=\"${PADDED_PHASE#0}|${PADDED_PHASE}\" ;;
41
- esac
42
- FALLOW_PHASE_COMMITS=$(git log --oneline --all --extended-regexp --grep=\"^[[:alpha:]]+!?\((phase-)?(${PHASE_SCOPE_NUM})(-[0-9]+)?\)!?:\" --format=\"%H\" 2>/dev/null)
43
- if [ -n \"$FALLOW_PHASE_COMMITS\" ]; then
44
- FALLOW_BASE=$(echo \"$FALLOW_PHASE_COMMITS\" | tail -1)^
36
+ # #3995: phase-directory anchor — same derivation as the Tier-3 scope step
37
+ # (lockstep per #3191). A phase number is unique within a milestone, not a
38
+ # repository; the former message grep matched previous milestones'
39
+ # same-numbered phases and tail -1 selected the oldest.
40
+ FALLOW_PHASE_START=$(git log --format=\"%H\" --diff-filter=A -- \"${PHASE_DIR}\" 2>/dev/null | tail -1)
41
+ if [ -n \"$FALLOW_PHASE_START\" ]; then
42
+ if git rev-parse \"${FALLOW_PHASE_START}^\" >/dev/null 2>&1; then
43
+ FALLOW_BASE=\"${FALLOW_PHASE_START}^\"
44
+ else
45
+ FALLOW_BASE=\"${FALLOW_PHASE_START}\"
46
+ fi
45
47
  FALLOW_SCOPE_ARGS=(--changed-since \"$FALLOW_BASE\")
46
48
  fi
47
49
  fi
@@ -1,3 +1,5 @@
1
+ @~/.claude/gsd-core/references/response-language-directive.md
2
+
1
3
  <purpose>
2
4
  Auto-fix issues from REVIEW.md. Validates phase, checks config gate, verifies REVIEW.md exists and has fixable issues, spawns gsd-code-fixer agent, handles --auto iteration loop (capped at 3), commits REVIEW-FIX.md once at the end, and presents results.
3
5
  </purpose>
@@ -1,3 +1,5 @@
1
+ @~/.claude/gsd-core/references/response-language-directive.md
2
+
1
3
  <purpose>
2
4
  Review source files changed during a phase for bugs, security issues, and code quality problems. Computes file scope (--files override > SUMMARY.md > git diff fallback), checks config gate, spawns gsd-code-reviewer agent, commits REVIEW.md, and presents results to user. When --fix is passed, delegates to code-review-fix.md after review to auto-apply findings via gsd-code-fixer.
3
5
  </purpose>
@@ -81,26 +83,36 @@ fi
81
83
  </step>
82
84
 
83
85
  <step name="check_config_gate">
84
- Check if code review is active via the capability registry:
86
+ Check if code review is active via `workflow.code_review` (the capability's on/off toggle — independent of `workflow.code_review_point`, the loop-point selector; a manual invocation must work regardless of which automatic point is currently configured):
85
87
 
86
88
  ```bash
87
- EXECUTE_POST_HOOKS_JSON=$(gsd_run loop render-hooks execute:post --raw)
89
+ CODE_REVIEW_ENABLED=$(gsd_run query config-get workflow.code_review --raw 2>/dev/null || echo "true")
88
90
  ```
89
91
 
90
- Resolve active step hooks from `EXECUTE_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "code-review"`.
91
-
92
- If no active code-review step hook exists:
92
+ If `CODE_REVIEW_ENABLED` is not `"true"`:
93
93
  ```
94
94
  Code review skipped (code-review capability inactive)
95
95
  ```
96
96
  Exit workflow.
97
97
 
98
- Default is active through the Capability Registry schema — only skip when the registry resolves no active code-review step hook. This check runs AFTER phase validation so invalid phase errors are shown first.
98
+ Default is active (`workflow.code_review` schema default is `true`) — only skip when explicitly disabled. This check runs AFTER phase validation so invalid phase errors are shown first.
99
99
  </step>
100
100
 
101
101
  <step name="compute_file_scope">
102
102
  Three-tier scoping with explicit precedence:
103
103
 
104
+ Compute the phase's last review commit, if any. This narrows Tiers 2 and 3 below to what
105
+ changed since that review (wave-scoped reviews under `workflow.code_review_point=execute:wave:post`):
106
+
107
+ ```bash
108
+ # #3661: incremental scoping — when this phase has a prior review, later tiers
109
+ # narrow to what changed since it (wave-scoped reviews under
110
+ # workflow.code_review_point=execute:wave:post). Empty on a phase's first review
111
+ # (the entire execute:post-default path), in which case Tiers 2 and 3 below are
112
+ # unchanged from today.
113
+ LAST_REVIEW_COMMIT=$(git log --format=%H -1 -- "${PHASE_DIR}/${PADDED_PHASE}-REVIEW.md" 2>/dev/null)
114
+ ```
115
+
104
116
  **Tier 1 — --files override (highest precedence per D-08):**
105
117
 
106
118
  If FILES_OVERRIDE is set (from --files flag):
@@ -140,7 +152,18 @@ if [ -z "$FILES_OVERRIDE" ]; then
140
152
  REVIEW_FILES=()
141
153
 
142
154
  if [ -n "$SUMMARIES" ]; then
143
- for summary in $SUMMARIES; do
155
+ # Rewrapped through unquoted command substitution (gsd-core#4109): a bare
156
+ # `$VAR` word-splits under bash but not zsh, collapsing every element onto
157
+ # one iteration there.
158
+ for summary in $(printf '%s' "$SUMMARIES"); do
159
+ # #3661: skip a SUMMARY.md unchanged since the phase's last review — this
160
+ # summary's plan was already reviewed. No-op (every summary is "changed") when
161
+ # LAST_REVIEW_COMMIT is empty. Fails OPEN on any git error (file stays in scope)
162
+ # — never silently drop a file because a git command errored.
163
+ if [ -n "$LAST_REVIEW_COMMIT" ] && git diff --quiet "${LAST_REVIEW_COMMIT}" HEAD -- "$summary" 2>/dev/null; then
164
+ continue
165
+ fi
166
+
144
167
  # Extract key_files.created and key_files.modified using node for reliable YAML parsing
145
168
  # This avoids fragile awk parsing that breaks on indentation differences
146
169
  EXTRACTED=$(node -e "
@@ -222,17 +245,31 @@ surface — so a partial SUMMARY result can no longer silently mask the rest of
222
245
  # #3191: stay POSIX-ERE portable — the boundary is the closing paren + colon,
223
246
  # never \b (not a POSIX ERE token; under --extended-regexp it silently matches
224
247
  # nothing on macOS regex(3), making this fallback dead on Apple platforms).
225
- PHASE_SCOPE_NUM="${PADDED_PHASE}"
226
- case "${PADDED_PHASE}" in
227
- 0[0-9]*) PHASE_SCOPE_NUM="${PADDED_PHASE#0}|${PADDED_PHASE}" ;;
228
- esac
229
- PHASE_COMMITS=$(git log --oneline --all --extended-regexp --grep="^[[:alpha:]]+!?\((phase-)?(${PHASE_SCOPE_NUM})(-[0-9]+)?\)!?:" --format="%H" 2>/dev/null)
248
+ # #3995: a phase number is unique within a MILESTONE, not a repository. The
249
+ # former message grep had no milestone bound, and its tail -1 deliberately
250
+ # selected the OLDEST matching subject — dragging in previous milestones'
251
+ # same-numbered phases and taking a 7-file phase to a 3388-file scope (plus
252
+ # the >50 depth downgrade). The phase's own directory is the unique identity:
253
+ # base = the parent of the first commit that added anything under PHASE_DIR
254
+ # (the same anchor class git-base-branch's phaseStartCommit uses for
255
+ # complexity triggering). Message subjects demonstrably do not carry enough
256
+ # information to identify a phase — this was the grep's fifth failure.
257
+ # KNOWN RESIDUAL: git log -- <dir> does not follow renames, so a LATER
258
+ # milestone that reuses BOTH number and slug re-creates the same literal
259
+ # path and the oldest A-commit is the previous occupant's. Number+slug
260
+ # reuse is the narrow trigger; the reported archived-milestone case (dirs
261
+ # move under milestones/ on archive) is closed.
262
+ PHASE_START=$(git log --format="%H" --diff-filter=A -- "${PHASE_DIR}" 2>/dev/null | tail -1)
230
263
  DIFF_BASE=""
231
- if [ -n "$PHASE_COMMITS" ]; then
232
- DIFF_BASE=$(echo "$PHASE_COMMITS" | tail -1)^
233
- # Verify the parent commit exists (first commit in repo has no parent)
234
- if ! git rev-parse "${DIFF_BASE}" >/dev/null 2>&1; then
235
- DIFF_BASE=$(echo "$PHASE_COMMITS" | tail -1)
264
+ if [ -n "$LAST_REVIEW_COMMIT" ]; then
265
+ # #3661: a prior review exists — narrow the diff base to since that review
266
+ # (wave-scoped) instead of the whole phase.
267
+ DIFF_BASE="$LAST_REVIEW_COMMIT"
268
+ elif [ -n "$PHASE_START" ]; then
269
+ if git rev-parse "${PHASE_START}^" >/dev/null 2>&1; then
270
+ DIFF_BASE="${PHASE_START}^"
271
+ else
272
+ DIFF_BASE="${PHASE_START}"
236
273
  fi
237
274
  fi
238
275
 
@@ -517,22 +554,27 @@ Compute the review output path:
517
554
  REVIEW_PATH="${PHASE_DIR}/${PADDED_PHASE}-REVIEW.md"
518
555
  ```
519
556
 
520
- Compute DIFF_BASE for agent context (in case agent needs it). #3191/#3503: this
521
- must be the SAME anchored, POSIX-portable conventional-commit-scope derivation
522
- the Tier-3 scope step uses — the reviewer agent consumes `diff_base` exactly
557
+ Compute DIFF_BASE for agent context (in case agent needs it). #3191/#3995: this
558
+ must be the SAME phase-directory-anchor derivation the Tier-3 scope step uses —
559
+ the reviewer agent consumes `diff_base` exactly
523
560
  when `files:` is empty, i.e. the same fail-closed scenario Tier 3 protects, so
524
561
  a divergent recomputation here re-arms the mis-scoping one tier down:
525
562
  ```bash
526
- PHASE_SCOPE_NUM="${PADDED_PHASE}"
527
- case "${PADDED_PHASE}" in
528
- 0[0-9]*) PHASE_SCOPE_NUM="${PADDED_PHASE#0}|${PADDED_PHASE}" ;;
529
- esac
530
- PHASE_COMMITS=$(git log --oneline --all --extended-regexp --grep="^[[:alpha:]]+!?\((phase-)?(${PHASE_SCOPE_NUM})(-[0-9]+)?\)!?:" --format="%H" 2>/dev/null)
531
- if [ -n "$PHASE_COMMITS" ]; then
532
- DIFF_BASE=$(echo "$PHASE_COMMITS" | tail -1)^
533
- # Verify the parent commit exists (first commit in repo has no parent)
534
- if ! git rev-parse "${DIFF_BASE}" >/dev/null 2>&1; then
535
- DIFF_BASE=$(echo "$PHASE_COMMITS" | tail -1)
563
+ # #3995: a phase number is unique within a MILESTONE, not a repository. The
564
+ # former message grep had no milestone bound, and its tail -1 deliberately
565
+ # selected the OLDEST matching subject — dragging in previous milestones'
566
+ # same-numbered phases and taking a 7-file phase to a 3388-file scope (plus
567
+ # the >50 depth downgrade). The phase's own directory is the unique identity:
568
+ # base = the parent of the first commit that added anything under PHASE_DIR
569
+ # (the same anchor class git-base-branch's phaseStartCommit uses for
570
+ # complexity triggering). Message subjects demonstrably do not carry enough
571
+ # information to identify a phase — this was the grep's fifth failure.
572
+ PHASE_START=$(git log --format="%H" --diff-filter=A -- "${PHASE_DIR}" 2>/dev/null | tail -1)
573
+ if [ -n "$PHASE_START" ]; then
574
+ if git rev-parse "${PHASE_START}^" >/dev/null 2>&1; then
575
+ DIFF_BASE="${PHASE_START}^"
576
+ else
577
+ DIFF_BASE="${PHASE_START}"
536
578
  fi
537
579
  else
538
580
  DIFF_BASE=""
@@ -756,7 +798,7 @@ If `--files` validation fails unexpectedly on macOS, install coreutils or use ab
756
798
 
757
799
  <success_criteria>
758
800
  - [ ] Phase validated before config gate check
759
- - [ ] Capability gate checked (execute:post code-review hook)
801
+ - [ ] Capability gate checked (`workflow.code_review` config key)
760
802
  - [ ] --fix/--all/--auto flags parsed via code-review-flags.cjs typed IR (not ad-hoc bash)
761
803
  - [ ] Depth resolved with validation (quick|standard|deep)
762
804
  - [ ] File scope computed with 3 tiers: --files > SUMMARY.md > git diff
@@ -46,7 +46,7 @@ RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --raw --default "
46
46
  gsd_run query audit-open
47
47
  ```
48
48
 
49
- **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
49
+ **If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
50
50
 
51
51
  If the output contains open items (any section with count > 0):
52
52
 
@@ -775,7 +775,10 @@ CURRENT_BRANCH=$(git branch --show-current)
775
775
  git checkout ${BASE_BRANCH}
776
776
 
777
777
  if [ "$BRANCHING_STRATEGY" = "phase" ]; then
778
- for branch in $PHASE_BRANCHES; do
778
+ # Rewrapped through unquoted command substitution (gsd-core#4109): a bare
779
+ # `$VAR` word-splits under bash but not zsh, collapsing every element onto
780
+ # one iteration there.
781
+ for branch in $(printf '%s' "$PHASE_BRANCHES"); do
779
782
  git merge --squash "$branch"
780
783
  # Strip .planning/ from staging if commit_docs is false
781
784
  if [ "$COMMIT_DOCS" = "false" ]; then
@@ -804,7 +807,10 @@ CURRENT_BRANCH=$(git branch --show-current)
804
807
  git checkout ${BASE_BRANCH}
805
808
 
806
809
  if [ "$BRANCHING_STRATEGY" = "phase" ]; then
807
- for branch in $PHASE_BRANCHES; do
810
+ # Rewrapped through unquoted command substitution (gsd-core#4109): a bare
811
+ # `$VAR` word-splits under bash but not zsh, collapsing every element onto
812
+ # one iteration there.
813
+ for branch in $(printf '%s' "$PHASE_BRANCHES"); do
808
814
  git merge --no-ff --no-commit "$branch"
809
815
  # Strip .planning/ from staging if commit_docs is false
810
816
  if [ "$COMMIT_DOCS" = "false" ]; then
@@ -830,7 +836,10 @@ git checkout "$CURRENT_BRANCH"
830
836
 
831
837
  ```bash
832
838
  if [ "$BRANCHING_STRATEGY" = "phase" ]; then
833
- for branch in $PHASE_BRANCHES; do
839
+ # Rewrapped through unquoted command substitution (gsd-core#4109): a bare
840
+ # `$VAR` word-splits under bash but not zsh, collapsing every element onto
841
+ # one iteration there.
842
+ for branch in $(printf '%s' "$PHASE_BRANCHES"); do
834
843
  git branch -d "$branch" 2>/dev/null || git branch -D "$branch"
835
844
  done
836
845
  fi
@@ -30,7 +30,7 @@ One round-trip carries everything this workflow needs (#3149 — this call repla
30
30
  - `tdd_mode` — used as `{TDD_MODE}` in the session parameter blocks below.
31
31
  - `section_manifest` — `null` today, because this workflow declares no applicability-section markers of its own. **When it is `null`, read this workflow in full.** When it is present, read only the files named in its `read` array. `null` and an empty `included` array are NOT the same: `null` means "no manifest for this workflow", an empty `included` means "nothing applies".
32
32
 
33
- **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
33
+ **If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
34
34
 
35
35
  ## 1a. LIST subcommand
36
36
 
@@ -1,3 +1,5 @@
1
+ @~/.claude/gsd-core/references/response-language-directive.md
2
+
1
3
  <purpose>
2
4
  Orchestrate parallel debug agents to investigate UAT gaps and find root causes.
3
5
 
@@ -216,7 +218,9 @@ Parse each return to extract:
216
218
  - root_cause: The diagnosed cause
217
219
  - files: Files involved
218
220
  - debug_path: Path to debug session file
219
- - suggested_fix: Hint for gap closure plan
221
+ - fix_hint: NON-BINDING example route for the gap closure plan — the binding payload is
222
+ `root_cause`; a gap plan that removes the root cause by a smaller or different mechanism has
223
+ closed the gap in full
220
224
 
221
225
  If agent returns `## INVESTIGATION INCONCLUSIVE`:
222
226
  - root_cause: "Investigation inconclusive - manual review needed"
@@ -1,3 +1,5 @@
1
+ Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
2
+
1
3
  # Advisor mode — research-backed comparison tables
2
4
 
3
5
  > **Lazy-loaded and gated.** The parent `workflows/discuss-phase.md` Reads
@@ -1,3 +1,5 @@
1
+ Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
2
+
1
3
  # --all mode — auto-select ALL gray areas, discuss interactively
2
4
 
3
5
  > **Lazy-loaded.** Read this file from `workflows/discuss-phase.md` when
@@ -1,3 +1,5 @@
1
+ Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
2
+
1
3
  # --analyze mode — trade-off tables before each question
2
4
 
3
5
  > **Lazy-loaded overlay.** Read this file from `workflows/discuss-phase.md`
@@ -1,3 +1,5 @@
1
+ Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
2
+
1
3
  # --auto mode — fully autonomous discuss-phase
2
4
 
3
5
  > **Lazy-loaded.** Read this file from `workflows/discuss-phase.md` when
@@ -1,3 +1,5 @@
1
+ Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
2
+
1
3
  # --batch mode — grouped question batches
2
4
 
3
5
  > **Lazy-loaded overlay.** Read this file from `workflows/discuss-phase.md`
@@ -1,3 +1,5 @@
1
+ Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
2
+
1
3
  # --chain mode — interactive discuss, then auto-advance
2
4
 
3
5
  > **Lazy-loaded.** Read this file from `workflows/discuss-phase.md` when
@@ -1,3 +1,5 @@
1
+ Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
2
+
1
3
  # Default mode — interactive discuss-phase
2
4
 
3
5
  > **Lazy-loaded.** Read this file from `workflows/discuss-phase.md` when no
@@ -1,3 +1,5 @@
1
+ Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
2
+
1
3
  # --power mode — bulk question generation, async answering
2
4
 
3
5
  > **Lazy-loaded.** Read this file from `workflows/discuss-phase.md` when
@@ -1,3 +1,5 @@
1
+ Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
2
+
1
3
  # --text mode — plain-text overlay (no AskUserQuestion)
2
4
 
3
5
  > **Lazy-loaded overlay.** Read this file from `workflows/discuss-phase.md`
@@ -1,3 +1,5 @@
1
+ Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
2
+
1
3
  # CONTEXT.md template — for discuss-phase write_context step
2
4
 
3
5
  > **Lazy-loaded.** Read this file only inside the `write_context` step of
@@ -1,3 +1,5 @@
1
+ Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
2
+
1
3
  # DISCUSSION-LOG.md template — for discuss-phase git_commit step
2
4
 
3
5
  > **Lazy-loaded.** Read this file only inside the `git_commit` step of
@@ -73,7 +73,7 @@ AGENT_SKILLS_ANALYZER=$(gsd_run query agent-skills gsd-assumptions-analyzer)
73
73
  ANALYZER_MODEL=$(gsd_run query resolve-model gsd-assumptions-analyzer --raw)
74
74
  ```
75
75
 
76
- **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
76
+ **If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
77
77
 
78
78
  Parse JSON for: `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`,
79
79
  `phase_slug`, `padded_phase`, `has_research`, `has_context`, `has_plans`, `has_verification`,
@@ -1,3 +1,5 @@
1
+ @~/.claude/gsd-core/references/response-language-directive.md
2
+
1
3
  <purpose>
2
4
  Power user mode for discuss-phase. Generates ALL questions upfront into a JSON state file and an HTML companion UI, then waits for the user to answer at their own pace. When the user signals readiness, processes all answers in one pass and generates CONTEXT.md.
3
5
 
@@ -122,7 +122,7 @@ AGENT_SKILLS_ADVISOR=$(gsd_run query agent-skills gsd-advisor-researcher)
122
122
 
123
123
  Parse JSON for: `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_research`, `has_context`, `has_plans`, `has_verification`, `plan_count`, `roadmap_exists`, `planning_exists`, `response_language`.
124
124
 
125
- **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
125
+ **If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
126
126
 
127
127
  **If `phase_found` is false:**
128
128
  ```
@@ -13,7 +13,7 @@ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-pars
13
13
  RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --raw --default "" 2>/dev/null || echo "")
14
14
  ```
15
15
 
16
- **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
16
+ **If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
17
17
 
18
18
  <step name="validate">
19
19
  **Check for input.**
@@ -41,23 +41,31 @@ Track whether `.planning/` exists — some routes require it, others don't.
41
41
  <step name="route">
42
42
  **Match intent to command.**
43
43
 
44
- Evaluate `$ARGUMENTS` against these routing rules. Apply the **first matching** rule:
44
+ Evaluate `$ARGUMENTS` against these routing rules. Rules are ordered **most-specific first**: apply the **first matching** rule, and never let a generic keyword rule ("set up", "spike", "review") preempt a more specific operation that also matches ("set up this existing codebase", "wrap up the spike findings", "review the changed source code").
45
45
 
46
46
  | If the text describes... | Route to | Why |
47
47
  |--------------------------|----------|-----|
48
- | Starting a new greenfield project, "set up", "initialize" | `/gsd:new-project` | Needs full project initialization |
49
- | First-time setup for an existing codebase, brownfield onboarding | `/gsd:onboard` | Safe map → docs ingest → project setup sequence |
48
+ | First-time setup for an existing codebase, brownfield onboarding, "onboard this codebase" | `/gsd:onboard` | Safe map → docs ingest → project setup sequence |
49
+ | Starting a new greenfield project, "set up", "initialize" (no existing codebase named) | `/gsd:new-project` | Needs full project initialization |
50
50
  | Mapping or analyzing an existing codebase map | `/gsd:map-codebase` | Codebase discovery or refresh |
51
51
  | A bug, error, crash, failure, or something broken | `/gsd:debug` | Needs systematic investigation |
52
- | Spiking, "test if", "will this work", "experiment", "prove this out", validate feasibility | `/gsd:spike` | Throwaway experiment to validate feasibility |
53
- | Sketching, "mockup", "what would this look like", "prototype the UI", "design this", explore visual direction | `/gsd:sketch` | Throwaway HTML mockups to explore design |
54
52
  | Wrapping up spikes, "package the spikes", "consolidate spike findings" | `/gsd:spike --wrap-up` | Package spike findings into reusable skill |
55
53
  | Wrapping up sketches, "package the designs", "consolidate sketch findings" | `/gsd:sketch --wrap-up` | Package sketch findings into reusable skill |
54
+ | Spiking, "test if", "will this work", "experiment", "prove this out", validate feasibility | `/gsd:spike` | Throwaway experiment to validate feasibility |
55
+ | Sketching, "mockup", "what would this look like", "prototype the UI", "design this", explore visual direction | `/gsd:sketch` | Throwaway HTML mockups to explore design |
56
+ | Reviewing changed source code for bugs, security issues, or code quality ("code review the changes") | `/gsd:code-review` | Source review of phase-changed files |
57
+ | Requesting peer review of phase plans from another AI CLI ("plan review", "review the plan") | `/gsd:review` | Cross-AI plan review |
58
+ | Reviewing or hardening implemented UI ("visual audit", "review the UI") | `/gsd:ui-review` | Retroactive 6-pillar visual audit |
59
+ | Verifying security mitigations of a completed phase ("security check", "secure phase N") | `/gsd:secure-phase` | Retroactive threat-mitigation verification |
60
+ | Auditing milestone completion against original intent ("audit the milestone") | `/gsd:audit-milestone` | Milestone audit against original intent |
61
+ | An autonomous audit-to-fix pass ("audit and fix", "audit the repo and fix what it finds") | `/gsd:audit-fix` | Audit-to-fix pipeline |
62
+ | Generating or updating project documentation ("update the docs", "documentation update") | `/gsd:docs-update` | Docs verified against the codebase |
56
63
  | Exploring, researching, comparing, or "how does X work" | `/gsd:explore` | Socratic ideation and idea routing |
57
64
  | Discussing vision, "how should X look", brainstorming | `/gsd:discuss-phase` | Needs context gathering |
58
- | A complex task: refactoring, migration, multi-file architecture, system redesign | `/gsd:phase` | Needs a full phase with plan/build cycle |
59
65
  | Planning a specific phase or "plan phase N" | `/gsd:plan-phase` | Direct planning request |
60
- | Executing a phase or "build phase N", "run phase N" | `/gsd:execute-phase` | Direct execution request |
66
+ | Executing a phase or "build phase N", "run phase N" (SDD dependency-aware wave execution) | `/gsd:execute-phase` | Direct execution request |
67
+ | Adding, inserting, removing, or editing phases in the roadmap ("multi-phase", roadmap phase management) | `/gsd:phase` | Roadmap phase CRUD |
68
+ | A complex task: refactoring, migration, multi-file architecture, system redesign | `/gsd:plan-phase` | Needs a full phase with plan/build cycle |
61
69
  | Running all remaining phases automatically | `/gsd:autonomous` | Full autonomous execution |
62
70
  | A review or quality concern about existing work | `/gsd:verify-work` | Needs verification |
63
71
  | Checking progress, status, "where am I" | `/gsd:progress` | Status check |
@@ -73,7 +81,7 @@ Evaluate `$ARGUMENTS` against these routing rules. Apply the **first matching**
73
81
 
74
82
  ```
75
83
  "Refactor the authentication system" could be:
76
- 1. /gsd:phase — Full planning cycle (recommended for multi-file refactors)
84
+ 1. /gsd:plan-phase — Full planning cycle (recommended for multi-file refactors)
77
85
  2. /gsd:quick — Quick execution (if scope is small and clear)
78
86
 
79
87
  Which approach fits better?
@@ -92,12 +100,33 @@ Which approach fits better?
92
100
  ```
93
101
  </step>
94
102
 
103
+ <step name="confirm">
104
+ **Confirm the route before dispatching (REQ-DO-03).**
105
+
106
+ Before invoking anything, ask the user to confirm the displayed route via AskUserQuestion:
107
+
108
+ ```
109
+ Route to {chosen command}?
110
+ 1. Yes — proceed with {chosen command} (recommended)
111
+ 2. Choose a different command
112
+ 3. Cancel — do not dispatch
113
+ ```
114
+
115
+ - **Yes / proceed:** continue to the dispatch step.
116
+ - **Choose a different command:** present the 2-3 next-best routes from the routing table as options and loop back through display + confirm with the new selection.
117
+ - **Cancel:** stop. Do not invoke any command.
118
+
119
+ **TEXT_MODE:** present the same choices as a plain-text numbered list and ask the user to type their choice number, exactly like other AskUserQuestion calls in this workflow.
120
+ </step>
121
+
95
122
  <step name="dispatch">
96
- **Invoke the chosen command.**
123
+ **Invoke the chosen command with only the arguments it accepts.**
97
124
 
98
- Run the selected `/gsd-*` command, passing `$ARGUMENTS` as args.
125
+ Read the chosen command's frontmatter `argument-hint` (in `commands/gsd/<name>.md`) and forward **only arguments that command accepts**. Do NOT pass the full freeform sentence wholesale.
99
126
 
100
- If the chosen command expects a phase number and one wasn't provided in the text, extract it from context or ask via AskUserQuestion.
127
+ - If the command expects a phase number or flags only (e.g. `/gsd:verify-work [phase number]`, `/gsd:plan-phase`, `/gsd:execute-phase`), extract the phase number / flags from the input; if none was provided, extract it from context or ask via AskUserQuestion. Drop the surrounding prose.
128
+ - If the command explicitly accepts a freeform task description (e.g. `/gsd:quick`, `/gsd:debug`, `/gsd:spike`, `/gsd:sketch`), forward the relevant portion of `$ARGUMENTS` as the description.
129
+ - If the command takes no arguments, invoke it without arguments.
101
130
 
102
131
  After invoking the command, stop. The dispatched command handles everything from here.
103
132
  </step>
@@ -110,6 +139,7 @@ After invoking the command, stop. The dispatched command handles everything from
110
139
  - [ ] Ambiguity resolved via user question (if needed)
111
140
  - [ ] Project existence checked for routes that require it
112
141
  - [ ] Routing decision displayed before dispatch
113
- - [ ] Command invoked with appropriate arguments
142
+ - [ ] Route confirmed by the user before dispatch (REQ-DO-03), with TEXT_MODE equivalent
143
+ - [ ] Command invoked with only the arguments it accepts (argument-hint aware; freeform text only where the command takes a freeform description)
114
144
  - [ ] No work done directly — dispatcher only
115
145
  </success_criteria>
@@ -34,7 +34,7 @@ Extract from init JSON:
34
34
  - `monorepo_workspaces` — array of workspace glob patterns (empty if not a monorepo)
35
35
  - `section_manifest` — parsed from `INIT_DOCS_UPDATE` (not `INIT`); gates the `dispatch-monorepo-packages` section below
36
36
  - `project_root` — absolute path to the project root
37
- - `response_language` — if set, present all user-facing questions, prompts, and explanations in this workflow in that language; technical terms, code, file paths, and subagent prompts stay in English
37
+ - `response_language` — if set, present all user-facing output of this workflow in that language — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations; technical terms, code, file paths, and subagent prompts stay in English
38
38
  </step>
39
39
 
40
40
  <step name="classify_project">
@@ -1,3 +1,5 @@
1
+ @~/.claude/gsd-core/references/response-language-directive.md
2
+
1
3
  <purpose>
2
4
  Edit any field of an existing phase in ROADMAP.md in place. The phase number and position are always preserved. Guarded against in-progress and completed phases unless --force is passed. Validates depends_on references before writing. Shows a diff and requests confirmation before writing.
3
5
  </purpose>
@@ -19,7 +19,7 @@ INIT=$(gsd_run query init.phase-op "${PHASE_ARG}")
19
19
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
20
20
  ```
21
21
 
22
- **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
22
+ **If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
23
23
 
24
24
  Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `commit_docs`.
25
25
 
@@ -1,3 +1,5 @@
1
+ Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
2
+
1
3
  # Step: codebase_drift_gate
2
4
 
3
5
  Post-execution structural drift detection (#2003). Runs after the last wave
@@ -161,6 +161,18 @@ Assign the composed prompt to a shell variable so it can be passed as one argume
161
161
  # no host subagent machinery, so the role definition must ride the prompt
162
162
  # (#3637 acceptance: resolved agent instructions as launch-level
163
163
  # instructions + provenance of which role definition was used).
164
+ # Resolve TDD-applicability for THIS plan (#4266/#4272) — fail closed on
165
+ # command failure, mirroring the ISOLATION resolution above: an absent
166
+ # verdict must never silently resolve to "not TDD" (ADR-3473 §8.4), since
167
+ # that would silently drop a real TDD plan's RED/GREEN/REFACTOR procedure.
168
+ _TDD_APPLICABLE_RAW=$(gsd_run query phase.tdd-applicable "{phase_dir}/{plan_file}" --pick applicable 2>/dev/null)
169
+ _TDD_APPLICABLE_RC=$?
170
+ if [ $_TDD_APPLICABLE_RC -ne 0 ]; then
171
+ echo "FATAL: could not resolve TDD-applicability for plan {plan_number} — 'gsd_run query phase.tdd-applicable' failed. Refusing to guess whether this dispatch needs the TDD procedure. Halting." >&2
172
+ exit 1
173
+ fi
174
+ TDD_APPLICABLE="$_TDD_APPLICABLE_RAW"
175
+
164
176
  EXECUTOR_PROMPT='<objective>
165
177
  Execute plan {plan_number} of phase {phase_number}-{phase_name}.
166
178
  Commit each task atomically. Create SUMMARY.md.
@@ -181,7 +193,7 @@ the executor workflow from repository search.
181
193
  SUMMARY commit semantics and the gitignored-planning skip contract)
182
194
  - summary.md template
183
195
  - checkpoints.md
184
- - tdd.md
196
+ ${TDD_APPLICABLE ? "- tdd.md" : ""} # #3990/#4265: only when this dispatch is TDD (plan type: tdd, a tdd="true" task, or workflow.tdd_mode config)
185
197
  - worktree-path-safety.md
186
198
  - agents/gsd-executor.md (the ROLE DEFINITION you are executing — its steps
187
199
  0/0a/0b per-commit HEAD/cwd-drift/path-guard discipline applies to every
@@ -257,6 +269,10 @@ printf '%s' "$EXECUTOR_PROMPT" | grep -q '\${AGENT_SKILLS}' && {
257
269
  echo "FATAL: executor prompt for plan {plan_number} still contains the un-substituted \${AGENT_SKILLS} marker — the role definition was not spliced in (#3637). Halting." >&2
258
270
  exit 1
259
271
  }
272
+ printf '%s' "$EXECUTOR_PROMPT" | grep -q '\${TDD_APPLICABLE' && {
273
+ echo "FATAL: executor prompt for plan {plan_number} still contains the un-substituted \${TDD_APPLICABLE marker — the TDD-applicability decision was not resolved into the prompt (#4266). Halting." >&2
274
+ exit 1
275
+ }
260
276
  ```
261
277
 
262
278
  The prompt body must contain no single-quote character, since the assignment above is single-quoted; keep apostrophes out of it when editing.
@@ -48,12 +48,18 @@ if [ -n "$SUBMODULE_PATHS" ] && [ "$USE_WORKTREES_FOR_PLAN" != "false" ]; then
48
48
  # submodule "vendor/foo".
49
49
  INTERSECT=""
50
50
  set -f # disable globbing while iterating literal patterns
51
- for sm_raw in $SUBMODULE_PATHS; do
51
+ # Rewrapped through unquoted command substitution (gsd-core#4109): a bare
52
+ # `$VAR` word-splits under bash but not zsh, collapsing every element onto
53
+ # one iteration there.
54
+ for sm_raw in $(printf '%s' "$SUBMODULE_PATHS"); do
52
55
  # Normalize submodule path: strip ./ prefix and trailing /
53
56
  sm="${sm_raw#./}"
54
57
  sm="${sm%/}"
55
58
  [ -z "$sm" ] && continue
56
- for pf_raw in $PLAN_SCOPE_PATHS; do
59
+ # Rewrapped through unquoted command substitution (gsd-core#4109): a bare
60
+ # `$VAR` word-splits under bash but not zsh, collapsing every element onto
61
+ # one iteration there.
62
+ for pf_raw in $(printf '%s' "$PLAN_SCOPE_PATHS"); do
57
63
  # Normalize planned path the same way
58
64
  pf="${pf_raw#./}"
59
65
  pf="${pf%/}"