@opengsd/gsd-core 1.14.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 (551) 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/README.ja-JP.md +3 -3
  5. package/README.ko-KR.md +3 -3
  6. package/README.pt-BR.md +3 -3
  7. package/README.zh-CN.md +3 -3
  8. package/agents/gsd-code-fixer.compact.md +7 -6
  9. package/agents/gsd-code-fixer.md +9 -8
  10. package/agents/gsd-code-reviewer.compact.md +5 -3
  11. package/agents/gsd-code-reviewer.md +8 -6
  12. package/agents/gsd-debug-session-manager.compact.md +17 -2
  13. package/agents/gsd-debug-session-manager.md +17 -2
  14. package/agents/gsd-debugger.md +3 -3
  15. package/agents/gsd-eval-auditor.compact.md +1 -1
  16. package/agents/gsd-eval-auditor.md +1 -1
  17. package/agents/gsd-executor.md +17 -12
  18. package/agents/gsd-intel-updater.compact.md +1 -1
  19. package/agents/gsd-intel-updater.md +1 -1
  20. package/agents/gsd-mempalace-curator.md +2 -2
  21. package/agents/gsd-phase-researcher.md +19 -11
  22. package/agents/gsd-plan-checker.md +15 -9
  23. package/agents/gsd-planner.md +15 -11
  24. package/agents/gsd-project-researcher.compact.md +1 -1
  25. package/agents/gsd-project-researcher.md +1 -1
  26. package/agents/gsd-research-synthesizer.compact.md +1 -1
  27. package/agents/gsd-research-synthesizer.md +1 -1
  28. package/agents/gsd-ui-auditor.compact.md +21 -30
  29. package/agents/gsd-ui-auditor.md +166 -37
  30. package/agents/gsd-ui-researcher.compact.md +1 -1
  31. package/agents/gsd-ui-researcher.md +1 -1
  32. package/agents/gsd-verifier.md +37 -14
  33. package/bin/install.js +764 -287
  34. package/commands/gsd/add-tests.md +6 -1
  35. package/commands/gsd/ai-integration-phase.md +6 -1
  36. package/commands/gsd/audit-fix.md +5 -0
  37. package/commands/gsd/audit-milestone.md +6 -1
  38. package/commands/gsd/autonomous.md +7 -2
  39. package/commands/gsd/capture.md +9 -5
  40. package/commands/gsd/code-review.md +7 -2
  41. package/commands/gsd/complete-milestone.md +4 -0
  42. package/commands/gsd/config.md +7 -3
  43. package/commands/gsd/debug.md +11 -7
  44. package/commands/gsd/discuss-phase.md +7 -3
  45. package/commands/gsd/docs-update.md +12 -7
  46. package/commands/gsd/eval-review.md +6 -1
  47. package/commands/gsd/execute-phase.md +12 -7
  48. package/commands/gsd/extract-learnings.md +5 -0
  49. package/commands/gsd/fast.md +4 -0
  50. package/commands/gsd/forensics.md +5 -1
  51. package/commands/gsd/graphify.md +10 -6
  52. package/commands/gsd/health.md +5 -0
  53. package/commands/gsd/help.md +7 -2
  54. package/commands/gsd/import.md +7 -3
  55. package/commands/gsd/inbox.md +5 -0
  56. package/commands/gsd/ingest-docs.md +5 -1
  57. package/commands/gsd/manager.md +6 -1
  58. package/commands/gsd/map-codebase.md +7 -3
  59. package/commands/gsd/mempalace-capture.md +12 -4
  60. package/commands/gsd/mempalace-recall.md +5 -1
  61. package/commands/gsd/milestone-summary.md +5 -1
  62. package/commands/gsd/mvp-phase.md +8 -3
  63. package/commands/gsd/new-milestone.md +6 -1
  64. package/commands/gsd/new-project.md +5 -0
  65. package/commands/gsd/next.md +6 -1
  66. package/commands/gsd/ns-context.md +4 -0
  67. package/commands/gsd/ns-ideate.md +4 -0
  68. package/commands/gsd/ns-manage.md +4 -0
  69. package/commands/gsd/ns-project.md +4 -0
  70. package/commands/gsd/ns-review.md +4 -0
  71. package/commands/gsd/ns-workflow.md +4 -0
  72. package/commands/gsd/onboard.md +6 -1
  73. package/commands/gsd/pause-work.md +5 -1
  74. package/commands/gsd/phase.md +8 -4
  75. package/commands/gsd/plan-phase.md +6 -1
  76. package/commands/gsd/plan-review-convergence.md +11 -7
  77. package/commands/gsd/pr-branch.md +4 -0
  78. package/commands/gsd/profile-user.md +5 -1
  79. package/commands/gsd/progress.md +7 -2
  80. package/commands/gsd/quick-batch.md +21 -9
  81. package/commands/gsd/quick.md +12 -7
  82. package/commands/gsd/review.md +7 -4
  83. package/commands/gsd/secure-phase.md +6 -1
  84. package/commands/gsd/ship.md +5 -0
  85. package/commands/gsd/sketch.md +7 -2
  86. package/commands/gsd/spec-phase.md +5 -1
  87. package/commands/gsd/spike.md +8 -3
  88. package/commands/gsd/surface.md +5 -1
  89. package/commands/gsd/thread.md +4 -0
  90. package/commands/gsd/ui-phase.md +6 -1
  91. package/commands/gsd/ui-review.md +6 -1
  92. package/commands/gsd/ultraplan-phase.md +5 -1
  93. package/commands/gsd/undo.md +5 -1
  94. package/commands/gsd/update.md +6 -2
  95. package/commands/gsd/validate-phase.md +6 -1
  96. package/commands/gsd/verify-work.md +6 -1
  97. package/commands/gsd/workspace.md +7 -3
  98. package/gsd-core/bin/gsd-tools.cjs +477 -78
  99. package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
  100. package/gsd-core/bin/lib/adr-parser.cjs +3 -1
  101. package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
  102. package/gsd-core/bin/lib/audit.cjs +144 -42
  103. package/gsd-core/bin/lib/broken-windows.cjs +13 -13
  104. package/gsd-core/bin/lib/capability-activation.cjs +9 -4
  105. package/gsd-core/bin/lib/capability-registry.cjs +197 -222
  106. package/gsd-core/bin/lib/capability-validator.cjs +16 -1
  107. package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
  108. package/gsd-core/bin/lib/check-command-router.cjs +164 -1625
  109. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
  110. package/gsd-core/bin/lib/cli-exit.cjs +12 -0
  111. package/gsd-core/bin/lib/codex-agent-toml.cjs +32 -33
  112. package/gsd-core/bin/lib/command-aliases.cjs +7 -0
  113. package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
  114. package/gsd-core/bin/lib/commands.cjs +343 -207
  115. package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
  116. package/gsd-core/bin/lib/config-loader.cjs +65 -4
  117. package/gsd-core/bin/lib/config.cjs +76 -19
  118. package/gsd-core/bin/lib/core-utils.cjs +6 -1
  119. package/gsd-core/bin/lib/coverage.cjs +4 -8
  120. package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
  121. package/gsd-core/bin/lib/decisions.cjs +30 -14
  122. package/gsd-core/bin/lib/drift.cjs +177 -42
  123. package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
  124. package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
  125. package/gsd-core/bin/lib/frontmatter.cjs +426 -234
  126. package/gsd-core/bin/lib/gap-checker.cjs +72 -29
  127. package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
  128. package/gsd-core/bin/lib/gate-args.cjs +53 -0
  129. package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
  130. package/gsd-core/bin/lib/gate-config.cjs +46 -0
  131. package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
  132. package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
  133. package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
  134. package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
  135. package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
  136. package/gsd-core/bin/lib/gate-exit.cjs +27 -0
  137. package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
  138. package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
  139. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
  140. package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
  141. package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
  142. package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
  143. package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
  144. package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
  145. package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
  146. package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
  147. package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
  148. package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
  149. package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
  150. package/gsd-core/bin/lib/graphify.cjs +10 -2
  151. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
  152. package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
  153. package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
  154. package/gsd-core/bin/lib/init.cjs +364 -132
  155. package/gsd-core/bin/lib/install-engine.cjs +30 -33
  156. package/gsd-core/bin/lib/install-profiles.cjs +7 -4
  157. package/gsd-core/bin/lib/installer-migrations.cjs +8 -1
  158. package/gsd-core/bin/lib/io.cjs +122 -3
  159. package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
  160. package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
  161. package/gsd-core/bin/lib/milestone.cjs +37 -6
  162. package/gsd-core/bin/lib/model-resolver.cjs +171 -62
  163. package/gsd-core/bin/lib/observability/event.cjs +1 -1
  164. package/gsd-core/bin/lib/observability/logger.cjs +46 -1
  165. package/gsd-core/bin/lib/pattern.cjs +10 -0
  166. package/gsd-core/bin/lib/phase-command-router.cjs +20 -5
  167. package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
  168. package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
  169. package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
  170. package/gsd-core/bin/lib/phase-id.cjs +110 -8
  171. package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
  172. package/gsd-core/bin/lib/phase-locator.cjs +29 -10
  173. package/gsd-core/bin/lib/phase-status.cjs +360 -0
  174. package/gsd-core/bin/lib/phase.cjs +489 -88
  175. package/gsd-core/bin/lib/plan-document.cjs +142 -20
  176. package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
  177. package/gsd-core/bin/lib/planning-document.cjs +692 -0
  178. package/gsd-core/bin/lib/planning-inspect.cjs +60 -9
  179. package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
  180. package/gsd-core/bin/lib/planning-workspace.cjs +83 -55
  181. package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
  182. package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
  183. package/gsd-core/bin/lib/probe-core.cjs +7 -1
  184. package/gsd-core/bin/lib/profile-output.cjs +6 -3
  185. package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
  186. package/gsd-core/bin/lib/project-root.cjs +41 -2
  187. package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
  188. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
  189. package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
  190. package/gsd-core/bin/lib/report-parser.cjs +269 -0
  191. package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
  192. package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
  193. package/gsd-core/bin/lib/roadmap-command-router.cjs +25 -19
  194. package/gsd-core/bin/lib/roadmap-parser.cjs +242 -15
  195. package/gsd-core/bin/lib/roadmap-upgrade.cjs +1653 -65
  196. package/gsd-core/bin/lib/roadmap.cjs +405 -88
  197. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +373 -187
  198. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +5 -2
  199. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
  200. package/gsd-core/bin/lib/runtime-homes.cjs +14 -7
  201. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +522 -624
  202. package/gsd-core/bin/lib/runtime-name-policy.cjs +246 -21
  203. package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
  204. package/gsd-core/bin/lib/shell-command-projection.cjs +47 -8
  205. package/gsd-core/bin/lib/smart-entry.cjs +19 -3
  206. package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
  207. package/gsd-core/bin/lib/state-contract.cjs +15 -18
  208. package/gsd-core/bin/lib/state-document.cjs +100 -22
  209. package/gsd-core/bin/lib/state-transition.cjs +39 -2
  210. package/gsd-core/bin/lib/state.cjs +256 -105
  211. package/gsd-core/bin/lib/surface.cjs +19 -2
  212. package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -79
  213. package/gsd-core/bin/lib/uat-predicate.cjs +359 -38
  214. package/gsd-core/bin/lib/uat.cjs +432 -7
  215. package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
  216. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +167 -40
  217. package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
  218. package/gsd-core/bin/lib/vendor/README.md +31 -9
  219. package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
  220. package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
  221. package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
  222. package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
  223. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  224. package/gsd-core/bin/lib/verification.cjs +1378 -274
  225. package/gsd-core/bin/lib/verify-command-grounding.cjs +46 -2
  226. package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
  227. package/gsd-core/bin/lib/verify.cjs +357 -531
  228. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
  229. package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
  230. package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
  231. package/gsd-core/bin/lib/workstream.cjs +11 -2
  232. package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
  233. package/gsd-core/bin/lib/worktree-safety.cjs +784 -51
  234. package/gsd-core/bin/shared/config-defaults.manifest.json +8 -0
  235. package/gsd-core/bin/shared/config-schema.manifest.json +5 -0
  236. package/gsd-core/references/autonomous-smart-discuss.md +2 -1
  237. package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
  238. package/gsd-core/references/checkpoints.md +5 -3
  239. package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
  240. package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
  241. package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
  242. package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
  243. package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
  244. package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
  245. package/gsd-core/references/edge-probe.md +195 -21
  246. package/gsd-core/references/execute-mvp-tdd.md +5 -10
  247. package/gsd-core/references/execute-phase-between-wave-reset.md +10 -6
  248. package/gsd-core/references/execute-phase-response-language.md +1 -1
  249. package/gsd-core/references/execute-phase-wave-guard.md +22 -11
  250. package/gsd-core/references/gsd-run-resolver.md +1 -1
  251. package/gsd-core/references/loop-hook-dispatch.md +7 -1
  252. package/gsd-core/references/model-profiles.md +1 -1
  253. package/gsd-core/references/offer-next.md +1 -1
  254. package/gsd-core/references/phase-argument-parsing.md +9 -7
  255. package/gsd-core/references/phase-id-convention.md +28 -0
  256. package/gsd-core/references/planner-gap-closure.md +2 -0
  257. package/gsd-core/references/planner-load-graph-context.md +24 -13
  258. package/gsd-core/references/planner-verify-command-grounding.md +14 -0
  259. package/gsd-core/references/planning-config.md +12 -3
  260. package/gsd-core/references/spidr-splitting.md +1 -1
  261. package/gsd-core/references/tdd.md +37 -8
  262. package/gsd-core/references/ui-consideration-probe.md +10 -5
  263. package/gsd-core/references/verifier-phase-gates.md +5 -2
  264. package/gsd-core/references/verify-command-path-resolvability.md +10 -2
  265. package/gsd-core/references/verify-mvp-mode.md +2 -2
  266. package/gsd-core/references/workstream-flag.md +33 -3
  267. package/gsd-core/references/worktree-path-safety.md +321 -0
  268. package/gsd-core/templates/README.md +1 -1
  269. package/gsd-core/templates/UAT.md +17 -1
  270. package/gsd-core/templates/config.json +2 -11
  271. package/gsd-core/templates/verification-report.md +1 -1
  272. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  273. package/gsd-core/workflows/add-backlog.md +1 -1
  274. package/gsd-core/workflows/add-phase.md +8 -7
  275. package/gsd-core/workflows/add-tests.md +4 -3
  276. package/gsd-core/workflows/add-todo.md +6 -5
  277. package/gsd-core/workflows/ai-integration-phase.md +13 -4
  278. package/gsd-core/workflows/audit-fix.md +1 -1
  279. package/gsd-core/workflows/audit-milestone.md +4 -3
  280. package/gsd-core/workflows/audit-uat.md +1 -1
  281. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
  282. package/gsd-core/workflows/autonomous.md +43 -23
  283. package/gsd-core/workflows/check-todos.md +7 -6
  284. package/gsd-core/workflows/cleanup.md +2 -2
  285. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
  286. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
  287. package/gsd-core/workflows/code-review-fix.md +112 -25
  288. package/gsd-core/workflows/code-review.md +146 -135
  289. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
  290. package/gsd-core/workflows/complete-milestone.md +13 -8
  291. package/gsd-core/workflows/debug.md +32 -7
  292. package/gsd-core/workflows/diagnose-issues.md +3 -2
  293. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  294. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  295. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  296. package/gsd-core/workflows/discuss-phase.md +4 -3
  297. package/gsd-core/workflows/do.md +2 -2
  298. package/gsd-core/workflows/docs-update.md +6 -5
  299. package/gsd-core/workflows/edit-phase.md +4 -3
  300. package/gsd-core/workflows/eval-review.md +14 -5
  301. package/gsd-core/workflows/execute-phase/detail/elaboration.md +2 -2
  302. package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1019 -0
  303. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
  304. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
  305. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +37 -3
  306. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
  307. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
  308. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  309. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
  310. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
  311. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
  312. package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
  313. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
  314. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
  315. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
  316. package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
  317. package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
  318. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
  319. package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
  320. package/gsd-core/workflows/execute-phase.md +96 -178
  321. package/gsd-core/workflows/execute-plan.md +18 -23
  322. package/gsd-core/workflows/explore.md +4 -4
  323. package/gsd-core/workflows/extract-learnings.md +4 -2
  324. package/gsd-core/workflows/fast.md +1 -1
  325. package/gsd-core/workflows/forensics.md +1 -1
  326. package/gsd-core/workflows/graduation.md +1 -1
  327. package/gsd-core/workflows/health.md +3 -2
  328. package/gsd-core/workflows/help/modes/full.compact.md +3 -3
  329. package/gsd-core/workflows/help/modes/full.md +5 -5
  330. package/gsd-core/workflows/help/modes/topic.md +15 -5
  331. package/gsd-core/workflows/import.md +4 -3
  332. package/gsd-core/workflows/inbox.md +2 -2
  333. package/gsd-core/workflows/ingest-docs.md +3 -3
  334. package/gsd-core/workflows/insert-phase.md +4 -3
  335. package/gsd-core/workflows/list-seeds.md +1 -1
  336. package/gsd-core/workflows/list-workspaces.md +1 -1
  337. package/gsd-core/workflows/manager.md +6 -4
  338. package/gsd-core/workflows/map-codebase.md +5 -4
  339. package/gsd-core/workflows/milestone-summary.md +3 -2
  340. package/gsd-core/workflows/mvp-phase.md +14 -14
  341. package/gsd-core/workflows/new-milestone.md +11 -11
  342. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
  343. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
  344. package/gsd-core/workflows/new-project.md +7 -7
  345. package/gsd-core/workflows/new-workspace.md +2 -2
  346. package/gsd-core/workflows/next.md +1 -1
  347. package/gsd-core/workflows/note.md +1 -1
  348. package/gsd-core/workflows/onboard.md +1 -1
  349. package/gsd-core/workflows/pause-work.md +2 -2
  350. package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
  351. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
  352. package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
  353. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  354. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
  355. package/gsd-core/workflows/plan-phase.md +50 -24
  356. package/gsd-core/workflows/plan-review-convergence.md +21 -5
  357. package/gsd-core/workflows/plant-seed.md +62 -20
  358. package/gsd-core/workflows/pr-branch.md +113 -13
  359. package/gsd-core/workflows/profile-user.md +2 -2
  360. package/gsd-core/workflows/progress.md +19 -49
  361. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +27 -0
  362. package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
  363. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
  364. package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
  365. package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
  366. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
  367. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
  368. package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
  369. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
  370. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
  371. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
  372. package/gsd-core/workflows/quick-batch.md +15 -10
  373. package/gsd-core/workflows/quick.md +62 -39
  374. package/gsd-core/workflows/reapply-patches.md +9 -3
  375. package/gsd-core/workflows/remove-phase.md +3 -2
  376. package/gsd-core/workflows/remove-workspace.md +2 -2
  377. package/gsd-core/workflows/resume-project.md +3 -2
  378. package/gsd-core/workflows/review.md +33 -17
  379. package/gsd-core/workflows/scan.md +3 -2
  380. package/gsd-core/workflows/secure-phase.md +13 -13
  381. package/gsd-core/workflows/settings-advanced.md +30 -10
  382. package/gsd-core/workflows/settings-integrations.md +2 -3
  383. package/gsd-core/workflows/settings.md +4 -4
  384. package/gsd-core/workflows/ship.md +14 -13
  385. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  386. package/gsd-core/workflows/sketch.md +1 -1
  387. package/gsd-core/workflows/smart-entry.md +2 -2
  388. package/gsd-core/workflows/spec-phase.md +15 -5
  389. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  390. package/gsd-core/workflows/spike.md +1 -1
  391. package/gsd-core/workflows/stats.md +1 -1
  392. package/gsd-core/workflows/sync-skills.md +5 -5
  393. package/gsd-core/workflows/thread.md +2 -2
  394. package/gsd-core/workflows/transition.md +13 -23
  395. package/gsd-core/workflows/ui-phase.md +48 -11
  396. package/gsd-core/workflows/ui-review.md +21 -6
  397. package/gsd-core/workflows/ultraplan-phase.md +3 -2
  398. package/gsd-core/workflows/undo.md +339 -20
  399. package/gsd-core/workflows/update.md +7 -7
  400. package/gsd-core/workflows/validate-phase.md +12 -13
  401. package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
  402. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
  403. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
  404. package/gsd-core/workflows/verify-work.md +129 -55
  405. package/hooks/dist/gsd-agent-isolation-guard.js +32 -0
  406. package/hooks/dist/gsd-check-update-worker.js +8 -0
  407. package/hooks/dist/gsd-check-update.js +8 -0
  408. package/hooks/dist/gsd-context-monitor.js +31 -8
  409. package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
  410. package/hooks/dist/gsd-secret-read-guard.js +161 -4
  411. package/hooks/dist/gsd-statusline.js +85 -20
  412. package/hooks/dist/gsd-update-banner.js +8 -0
  413. package/hooks/dist/gsd-validate-commit.sh +63 -4
  414. package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
  415. package/hooks/dist/gsd-workflow-guard.js +5 -4
  416. package/hooks/dist/gsd-worktree-path-guard.js +6 -2
  417. package/hooks/dist/lib/cli-exit.js +12 -0
  418. package/hooks/dist/lib/git-probe.js +17 -1
  419. package/hooks/dist/lib/isolation-sentinel.js +2 -2
  420. package/hooks/gsd-agent-isolation-guard.js +32 -0
  421. package/hooks/gsd-check-update-worker.js +8 -0
  422. package/hooks/gsd-check-update.js +8 -0
  423. package/hooks/gsd-context-monitor.js +31 -8
  424. package/hooks/gsd-cursor-subagent-start.js +8 -0
  425. package/hooks/gsd-secret-read-guard.js +161 -4
  426. package/hooks/gsd-statusline.js +85 -20
  427. package/hooks/gsd-update-banner.js +8 -0
  428. package/hooks/gsd-validate-commit.sh +63 -4
  429. package/hooks/gsd-windsurf-pre-write.js +11 -2
  430. package/hooks/gsd-workflow-guard.js +5 -4
  431. package/hooks/gsd-worktree-path-guard.js +6 -2
  432. package/hooks/hooks.json +5 -5
  433. package/hooks/lib/cli-exit.js +12 -0
  434. package/hooks/lib/git-probe.js +17 -1
  435. package/hooks/lib/isolation-sentinel.js +2 -2
  436. package/package.json +22 -4
  437. package/scripts/build-hooks.js +15 -6
  438. package/scripts/changeset/parse.cjs +52 -4
  439. package/scripts/check-contract-drift.cjs +127 -11
  440. package/scripts/ci-timeout-report.cjs +770 -4
  441. package/scripts/command-contract-helpers.cjs +15 -8
  442. package/scripts/docs-guard-registry.cjs +34 -0
  443. package/scripts/gen-features.cjs +13 -8
  444. package/scripts/gen-hooks-cli-exit.cjs +12 -28
  445. package/scripts/gen-loop-host-contract.cjs +79 -1
  446. package/scripts/gen-platform-conformance-tier.cjs +187 -1
  447. package/scripts/gen-plugin-skills.cjs +87 -1
  448. package/scripts/gen-research-agents.cjs +24 -31
  449. package/scripts/gen-scripts-cli-exit.cjs +30 -3
  450. package/scripts/gen-test-timings.cjs +32 -7
  451. package/scripts/lib/cli-exit.cjs +12 -0
  452. package/scripts/lib/macos-conformance-tier.generated.cjs +34 -2
  453. package/scripts/lib/ndjson-reporter.cjs +31 -5
  454. package/scripts/lib/platform-conformance-tier.generated.cjs +45 -5
  455. package/scripts/lib/registration-ledger-preload.cjs +155 -0
  456. package/scripts/lib/vendor-bundle.cjs +59 -0
  457. package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
  458. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  459. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  460. package/scripts/lint-completion-predicate-drift.cjs +18 -19
  461. package/scripts/lint-descriptions.cjs +7 -3
  462. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +38 -1
  463. package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
  464. package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
  465. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
  466. package/scripts/lint-phase-arg-assignment.cjs +257 -0
  467. package/scripts/lint-phase-enumeration-drift.cjs +12 -8
  468. package/scripts/lint-phase-id-drift.cjs +319 -5
  469. package/scripts/lint-planning-document-positive-control.cjs +329 -0
  470. package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
  471. package/scripts/lint-response-language-coverage.cjs +3 -0
  472. package/scripts/lint-retired-runtime-name.cjs +619 -0
  473. package/scripts/lint-skill-deps.cjs +7 -3
  474. package/scripts/lint-state-write-path-drift.cjs +93 -0
  475. package/scripts/lint-test-file-count.allowlist.json +38 -9
  476. package/scripts/lint-test-file-count.cjs +34 -1
  477. package/scripts/lint-vendored-deps.cjs +41 -5
  478. package/scripts/lint-workflow-shellcheck-baseline.json +25 -10
  479. package/scripts/mutation-matrix.cjs +50 -5
  480. package/scripts/prompt-injection-scan.sh +4 -0
  481. package/scripts/release-tarball-smoke.cjs +194 -1
  482. package/scripts/require-issue-link-policy.cjs +6 -2
  483. package/scripts/sync-runtime-launcher.cjs +184 -2
  484. package/scripts/verify-npm-publish.cjs +76 -20
  485. package/skills/gsd-add-tests/SKILL.md +6 -1
  486. package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
  487. package/skills/gsd-audit-fix/SKILL.md +5 -0
  488. package/skills/gsd-audit-milestone/SKILL.md +6 -1
  489. package/skills/gsd-autonomous/SKILL.md +7 -2
  490. package/skills/gsd-capture/SKILL.md +9 -5
  491. package/skills/gsd-code-review/SKILL.md +7 -2
  492. package/skills/gsd-complete-milestone/SKILL.md +4 -0
  493. package/skills/gsd-config/SKILL.md +8 -4
  494. package/skills/gsd-debug/SKILL.md +11 -7
  495. package/skills/gsd-discuss-phase/SKILL.md +7 -3
  496. package/skills/gsd-docs-update/SKILL.md +12 -7
  497. package/skills/gsd-eval-review/SKILL.md +6 -1
  498. package/skills/gsd-execute-phase/SKILL.md +12 -7
  499. package/skills/gsd-extract-learnings/SKILL.md +5 -0
  500. package/skills/gsd-fast/SKILL.md +4 -0
  501. package/skills/gsd-forensics/SKILL.md +5 -1
  502. package/skills/gsd-graphify/SKILL.md +10 -6
  503. package/skills/gsd-health/SKILL.md +5 -0
  504. package/skills/gsd-help/SKILL.md +7 -2
  505. package/skills/gsd-import/SKILL.md +7 -3
  506. package/skills/gsd-inbox/SKILL.md +5 -0
  507. package/skills/gsd-ingest-docs/SKILL.md +5 -1
  508. package/skills/gsd-manager/SKILL.md +6 -1
  509. package/skills/gsd-map-codebase/SKILL.md +7 -3
  510. package/skills/gsd-mempalace-capture/SKILL.md +12 -4
  511. package/skills/gsd-mempalace-recall/SKILL.md +5 -1
  512. package/skills/gsd-milestone-summary/SKILL.md +5 -1
  513. package/skills/gsd-mvp-phase/SKILL.md +8 -3
  514. package/skills/gsd-new-milestone/SKILL.md +6 -1
  515. package/skills/gsd-new-project/SKILL.md +5 -0
  516. package/skills/gsd-next/SKILL.md +6 -1
  517. package/skills/gsd-ns-context/SKILL.md +4 -0
  518. package/skills/gsd-ns-ideate/SKILL.md +4 -0
  519. package/skills/gsd-ns-manage/SKILL.md +4 -0
  520. package/skills/gsd-ns-project/SKILL.md +4 -0
  521. package/skills/gsd-ns-review/SKILL.md +4 -0
  522. package/skills/gsd-ns-workflow/SKILL.md +4 -0
  523. package/skills/gsd-onboard/SKILL.md +6 -1
  524. package/skills/gsd-pause-work/SKILL.md +5 -1
  525. package/skills/gsd-phase/SKILL.md +8 -4
  526. package/skills/gsd-plan-phase/SKILL.md +6 -1
  527. package/skills/gsd-plan-review-convergence/SKILL.md +10 -6
  528. package/skills/gsd-pr-branch/SKILL.md +4 -0
  529. package/skills/gsd-profile-user/SKILL.md +5 -1
  530. package/skills/gsd-progress/SKILL.md +7 -2
  531. package/skills/gsd-quick/SKILL.md +16 -10
  532. package/skills/gsd-quick-batch/SKILL.md +21 -9
  533. package/skills/gsd-review/SKILL.md +7 -4
  534. package/skills/gsd-review-backlog/SKILL.md +3 -2
  535. package/skills/gsd-secure-phase/SKILL.md +6 -1
  536. package/skills/gsd-ship/SKILL.md +5 -0
  537. package/skills/gsd-sketch/SKILL.md +7 -2
  538. package/skills/gsd-spec-phase/SKILL.md +5 -1
  539. package/skills/gsd-spike/SKILL.md +8 -3
  540. package/skills/gsd-surface/SKILL.md +5 -1
  541. package/skills/gsd-thread/SKILL.md +4 -0
  542. package/skills/gsd-ui-phase/SKILL.md +6 -1
  543. package/skills/gsd-ui-review/SKILL.md +6 -1
  544. package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
  545. package/skills/gsd-undo/SKILL.md +5 -1
  546. package/skills/gsd-update/SKILL.md +6 -2
  547. package/skills/gsd-validate-phase/SKILL.md +6 -1
  548. package/skills/gsd-verify-work/SKILL.md +6 -1
  549. package/skills/gsd-workspace/SKILL.md +7 -3
  550. package/skills/gsd-workstreams/SKILL.md +6 -6
  551. package/vscode/package.json +1 -1
