@opengsd/gsd-core 1.15.0 → 1.16.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 (487) 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 +85 -5
  4. package/agents/gsd-code-fixer.compact.md +1 -1
  5. package/agents/gsd-code-fixer.md +1 -1
  6. package/agents/gsd-code-reviewer.compact.md +5 -3
  7. package/agents/gsd-code-reviewer.md +8 -6
  8. package/agents/gsd-debug-session-manager.compact.md +1 -1
  9. package/agents/gsd-debug-session-manager.md +1 -1
  10. package/agents/gsd-debugger.md +2 -2
  11. package/agents/gsd-eval-auditor.compact.md +1 -1
  12. package/agents/gsd-eval-auditor.md +1 -1
  13. package/agents/gsd-executor.md +4 -4
  14. package/agents/gsd-intel-updater.compact.md +1 -1
  15. package/agents/gsd-intel-updater.md +1 -1
  16. package/agents/gsd-mempalace-curator.md +2 -2
  17. package/agents/gsd-phase-researcher.md +1 -1
  18. package/agents/gsd-plan-checker.md +7 -2
  19. package/agents/gsd-planner.md +3 -3
  20. package/agents/gsd-project-researcher.compact.md +1 -1
  21. package/agents/gsd-project-researcher.md +1 -1
  22. package/agents/gsd-research-synthesizer.compact.md +1 -1
  23. package/agents/gsd-research-synthesizer.md +1 -1
  24. package/agents/gsd-ui-auditor.compact.md +21 -30
  25. package/agents/gsd-ui-auditor.md +42 -51
  26. package/agents/gsd-ui-researcher.compact.md +1 -1
  27. package/agents/gsd-ui-researcher.md +1 -1
  28. package/agents/gsd-verifier.md +31 -9
  29. package/bin/install.js +126 -196
  30. package/commands/gsd/add-tests.md +6 -1
  31. package/commands/gsd/ai-integration-phase.md +6 -1
  32. package/commands/gsd/audit-fix.md +5 -0
  33. package/commands/gsd/audit-milestone.md +6 -1
  34. package/commands/gsd/autonomous.md +5 -0
  35. package/commands/gsd/capture.md +8 -4
  36. package/commands/gsd/code-review.md +7 -2
  37. package/commands/gsd/complete-milestone.md +4 -0
  38. package/commands/gsd/config.md +7 -3
  39. package/commands/gsd/debug.md +11 -7
  40. package/commands/gsd/discuss-phase.md +7 -3
  41. package/commands/gsd/docs-update.md +12 -7
  42. package/commands/gsd/eval-review.md +6 -1
  43. package/commands/gsd/execute-phase.md +12 -7
  44. package/commands/gsd/extract-learnings.md +5 -0
  45. package/commands/gsd/fast.md +4 -0
  46. package/commands/gsd/forensics.md +5 -1
  47. package/commands/gsd/graphify.md +10 -6
  48. package/commands/gsd/health.md +5 -0
  49. package/commands/gsd/help.md +7 -2
  50. package/commands/gsd/import.md +7 -3
  51. package/commands/gsd/inbox.md +5 -0
  52. package/commands/gsd/ingest-docs.md +5 -1
  53. package/commands/gsd/manager.md +6 -1
  54. package/commands/gsd/map-codebase.md +7 -3
  55. package/commands/gsd/mempalace-capture.md +5 -1
  56. package/commands/gsd/mempalace-recall.md +5 -1
  57. package/commands/gsd/milestone-summary.md +5 -1
  58. package/commands/gsd/mvp-phase.md +8 -3
  59. package/commands/gsd/new-milestone.md +6 -1
  60. package/commands/gsd/new-project.md +5 -0
  61. package/commands/gsd/next.md +6 -1
  62. package/commands/gsd/ns-context.md +4 -0
  63. package/commands/gsd/ns-ideate.md +4 -0
  64. package/commands/gsd/ns-manage.md +4 -0
  65. package/commands/gsd/ns-project.md +4 -0
  66. package/commands/gsd/ns-review.md +4 -0
  67. package/commands/gsd/ns-workflow.md +4 -0
  68. package/commands/gsd/onboard.md +6 -1
  69. package/commands/gsd/pause-work.md +5 -1
  70. package/commands/gsd/phase.md +8 -4
  71. package/commands/gsd/plan-phase.md +6 -1
  72. package/commands/gsd/plan-review-convergence.md +5 -1
  73. package/commands/gsd/pr-branch.md +4 -0
  74. package/commands/gsd/profile-user.md +5 -1
  75. package/commands/gsd/progress.md +6 -1
  76. package/commands/gsd/quick-batch.md +20 -8
  77. package/commands/gsd/quick.md +12 -7
  78. package/commands/gsd/review.md +5 -1
  79. package/commands/gsd/secure-phase.md +6 -1
  80. package/commands/gsd/ship.md +5 -0
  81. package/commands/gsd/sketch.md +7 -2
  82. package/commands/gsd/spec-phase.md +5 -1
  83. package/commands/gsd/spike.md +8 -3
  84. package/commands/gsd/surface.md +5 -1
  85. package/commands/gsd/thread.md +4 -0
  86. package/commands/gsd/ui-phase.md +6 -1
  87. package/commands/gsd/ui-review.md +6 -1
  88. package/commands/gsd/ultraplan-phase.md +5 -1
  89. package/commands/gsd/undo.md +5 -1
  90. package/commands/gsd/update.md +6 -2
  91. package/commands/gsd/validate-phase.md +6 -1
  92. package/commands/gsd/verify-work.md +6 -1
  93. package/commands/gsd/workspace.md +7 -3
  94. package/gsd-core/bin/gsd-tools.cjs +142 -56
  95. package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
  96. package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
  97. package/gsd-core/bin/lib/audit.cjs +78 -44
  98. package/gsd-core/bin/lib/broken-windows.cjs +13 -13
  99. package/gsd-core/bin/lib/capability-activation.cjs +9 -4
  100. package/gsd-core/bin/lib/capability-registry.cjs +183 -103
  101. package/gsd-core/bin/lib/capability-validator.cjs +16 -0
  102. package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
  103. package/gsd-core/bin/lib/check-command-router.cjs +164 -1712
  104. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
  105. package/gsd-core/bin/lib/cli-exit.cjs +12 -0
  106. package/gsd-core/bin/lib/codex-agent-toml.cjs +11 -8
  107. package/gsd-core/bin/lib/command-aliases.cjs +7 -0
  108. package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
  109. package/gsd-core/bin/lib/commands.cjs +173 -170
  110. package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
  111. package/gsd-core/bin/lib/config.cjs +43 -12
  112. package/gsd-core/bin/lib/core-utils.cjs +6 -1
  113. package/gsd-core/bin/lib/coverage.cjs +4 -8
  114. package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
  115. package/gsd-core/bin/lib/drift.cjs +177 -42
  116. package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
  117. package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
  118. package/gsd-core/bin/lib/frontmatter.cjs +413 -234
  119. package/gsd-core/bin/lib/gap-checker.cjs +72 -29
  120. package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
  121. package/gsd-core/bin/lib/gate-args.cjs +53 -0
  122. package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
  123. package/gsd-core/bin/lib/gate-config.cjs +46 -0
  124. package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
  125. package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
  126. package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
  127. package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
  128. package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
  129. package/gsd-core/bin/lib/gate-exit.cjs +27 -0
  130. package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
  131. package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
  132. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
  133. package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
  134. package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
  135. package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
  136. package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
  137. package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
  138. package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
  139. package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
  140. package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
  141. package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
  142. package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
  143. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
  144. package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
  145. package/gsd-core/bin/lib/init.cjs +162 -96
  146. package/gsd-core/bin/lib/install-engine.cjs +19 -35
  147. package/gsd-core/bin/lib/install-profiles.cjs +7 -4
  148. package/gsd-core/bin/lib/io.cjs +122 -3
  149. package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
  150. package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
  151. package/gsd-core/bin/lib/milestone.cjs +19 -1
  152. package/gsd-core/bin/lib/model-resolver.cjs +18 -18
  153. package/gsd-core/bin/lib/observability/event.cjs +1 -1
  154. package/gsd-core/bin/lib/observability/logger.cjs +46 -1
  155. package/gsd-core/bin/lib/pattern.cjs +10 -0
  156. package/gsd-core/bin/lib/phase-command-router.cjs +11 -4
  157. package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
  158. package/gsd-core/bin/lib/phase-id.cjs +1 -1
  159. package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
  160. package/gsd-core/bin/lib/phase-status.cjs +360 -0
  161. package/gsd-core/bin/lib/phase.cjs +280 -80
  162. package/gsd-core/bin/lib/plan-document.cjs +93 -19
  163. package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
  164. package/gsd-core/bin/lib/planning-document.cjs +273 -40
  165. package/gsd-core/bin/lib/planning-inspect.cjs +42 -8
  166. package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
  167. package/gsd-core/bin/lib/planning-workspace.cjs +76 -53
  168. package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
  169. package/gsd-core/bin/lib/profile-output.cjs +6 -3
  170. package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
  171. package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
  172. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
  173. package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
  174. package/gsd-core/bin/lib/report-parser.cjs +269 -0
  175. package/gsd-core/bin/lib/roadmap-command-router.cjs +13 -15
  176. package/gsd-core/bin/lib/roadmap-parser.cjs +82 -15
  177. package/gsd-core/bin/lib/roadmap-upgrade.cjs +127 -65
  178. package/gsd-core/bin/lib/roadmap.cjs +169 -72
  179. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +91 -157
  180. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +2 -1
  181. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
  182. package/gsd-core/bin/lib/runtime-homes.cjs +13 -10
  183. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +307 -591
  184. package/gsd-core/bin/lib/runtime-name-policy.cjs +142 -27
  185. package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
  186. package/gsd-core/bin/lib/shell-command-projection.cjs +37 -2
  187. package/gsd-core/bin/lib/smart-entry.cjs +19 -3
  188. package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
  189. package/gsd-core/bin/lib/state-contract.cjs +15 -18
  190. package/gsd-core/bin/lib/state-document.cjs +100 -22
  191. package/gsd-core/bin/lib/state.cjs +214 -105
  192. package/gsd-core/bin/lib/surface.cjs +2 -1
  193. package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -152
  194. package/gsd-core/bin/lib/uat-predicate.cjs +313 -35
  195. package/gsd-core/bin/lib/uat.cjs +424 -7
  196. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +94 -58
  197. package/gsd-core/bin/lib/vendor/README.md +31 -9
  198. package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
  199. package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
  200. package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
  201. package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
  202. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  203. package/gsd-core/bin/lib/verification.cjs +1165 -314
  204. package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
  205. package/gsd-core/bin/lib/verify.cjs +286 -567
  206. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
  207. package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
  208. package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
  209. package/gsd-core/bin/lib/workstream.cjs +11 -2
  210. package/gsd-core/bin/shared/config-defaults.manifest.json +5 -0
  211. package/gsd-core/bin/shared/config-schema.manifest.json +4 -0
  212. package/gsd-core/references/autonomous-smart-discuss.md +2 -1
  213. package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
  214. package/gsd-core/references/execute-mvp-tdd.md +5 -10
  215. package/gsd-core/references/execute-phase-between-wave-reset.md +3 -0
  216. package/gsd-core/references/execute-phase-response-language.md +1 -1
  217. package/gsd-core/references/gsd-run-resolver.md +1 -1
  218. package/gsd-core/references/loop-hook-dispatch.md +7 -1
  219. package/gsd-core/references/offer-next.md +1 -1
  220. package/gsd-core/references/planning-config.md +1 -1
  221. package/gsd-core/references/spidr-splitting.md +1 -1
  222. package/gsd-core/references/tdd.md +10 -4
  223. package/gsd-core/references/verifier-phase-gates.md +5 -2
  224. package/gsd-core/references/verify-mvp-mode.md +2 -2
  225. package/gsd-core/references/workstream-flag.md +33 -3
  226. package/gsd-core/templates/README.md +1 -1
  227. package/gsd-core/templates/UAT.md +17 -1
  228. package/gsd-core/templates/config.json +2 -11
  229. package/gsd-core/templates/verification-report.md +1 -1
  230. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  231. package/gsd-core/workflows/add-backlog.md +1 -1
  232. package/gsd-core/workflows/add-phase.md +8 -7
  233. package/gsd-core/workflows/add-tests.md +3 -2
  234. package/gsd-core/workflows/add-todo.md +4 -3
  235. package/gsd-core/workflows/ai-integration-phase.md +3 -2
  236. package/gsd-core/workflows/audit-fix.md +1 -1
  237. package/gsd-core/workflows/audit-milestone.md +4 -3
  238. package/gsd-core/workflows/audit-uat.md +1 -1
  239. package/gsd-core/workflows/autonomous.md +28 -18
  240. package/gsd-core/workflows/check-todos.md +6 -5
  241. package/gsd-core/workflows/cleanup.md +1 -1
  242. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
  243. package/gsd-core/workflows/code-review-fix.md +5 -4
  244. package/gsd-core/workflows/code-review.md +84 -90
  245. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
  246. package/gsd-core/workflows/complete-milestone.md +12 -7
  247. package/gsd-core/workflows/debug.md +30 -5
  248. package/gsd-core/workflows/diagnose-issues.md +3 -2
  249. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  250. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  251. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  252. package/gsd-core/workflows/discuss-phase.md +4 -3
  253. package/gsd-core/workflows/do.md +1 -1
  254. package/gsd-core/workflows/docs-update.md +4 -3
  255. package/gsd-core/workflows/edit-phase.md +4 -3
  256. package/gsd-core/workflows/eval-review.md +5 -3
  257. package/gsd-core/workflows/execute-phase/detail/elaboration.md +1 -1
  258. package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +4 -2
  259. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
  260. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
  261. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +1 -1
  262. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
  263. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
  264. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  265. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
  266. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +1 -1
  267. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
  268. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
  269. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
  270. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
  271. package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
  272. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
  273. package/gsd-core/workflows/execute-phase.md +78 -170
  274. package/gsd-core/workflows/execute-plan.md +13 -19
  275. package/gsd-core/workflows/explore.md +2 -2
  276. package/gsd-core/workflows/extract-learnings.md +3 -2
  277. package/gsd-core/workflows/fast.md +1 -1
  278. package/gsd-core/workflows/forensics.md +1 -1
  279. package/gsd-core/workflows/graduation.md +1 -1
  280. package/gsd-core/workflows/health.md +2 -1
  281. package/gsd-core/workflows/import.md +3 -2
  282. package/gsd-core/workflows/inbox.md +1 -1
  283. package/gsd-core/workflows/ingest-docs.md +1 -1
  284. package/gsd-core/workflows/insert-phase.md +4 -3
  285. package/gsd-core/workflows/list-seeds.md +1 -1
  286. package/gsd-core/workflows/list-workspaces.md +1 -1
  287. package/gsd-core/workflows/manager.md +5 -3
  288. package/gsd-core/workflows/map-codebase.md +4 -3
  289. package/gsd-core/workflows/milestone-summary.md +3 -2
  290. package/gsd-core/workflows/mvp-phase.md +14 -14
  291. package/gsd-core/workflows/new-milestone.md +10 -10
  292. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  293. package/gsd-core/workflows/new-project.md +1 -1
  294. package/gsd-core/workflows/new-workspace.md +1 -1
  295. package/gsd-core/workflows/next.md +1 -1
  296. package/gsd-core/workflows/pause-work.md +2 -2
  297. package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
  298. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
  299. package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
  300. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  301. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +1 -1
  302. package/gsd-core/workflows/plan-phase.md +27 -18
  303. package/gsd-core/workflows/plan-review-convergence.md +1 -1
  304. package/gsd-core/workflows/plant-seed.md +1 -1
  305. package/gsd-core/workflows/pr-branch.md +1 -1
  306. package/gsd-core/workflows/profile-user.md +1 -1
  307. package/gsd-core/workflows/progress.md +19 -49
  308. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -2
  309. package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
  310. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
  311. package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
  312. package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
  313. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
  314. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
  315. package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
  316. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
  317. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
  318. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
  319. package/gsd-core/workflows/quick-batch.md +15 -10
  320. package/gsd-core/workflows/quick.md +42 -31
  321. package/gsd-core/workflows/remove-phase.md +3 -2
  322. package/gsd-core/workflows/remove-workspace.md +1 -1
  323. package/gsd-core/workflows/resume-project.md +3 -2
  324. package/gsd-core/workflows/review.md +3 -2
  325. package/gsd-core/workflows/scan.md +3 -2
  326. package/gsd-core/workflows/secure-phase.md +11 -12
  327. package/gsd-core/workflows/settings-advanced.md +1 -1
  328. package/gsd-core/workflows/settings-integrations.md +1 -1
  329. package/gsd-core/workflows/settings.md +1 -1
  330. package/gsd-core/workflows/ship.md +12 -12
  331. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  332. package/gsd-core/workflows/sketch.md +1 -1
  333. package/gsd-core/workflows/smart-entry.md +1 -1
  334. package/gsd-core/workflows/spec-phase.md +1 -1
  335. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  336. package/gsd-core/workflows/spike.md +1 -1
  337. package/gsd-core/workflows/stats.md +1 -1
  338. package/gsd-core/workflows/sync-skills.md +1 -1
  339. package/gsd-core/workflows/thread.md +2 -2
  340. package/gsd-core/workflows/transition.md +13 -23
  341. package/gsd-core/workflows/ui-phase.md +5 -4
  342. package/gsd-core/workflows/ui-review.md +4 -3
  343. package/gsd-core/workflows/ultraplan-phase.md +3 -2
  344. package/gsd-core/workflows/undo.md +1 -1
  345. package/gsd-core/workflows/validate-phase.md +10 -12
  346. package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
  347. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
  348. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
  349. package/gsd-core/workflows/verify-work.md +68 -59
  350. package/hooks/dist/gsd-agent-isolation-guard.js +8 -0
  351. package/hooks/dist/gsd-check-update-worker.js +8 -0
  352. package/hooks/dist/gsd-check-update.js +8 -0
  353. package/hooks/dist/gsd-context-monitor.js +31 -8
  354. package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
  355. package/hooks/dist/gsd-secret-read-guard.js +147 -16
  356. package/hooks/dist/gsd-statusline.js +15 -7
  357. package/hooks/dist/gsd-update-banner.js +8 -0
  358. package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
  359. package/hooks/dist/gsd-workflow-guard.js +5 -4
  360. package/hooks/dist/gsd-worktree-path-guard.js +6 -2
  361. package/hooks/dist/lib/cli-exit.js +12 -0
  362. package/hooks/dist/lib/git-probe.js +17 -1
  363. package/hooks/dist/lib/isolation-sentinel.js +2 -2
  364. package/hooks/gsd-agent-isolation-guard.js +8 -0
  365. package/hooks/gsd-check-update-worker.js +8 -0
  366. package/hooks/gsd-check-update.js +8 -0
  367. package/hooks/gsd-context-monitor.js +31 -8
  368. package/hooks/gsd-cursor-subagent-start.js +8 -0
  369. package/hooks/gsd-secret-read-guard.js +147 -16
  370. package/hooks/gsd-statusline.js +15 -7
  371. package/hooks/gsd-update-banner.js +8 -0
  372. package/hooks/gsd-windsurf-pre-write.js +11 -2
  373. package/hooks/gsd-workflow-guard.js +5 -4
  374. package/hooks/gsd-worktree-path-guard.js +6 -2
  375. package/hooks/hooks.json +5 -5
  376. package/hooks/lib/cli-exit.js +12 -0
  377. package/hooks/lib/git-probe.js +17 -1
  378. package/hooks/lib/isolation-sentinel.js +2 -2
  379. package/package.json +21 -4
  380. package/scripts/changeset/parse.cjs +52 -4
  381. package/scripts/ci-timeout-report.cjs +770 -4
  382. package/scripts/command-contract-helpers.cjs +12 -8
  383. package/scripts/docs-guard-registry.cjs +6 -0
  384. package/scripts/gen-features.cjs +13 -8
  385. package/scripts/gen-hooks-cli-exit.cjs +12 -28
  386. package/scripts/gen-loop-host-contract.cjs +10 -1
  387. package/scripts/gen-platform-conformance-tier.cjs +187 -1
  388. package/scripts/gen-plugin-skills.cjs +87 -1
  389. package/scripts/gen-research-agents.cjs +24 -31
  390. package/scripts/gen-scripts-cli-exit.cjs +30 -3
  391. package/scripts/gen-test-timings.cjs +32 -7
  392. package/scripts/lib/cli-exit.cjs +12 -0
  393. package/scripts/lib/macos-conformance-tier.generated.cjs +20 -2
  394. package/scripts/lib/ndjson-reporter.cjs +28 -3
  395. package/scripts/lib/platform-conformance-tier.generated.cjs +34 -5
  396. package/scripts/lib/registration-ledger-preload.cjs +155 -0
  397. package/scripts/lib/vendor-bundle.cjs +59 -0
  398. package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
  399. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  400. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  401. package/scripts/lint-completion-predicate-drift.cjs +18 -19
  402. package/scripts/lint-descriptions.cjs +7 -3
  403. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +10 -0
  404. package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
  405. package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
  406. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
  407. package/scripts/lint-phase-enumeration-drift.cjs +12 -8
  408. package/scripts/lint-phase-id-drift.cjs +29 -0
  409. package/scripts/lint-planning-document-positive-control.cjs +329 -0
  410. package/scripts/lint-response-language-coverage.cjs +3 -0
  411. package/scripts/lint-skill-deps.cjs +7 -3
  412. package/scripts/lint-test-file-count.allowlist.json +11 -1
  413. package/scripts/lint-test-file-count.cjs +34 -1
  414. package/scripts/lint-vendored-deps.cjs +41 -5
  415. package/scripts/lint-workflow-shellcheck-baseline.json +10 -10
  416. package/scripts/mutation-matrix.cjs +50 -5
  417. package/scripts/require-issue-link-policy.cjs +6 -2
  418. package/scripts/sync-runtime-launcher.cjs +184 -2
  419. package/scripts/verify-npm-publish.cjs +76 -20
  420. package/skills/gsd-add-tests/SKILL.md +6 -1
  421. package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
  422. package/skills/gsd-audit-fix/SKILL.md +5 -0
  423. package/skills/gsd-audit-milestone/SKILL.md +6 -1
  424. package/skills/gsd-autonomous/SKILL.md +5 -0
  425. package/skills/gsd-capture/SKILL.md +8 -4
  426. package/skills/gsd-code-review/SKILL.md +7 -2
  427. package/skills/gsd-complete-milestone/SKILL.md +4 -0
  428. package/skills/gsd-config/SKILL.md +8 -4
  429. package/skills/gsd-debug/SKILL.md +11 -7
  430. package/skills/gsd-discuss-phase/SKILL.md +7 -3
  431. package/skills/gsd-docs-update/SKILL.md +12 -7
  432. package/skills/gsd-eval-review/SKILL.md +6 -1
  433. package/skills/gsd-execute-phase/SKILL.md +12 -7
  434. package/skills/gsd-extract-learnings/SKILL.md +5 -0
  435. package/skills/gsd-fast/SKILL.md +4 -0
  436. package/skills/gsd-forensics/SKILL.md +5 -1
  437. package/skills/gsd-graphify/SKILL.md +10 -6
  438. package/skills/gsd-health/SKILL.md +5 -0
  439. package/skills/gsd-help/SKILL.md +7 -2
  440. package/skills/gsd-import/SKILL.md +7 -3
  441. package/skills/gsd-inbox/SKILL.md +5 -0
  442. package/skills/gsd-ingest-docs/SKILL.md +5 -1
  443. package/skills/gsd-manager/SKILL.md +6 -1
  444. package/skills/gsd-map-codebase/SKILL.md +7 -3
  445. package/skills/gsd-mempalace-capture/SKILL.md +5 -1
  446. package/skills/gsd-mempalace-recall/SKILL.md +5 -1
  447. package/skills/gsd-milestone-summary/SKILL.md +5 -1
  448. package/skills/gsd-mvp-phase/SKILL.md +8 -3
  449. package/skills/gsd-new-milestone/SKILL.md +6 -1
  450. package/skills/gsd-new-project/SKILL.md +5 -0
  451. package/skills/gsd-next/SKILL.md +6 -1
  452. package/skills/gsd-ns-context/SKILL.md +4 -0
  453. package/skills/gsd-ns-ideate/SKILL.md +4 -0
  454. package/skills/gsd-ns-manage/SKILL.md +4 -0
  455. package/skills/gsd-ns-project/SKILL.md +4 -0
  456. package/skills/gsd-ns-review/SKILL.md +4 -0
  457. package/skills/gsd-ns-workflow/SKILL.md +4 -0
  458. package/skills/gsd-onboard/SKILL.md +6 -1
  459. package/skills/gsd-pause-work/SKILL.md +5 -1
  460. package/skills/gsd-phase/SKILL.md +8 -4
  461. package/skills/gsd-plan-phase/SKILL.md +6 -1
  462. package/skills/gsd-plan-review-convergence/SKILL.md +5 -1
  463. package/skills/gsd-pr-branch/SKILL.md +4 -0
  464. package/skills/gsd-profile-user/SKILL.md +5 -1
  465. package/skills/gsd-progress/SKILL.md +6 -1
  466. package/skills/gsd-quick/SKILL.md +16 -10
  467. package/skills/gsd-quick-batch/SKILL.md +20 -8
  468. package/skills/gsd-review/SKILL.md +5 -1
  469. package/skills/gsd-review-backlog/SKILL.md +3 -2
  470. package/skills/gsd-secure-phase/SKILL.md +6 -1
  471. package/skills/gsd-ship/SKILL.md +5 -0
  472. package/skills/gsd-sketch/SKILL.md +7 -2
  473. package/skills/gsd-spec-phase/SKILL.md +5 -1
  474. package/skills/gsd-spike/SKILL.md +8 -3
  475. package/skills/gsd-surface/SKILL.md +5 -1
  476. package/skills/gsd-thread/SKILL.md +4 -0
  477. package/skills/gsd-ui-phase/SKILL.md +6 -1
  478. package/skills/gsd-ui-review/SKILL.md +6 -1
  479. package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
  480. package/skills/gsd-undo/SKILL.md +5 -1
  481. package/skills/gsd-update/SKILL.md +6 -2
  482. package/skills/gsd-validate-phase/SKILL.md +6 -1
  483. package/skills/gsd-verify-work/SKILL.md +6 -1
  484. package/skills/gsd-workspace/SKILL.md +7 -3
  485. package/skills/gsd-workstreams/SKILL.md +6 -6
  486. package/vscode/package.json +1 -1
  487. package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +0 -24