@@ -395,6 +395,14 @@ function parseCliWorkstream(args) {
395
395
  args: args.slice(),
396
396
  };
397
397
  }
398
+ function workstreamDirectoryExists(cwd, name) {
399
+ try {
400
+ return node_fs_1.default.readdirSync(node_path_1.default.join(planningRoot(cwd), 'workstreams')).includes(name);
401
+ }
402
+ catch {
403
+ return false;
404
+ }
405
+ }
398
406
  function resolveActiveWorkstream(cwd, args, env = process.env, deps = {}) {
399
407
  const parsed = parseCliWorkstream(args);
400
408
  const getStored = deps.getStored || ((dir) => getActiveWorkstream(dir, deps));
@@ -415,6 +423,13 @@ function resolveActiveWorkstream(cwd, args, env = process.env, deps = {}) {
415
423
  if (ws && !validateWorkstreamName(ws)) {
416
424
  throw new Error('Invalid workstream name: must be alphanumeric, hyphens, underscores, or dots');
417
425
  }
426
+ // #4772: a reserved name (`none`) is rejected from every source (--ws, env,
427
+ // pointer) unless a directory of that name already exists (grandfathered).
428
+ // Grandfathering compares the directory listing exactly, so a case-insensitive
429
+ // filesystem (macOS, Windows) cannot let `NONE` through on the strength of `none`.
430
+ if (ws && (0, workstream_name_policy_cjs_1.isReservedWorkstreamName)(ws) && !workstreamDirectoryExists(cwd, ws)) {
431
+ throw new Error((0, workstream_name_policy_cjs_1.reservedWorkstreamNameMessage)(ws, source));
432
+ }
418
433
  return {
419
434
  ws,
420
435
  source,
@@ -52,6 +52,7 @@ const CANONICAL_HEADERS = {
52
52
  'recommendation',
53
53
  'strategy',
54
54
  'decision outcome',
55
+ 'locked decisions',
55
56
  ],
56
57
  considered_options: [
57
58
  'considered options',
@@ -190,7 +191,8 @@ function normalizeAdrHeader(raw) {
190
191
  .toLowerCase()
191
192
  .replace(/[\s:._-]+/g, ' ')
192
193
  .replace(/[^\w\s]/g, '')
193
- .trim();
194
+ .trim()
195
+ .replace(/^\d+(?:\s+\d+)*\s+/, '');
194
196
  }
195
197
  // Normalized synonym index (audit M7). classifyHeader receives an ALREADY-normalized
196
198
  // header (via normalizeAdrHeader), but historically compared it against the RAW synonym
@@ -483,7 +483,10 @@ function agentFileExists(agentsDir, name, runtime) {
483
483
  // kimi requires BOTH the persona yaml and the prompt md (same as checkAgentsInstalled).
484
484
  const kimiYaml = node_path_1.default.join(agentsDir, 'subagents', `${name}.yaml`);
485
485
  const kimiPrompt = node_path_1.default.join(agentsDir, 'subagents', `${name}.md`);
486
- return runtime === 'kimi' && node_fs_1.default.existsSync(kimiYaml) && node_fs_1.default.existsSync(kimiPrompt);
486
+ // #5169: descriptor-declared (`hostBehaviors.requiresSubagentPair`); a label
487
+ // that is not a registered runtime declares nothing, so it never requires the pair.
488
+ return (0, runtime_name_policy_cjs_1.hostBehaviorsFor)(runtime).requiresSubagentPair === true
489
+ && node_fs_1.default.existsSync(kimiYaml) && node_fs_1.default.existsSync(kimiPrompt);
487
490
  }
488
491
  /**
489
492
  * Resolve a per-plan `agent_hint` specialist name to a dispatchable subagent
@@ -25,10 +25,15 @@ const coreUtils = require("./core-utils.cjs");
25
25
  const { normalizeLineEndings } = coreUtils;
26
26
  // eslint-disable-next-line @typescript-eslint/no-require-imports
27
27
  const planningWorkspace = require("./planning-workspace.cjs");
28
- const { planningDir, quickDirFrom, todosDir } = planningWorkspace;
28
+ const { planningDir, quickDirFrom, debugDir, todosDir } = planningWorkspace;
29
29
  // eslint-disable-next-line @typescript-eslint/no-require-imports
30
30
  const frontmatter = require("./frontmatter.cjs");
31
- const { extractFrontmatter, spliceFrontmatter } = frontmatter;
31
+ // #4378 (roll-in): scanSeeds publishes the SAME canonical seed identity the
32
+ // list-seeds gate derives — one grammar, two surfaces, no drift. commands.cjs
33
+ // does not require this module, so the edge is acyclic.
34
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
35
+ const commandsModule = require("./commands.cjs");
36
+ const { extractFrontmatter, frontmatterBlock, spliceFrontmatter, isFrontmatterWriteRefusal } = frontmatter;
32
37
  // eslint-disable-next-line @typescript-eslint/no-require-imports
33
38
  const phaseIdMod = require("./phase-id.cjs");
34
39
  const { PHASE_NUMBER_TOKEN_SOURCE, scopeToPhase } = phaseIdMod;
@@ -41,6 +46,11 @@ const shell_command_projection_cjs_2 = require("./shell-command-projection.cjs")
41
46
  const io = require("./io.cjs");
42
47
  const { output, error: ioError } = io;
43
48
  const command_arg_projection_cjs_1 = require("./command-arg-projection.cjs");
49
+ // #5118: the verification-status owner's report reader and closed enum.
50
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
51
+ const verificationMod = require("./verification.cjs");
52
+ const { reportStatusOf, VERIFICATION_STATUS, VerificationStatusError } = verificationMod;
53
+ const clock_cjs_1 = require("./clock.cjs");
44
54
  // The SCOPE BOUNDARY convention's filename (`agents/gsd-executor.md`), shared
45
55
  // verbatim with the #2287 phase-boundary reader in `uat.cts`.
46
56
  const DEFERRED_ITEMS_FILENAME = 'deferred-items.md';
@@ -252,19 +262,27 @@ function deriveOpenQuestionsDigest(questions) {
252
262
  }
253
263
  // ─── scanDebugSessions ────────────────────────────────────────────────────────
254
264
  /**
255
- * Scan .planning/debug/ for open sessions.
265
+ * #4869: gsd-debugger's archive_session step appends every resolved session to
266
+ * this file in the debug directory. It is a document, not a session: it has no
267
+ * frontmatter, so its status would derive `unknown` and read as open forever.
268
+ * Excluded by this fixed name only. Any other file with missing or unparseable
269
+ * frontmatter is still an open session. Every shipped debug-directory reader
270
+ * excludes the same name from active sessions (#5011).
271
+ */
272
+ const DEBUG_KNOWLEDGE_BASE_FILENAME = 'knowledge-base.md';
273
+ /**
274
+ * Scan the root-scoped .planning/debug/ directory supplied by the caller for open sessions.
256
275
  * Open = status NOT in ['resolved', 'complete'].
257
- * Ignores the resolved/ subdirectory.
276
+ * Ignores the resolved/ subdirectory and the debugger's knowledge base.
258
277
  */
259
- function scanDebugSessions(planDir) {
260
- const debugDir = node_path_1.default.join(planDir, 'debug');
261
- if (!node_fs_1.default.existsSync(debugDir))
278
+ function scanDebugSessions(debugPath) {
279
+ if (!node_fs_1.default.existsSync(debugPath))
262
280
  return { items: [], acknowledged: 0 };
263
281
  const results = [];
264
282
  let acknowledged = 0;
265
283
  let files;
266
284
  try {
267
- files = node_fs_1.default.readdirSync(debugDir, { withFileTypes: true });
285
+ files = node_fs_1.default.readdirSync(debugPath, { withFileTypes: true });
268
286
  }
269
287
  catch {
270
288
  return { items: [{ scan_error: true, slug: '', status: '', updated: '', hypothesis: '' }], acknowledged: 0 };
@@ -274,10 +292,12 @@ function scanDebugSessions(planDir) {
274
292
  continue;
275
293
  if (!entry.name.endsWith('.md'))
276
294
  continue;
277
- const filePath = node_path_1.default.join(debugDir, entry.name);
295
+ if (entry.name === DEBUG_KNOWLEDGE_BASE_FILENAME)
296
+ continue;
297
+ const filePath = node_path_1.default.join(debugPath, entry.name);
278
298
  let safeFilePath;
279
299
  try {
280
- safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'debug session file', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
300
+ safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, node_path_1.default.dirname(debugPath), 'debug session file', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
281
301
  }
282
302
  catch {
283
303
  continue;
@@ -286,9 +306,9 @@ function scanDebugSessions(planDir) {
286
306
  // document at this read boundary, same seam as `src/uat.cts`'s
287
307
  // `readNormalizedDocument` — `platformReadSync` performs no line-ending
288
308
  // normalization itself, and extractFrontmatter/status-derivation below
289
- // degrade a lone-CR file's frontmatter to `unknown`, which every scan
290
- // in this module treats as "not open" (fail-open, the permissive
291
- // direction) rather than a real parse gap.
309
+ // degrade a lone-CR file's frontmatter to `unknown`, which this scan
310
+ // reports as an open session (#4869) — so an un-normalized resolved
311
+ // session would resurface as open.
292
312
  const rawContent = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
293
313
  if (rawContent === null)
294
314
  continue;
@@ -586,9 +606,11 @@ function scanTodos(todosBase) {
586
606
  }
587
607
  const displayFiles = openFiles.slice(0, 5);
588
608
  for (const { entry, content, fm } of displayFiles) {
589
- // Extract first line of body after frontmatter
590
- const bodyMatch = content.replace(/^---[\s\S]*?---\r?\n?/, '');
591
- const firstLine = (0, text_lines_cjs_1.splitLines)(bodyMatch.trim())[0] || '';
609
+ // Extract first line of body after frontmatter — the block `extractFrontmatter` read above
610
+ // (the one fence owner), so a `---` inside a value cannot end it early.
611
+ const block = frontmatterBlock(content);
612
+ const todoBody = block ? block.rest : content;
613
+ const firstLine = (0, text_lines_cjs_1.splitLines)(todoBody.trim())[0] || '';
592
614
  const summary = (0, security_cjs_1.sanitizeForDisplay)(firstLine.slice(0, 100));
593
615
  results.push({
594
616
  filename: (0, security_cjs_1.sanitizeLabel)(entry.name),
@@ -602,6 +624,14 @@ function scanTodos(todosBase) {
602
624
  }
603
625
  return { items: results, acknowledged };
604
626
  }
627
+ // #4378 (roll-in): true when the filename is a well-formed seed name —
628
+ // `SEED-` prefix, `.md` suffix, and no control bytes anywhere in between (the
629
+ // scanSeeds admission filter passes such names through to the identity
630
+ // derivation; a name with an embedded control byte falls back to its raw
631
+ // stem exactly as the pre-canonical code did).
632
+ function seedIdMatchRawName(name) {
633
+ return !/[\u0000-\u001f\u007f]/.test(name);
634
+ }
605
635
  // ─── scanSeeds ────────────────────────────────────────────────────────────────
606
636
  /**
607
637
  * Scan .planning/seeds/SEED-*.md for unimplemented seeds.
@@ -653,16 +683,18 @@ function scanSeeds(planDir) {
653
683
  acknowledged++;
654
684
  continue;
655
685
  }
656
- // Extract seed_id from filename or frontmatter. The regex match is
657
- // `\w`/hyphen-constrained (safe by construction, like `archived_milestone`)
658
- // but the fallback taken when a filename doesn't fully match — e.g. a
659
- // `SEED-`-prefixed, `.md`-suffixed name with a control byte SOMEWHERE in
660
- // the middle, which still passes the `startsWith`/`endsWith` filter above
661
- // — is the raw, unconstrained basename. Both branches are routed through
662
- // sanitizeLabel below.
663
- const seedIdMatch = entry.name.match(/^(SEED-[\w-]+)\.md$/);
664
- const seed_id = seedIdMatch ? seedIdMatch[1] : node_path_1.default.basename(entry.name, '.md');
665
- const slug = (0, security_cjs_1.sanitizeLabel)(seed_id.replace(/^SEED-/, ''));
686
+ // #4378 (roll-in): the canonical identity comes from the SAME derivation
687
+ // the list-seeds surface uses — frontmatter `id:` when it matches a seed
688
+ // grammar (legacy `SEED-NNN` or date-suffixed `SEED-YYMMDD-xxx`), else the
689
+ // filename's id prefix, else the whole stem. The old fused
690
+ // filename-stem id (e.g. `SEED-081-region` for `SEED-081-region.md`)
691
+ // disagreed with list-seeds and misfiled deferrals; publishing the
692
+ // canonical id keeps the two surfaces answering identically. The raw-
693
+ // basename fallback for control-byte-bearing names is preserved.
694
+ const stem = node_path_1.default.basename(entry.name, '.md');
695
+ const derived = commandsModule.deriveSeedIdentity(stem, fm.id);
696
+ const seed_id = seedIdMatchRawName(entry.name) ? derived.seed_id : stem;
697
+ const slug = (0, security_cjs_1.sanitizeLabel)(derived.slug);
666
698
  let title = (0, security_cjs_1.sanitizeForDisplay)(fm.title || '');
667
699
  if (!title) {
668
700
  const headingMatch = content.match(/^#\s*(.+)$/m);
@@ -801,9 +833,9 @@ function scanUatGaps(planDir, cwd) {
801
833
  // document at this read boundary, same seam as `src/uat.cts`'s
802
834
  // `readNormalizedDocument` — `platformReadSync` performs no line-ending
803
835
  // normalization itself, and extractFrontmatter/status-derivation below
804
- // degrade a lone-CR file's frontmatter to `unknown`, which every scan
805
- // in this module treats as "not open" (fail-open, the permissive
806
- // direction) rather than a real parse gap.
836
+ // degrade a lone-CR file's frontmatter to `unknown`, which this scan
837
+ // reports as an open gap unless `result: all_pass` (#4869 triage) — so
838
+ // an un-normalized terminal UAT would resurface as open.
807
839
  const rawContent = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
808
840
  if (rawContent === null)
809
841
  continue;
@@ -882,8 +914,10 @@ function scanVerificationGaps(planDir, cwd) {
882
914
  continue;
883
915
  const content = normalizeLineEndings(rawContent);
884
916
  const fm = extractFrontmatter(content, safeFilePath);
885
- const status = (fm.status || 'unknown').toLowerCase();
886
- if (status !== 'gaps_found' && status !== 'human_needed')
917
+ // #5118: the owner's report reader judges `status` — exact match, no
918
+ // case folding; an out-of-set value throws VerificationStatusError.
919
+ const status = reportStatusOf(fm, safeFilePath);
920
+ if (status !== VERIFICATION_STATUS.GAPS_FOUND && status !== VERIFICATION_STATUS.HUMAN_NEEDED)
887
921
  continue;
888
922
  if (isAuditItemAcknowledged(fm, { snapshotKey: 'status', currentValue: status })) {
889
923
  acknowledged++;
@@ -1059,8 +1093,10 @@ function scanDeferredItems(planDir, cwd) {
1059
1093
  function auditOpenArtifacts(cwd) {
1060
1094
  const planDir = planningDir(cwd);
1061
1095
  const debugSessions = (() => {
1096
+ // #5042: debug sessions are shared project state; workflow writers use
1097
+ // the root .planning/debug directory even when a workstream is active.
1062
1098
  try {
1063
- return scanDebugSessions(planDir);
1099
+ return scanDebugSessions(debugDir(cwd));
1064
1100
  }
1065
1101
  catch {
1066
1102
  return { items: [{ scan_error: true, slug: '', status: '', updated: '', hypothesis: '' }], acknowledged: 0 };
@@ -1083,7 +1119,7 @@ function auditOpenArtifacts(cwd) {
1083
1119
  }
1084
1120
  })();
1085
1121
  const todos = (() => {
1086
- // #4256: the ONE root-scoped category — todos are shared project state,
1122
+ // #4256: todos are shared project state, like debug sessions (#5042),
1087
1123
  // so the close gate reads todosDir(cwd) (the root), not the workstream-
1088
1124
  // scoped planDir every other scan below receives. Reading planDir here
1089
1125
  // made audit-open print "All artifact types clear. Safe to proceed."
@@ -1115,7 +1151,11 @@ function auditOpenArtifacts(cwd) {
1115
1151
  try {
1116
1152
  return scanVerificationGaps(planDir, cwd);
1117
1153
  }
1118
- catch {
1154
+ catch (err) {
1155
+ // #5118: an out-of-set report status is the owner's hard error, not a
1156
+ // scan failure to fold into a sentinel — let it reach the CLI seam.
1157
+ if (err instanceof VerificationStatusError)
1158
+ throw err;
1119
1159
  return { items: [{ scan_error: true, phase: '', file: '', status: '' }], acknowledged: 0 };
1120
1160
  }
1121
1161
  })();
@@ -1384,6 +1424,26 @@ function resolvePhaseTargetDir(planDir, cwd, phase, archivedMilestone) {
1384
1424
  * artifact identifier that resolves outside the project is refused before
1385
1425
  * any read or write is attempted.
1386
1426
  */
1427
+ /**
1428
+ * #4802: splice the acknowledgement marker, surfacing `spliceFrontmatter`'s
1429
+ * write refusal (the one owner of that decision) as an `ioError` naming the
1430
+ * file — an unparseable frontmatter block is NOT an empty one, and splicing
1431
+ * over it would discard every field the author actually wrote.
1432
+ */
1433
+ function spliceAcknowledgement(content, fm, fileLabel) {
1434
+ try {
1435
+ return spliceFrontmatter(content, fm);
1436
+ }
1437
+ catch (err) {
1438
+ if (!isFrontmatterWriteRefusal(err))
1439
+ throw err;
1440
+ if (err.code === 'FRONTMATTER_UNPARSEABLE') {
1441
+ ioError(`refusing to acknowledge — the frontmatter of "${fileLabel}" is not parseable YAML (splicing would discard every other frontmatter field); fix the YAML syntax error first, then re-run`);
1442
+ }
1443
+ ioError(`refusing to acknowledge "${fileLabel}" — ${err.message}`);
1444
+ throw err; // unreachable — ioError throws
1445
+ }
1446
+ }
1387
1447
  function cmdAuditAcknowledge(cwd, args, raw) {
1388
1448
  // args already has the family + subcommand tokens stripped by the caller
1389
1449
  // (audit-command-router.cts:147 passes `hubArgs.slice(2)`), so validation
@@ -1403,7 +1463,9 @@ function cmdAuditAcknowledge(cwd, args, raw) {
1403
1463
  // All declared flags above are value flags, so each resolves to `string |
1404
1464
  // null` at runtime; the cast narrows away the `boolean` arm of
1405
1465
  // ParsedNamedArgs's value type that this call site never produces.
1406
- const at = atFlag || new Date().toISOString().slice(0, 10);
1466
+ // #4905: without --at, the operator-facing local calendar day (#2136)
1467
+ // through the clock seam, which honors the GSD_NOW_MS pin (#474).
1468
+ const at = atFlag || clock_cjs_1.realClock.localToday();
1407
1469
  const planDir = planningDir(cwd);
1408
1470
  const markerBase = { milestone: milestone, at };
1409
1471
  // #3078-CR MEDIUM 2: every `fs.readFileSync` in this function (below, and
@@ -1494,7 +1556,7 @@ function cmdAuditAcknowledge(cwd, args, raw) {
1494
1556
  currentValue = deriveOpenQuestionsDigest(deriveOpenQuestions(normalizedContent, fm));
1495
1557
  }
1496
1558
  fm.audit_acknowledged = { ...markerBase, [snapshotKey]: currentValue };
1497
- const newContent = spliceFrontmatter(content, fm);
1559
+ const newContent = spliceAcknowledgement(content, fm, file);
1498
1560
  (0, shell_command_projection_cjs_2.platformWriteSync)(safeFilePath, newContent);
1499
1561
  output({ acknowledged: true, category, phase, file, [snapshotKey]: currentValue }, raw, 'true');
1500
1562
  return;
@@ -1533,9 +1595,48 @@ function cmdAuditAcknowledge(cwd, args, raw) {
1533
1595
  else if (category === 'seeds') {
1534
1596
  if (!seedId)
1535
1597
  ioError('--seed-id is required for --category seeds');
1536
- safeFilePath = (0, security_cjs_1.requireSafePath)(node_path_1.default.join(planDir, 'seeds', `${seedId}.md`), planDir, 'audit acknowledge target', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
1537
- if (!node_fs_1.default.existsSync(safeFilePath))
1598
+ // #4378 (roll-in): `--seed-id` arrives as whichever id an audit/list
1599
+ // surface published — the canonical identity (frontmatter `id:` or the
1600
+ // derived prefix, e.g. `SEED-081`, `SEED-260914-k3x`) or, for callers
1601
+ // scripted against pre-canonical output, the full filename stem. Resolve
1602
+ // by scanning the seeds directory and matching each candidate's derived
1603
+ // identity (falling back to the literal stem), then prove the winner with
1604
+ // requireSafePath exactly like every other acknowledge target. The direct
1605
+ // `seeds/<seedId>.md` build stays as the final fallback so a genuine
1606
+ // miss still reports the same "file not found" error as before.
1607
+ const seedsAckDir = node_path_1.default.join(planDir, 'seeds');
1608
+ let ackCandidate = null;
1609
+ let ackEntries = [];
1610
+ try {
1611
+ ackEntries = node_fs_1.default.readdirSync(seedsAckDir).filter((n) => n.startsWith('SEED-') && n.endsWith('.md'));
1612
+ }
1613
+ catch {
1614
+ ackEntries = [];
1615
+ }
1616
+ for (const name of ackEntries) {
1617
+ const stem = node_path_1.default.basename(name, '.md');
1618
+ let fmId;
1619
+ try {
1620
+ const rawAck = (0, shell_command_projection_cjs_1.platformReadSync)(node_path_1.default.join(seedsAckDir, name));
1621
+ if (rawAck !== null)
1622
+ fmId = extractFrontmatter(normalizeLineEndings(rawAck), node_path_1.default.join(seedsAckDir, name)).id;
1623
+ }
1624
+ catch {
1625
+ fmId = undefined;
1626
+ }
1627
+ const { seed_id: derivedAckId } = commandsModule.deriveSeedIdentity(stem, fmId);
1628
+ if (derivedAckId === seedId || stem === seedId) {
1629
+ ackCandidate = name;
1630
+ break;
1631
+ }
1632
+ }
1633
+ if (ackCandidate !== null) {
1634
+ safeFilePath = (0, security_cjs_1.requireSafePath)(node_path_1.default.join(seedsAckDir, ackCandidate), planDir, 'audit acknowledge target', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
1635
+ }
1636
+ else {
1637
+ safeFilePath = (0, security_cjs_1.requireSafePath)(node_path_1.default.join(seedsAckDir, `${seedId}.md`), planDir, 'audit acknowledge target', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
1538
1638
  ioError(`file not found: seeds/${seedId}.md`);
1639
+ }
1539
1640
  const content = node_fs_1.default.readFileSync(safeFilePath, 'utf-8');
1540
1641
  currentValue = (extractFrontmatter(content, safeFilePath).status || 'dormant').toLowerCase();
1541
1642
  }
@@ -1584,11 +1685,12 @@ function cmdAuditAcknowledge(cwd, args, raw) {
1584
1685
  return; // unreachable — ioError throws — satisfies TS control-flow analysis
1585
1686
  }
1586
1687
  const presenceOnly = category === 'todos';
1587
- const fm = createIfMissing ? fmForCreate : extractFrontmatter(node_fs_1.default.readFileSync(safeFilePath, 'utf-8'), safeFilePath);
1688
+ const existingContent = createIfMissing ? '' : node_fs_1.default.readFileSync(safeFilePath, 'utf-8');
1689
+ const fm = createIfMissing ? fmForCreate : extractFrontmatter(existingContent, safeFilePath);
1588
1690
  fm.audit_acknowledged = presenceOnly ? { ...markerBase } : { ...markerBase, [snapshotKey]: currentValue };
1589
- const newContent = createIfMissing
1590
- ? spliceFrontmatter('', fm)
1591
- : spliceFrontmatter(node_fs_1.default.readFileSync(safeFilePath, 'utf-8'), fm);
1691
+ // #4802: createIfMissing splices into '' (no block to refuse on); an existing
1692
+ // file with broken YAML is refused by `spliceAcknowledgement`.
1693
+ const newContent = spliceAcknowledgement(existingContent, fm, safeFilePath);
1592
1694
  (0, shell_command_projection_cjs_2.platformWriteSync)(safeFilePath, newContent);
1593
1695
  output({ acknowledged: true, category, ...(presenceOnly ? {} : { [snapshotKey]: currentValue }) }, raw, 'true');
1594
1696
  }
@@ -7,10 +7,10 @@
7
7
  * When `workflow.windows_enforce` is true, `/gsd-ship` blocks while any entry is
8
8
  * `open`; an entry can be `waived` only with a recorded reason or `fixed`.
9
9
  *
10
- * LEAF MODULE — imports node:fs + node:path, plus two compiled sibling lib
11
- * modules require()d at runtime: workstream-inventory.cjs (the #4487
12
- * milestone stamp) and capability-lock.cjs (the #3780 cross-process ledger
13
- * lock). No other src/ imports.
10
+ * LEAF MODULE — imports node:fs + node:path, the leaf frontmatter-fence.cjs (the one
11
+ * frontmatter fence owner), plus two compiled sibling lib modules require()d at runtime:
12
+ * workstream-inventory.cjs (the #4487 milestone stamp) and capability-lock.cjs (the #3780
13
+ * cross-process ledger lock). No other src/ imports.
14
14
  *
15
15
  * Storage format (`.planning/WINDOWS.md`):
16
16
  * ---
@@ -68,6 +68,7 @@ exports.cmdWindowsWaive = cmdWindowsWaive;
68
68
  exports.cmdWindowsMarkFixed = cmdWindowsMarkFixed;
69
69
  const node_fs_1 = __importDefault(require("node:fs"));
70
70
  const node_path_1 = __importDefault(require("node:path"));
71
+ const frontmatter_fence_cjs_1 = require("./frontmatter-fence.cjs");
71
72
  // eslint-disable-next-line @typescript-eslint/no-require-imports
72
73
  const workstreamInventory = require("./workstream-inventory.cjs");
73
74
  // ─── Constants ─────────────────────────────────────────────────────────────
@@ -385,21 +386,20 @@ function locateJsonBlock(raw, expectedTotal) {
385
386
  * structural deviation — fail-closed on drift.
386
387
  */
387
388
  function parseFrontmatterStrict(raw) {
388
- if (!raw.startsWith('---\n') && !raw.startsWith('---\r\n')) {
389
+ // The block is the one the one fence owner finds (`locateFrontmatterFence`).
390
+ const fence = (0, frontmatter_fence_cjs_1.locateFrontmatterFence)(raw);
391
+ if (!fence) {
389
392
  throw new WindowsError(exports.REASON.WINDOWS_LEDGER_MALFORMED, 'Ledger missing frontmatter opening ---');
390
393
  }
391
- const headerEnd = raw.startsWith('---\r\n') ? 5 : 4;
392
- const closeIdx = raw.indexOf('\n---', headerEnd);
393
- if (closeIdx === -1) {
394
+ if (!fence.closed) {
394
395
  throw new WindowsError(exports.REASON.WINDOWS_LEDGER_MALFORMED, 'Ledger missing frontmatter closing ---');
395
396
  }
396
- const yamlBody = raw.slice(headerEnd, closeIdx);
397
+ const yamlBody = raw.slice(fence.openEnd, fence.bodyEnd);
397
398
  const out = {};
398
399
  for (const rawLine of yamlBody.split(/\r?\n/)) {
399
- // #3116: the `\n---` scan leaves the final line's CR attached on a CRLF
400
- // ledger, and `.` never matches CR, so the key: value regex below fails on
401
- // it. Strip the trailing CR per line so the rest of `raw` (which
402
- // parseJsonBlock also slices by byte offset) is unaffected.
400
+ // #3116: strip a trailing CR per line (`.` never matches CR, so the key: value regex
401
+ // below would fail on it) without touching the rest of `raw`, which parseJsonBlock also
402
+ // slices by byte offset.
403
403
  const line = rawLine.replace(/\r$/, '');
404
404
  if (line.trim() === '')
405
405
  continue;
@@ -32,7 +32,7 @@ function _getNestedConfigValue(config, dotKey) {
32
32
  return { found: true, value: current };
33
33
  }
34
34
  const _warnedRawConfigPaths = new Set();
35
- function _readRawConfigKey(filePath, dotKey) {
35
+ function _readRawConfigKey(filePath, dotKey, quiet = false) {
36
36
  try {
37
37
  const raw = node_fs_1.default.readFileSync(filePath, 'utf8');
38
38
  let parsed;
@@ -40,7 +40,7 @@ function _readRawConfigKey(filePath, dotKey) {
40
40
  parsed = JSON.parse(raw);
41
41
  }
42
42
  catch {
43
- if (!_warnedRawConfigPaths.has(filePath)) {
43
+ if (!quiet && !_warnedRawConfigPaths.has(filePath)) {
44
44
  _warnedRawConfigPaths.add(filePath);
45
45
  try {
46
46
  process.stderr.write(`gsd-tools: warning: failed to parse ${filePath} as JSON — skipping for activation resolution\n`);
@@ -67,9 +67,14 @@ function _readRawConfigKey(filePath, dotKey) {
67
67
  * 3. Root config.json at planningRoot(cwd)/config.json (only if path differs).
68
68
  * 4. registry.configSchema[dotKey].default — schema default.
69
69
  * 5. Absent → { found: false, value: undefined }.
70
+ *
71
+ * `quiet: true` (default false) suppresses the one-time stderr warning for a config.json that is
72
+ * not valid JSON: a gate reads its switch quietly (a malformed config is simply "key absent"), it
73
+ * never writes to stderr (#5139).
70
74
  */
71
75
  function resolveConfigKey(dotKey, opts) {
72
76
  const { config, cwd, registry } = opts;
77
+ const quiet = opts.quiet === true;
73
78
  // Level 1: loadConfig result
74
79
  const fromConfig = _getNestedConfigValue(config, dotKey);
75
80
  if (fromConfig.found)
@@ -78,11 +83,11 @@ function resolveConfigKey(dotKey, opts) {
78
83
  if (cwd) {
79
84
  const wsConfigPath = node_path_1.default.join(planningDir(cwd), 'config.json');
80
85
  const rootConfigPath = node_path_1.default.join(planningRoot(cwd), 'config.json');
81
- const fromWs = _readRawConfigKey(wsConfigPath, dotKey);
86
+ const fromWs = _readRawConfigKey(wsConfigPath, dotKey, quiet);
82
87
  if (fromWs.found)
83
88
  return { found: true, value: fromWs.value };
84
89
  if (wsConfigPath !== rootConfigPath) {
85
- const fromRoot = _readRawConfigKey(rootConfigPath, dotKey);
90
+ const fromRoot = _readRawConfigKey(rootConfigPath, dotKey, quiet);
86
91
  if (fromRoot.found)
87
92
  return { found: true, value: fromRoot.value };
88
93
  }