@@ -17,11 +17,16 @@ exports.isCompletedInventory = isCompletedInventory;
17
17
  exports.buildWorkstreamInventory = buildWorkstreamInventory;
18
18
  const node_path_1 = __importDefault(require("node:path"));
19
19
  const phase_lifecycle_cjs_1 = require("./phase-lifecycle.cjs");
20
+ // #5060: `phase-status.cjs` is a load-time leaf (no top-level requires) — its
21
+ // `phaseStatusFromFacts`/`toWireStatus` are pure functions of facts, so
22
+ // importing them here does not violate this module's "No I/O. No async."
23
+ // contract.
24
+ const phase_status_cjs_1 = require("./phase-status.cjs");
20
25
  // Internal helpers
21
26
  function toPosixPath(p) {
22
27
  return p.split('\\').join('/');
23
28
  }
24
- // #2562/#2645's FAILING_VERIFICATION_STATUSES set (the verdicts that used to
29
+ // #2562/#2645's former failing-verdict set (the verdicts that used to
25
30
  // disqualify a phase from `complete` when combined with a local
26
31
  // summary-count-meets-plan-count check) was removed by ADR-3180 §7.4
27
32
  // (#3186): `complete` is now the single canonical owner's verdict
@@ -133,11 +138,14 @@ function buildWorkstreamInventory(inputs) {
133
138
  // read `pending` instead of `complete`. `complete` defaults to `false`
134
139
  // when absent so a caller that has not been updated to pass it never
135
140
  // silently reads as complete.
136
- const status = (counts?.complete ?? false)
137
- ? 'complete'
138
- : planCount > 0
139
- ? 'in_progress'
140
- : 'pending';
141
+ // #5060: routed through the Phase Status Module's owner ladder rather
142
+ // than a local re-derivation of the same complete/planCount branches.
143
+ const status = (0, phase_status_cjs_1.toWireStatus)((0, phase_status_cjs_1.phaseStatusFromFacts)({
144
+ planCount,
145
+ summaryCount,
146
+ complete: counts?.complete ?? false,
147
+ verificationStatus: counts?.verificationStatus ?? null,
148
+ }));
141
149
  // #2562: only current-milestone phases feed the rollup when scoping is on,
142
150
  // and only one directory per phase key (see rollupDirs above).
143
151
  const countsTowardMilestone = (!scoped || counts?.inMilestone !== false) && rollupDirs.has(dir);
@@ -33,7 +33,7 @@ const { extractFrontmatter, stripFrontmatter } = frontmatterMod;
33
33
  const markdown_table_cjs_1 = require("./markdown-table.cjs");
34
34
  // eslint-disable-next-line @typescript-eslint/no-require-imports -- verification.cjs is an export= CommonJS module
35
35
  const verificationMod = require("./verification.cjs");
36
- const { isPhaseComplete } = verificationMod;
36
+ const { isPhaseComplete, isVerificationStatus, VERIFICATION_STATUS } = verificationMod;
37
37
  // eslint-disable-next-line @typescript-eslint/no-require-imports -- phase-id.cjs is an export= CommonJS module
38
38
  const phaseIdMod = require("./phase-id.cjs");
39
39
  const { phaseKeyFromDir, phaseKeyFromProse, parentPhaseKey } = phaseIdMod;
@@ -269,7 +269,10 @@ function readVerificationLedger(wsDir) {
269
269
  }
270
270
  const out = {};
271
271
  for (const [key, value] of Object.entries(parsed)) {
272
- if (typeof value === 'string')
272
+ // #5118: an entry outside the closed enum (a stored `unknown` from an
273
+ // older run) reads as absent — the phase then fails CLOSED to
274
+ // `unrecorded`, the same posture as a corrupt ledger.
275
+ if (isVerificationStatus(value))
273
276
  out[key] = value;
274
277
  }
275
278
  return { state: 'ok', entries: out };
@@ -555,7 +558,7 @@ function inspectWorkstream(cwd, name, options = {}) {
555
558
  // unverified-fallback diagnostic (#3057 B4) — the closest existing idiom,
556
559
  // since `WorkstreamInventory`'s aggregate return shape carries no
557
560
  // per-phase verification detail for this to attach to.
558
- if (verificationResult.staleCheckIndeterminate) {
561
+ if ('staleCheckIndeterminate' in verificationResult && verificationResult.staleCheckIndeterminate) {
559
562
  writeDiagnostic(`⚠ workstream-inventory: verification staleness check could not complete for phase directory '${dir}' in workstream '${name}' — routed as not-stale, but this was not actually verified. See #3057.\n`, { phaseDir: dir, reason: 'staleCheckIndeterminate' });
560
563
  }
561
564
  return {
@@ -566,14 +569,24 @@ function inspectWorkstream(cwd, name, options = {}) {
566
569
  summaryCount: counts.summaryCount,
567
570
  inMilestone: isDirInCurrentMilestone(dir),
568
571
  liveVerificationStatus: verificationResult.status,
572
+ // #5118: the owner's out-of-set report error, carried to the check below.
573
+ statusError: completionResult.value.statusError,
569
574
  // ADR-3180 §7.4 (#3186): the owner's verdict, read live off disk — never
570
575
  // ledger-adjusted (see the phaseFilesCounts map below; the ledger only
571
576
  // ever substitutes a 'missing' status with a remembered one, and under
572
- // disk-strict neither 'missing' nor 'unrecorded' is ever complete, so
573
- // there is nothing for the ledger to override here).
577
+ // disk-strict 'missing' is never complete, so there is nothing for the
578
+ // ledger to override here).
574
579
  complete: completionResult.value.complete,
575
580
  };
576
581
  });
582
+ // #5118 (no write before the error): this inspection WRITES the ledger
583
+ // below, so a report whose `status` is outside the closed set fails it
584
+ // first — the owner's own error thrown as-is (like `init *`, `phase *` and
585
+ // `state *`), which the CLI entry seam projects once into its reason and
586
+ // message; nothing persisted.
587
+ const firstStatusError = rawPhaseEntries.find((entry) => entry.statusError)?.statusError;
588
+ if (firstStatusError)
589
+ throw firstStatusError;
577
590
  // #2645: only the directory Bug #2445's de-dup rollup would actually pick
578
591
  // for a phase key may read or write that key's ledger entry. Letting every
579
592
  // same-keyed directory (including a stale leftover) write would let a
@@ -604,10 +617,11 @@ function inspectWorkstream(cwd, name, options = {}) {
604
617
  const verificationLedger = ledgerRead.entries;
605
618
  let ledgerDirty = false;
606
619
  for (const winner of ledgerWinnerByKey.values()) {
607
- if (winner.liveVerificationStatus === 'missing')
620
+ const live = winner.liveVerificationStatus;
621
+ if (live === null || live === VERIFICATION_STATUS.MISSING)
608
622
  continue;
609
- if (verificationLedger[winner.phaseKey] !== winner.liveVerificationStatus) {
610
- verificationLedger[winner.phaseKey] = winner.liveVerificationStatus;
623
+ if (verificationLedger[winner.phaseKey] !== live) {
624
+ verificationLedger[winner.phaseKey] = live;
611
625
  ledgerDirty = true;
612
626
  }
613
627
  }
@@ -620,20 +634,16 @@ function inspectWorkstream(cwd, name, options = {}) {
620
634
  writeVerificationLedger(wsDir, verificationLedger);
621
635
  const phaseFilesCounts = rawPhaseEntries.map(entry => {
622
636
  const isLedgerWinner = ledgerWinnerByKey.get(entry.phaseKey) === entry;
637
+ // A live `missing` on the ledger winner reads the remembered verdict when
638
+ // there is one. #5118: the former `unrecorded` state ("adopted, never
639
+ // recorded") is deleted — its only reader, phaseStatusFromFacts, treats it
640
+ // exactly like `missing` (only `human_needed` changes the ladder, and under
641
+ // disk-strict neither is ever complete), so it was a dead distinction.
623
642
  let verificationStatus = entry.liveVerificationStatus;
624
- if (entry.liveVerificationStatus === 'missing' && isLedgerWinner) {
625
- if (ledgerRead.state === 'absent') {
626
- // State 1: pre-adoption. Exactly today's behavior — 'missing' is
627
- // NOT in FAILING_VERIFICATION_STATUSES, so this does not gate.
628
- verificationStatus = 'missing';
629
- }
630
- else {
631
- // States 2/3 ('corrupt' or 'ok'): this workstream has adopted the
632
- // ledger. A remembered entry wins; no entry fails CLOSED to the
633
- // 'unrecorded' sentinel rather than falling open to 'missing'.
634
- const remembered = verificationLedger[entry.phaseKey];
635
- verificationStatus = remembered !== undefined ? remembered : 'unrecorded';
636
- }
643
+ if (entry.liveVerificationStatus === VERIFICATION_STATUS.MISSING && isLedgerWinner) {
644
+ const remembered = verificationLedger[entry.phaseKey];
645
+ if (remembered !== undefined)
646
+ verificationStatus = remembered;
637
647
  }
638
648
  return {
639
649
  directory: entry.directory,
@@ -26,7 +26,9 @@
26
26
  * phase-id.cts's toDir/getPhaseDirFromPhaseId.
27
27
  */
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE = void 0;
29
+ exports.RESERVED_WORKSTREAM_NAMES = exports.INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE = void 0;
30
+ exports.isReservedWorkstreamName = isReservedWorkstreamName;
31
+ exports.reservedWorkstreamNameMessage = reservedWorkstreamNameMessage;
30
32
  exports.normalizeWorkstreamNameInput = normalizeWorkstreamNameInput;
31
33
  exports.hasInvalidPathSegment = hasInvalidPathSegment;
32
34
  exports.validateActiveWorkstreamName = validateActiveWorkstreamName;
@@ -36,6 +38,34 @@ exports.isValidActiveWorkstreamName = isValidActiveWorkstreamName;
36
38
  exports.assertValidActiveWorkstreamName = assertValidActiveWorkstreamName;
37
39
  exports.INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE = 'Invalid workstream name: must be alphanumeric, hyphens, underscores, or dots';
38
40
  const ACTIVE_WORKSTREAM_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
41
+ /**
42
+ * Names that pass the charset check but can never name a workstream (#4772).
43
+ * `none` reads as "no workstream" to every caller that types it, yet the path
44
+ * layer treated it as a literal directory, so `--ws none` silently resolved
45
+ * `.planning/workstreams/none/...` (and fell back to the root config). Single
46
+ * owner: resolveActiveWorkstream and workstream create/set all consume this list.
47
+ */
48
+ exports.RESERVED_WORKSTREAM_NAMES = Object.freeze(['none']);
49
+ /** True when `name` (trimmed, case-insensitive) is a reserved workstream name. */
50
+ function isReservedWorkstreamName(name) {
51
+ const value = normalizeWorkstreamNameInput(name);
52
+ return value !== null && exports.RESERVED_WORKSTREAM_NAMES.includes(value.toLowerCase());
53
+ }
54
+ /**
55
+ * The error text shared by every site that rejects a reserved name. `source`
56
+ * (where the name came from: 'cli' | 'env' | 'store') picks a remedy that can
57
+ * actually be carried out: the rejection happens in the gsd-tools bootstrap
58
+ * before any verb runs, so advising `workstream set --clear` would fail too.
59
+ */
60
+ function reservedWorkstreamNameMessage(name, source = null) {
61
+ const value = normalizeWorkstreamNameInput(name) ?? '';
62
+ const remedy = source === 'env'
63
+ ? 'unset GSD_WORKSTREAM for flat mode'
64
+ : source === 'store'
65
+ ? 'delete the stale active-workstream pointer for flat mode'
66
+ : 'omit --ws for flat mode';
67
+ return `Workstream name '${value}' is reserved and cannot name a workstream; ${remedy}`;
68
+ }
39
69
  function normalizeWorkstreamNameInput(name) {
40
70
  const value = String(name ?? '').trim();
41
71
  return value || null;
@@ -50,6 +50,9 @@ function migrateToWorkstreams(cwd, workstreamName) {
50
50
  catch {
51
51
  throw new Error('Invalid workstream name for migration');
52
52
  }
53
+ if ((0, workstream_name_policy_cjs_1.isReservedWorkstreamName)(workstreamName)) {
54
+ throw new Error((0, workstream_name_policy_cjs_1.reservedWorkstreamNameMessage)(workstreamName));
55
+ }
53
56
  const baseDir = planningRoot(cwd);
54
57
  const wsDir = node_path_1.default.join(baseDir, 'workstreams', workstreamName);
55
58
  if (node_fs_1.default.existsSync(node_path_1.default.join(baseDir, 'workstreams'))) {
@@ -101,6 +104,9 @@ function cmdWorkstreamCreate(cwd, name, options, raw) {
101
104
  if (!slug) {
102
105
  error('Invalid workstream name — must contain at least one alphanumeric character');
103
106
  }
107
+ if ((0, workstream_name_policy_cjs_1.isReservedWorkstreamName)(slug)) {
108
+ error((0, workstream_name_policy_cjs_1.reservedWorkstreamNameMessage)(slug));
109
+ }
104
110
  const baseDir = planningRoot(cwd);
105
111
  if (!node_fs_1.default.existsSync(baseDir)) {
106
112
  error(`.planning/ directory not found — run ${(0, runtime_slash_cjs_1.formatGsdSlash)('new-project', (0, runtime_slash_cjs_1.resolveRuntime)(cwd))} first`);
@@ -331,8 +337,11 @@ function cmdWorkstreamSet(cwd, name, raw) {
331
337
  output({ active: null, cleared: true, previous: previous || null }, raw, undefined);
332
338
  return;
333
339
  }
334
- if (!(0, workstream_name_policy_cjs_1.isValidActiveWorkstreamName)(name)) {
335
- output({ active: null, error: 'invalid_name', message: 'Workstream name must be alphanumeric, hyphens, underscores, or dots' }, raw, undefined);
340
+ if (!(0, workstream_name_policy_cjs_1.isValidActiveWorkstreamName)(name) || (0, workstream_name_policy_cjs_1.isReservedWorkstreamName)(name)) {
341
+ const message = (0, workstream_name_policy_cjs_1.isReservedWorkstreamName)(name)
342
+ ? (0, workstream_name_policy_cjs_1.reservedWorkstreamNameMessage)(name)
343
+ : 'Workstream name must be alphanumeric, hyphens, underscores, or dots';
344
+ output({ active: null, error: 'invalid_name', message }, raw, undefined);
336
345
  return;
337
346
  }
338
347
  const wsDir = node_path_1.default.join(planningRoot(cwd), 'workstreams', name);
@@ -14,6 +14,11 @@
14
14
  "phase_id_convention": null,
15
15
  "mode": "interactive",
16
16
  "claude_md_path": "./.claude/CLAUDE.md",
17
+ "gates": {
18
+ "execute_next_plan": true,
19
+ "confirm_transition": true,
20
+ "confirm_milestone_scope": true
21
+ },
17
22
  "git": {
18
23
  "branching_strategy": "none",
19
24
  "create_tag": true,
@@ -2,6 +2,9 @@
2
2
  "_comment": "Canonical schema manifest for valid config key paths. This manifest is the single CJS source of truth for valid config keys; dynamicKeyPatterns source strings are recompiled to RegExp at runtime by config-schema.cjs. runtimeStateKeys mirrors RUNTIME_STATE_KEYS.",
3
3
  "validKeys": [
4
4
  "mode",
5
+ "gates.execute_next_plan",
6
+ "gates.confirm_transition",
7
+ "gates.confirm_milestone_scope",
5
8
  "granularity",
6
9
  "parallelization",
7
10
  "commit_docs",
@@ -111,6 +114,7 @@
111
114
  "resolve_model_ids",
112
115
  "effort.default",
113
116
  "fast_mode.enabled",
117
+ "audit.enabled",
114
118
  "plan_review.source_grounding",
115
119
  "plan_review.source_grounding_authority",
116
120
  "model_policy.provider",
@@ -5,7 +5,8 @@ Smart discuss is the autonomous-optimized variant of `gsd-discuss-phase`. It pro
5
5
  **Inputs:** `PHASE_NUM` from execute_phase. Run init to get phase paths:
6
6
 
7
7
  ```bash
8
- PHASE_STATE=$(gsd_run query init.phase-op ${PHASE_NUM})
8
+ GSD_WS=$(echo " $ARGUMENTS" | sed -nE 's/.* --ws +([A-Za-z0-9][A-Za-z0-9._-]*).*/--ws \1/p' | head -n 1)
9
+ PHASE_STATE=$(gsd_run query init.phase-op ${GSD_WS:+--ws=${GSD_WS##* }} ${PHASE_NUM})
9
10
  ```
10
11
 
11
12
  Parse from JSON: `phase_dir`, `phase_slug`, `padded_phase`, `phase_name`.
@@ -1,6 +1,6 @@
1
1
  # UI Design Contract (Frontend Phases) — Autonomous Mode
2
2
 
3
- Step 3a.5 of `/gsd:autonomous`: resolve whether the current phase needs a UI-SPEC.md generated before planning, and generate one via active `plan:pre` step hooks if so. Always non-blocking — proceeds to step 3b (Plan) regardless of outcome.
3
+ Step 3a.5 of `/gsd:autonomous`: resolve whether the current phase needs a UI-SPEC.md generated before planning, and generate one via active `plan:pre` step hooks if so. Non-blocking for every answer it gets — proceeds to step 3b (Plan) — except a gate that could not look (below), which is surfaced and stops.
4
4
 
5
5
  **Inputs:** `PHASE_NUM`, `PHASE_DIR` from execute_phase.
6
6
 
@@ -16,10 +16,10 @@ Read the `activeHooks` array directly from `HOOKS_JSON` (in-context — do NOT i
16
16
  (At least one active step hook ⇒ `workflow.ui_phase` is on.) Run the UI-SPEC gate:
17
17
 
18
18
  ```bash
19
- GATE=$(gsd_run check ui-plan-gate "${PHASE_NUM}" --raw)
19
+ GATE=$(gsd_run check ui-plan-gate "${PHASE_NUM}" --raw) && GATE_RC=0 || GATE_RC=$?
20
20
  ```
21
21
 
22
- Read `frontend` and `hasUiSpec` from `GATE` (in-context).
22
+ A non-zero `GATE_RC` is a command failure, including `69` (`UNAVAILABLE`: the gate could not read its evidence, so its `frontend: false` is not an answer): surface it and stop — never skip silently to 3b as if the phase had no frontend. Otherwise read `frontend` and `hasUiSpec` from `GATE` (in-context).
23
23
 
24
24
  **If `frontend` is false:** Skip silently to 3b.
25
25
 
@@ -15,15 +15,10 @@ If any of these is false, the gate is inactive — execution proceeds normally.
15
15
  For each task gated by TDD, the executor MUST verify (before running the implementation step):
16
16
 
17
17
  1. **A failing-test commit exists.** Search git log on the current branch for a commit matching `test({phase}-{plan})` whose subject mentions the same plan as the current task. The commit must touch a test file (`*.test.*`, `*.spec.*`, `tests/**`).
18
- 2. **The test was actually red — INTENTIONALLY (#3770).** A nonzero exit is not RED by itself: syntax errors, zero-test discovery, fixture crashes, parser errors, and unrelated assertions are INVALID_RED. The executor must persist the RED evidence record (command, exit code, failing test, expected result from `<behavior>`, actual result) and verify it:
19
- ```bash
20
- gsd_run check tdd-red-evidence <record.json> --raw
21
- ```
22
- - `RED_EVIDENCE_OK` (reason `target_test_failed`): the TARGET test named by the plan failed on a real assertion — the ONLY verdict that authorizes GREEN.
23
- - `INVALID_RED` (reasons `unexpected_green`, `zero_tests_discovered`, `nonzero_exit_without_test_failure`, `fixture_or_load_failure`, `no_target_test_failure`, `invalid_record`, `unreadable_record`): the gate trips — halt, fix the RED phase (test identity, fixture, discovery), and re-verify before any implementation step. A `RED:` prefix or `(RED)` tag in the commit message is NOT sufficient evidence on its own.
18
+ 2. **The test was actually red — INTENTIONALLY (#3770).** Read `gsd-core/references/tdd.md`, "Red-Green-Refactor Cycle", RED step 4, and follow its complete evidence contract before GREEN. That section owns format selection (TAP, including Node/Vitest; JUnit XML, including Surefire/Failsafe; swift-testing console; or Python `unittest` text), reporter reruns, report freshness, the classifier invocation, and semantic inspection. Require `RED_EVIDENCE_OK` for the actual run and verify the planned target assertion failed for the intended reason. An `INVALID_RED` verdict, unsupported format, or failed semantic assessment trips this gate; self-attestation cannot substitute for machine validation. A `RED:` prefix or `(RED)` tag in the commit message is not evidence.
24
19
  3. **No implementation commit yet.** No `feat({phase}-{plan})` commit may exist for the same plan ID before the failing-test commit.
25
20
 
26
- If any check fails, the gate trips. For check 2, an INVALID_RED verdict (`check tdd-red-evidence`) trips the gate — the executor MUST halt and block the implementation step.
21
+ If any check fails, the gate trips. A non-zero exit from `gsd_run check tdd-red-evidence` (`69` `UNAVAILABLE`: the record could not be read, #5170) is a command failure that has NOT authorized GREEN — the gate trips. For check 2, an `INVALID_RED` classifier verdict or a failed semantic assessment trips the gate (halt reason `invalid_red`) — the executor MUST halt and block the implementation step.
27
22
 
28
23
  ## What "behavior-adding task" means
29
24
 
@@ -52,7 +47,7 @@ The executor MUST:
52
47
  Required next step:
53
48
  1. Write a failing test for the behavior above.
54
49
  2. Commit it as: test({phase}-{plan}): {short description}
55
- 3. Re-run /gsd execute-phase
50
+ 3. Re-run /gsd:execute-phase
56
51
  ```
57
52
 
58
53
  3. Exit the current execution wave cleanly. Do NOT roll back any prior commits in the same wave.
@@ -65,7 +60,7 @@ The existing end-of-phase TDD review (in `workflows/execute-phase.md`'s `tdd_rev
65
60
  Under TDD mode, escalate this to **blocking**:
66
61
  - If any TDD plan is missing a RED or GREEN commit, the executor MUST refuse to mark the phase complete.
67
62
  - The user is shown the same review table, but the verdict line reads:
68
- > "Phase blocked: {N} TDD plan(s) violate the RED→GREEN gate sequence under TDD. Resolve and re-run /gsd execute-phase, or override with `/gsd execute-phase {phase} --force-mvp-gate` to ship anyway."
63
+ > "Phase blocked: {N} TDD plan(s) violate the RED→GREEN gate sequence under TDD. Resolve and re-run /gsd:execute-phase, or override with `/gsd:execute-phase {phase} --force-mvp-gate` to ship anyway."
69
64
 
70
65
  The `--force-mvp-gate` flag is documented but not introduced by this plan — it is the escape hatch the spec mentions; if the user later builds it, the workflow already references the contract.
71
66
 
@@ -73,7 +68,7 @@ The `--force-mvp-gate` flag is documented but not introduced by this plan — it
73
68
 
74
69
  - It does not enforce REFACTOR commits. REFACTOR remains optional (per `gsd-core/references/tdd.md`).
75
70
  - It does not check test quality (the test could be trivially weak). That's the planner's job. It DOES check that the RED failure was intentional — the target test failing an assertion (#3770).
76
- - It does not run tests. The executor only inspects git log + file system. Running tests is the implementation step's job.
71
+ - It does not start implementation by running tests. During RED, the executor runs the planned test and captures its result, rerunning the planned target with a supported reporter when the first report is unsupported (`tdd.md` RED step 4); before GREEN, this gate inspects that persisted evidence, git history, and test assertion. The implementation step starts only after the RED gate passes.
77
72
  - It does not gate config-only or doc-only tasks (see "behavior-adding task" definition).
78
73
 
79
74
  ## Compatibility with existing TDD discipline
@@ -4,6 +4,9 @@
4
4
  - `## Cross-Plan Wiring Gap` with plan/link/from/pattern rows
5
5
  - Options: investigate+fix before continue, or continue with cascade risk
6
6
  Skip key-links that reference files in the CURRENT (upcoming) wave.
7
+ Exit status (#5170): `0` all verified; `1` a link failed (read the JSON); `66` the plan declares no
8
+ key_links (nothing to check); `69` the plan is missing/unreadable (could not look — surface it, never
9
+ treat the plan as wired).
7
10
 
8
11
  7c. **Between-wave manifest reset and worktree base refresh (waves 2+ only — #1369):**
9
12
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  **If `response_language` is set:** User-facing orchestrator output (questions, narration, report-template prose) in `{response_language}`; technical terms, code, file paths, and subagent prompts stay in English. Pass `response_language: {value}` into every spawned subagent prompt so any user-facing output they produce stays in the configured language.
4
4
 
5
- **The `gsd-verifier` subagent has no workflow file of its own (#2529):** the `verify_phase_goal` step reaches it by dispatch, not by reading a workflow, so there is no file in which to place a directive — the dispatch prompt is the only place its coverage can live. That prompt MUST carry this line verbatim, immediately after `Create VERIFICATION.md.`:
5
+ **The `gsd-verifier` subagent has no workflow file of its own (#2529):** the shared verification step (`workflows/execute-phase/steps/verify-phase-goal.md`, included by execute-phase's `verify_phase_goal` and by verify-work, #5118) reaches it by dispatch, not by reading a workflow, so there is no file in which to place a directive — the dispatch prompt is the only place its coverage can live. That prompt MUST carry this line verbatim, immediately after `Create VERIFICATION.md.` (the shared step's prompt carries it inline, so both callers inject it):
6
6
 
7
7
  `Use response_language {response_language} for all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code and paths.`
8
8
 
@@ -4,5 +4,5 @@ Use this bootstrap block when a workflow must call `gsd-tools` from the active w
4
4
  Keep this resolver centralized; workflows should reference this file instead of copying the shell probe.
5
5
 
6
6
  ```bash
7
- _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; _gsd_at() { for _p; do if [ -f "$_p" ]; then GSD_TOOLS="$_p"; return 0; fi; done; return 1; }; _gsd_id_ok() { case "$("$1" runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') return 0;; *) return 1;; esac; }; _gsd_homes() { _gsd_at "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; }; if _gsd_at "${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif _gsd_homes; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif unset -f gsd_run; _G="$(command -v gsd_run)"; [ -n "$_G" ] && _gsd_id_ok "$_G"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and no identity-proving gsd_run is on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; _gsd_id_ok gsd_run && GSD_IDENTITY_STATUS=ok; export GSD_IDENTITY_STATUS; [ "$GSD_IDENTITY_STATUS" = ok ] || echo "WARNING: \"$GSD_TOOLS\" did not prove it is @opengsd/gsd-core - it is either a different package or an @opengsd/gsd-core older than the runtime-identity verb. See docs/how-to/diagnose-a-foreign-gsd-tools.md" >&2; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
7
+ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; _gsd_at() { for _p; do if [ -f "$_p" ]; then GSD_TOOLS="$_p"; return 0; fi; done; return 1; }; _gsd_id_ok() { case "$("$1" runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') return 0;; *) return 1;; esac; }; _gsd_homes() { set -- "${CLAUDE_CONFIG_DIR:-$HOME/.claude}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}" "$HOME/.gemini/antigravity-ide" "$HOME/.gemini/antigravity-cli" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}" "${CLINE_CONFIG_DIR:-$HOME/.cline}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}" "${CODEX_HOME:-$HOME/.codex}" "${COPILOT_CONFIG_DIR:-${COPILOT_HOME:-$HOME/.copilot}}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}" "${HERMES_HOME:-$HOME/.hermes}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}" "${KIMI_CONFIG_DIR:-$HOME/.config/agents}" "$HOME/.agents" "${KIMI_CODE_HOME:-$HOME/.kimi-code}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}" "${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}" "${TRAE_CONFIG_DIR:-$HOME/.trae}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}" "${ZCODE_CONFIG_DIR:-$HOME/.zcode}" "${GROK_AGENTS_HOME:-$HOME/.agents}"; for _h; do _gsd_at "$_h/gsd-core/bin/${_GSD_SHIM_NAME}" && return 0; done; return 1; }; if _gsd_at "${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif _gsd_homes; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif unset -f gsd_run; _G="$(command -v gsd_run)"; [ -n "$_G" ] && _gsd_id_ok "$_G"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and no identity-proving gsd_run is on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; _gsd_id_ok gsd_run && GSD_IDENTITY_STATUS=ok; export GSD_IDENTITY_STATUS; [ "$GSD_IDENTITY_STATUS" = ok ] || echo "WARNING: \"$GSD_TOOLS\" did not prove it is @opengsd/gsd-core - it is either a different package or an @opengsd/gsd-core older than the runtime-identity verb. See docs/how-to/diagnose-a-foreign-gsd-tools.md" >&2; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
8
8
  ```
@@ -108,7 +108,13 @@ Evaluate `check` (one of `query`, `predicate`, or `agentVerdict`). Then honor `b
108
108
  - `blocking: false` → advisory only; surface the message but continue regardless of outcome.
109
109
 
110
110
  Honor `onError` if the check itself errors: `skip` means treat as non-blocking and continue;
111
- `halt` means surface the error and stop.
111
+ `halt` means surface the error and stop. "Errors" means a non-zero exit from `gsd_run check ...`,
112
+ and that includes `69` (`UNAVAILABLE`, #5170): a gate verb exits `69` when it **could not look** at
113
+ its evidence, still printing the gate's usual JSON (its own fields name what could not be read, such
114
+ as `status: "unresolvable"`, `readError`, or `unreadable`). That JSON is not a verdict — do not act
115
+ on its `block`; route it by `onError` as a step-1 command failure. Exit `0` always means a
116
+ delivered verdict, a blocking one included (`block: true`): a gate verb never exits non-zero to say
117
+ "blocked".
112
118
 
113
119
  ## Empty / absent `activeHooks`
114
120
 
@@ -34,7 +34,7 @@ STOP. Do not proceed to auto-advance or transition.
34
34
  1. Parse `--auto` flag from $ARGUMENTS
35
35
  2. Read consolidated auto-mode (`active` = chain flag OR user preference; chain flag already synced in init step):
36
36
  ```bash
37
- AUTO_MODE=$(gsd_run query check auto-mode --pick active 2>/dev/null || echo "false")
37
+ AUTO_MODE=$(gsd_run query check auto-mode --pick active 2>/dev/null) || AUTO_MODE="false"
38
38
  ```
39
39
 
40
40
  **If `--auto` flag present OR `AUTO_MODE` is true (AND verification passed with no gaps):**
@@ -432,7 +432,7 @@ Several config fields affect each other or trigger special behavior:
432
432
 
433
433
  4. **`parallelization` polymorphism** -- Accepts both a simple boolean and an object with an `enabled` field. `loadConfig()` normalizes either form to a boolean. `{ "enabled": true }` is equivalent to `true`.
434
434
 
435
- 5. **Search API keys and flags** -- `brave_search`, `firecrawl`, and `exa_search` are auto-set to `true` during project creation if the corresponding API key is detected (environment variable or `~/.gsd/<name>_api_key` file). Setting them to `true` without the API key has no effect.
435
+ 5. **Search API keys and flags** -- `brave_search`, `firecrawl`, and `exa_search` are auto-set to `true` during project creation if the corresponding API key is detected (environment variable or `$GSD_HOME/.gsd/<name>_api_key` file; `GSD_HOME` defaults to the home directory). Setting them to `true` without the API key has no effect.
436
436
 
437
437
  6. **`planning.*` and top-level equivalence** -- `planning.commit_docs` and `commit_docs` are equivalent; `planning.search_gitignored` and `search_gitignored` are equivalent. If both are set, the top-level value takes precedence.
438
438
 
@@ -55,7 +55,7 @@ When SPIDR triggers, the workflow:
55
55
  2. Asks "Which SPIDR axis fits best?" with the five options above.
56
56
  3. Walks through the chosen axis interactively (one focused question), produces a split proposal: "Phase N (this one): X. Phase N+1: Y. Phase N+2: Z."
57
57
  4. Confirms the split with the user.
58
- 5. On accept: writes the FIRST phase's story to the current ROADMAP entry; defers creating new phases for the splits to a follow-up step (the workflow surfaces a list of `/gsd add-phase` invocations the user can run after `mvp-phase` completes — but does not run them automatically, to preserve user control over phase numbering).
58
+ 5. On accept: writes the FIRST phase's story to the current ROADMAP entry; defers creating new phases for the splits to a follow-up step (the workflow surfaces a list of `/gsd:phase` invocations the user can run after `mvp-phase` completes — but does not run them automatically, to preserve user control over phase numbering).
59
59
  6. On reject: proceeds with the original story unchanged.
60
60
 
61
61
  ## Anti-patterns to reject
@@ -78,7 +78,7 @@ Output: [Working, tested feature]
78
78
 
79
79
  <output>
80
80
  After completion, create SUMMARY.md with:
81
- - RED: What test was written, why it failed
81
+ - RED: What test was written, why it failed, and the semantic assessment of its RED evidence
82
82
  - GREEN: What implementation made it pass
83
83
  - REFACTOR: What cleanup was done (if any)
84
84
  - Commits: List of commits produced
@@ -95,7 +95,13 @@ After completion, create SUMMARY.md with:
95
95
  1. Create test file following project conventions
96
96
  2. Write test describing expected behavior (from `<behavior>` element)
97
97
  3. Run test - it MUST fail **intentionally** (#3770): the TARGET test you named must be the test that fails, on an assertion for the planned behavior. A nonzero exit alone is NOT RED — syntax errors, zero-test discovery, fixture crashes, parser errors, and unrelated assertions are INVALID_RED and must not authorize GREEN.
98
- 4. Persist the RED evidence record (command, exit code, failing test, expected result, actual result) and verify it: `gsd_run check tdd-red-evidence <record.json>`. Only verdict `RED_EVIDENCE_OK` satisfies the RED gate; `INVALID_RED` blocks GREEN until the RED phase is fixed.
98
+ 4. Persist the RED evidence from the actual command: `{command, exitCode, output, targetTest, targetFile, expected, actual}`. Preserve the real exit status and unmodified report; record the planned expected result and observed actual result. Write the record inside the project directory; the classifier refuses a path outside it. It reads only these fields, so the further fields below stay in the record for review.
99
+ - Select evidence by **report format**, regardless of runner or package manager. The classifier has a shared TAP adapter for Node's built-in test runner and Vitest (`tap` / `tap-flat`), a JUnit XML adapter for Maven Surefire/Failsafe, a swift-testing console adapter for `swift test`, and a Python `unittest` text adapter. Other producers of these formats use the same adapters.
100
+ - TAP: capture the complete reporter output, including its test plan. Node summary comments are optional. The report must start with its TAP output: capture the reporter's own stdout (for npm scripts, `npm run --silent`), not package-manager banners. Use the target test's exact name; when names repeat, use its qualified name as emitted in the report (`tap-flat` emits only the full `file > suite > test` name). Suite/file summary failures are not target assertions. If the reporter is incompatible, rerun the planned target with a supported reporter through the project's test command, capture that real command and result, then submit the rerun's record to the classifier below. Preserve other console output separately rather than editing the report to make it parse.
101
+ - JUnit XML: capture the unchanged target report generated by the actual run. For Maven this is `target/surefire-reports/TEST-*.xml` or `target/failsafe-reports/TEST-*.xml`. Record the report path, run start, and modification time as `reportPath`, `runStartedAt`, and `reportModifiedAt`; require the report to be newer than the run start and verify the named target class or method executed in that run. Name the target as the method, the class (simple or package-qualified), or `<package.Class>#<method>`. Put one complete XML document in `output`, preserving console output alongside it. Missing, stale, or ambiguous reports require STOP and investigation.
102
+ - swift-testing and `unittest`: capture the complete console output without color (`NO_COLOR=1`), including the final summary. swift-testing needs one `Test` result line (passed, failed, skipped, or cancelled) for every test its `Test run with N tests` summary counts; it names a test by its quoted display name or, without one, by its function name (`addsNumbers()`), and either name identifies the target; repeated swift-testing names are ambiguous and block GREEN. `unittest` needs one `FAIL:`/`ERROR:` header for every failure or error its `FAILED (...)` line counts; repeated headers from one test's failing subTests count as one failing test, a method name that repeats across classes needs its `module.Class.method` id, and a `unittest.loader._FailedTest` entry is a load failure, never RED.
103
+ - Pass the unchanged record to `gsd_run check tdd-red-evidence <record.json> --raw` and require `RED_EVIDENCE_OK` before GREEN. Every `INVALID_RED` reason (`unexpected_green`, `zero_tests_discovered`, `nonzero_exit_without_test_failure`, `fixture_or_load_failure`, `no_target_test_failure`, `invalid_record`, `unreadable_record`) trips the gate. `invalid_record` includes unsupported or malformed reports; inspect `evidence.report_errors`. An unsupported format requires a supported reporter or a parser adapter before GREEN. Classifier rejection never authorizes a fallback to self-attestation.
104
+ - After machine validation, inspect whether the target actually executed and failed on the planned assertion for the intended reason. Zero tests, a missing, skipped, or cancelled target, setup, collection, import, syntax, or fixture faults, unrelated failures, unexpected green, and incomplete or ambiguous evidence block GREEN. Record this semantic assessment as `semanticAssessment` in the RED evidence and in the SUMMARY's RED entry; never fabricate reports, counters, or parser verdicts.
99
105
  5. If test passes: feature exists or test is wrong. Investigate.
100
106
  6. Commit: `test({phase}-{plan}): add failing test for [feature]`
101
107
 
@@ -279,14 +285,14 @@ When `workflow.tdd_mode` is enabled in config, the RED/GREEN/REFACTOR gate seque
279
285
 
280
286
  | Gate | Required | Commit Pattern | Validation |
281
287
  |------|----------|---------------|------------|
282
- | RED | Yes | `test({phase}-{plan}): ...` | Test exists AND fails before implementation — intentionally: `check tdd-red-evidence` returns `RED_EVIDENCE_OK` (target test failed on an assertion for the behavior; anything else is INVALID_RED) |
288
+ | RED | Yes | `test({phase}-{plan}): ...` | Target test exists AND fails before implementation: a complete report in a supported format (RED step 4) from the current run must return `RED_EVIDENCE_OK`, followed by semantic inspection of the planned assertion (RED step 4) |
283
289
  | GREEN | Yes | `feat({phase}-{plan}): ...` | Test passes after implementation |
284
290
  | REFACTOR | No | `refactor({phase}-{plan}): ...` | Tests still pass after cleanup |
285
291
 
286
292
  ### Fail-Fast Rules
287
293
 
288
294
  1. **Unexpected GREEN in RED phase:** If the test passes before any implementation code is written, STOP. The feature may already exist or the test is wrong. Investigate before proceeding.
289
- 2. **INVALID_RED in RED phase (#3770):** A nonzero exit is not RED by itself. Zero-test discovery, fixture/load crashes, nonzero exits with no failing test, unrelated failing tests, and unexpected greens all classify as INVALID_RED (`gsd_run check tdd-red-evidence`). STOP and fix the RED phase — do NOT proceed to GREEN.
295
+ 2. **INVALID_RED in RED phase (#3770):** A nonzero exit is not RED by itself. Follow the format-based evidence contract in RED step 4, including reporter reruns and report freshness. An `INVALID_RED` verdict or failed semantic assessment halts GREEN. Unsupported, incomplete, ambiguous, or contradictory evidence cannot authorize implementation.
290
296
  3. **Missing RED commit:** If no `test(...)` commit precedes the `feat(...)` commit, the TDD discipline was violated. Flag in SUMMARY.md.
291
297
  4. **REFACTOR breaks tests:** Undo the refactor immediately. Commit was premature — refactor in smaller steps.
292
298
 
@@ -34,12 +34,15 @@ no `<decisions>` block.
34
34
  GATE_CFG=$(gsd_run query config-get workflow.context_coverage_gate 2>/dev/null || echo "true")
35
35
  if [ "$GATE_CFG" != "false" ]; then
36
36
  CONTEXT_PATH=$(ls "${PHASE_DIR}"/*-CONTEXT.md 2>/dev/null | head -1) # #2962: not a for-glob (zsh aborts)
37
- DECISION_RESULT=$(gsd_run query check.decision-coverage-verify "${PHASE_DIR}" "${CONTEXT_PATH}")
37
+ DECISION_RESULT=$(gsd_run query check.decision-coverage-verify "${PHASE_DIR}" "${CONTEXT_PATH}") && DECISION_EXIT=0 || DECISION_EXIT=$?
38
38
  fi
39
39
  ```
40
40
 
41
41
  The handler returns JSON `{ skipped, blocking: false, total, honored,
42
- not_honored: [...], message }`.
42
+ not_honored: [...], message }`. A non-zero `DECISION_EXIT` (`69` `UNAVAILABLE`: the gate
43
+ could not read CONTEXT.md or the phase artifacts, #5170) is **not** "no decisions": record
44
+ `Decision coverage: not evaluated (the gate could not read its evidence)` in VERIFICATION.md
45
+ and do not report counts.
43
46
 
44
47
  **Reporting:** Append the handler's `message` (a `### Decision Coverage`
45
48
  section) to VERIFICATION.md regardless of outcome — even when all
@@ -15,9 +15,9 @@ The user-flow form mirrors what a real user does: open, fill, click, see. No HTT
15
15
 
16
16
  The framing fires when:
17
17
  - The phase under verification has `**Mode:** mvp` in ROADMAP.md (parsed via `gsd_run query roadmap.get-phase --pick mode`).
18
- - AND the phase has a user-story-formatted goal (set by `/gsd mvp-phase` per Phase 2): "As a [user role], I want to [capability], so that [outcome]."
18
+ - AND the phase has a user-story-formatted goal (set by `/gsd:mvp-phase` per Phase 2): "As a [user role], I want to [capability], so that [outcome]."
19
19
 
20
- If the phase has `mode: mvp` but the goal is NOT in user-story format, the verifier surfaces this as a discrepancy and asks the user to run `/gsd mvp-phase` to reformat the goal — same pattern as the planner agent under MVP_MODE (per `gsd-core/references/planner-mvp-mode.md`).
20
+ If the phase has `mode: mvp` but the goal is NOT in user-story format, the verifier surfaces this as a discrepancy and asks the user to run `/gsd:mvp-phase` to reformat the goal — same pattern as the planner agent under MVP_MODE (per `gsd-core/references/planner-mvp-mode.md`).
21
21
 
22
22
  ## Generated UAT script structure under MVP mode
23
23
 
@@ -77,13 +77,43 @@ and broader temp hygiene is left to OS temp cleanup or future maintenance work.
77
77
 
78
78
  ## Routing Propagation
79
79
 
80
- All workflow routing commands include `${GSD_WS}` which:
81
- - Expands to `--ws <name>` when a workstream is active
82
- - Expands to empty string in flat mode (backward compatible)
80
+ Every workstream-scoped workflow parses the `--ws <name>` it was started with out of
81
+ `$ARGUMENTS` in each shell fence that needs it (fences are separate shells, so nothing is
82
+ carried over between them) and sets `GSD_WS`:
83
+ - `GSD_WS` is `--ws <name>` when the command was started with `--ws`, and empty otherwise
84
+ (flat mode, backward compatible). It is always re-assigned, so a stale value never leaks in.
85
+ - Every `gsd_run query agent-skills <agent>` and `gsd_run query init.*` call in those
86
+ workflows forwards it as the single token `${GSD_WS:+--ws=${GSD_WS##* }}`. The explicit
87
+ flag has the highest priority above, so the workstream a command was started for wins over
88
+ the session pointer and the shared marker. The single-token form is required because zsh
89
+ does not word-split an unquoted `$GSD_WS`.
90
+ - Workflows recognize the documented spelling `--ws <name>`; `--ws=<name>` is accepted by the
91
+ CLI itself but is not parsed out of `$ARGUMENTS` by workflows.
92
+ - Routing suggestions (`/gsd:plan-phase {X} ${GSD_WS}`) carry the same value to the next command.
93
+ - Project and workspace lifecycle workflows (`new-project`, `new-workspace`,
94
+ `list-workspaces`, `remove-workspace`, `update`) are root-scoped and do not forward it.
95
+
96
+ `tests/agent-skills.test.cjs` scans every fenced call in `gsd-core/workflows/` so a new call
97
+ that omits the flag fails CI.
83
98
 
84
99
  This ensures workstream scope chains automatically through the workflow:
85
100
  `new-milestone → discuss-phase → plan-phase → execute-phase → transition`
86
101
 
102
+ ## Reserved names
103
+
104
+ `none` (case-insensitive) cannot name a workstream. `--ws none`, `--ws=none`, `GSD_WORKSTREAM=none`
105
+ and a pointer of `none` are all rejected with a "reserved" error, and `workstream create` and
106
+ `workstream set` refuse it unconditionally. The one exception on the read side is a
107
+ `.planning/workstreams/none/` directory that already exists: it stays addressable with `--ws none`
108
+ so projects that used the name before it was reserved keep working (the directory name must match
109
+ exactly; `NONE` is still rejected). Such a grandfathered directory is reachable through `--ws` and
110
+ `GSD_WORKSTREAM` only, because `workstream set none` refuses unconditionally. To force flat mode,
111
+ omit `--ws`, unset `GSD_WORKSTREAM`, or clear the pointer (`workstream set --clear`). The rejection
112
+ happens before any command runs, so a stale `GSD_WORKSTREAM=none` in the environment must be unset
113
+ first. The reserved list has a single owner
114
+ (`RESERVED_WORKSTREAM_NAMES` in `src/workstream-name-policy.cts`); near-misses such as `none1` or
115
+ `nonexistent` are ordinary names.
116
+
87
117
  ## Directory Structure
88
118
 
89
119
  ```
@@ -17,7 +17,7 @@ These files live directly at `.planning/` — not inside phase subdirectories.
17
17
  | `STATE.md` | `state.md` | `/gsd:new-project`, `/gsd:health --repair` | Current session state, active phase, last activity |
18
18
  | `REQUIREMENTS.md` | `requirements.md` | `/gsd:new-milestone` | Functional requirements with traceability |
19
19
  | `MILESTONES.md` | `milestone.md` | `/gsd:complete-milestone` | Log of completed milestones with accomplishments |
20
- | `BACKLOG.md` | *(inline)* | `/gsd-add-backlog` | Pending ideas and deferred work |
20
+ | `BACKLOG.md` | *(inline)* | `/gsd:capture --backlog` | Pending ideas and deferred work |
21
21
  | `LEARNINGS.md` | *(inline)* | `/gsd:extract-learnings`, `/gsd:execute-phase` (gated: `features.global_learnings`) | Phase retrospective learnings for future plans |
22
22
  | `THREADS.md` | *(inline)* | `/gsd:thread` | Persistent discussion threads |
23
23
  | `config.json` | `config.json` | `/gsd:new-project`, `/gsd:health --repair` | Project-specific GSD configuration |
@@ -66,7 +66,7 @@ blocked: [N]
66
66
 
67
67
  <!-- YAML format for plan-phase --gaps consumption -->
68
68
  - truth: "[expected behavior from test]"
69
- status: failed
69
+ status: failed | resolved
70
70
  reason: "User reported: [verbatim response]"
71
71
  severity: blocker | major | minor | cosmetic
72
72
  test: [N]
@@ -74,6 +74,10 @@ blocked: [N]
74
74
  artifacts: [] # Filled by diagnosis
75
75
  missing: [] # Filled by diagnosis
76
76
  debug_session: "" # Filled by diagnosis
77
+ resolved_by: "" # Written by verify-work's reconcile_gaps (#1921) when
78
+ # an executed gap-closure plan resolves this gap —
79
+ # never author this directly. Plan basename.
80
+ resolved_at: "" # Written alongside resolved_by (#1921).
77
81
  ```
78
82
 
79
83
  ---
@@ -107,6 +111,18 @@ blocked: [N]
107
111
  - APPEND only when issue found (YAML format)
108
112
  - After diagnosis: fill `root_cause`, `artifacts`, `missing`, `debug_session`
109
113
  - This section feeds directly into /gsd:plan-phase --gaps
114
+ - `status: resolved` (#1921, #4983): when `/gsd:verify-work`'s `reconcile_gaps`
115
+ step finds an executed gap-closure plan (a `*-PLAN.md` naming this entry's
116
+ `gap_id` with a matching `*-SUMMARY.md`), it updates the entry IN PLACE —
117
+ `status: failed` → `status: resolved` — and adds `resolved_by` (the
118
+ resolving plan's basename) and `resolved_at` (the date). A resolved entry
119
+ is no longer surfaced as an open gap, and its matching `### N.` test's
120
+ `result: issue` no longer blocks `phase uat-passed` — but only when
121
+ `resolved_by` names a plan that actually exists in the phase directory with
122
+ a matching SUMMARY; a hand-written `status: resolved` with no valid
123
+ `resolved_by` still blocks (src/uat-predicate.cts's `isTestGapResolved`).
124
+ A later regression against the same test gets a fresh `gap_id`, never a
125
+ reopened resolved one.
110
126
 
111
127
  </section_rules>
112
128