@opengsd/gsd-core 1.15.0 → 1.17.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 (505) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -2
  3. package/.opencode/plugins/gsd-core.js +336 -6
  4. package/.opencode/plugins/gsd-statusline/tui.tsx +55 -0
  5. package/GEMINI.md +1 -1
  6. package/agents/gsd-code-fixer.compact.md +1 -1
  7. package/agents/gsd-code-fixer.md +1 -1
  8. package/agents/gsd-code-reviewer.compact.md +5 -3
  9. package/agents/gsd-code-reviewer.md +8 -6
  10. package/agents/gsd-debug-session-manager.compact.md +7 -1
  11. package/agents/gsd-debug-session-manager.md +7 -1
  12. package/agents/gsd-debugger.md +2 -2
  13. package/agents/gsd-eval-auditor.compact.md +1 -1
  14. package/agents/gsd-eval-auditor.md +1 -1
  15. package/agents/gsd-executor.md +4 -4
  16. package/agents/gsd-intel-updater.compact.md +1 -1
  17. package/agents/gsd-intel-updater.md +1 -1
  18. package/agents/gsd-mempalace-curator.md +2 -2
  19. package/agents/gsd-phase-researcher.md +1 -1
  20. package/agents/gsd-plan-checker.md +7 -2
  21. package/agents/gsd-planner.md +3 -3
  22. package/agents/gsd-project-researcher.compact.md +1 -1
  23. package/agents/gsd-project-researcher.md +1 -1
  24. package/agents/gsd-research-synthesizer.compact.md +1 -1
  25. package/agents/gsd-research-synthesizer.md +1 -1
  26. package/agents/gsd-ui-auditor.compact.md +21 -30
  27. package/agents/gsd-ui-auditor.md +42 -51
  28. package/agents/gsd-ui-researcher.compact.md +1 -1
  29. package/agents/gsd-ui-researcher.md +1 -1
  30. package/agents/gsd-verifier.md +31 -9
  31. package/bin/gsd-mcp-server.js +3 -1
  32. package/bin/install.js +487 -290
  33. package/commands/gsd/add-tests.md +6 -1
  34. package/commands/gsd/ai-integration-phase.md +6 -1
  35. package/commands/gsd/audit-fix.md +5 -0
  36. package/commands/gsd/audit-milestone.md +6 -1
  37. package/commands/gsd/autonomous.md +5 -0
  38. package/commands/gsd/capture.md +8 -4
  39. package/commands/gsd/code-review.md +7 -2
  40. package/commands/gsd/complete-milestone.md +4 -0
  41. package/commands/gsd/config.md +7 -3
  42. package/commands/gsd/debug.md +11 -7
  43. package/commands/gsd/discuss-phase.md +7 -3
  44. package/commands/gsd/docs-update.md +12 -7
  45. package/commands/gsd/eval-review.md +6 -1
  46. package/commands/gsd/execute-phase.md +12 -7
  47. package/commands/gsd/extract-learnings.md +5 -0
  48. package/commands/gsd/fast.md +4 -0
  49. package/commands/gsd/forensics.md +5 -1
  50. package/commands/gsd/graphify.md +10 -6
  51. package/commands/gsd/health.md +5 -0
  52. package/commands/gsd/help.md +7 -2
  53. package/commands/gsd/import.md +7 -3
  54. package/commands/gsd/inbox.md +5 -0
  55. package/commands/gsd/ingest-docs.md +5 -1
  56. package/commands/gsd/manager.md +6 -1
  57. package/commands/gsd/map-codebase.md +7 -3
  58. package/commands/gsd/mempalace-capture.md +5 -1
  59. package/commands/gsd/mempalace-recall.md +5 -1
  60. package/commands/gsd/milestone-summary.md +5 -1
  61. package/commands/gsd/mvp-phase.md +8 -3
  62. package/commands/gsd/new-milestone.md +6 -1
  63. package/commands/gsd/new-project.md +5 -0
  64. package/commands/gsd/next.md +6 -1
  65. package/commands/gsd/ns-context.md +4 -0
  66. package/commands/gsd/ns-ideate.md +4 -0
  67. package/commands/gsd/ns-manage.md +4 -0
  68. package/commands/gsd/ns-project.md +4 -0
  69. package/commands/gsd/ns-review.md +4 -0
  70. package/commands/gsd/ns-workflow.md +4 -0
  71. package/commands/gsd/onboard.md +6 -1
  72. package/commands/gsd/pause-work.md +5 -1
  73. package/commands/gsd/phase.md +8 -4
  74. package/commands/gsd/plan-phase.md +6 -1
  75. package/commands/gsd/plan-review-convergence.md +5 -1
  76. package/commands/gsd/pr-branch.md +4 -0
  77. package/commands/gsd/profile-user.md +5 -1
  78. package/commands/gsd/progress.md +6 -1
  79. package/commands/gsd/quick-batch.md +20 -8
  80. package/commands/gsd/quick.md +12 -7
  81. package/commands/gsd/review.md +5 -1
  82. package/commands/gsd/secure-phase.md +6 -1
  83. package/commands/gsd/ship.md +5 -0
  84. package/commands/gsd/sketch.md +7 -2
  85. package/commands/gsd/spec-phase.md +5 -1
  86. package/commands/gsd/spike.md +8 -3
  87. package/commands/gsd/surface.md +5 -1
  88. package/commands/gsd/thread.md +4 -0
  89. package/commands/gsd/ui-phase.md +6 -1
  90. package/commands/gsd/ui-review.md +6 -1
  91. package/commands/gsd/ultraplan-phase.md +5 -1
  92. package/commands/gsd/undo.md +5 -1
  93. package/commands/gsd/update.md +6 -2
  94. package/commands/gsd/validate-phase.md +6 -1
  95. package/commands/gsd/verify-work.md +6 -1
  96. package/commands/gsd/workspace.md +7 -3
  97. package/gsd-core/bin/gsd-tools.cjs +159 -58
  98. package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
  99. package/gsd-core/bin/lib/adr-parser.cjs +37 -5
  100. package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
  101. package/gsd-core/bin/lib/audit.cjs +78 -44
  102. package/gsd-core/bin/lib/broken-windows.cjs +13 -13
  103. package/gsd-core/bin/lib/capability-activation.cjs +9 -4
  104. package/gsd-core/bin/lib/capability-registry.cjs +249 -117
  105. package/gsd-core/bin/lib/capability-validator.cjs +18 -1
  106. package/gsd-core/bin/lib/capability-writer.cjs +2 -1
  107. package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
  108. package/gsd-core/bin/lib/check-command-router.cjs +164 -1712
  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 +11 -8
  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 +201 -178
  115. package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
  116. package/gsd-core/bin/lib/config.cjs +43 -12
  117. package/gsd-core/bin/lib/core-utils.cjs +6 -1
  118. package/gsd-core/bin/lib/coverage.cjs +4 -8
  119. package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
  120. package/gsd-core/bin/lib/drift.cjs +177 -42
  121. package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
  122. package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
  123. package/gsd-core/bin/lib/frontmatter.cjs +413 -234
  124. package/gsd-core/bin/lib/gap-checker.cjs +72 -29
  125. package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
  126. package/gsd-core/bin/lib/gate-args.cjs +53 -0
  127. package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
  128. package/gsd-core/bin/lib/gate-config.cjs +46 -0
  129. package/gsd-core/bin/lib/gate-context-drift.cjs +142 -0
  130. package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
  131. package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
  132. package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
  133. package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
  134. package/gsd-core/bin/lib/gate-exit.cjs +27 -0
  135. package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
  136. package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
  137. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
  138. package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
  139. package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
  140. package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
  141. package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
  142. package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
  143. package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
  144. package/gsd-core/bin/lib/gate-ui-safety.cjs +81 -0
  145. package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
  146. package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
  147. package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
  148. package/gsd-core/bin/lib/graphify.cjs +3 -2
  149. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
  150. package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
  151. package/gsd-core/bin/lib/init.cjs +194 -108
  152. package/gsd-core/bin/lib/install-engine.cjs +30 -35
  153. package/gsd-core/bin/lib/install-profiles.cjs +7 -4
  154. package/gsd-core/bin/lib/install-shadow-report.cjs +12 -0
  155. package/gsd-core/bin/lib/installer-migrations/011-opencode-mcp-no-prompts.cjs +99 -0
  156. package/gsd-core/bin/lib/installer-migrations.cjs +54 -1
  157. package/gsd-core/bin/lib/io.cjs +122 -3
  158. package/gsd-core/bin/lib/jsonc-edit.cjs +418 -0
  159. package/gsd-core/bin/lib/loop-host-contract.cjs +2 -1
  160. package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
  161. package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
  162. package/gsd-core/bin/lib/mcp-server.cjs +5 -1
  163. package/gsd-core/bin/lib/milestone.cjs +19 -1
  164. package/gsd-core/bin/lib/model-resolver.cjs +18 -18
  165. package/gsd-core/bin/lib/observability/event.cjs +1 -1
  166. package/gsd-core/bin/lib/observability/logger.cjs +46 -1
  167. package/gsd-core/bin/lib/opencode-mcp-entry.cjs +39 -0
  168. package/gsd-core/bin/lib/opencode-version.cjs +486 -0
  169. package/gsd-core/bin/lib/pattern.cjs +10 -0
  170. package/gsd-core/bin/lib/phase-command-router.cjs +11 -4
  171. package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
  172. package/gsd-core/bin/lib/phase-id.cjs +1 -1
  173. package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
  174. package/gsd-core/bin/lib/phase-status.cjs +360 -0
  175. package/gsd-core/bin/lib/phase.cjs +301 -80
  176. package/gsd-core/bin/lib/plan-document.cjs +93 -19
  177. package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
  178. package/gsd-core/bin/lib/planning-document.cjs +273 -40
  179. package/gsd-core/bin/lib/planning-inspect.cjs +42 -8
  180. package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
  181. package/gsd-core/bin/lib/planning-workspace.cjs +76 -53
  182. package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
  183. package/gsd-core/bin/lib/profile-output.cjs +6 -3
  184. package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
  185. package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
  186. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +13 -9
  187. package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
  188. package/gsd-core/bin/lib/report-parser.cjs +269 -0
  189. package/gsd-core/bin/lib/roadmap-command-router.cjs +13 -15
  190. package/gsd-core/bin/lib/roadmap-parser.cjs +82 -15
  191. package/gsd-core/bin/lib/roadmap-upgrade.cjs +127 -65
  192. package/gsd-core/bin/lib/roadmap.cjs +169 -72
  193. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +186 -161
  194. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +2 -1
  195. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
  196. package/gsd-core/bin/lib/runtime-homes.cjs +13 -10
  197. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +365 -594
  198. package/gsd-core/bin/lib/runtime-name-policy.cjs +142 -27
  199. package/gsd-core/bin/lib/runtime-slash.cjs +60 -30
  200. package/gsd-core/bin/lib/shell-command-projection.cjs +37 -2
  201. package/gsd-core/bin/lib/smart-entry.cjs +111 -56
  202. package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
  203. package/gsd-core/bin/lib/state-contract.cjs +15 -18
  204. package/gsd-core/bin/lib/state-document.cjs +100 -22
  205. package/gsd-core/bin/lib/state-transition.cjs +67 -9
  206. package/gsd-core/bin/lib/state.cjs +668 -171
  207. package/gsd-core/bin/lib/surface.cjs +2 -1
  208. package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -152
  209. package/gsd-core/bin/lib/uat-predicate.cjs +313 -35
  210. package/gsd-core/bin/lib/uat.cjs +424 -7
  211. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +94 -58
  212. package/gsd-core/bin/lib/update-context.cjs +18 -1
  213. package/gsd-core/bin/lib/vendor/README.md +31 -9
  214. package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
  215. package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
  216. package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
  217. package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
  218. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  219. package/gsd-core/bin/lib/verification.cjs +1265 -324
  220. package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
  221. package/gsd-core/bin/lib/verify.cjs +286 -567
  222. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
  223. package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
  224. package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
  225. package/gsd-core/bin/lib/workstream.cjs +11 -2
  226. package/gsd-core/bin/shared/config-defaults.manifest.json +5 -0
  227. package/gsd-core/bin/shared/config-schema.manifest.json +4 -0
  228. package/gsd-core/references/autonomous-smart-discuss.md +2 -1
  229. package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
  230. package/gsd-core/references/execute-mvp-tdd.md +5 -10
  231. package/gsd-core/references/execute-phase-between-wave-reset.md +3 -0
  232. package/gsd-core/references/execute-phase-response-language.md +1 -1
  233. package/gsd-core/references/gsd-run-resolver.md +1 -1
  234. package/gsd-core/references/loop-hook-dispatch.md +7 -1
  235. package/gsd-core/references/offer-next.md +1 -1
  236. package/gsd-core/references/planning-config.md +1 -1
  237. package/gsd-core/references/spidr-splitting.md +1 -1
  238. package/gsd-core/references/tdd.md +10 -4
  239. package/gsd-core/references/verifier-phase-gates.md +5 -2
  240. package/gsd-core/references/verify-mvp-mode.md +2 -2
  241. package/gsd-core/references/workstream-flag.md +33 -3
  242. package/gsd-core/templates/README.md +1 -1
  243. package/gsd-core/templates/UAT.md +17 -1
  244. package/gsd-core/templates/config.json +2 -11
  245. package/gsd-core/templates/verification-report.md +1 -1
  246. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  247. package/gsd-core/workflows/add-backlog.md +1 -1
  248. package/gsd-core/workflows/add-phase.md +8 -7
  249. package/gsd-core/workflows/add-tests.md +3 -2
  250. package/gsd-core/workflows/add-todo.md +4 -3
  251. package/gsd-core/workflows/ai-integration-phase.md +3 -2
  252. package/gsd-core/workflows/audit-fix.md +1 -1
  253. package/gsd-core/workflows/audit-milestone.md +4 -3
  254. package/gsd-core/workflows/audit-uat.md +1 -1
  255. package/gsd-core/workflows/autonomous.md +28 -18
  256. package/gsd-core/workflows/check-todos.md +6 -5
  257. package/gsd-core/workflows/cleanup.md +1 -1
  258. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
  259. package/gsd-core/workflows/code-review-fix.md +5 -4
  260. package/gsd-core/workflows/code-review.md +100 -91
  261. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
  262. package/gsd-core/workflows/complete-milestone.md +12 -7
  263. package/gsd-core/workflows/debug.md +30 -5
  264. package/gsd-core/workflows/diagnose-issues.md +3 -2
  265. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  266. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  267. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  268. package/gsd-core/workflows/discuss-phase.md +4 -3
  269. package/gsd-core/workflows/do.md +1 -1
  270. package/gsd-core/workflows/docs-update.md +4 -3
  271. package/gsd-core/workflows/edit-phase.md +4 -3
  272. package/gsd-core/workflows/eval-review.md +5 -3
  273. package/gsd-core/workflows/execute-phase/detail/elaboration.md +1 -1
  274. package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +4 -2
  275. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
  276. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
  277. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +2 -2
  278. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
  279. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
  280. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  281. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
  282. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +1 -1
  283. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
  284. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
  285. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
  286. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
  287. package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
  288. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
  289. package/gsd-core/workflows/execute-phase.md +81 -171
  290. package/gsd-core/workflows/execute-plan.md +13 -19
  291. package/gsd-core/workflows/explore.md +2 -2
  292. package/gsd-core/workflows/extract-learnings.md +3 -2
  293. package/gsd-core/workflows/fast.md +1 -1
  294. package/gsd-core/workflows/forensics.md +1 -1
  295. package/gsd-core/workflows/graduation.md +1 -1
  296. package/gsd-core/workflows/health.md +2 -1
  297. package/gsd-core/workflows/import.md +3 -2
  298. package/gsd-core/workflows/inbox.md +1 -1
  299. package/gsd-core/workflows/ingest-docs.md +1 -1
  300. package/gsd-core/workflows/insert-phase.md +4 -3
  301. package/gsd-core/workflows/list-seeds.md +1 -1
  302. package/gsd-core/workflows/list-workspaces.md +1 -1
  303. package/gsd-core/workflows/manager.md +5 -3
  304. package/gsd-core/workflows/map-codebase.md +4 -3
  305. package/gsd-core/workflows/milestone-summary.md +3 -2
  306. package/gsd-core/workflows/mvp-phase.md +14 -14
  307. package/gsd-core/workflows/new-milestone.md +10 -10
  308. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  309. package/gsd-core/workflows/new-project.md +1 -1
  310. package/gsd-core/workflows/new-workspace.md +1 -1
  311. package/gsd-core/workflows/next.md +1 -1
  312. package/gsd-core/workflows/pause-work.md +2 -2
  313. package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
  314. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
  315. package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
  316. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  317. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +1 -1
  318. package/gsd-core/workflows/plan-phase.md +27 -18
  319. package/gsd-core/workflows/plan-review-convergence.md +1 -1
  320. package/gsd-core/workflows/plant-seed.md +1 -1
  321. package/gsd-core/workflows/pr-branch.md +1 -1
  322. package/gsd-core/workflows/profile-user.md +1 -1
  323. package/gsd-core/workflows/progress.md +19 -49
  324. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -2
  325. package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
  326. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
  327. package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
  328. package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
  329. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
  330. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
  331. package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
  332. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
  333. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
  334. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
  335. package/gsd-core/workflows/quick-batch.md +15 -10
  336. package/gsd-core/workflows/quick.md +42 -31
  337. package/gsd-core/workflows/remove-phase.md +3 -2
  338. package/gsd-core/workflows/remove-workspace.md +1 -1
  339. package/gsd-core/workflows/resume-project.md +17 -12
  340. package/gsd-core/workflows/review.md +3 -2
  341. package/gsd-core/workflows/scan.md +3 -2
  342. package/gsd-core/workflows/secure-phase.md +11 -12
  343. package/gsd-core/workflows/settings-advanced.md +1 -1
  344. package/gsd-core/workflows/settings-integrations.md +1 -1
  345. package/gsd-core/workflows/settings.md +1 -1
  346. package/gsd-core/workflows/ship.md +12 -12
  347. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  348. package/gsd-core/workflows/sketch.md +1 -1
  349. package/gsd-core/workflows/smart-entry.md +1 -1
  350. package/gsd-core/workflows/spec-phase.md +1 -1
  351. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  352. package/gsd-core/workflows/spike.md +1 -1
  353. package/gsd-core/workflows/stats.md +1 -1
  354. package/gsd-core/workflows/sync-skills.md +1 -1
  355. package/gsd-core/workflows/thread.md +2 -2
  356. package/gsd-core/workflows/transition.md +13 -23
  357. package/gsd-core/workflows/ui-phase.md +5 -4
  358. package/gsd-core/workflows/ui-review.md +4 -3
  359. package/gsd-core/workflows/ultraplan-phase.md +3 -2
  360. package/gsd-core/workflows/undo.md +1 -1
  361. package/gsd-core/workflows/validate-phase.md +10 -12
  362. package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
  363. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
  364. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
  365. package/gsd-core/workflows/verify-work.md +68 -59
  366. package/hooks/dist/gsd-agent-isolation-guard.js +8 -0
  367. package/hooks/dist/gsd-check-update-worker.js +8 -0
  368. package/hooks/dist/gsd-check-update.js +34 -20
  369. package/hooks/dist/gsd-context-monitor.js +45 -13
  370. package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
  371. package/hooks/dist/gsd-secret-read-guard.js +263 -16
  372. package/hooks/dist/gsd-statusline.js +336 -29
  373. package/hooks/dist/gsd-update-banner.js +8 -0
  374. package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
  375. package/hooks/dist/gsd-workflow-guard.js +5 -4
  376. package/hooks/dist/gsd-worktree-path-guard.js +6 -2
  377. package/hooks/dist/lib/cli-exit.js +12 -0
  378. package/hooks/dist/lib/git-probe.js +17 -1
  379. package/hooks/dist/lib/isolation-sentinel.js +2 -2
  380. package/hooks/gsd-agent-isolation-guard.js +8 -0
  381. package/hooks/gsd-check-update-worker.js +8 -0
  382. package/hooks/gsd-check-update.js +34 -20
  383. package/hooks/gsd-context-monitor.js +45 -13
  384. package/hooks/gsd-cursor-subagent-start.js +8 -0
  385. package/hooks/gsd-secret-read-guard.js +263 -16
  386. package/hooks/gsd-statusline.js +336 -29
  387. package/hooks/gsd-update-banner.js +8 -0
  388. package/hooks/gsd-windsurf-pre-write.js +11 -2
  389. package/hooks/gsd-workflow-guard.js +5 -4
  390. package/hooks/gsd-worktree-path-guard.js +6 -2
  391. package/hooks/hooks.json +5 -5
  392. package/hooks/lib/cli-exit.js +12 -0
  393. package/hooks/lib/git-probe.js +17 -1
  394. package/hooks/lib/isolation-sentinel.js +2 -2
  395. package/package.json +21 -4
  396. package/scripts/changeset/parse.cjs +52 -4
  397. package/scripts/ci-timeout-report.cjs +770 -4
  398. package/scripts/command-contract-helpers.cjs +12 -8
  399. package/scripts/docs-guard-registry.cjs +6 -0
  400. package/scripts/gen-capability-registry.cjs +7 -1
  401. package/scripts/gen-features.cjs +13 -8
  402. package/scripts/gen-hooks-cli-exit.cjs +12 -28
  403. package/scripts/gen-loop-host-contract.cjs +14 -2
  404. package/scripts/gen-platform-conformance-tier.cjs +187 -1
  405. package/scripts/gen-plugin-skills.cjs +87 -1
  406. package/scripts/gen-research-agents.cjs +24 -31
  407. package/scripts/gen-scripts-cli-exit.cjs +30 -3
  408. package/scripts/gen-test-timings.cjs +32 -7
  409. package/scripts/lib/cli-exit.cjs +12 -0
  410. package/scripts/lib/macos-conformance-tier.generated.cjs +24 -2
  411. package/scripts/lib/ndjson-reporter.cjs +28 -3
  412. package/scripts/lib/platform-conformance-tier.generated.cjs +44 -5
  413. package/scripts/lib/registration-ledger-preload.cjs +155 -0
  414. package/scripts/lib/vendor-bundle.cjs +59 -0
  415. package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
  416. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  417. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  418. package/scripts/lint-completion-predicate-drift.cjs +18 -19
  419. package/scripts/lint-descriptions.cjs +7 -3
  420. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +10 -0
  421. package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
  422. package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
  423. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
  424. package/scripts/lint-phase-enumeration-drift.cjs +12 -8
  425. package/scripts/lint-phase-id-drift.cjs +29 -0
  426. package/scripts/lint-planning-document-positive-control.cjs +329 -0
  427. package/scripts/lint-response-language-coverage.cjs +3 -0
  428. package/scripts/lint-skill-deps.cjs +7 -3
  429. package/scripts/lint-test-file-count.allowlist.json +11 -1
  430. package/scripts/lint-test-file-count.cjs +34 -1
  431. package/scripts/lint-vendored-deps.cjs +41 -5
  432. package/scripts/lint-workflow-shellcheck-baseline.json +10 -10
  433. package/scripts/mutation-matrix.cjs +53 -6
  434. package/scripts/release-tarball-smoke.cjs +14 -7
  435. package/scripts/require-issue-link-policy.cjs +6 -2
  436. package/scripts/sync-runtime-launcher.cjs +184 -2
  437. package/scripts/verify-npm-publish.cjs +76 -20
  438. package/skills/gsd-add-tests/SKILL.md +6 -1
  439. package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
  440. package/skills/gsd-audit-fix/SKILL.md +5 -0
  441. package/skills/gsd-audit-milestone/SKILL.md +6 -1
  442. package/skills/gsd-autonomous/SKILL.md +5 -0
  443. package/skills/gsd-capture/SKILL.md +8 -4
  444. package/skills/gsd-code-review/SKILL.md +7 -2
  445. package/skills/gsd-complete-milestone/SKILL.md +4 -0
  446. package/skills/gsd-config/SKILL.md +8 -4
  447. package/skills/gsd-debug/SKILL.md +11 -7
  448. package/skills/gsd-discuss-phase/SKILL.md +7 -3
  449. package/skills/gsd-docs-update/SKILL.md +12 -7
  450. package/skills/gsd-eval-review/SKILL.md +6 -1
  451. package/skills/gsd-execute-phase/SKILL.md +12 -7
  452. package/skills/gsd-extract-learnings/SKILL.md +5 -0
  453. package/skills/gsd-fast/SKILL.md +4 -0
  454. package/skills/gsd-forensics/SKILL.md +5 -1
  455. package/skills/gsd-graphify/SKILL.md +10 -6
  456. package/skills/gsd-health/SKILL.md +5 -0
  457. package/skills/gsd-help/SKILL.md +7 -2
  458. package/skills/gsd-import/SKILL.md +7 -3
  459. package/skills/gsd-inbox/SKILL.md +5 -0
  460. package/skills/gsd-ingest-docs/SKILL.md +5 -1
  461. package/skills/gsd-manager/SKILL.md +6 -1
  462. package/skills/gsd-map-codebase/SKILL.md +7 -3
  463. package/skills/gsd-mempalace-capture/SKILL.md +5 -1
  464. package/skills/gsd-mempalace-recall/SKILL.md +5 -1
  465. package/skills/gsd-milestone-summary/SKILL.md +5 -1
  466. package/skills/gsd-mvp-phase/SKILL.md +8 -3
  467. package/skills/gsd-new-milestone/SKILL.md +6 -1
  468. package/skills/gsd-new-project/SKILL.md +5 -0
  469. package/skills/gsd-next/SKILL.md +6 -1
  470. package/skills/gsd-ns-context/SKILL.md +4 -0
  471. package/skills/gsd-ns-ideate/SKILL.md +4 -0
  472. package/skills/gsd-ns-manage/SKILL.md +4 -0
  473. package/skills/gsd-ns-project/SKILL.md +4 -0
  474. package/skills/gsd-ns-review/SKILL.md +4 -0
  475. package/skills/gsd-ns-workflow/SKILL.md +4 -0
  476. package/skills/gsd-onboard/SKILL.md +6 -1
  477. package/skills/gsd-pause-work/SKILL.md +5 -1
  478. package/skills/gsd-phase/SKILL.md +8 -4
  479. package/skills/gsd-plan-phase/SKILL.md +6 -1
  480. package/skills/gsd-plan-review-convergence/SKILL.md +5 -1
  481. package/skills/gsd-pr-branch/SKILL.md +4 -0
  482. package/skills/gsd-profile-user/SKILL.md +5 -1
  483. package/skills/gsd-progress/SKILL.md +6 -1
  484. package/skills/gsd-quick/SKILL.md +16 -10
  485. package/skills/gsd-quick-batch/SKILL.md +20 -8
  486. package/skills/gsd-review/SKILL.md +5 -1
  487. package/skills/gsd-review-backlog/SKILL.md +3 -2
  488. package/skills/gsd-secure-phase/SKILL.md +6 -1
  489. package/skills/gsd-ship/SKILL.md +5 -0
  490. package/skills/gsd-sketch/SKILL.md +7 -2
  491. package/skills/gsd-spec-phase/SKILL.md +5 -1
  492. package/skills/gsd-spike/SKILL.md +8 -3
  493. package/skills/gsd-surface/SKILL.md +5 -1
  494. package/skills/gsd-thread/SKILL.md +4 -0
  495. package/skills/gsd-ui-phase/SKILL.md +6 -1
  496. package/skills/gsd-ui-review/SKILL.md +6 -1
  497. package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
  498. package/skills/gsd-undo/SKILL.md +5 -1
  499. package/skills/gsd-update/SKILL.md +6 -2
  500. package/skills/gsd-validate-phase/SKILL.md +6 -1
  501. package/skills/gsd-verify-work/SKILL.md +6 -1
  502. package/skills/gsd-workspace/SKILL.md +7 -3
  503. package/skills/gsd-workstreams/SKILL.md +6 -6
  504. package/vscode/package.json +1 -1
  505. package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +0 -24
@@ -25,7 +25,7 @@ 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
31
  // #4378 (roll-in): scanSeeds publishes the SAME canonical seed identity the
@@ -33,7 +33,7 @@ const frontmatter = require("./frontmatter.cjs");
33
33
  // does not require this module, so the edge is acyclic.
34
34
  // eslint-disable-next-line @typescript-eslint/no-require-imports
35
35
  const commandsModule = require("./commands.cjs");
36
- const { extractFrontmatter, FRONTMATTER_UNPARSEABLE, spliceFrontmatter } = frontmatter;
36
+ const { extractFrontmatter, frontmatterBlock, spliceFrontmatter, isFrontmatterWriteRefusal } = frontmatter;
37
37
  // eslint-disable-next-line @typescript-eslint/no-require-imports
38
38
  const phaseIdMod = require("./phase-id.cjs");
39
39
  const { PHASE_NUMBER_TOKEN_SOURCE, scopeToPhase } = phaseIdMod;
@@ -46,6 +46,11 @@ const shell_command_projection_cjs_2 = require("./shell-command-projection.cjs")
46
46
  const io = require("./io.cjs");
47
47
  const { output, error: ioError } = io;
48
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");
49
54
  // The SCOPE BOUNDARY convention's filename (`agents/gsd-executor.md`), shared
50
55
  // verbatim with the #2287 phase-boundary reader in `uat.cts`.
51
56
  const DEFERRED_ITEMS_FILENAME = 'deferred-items.md';
@@ -257,19 +262,27 @@ function deriveOpenQuestionsDigest(questions) {
257
262
  }
258
263
  // ─── scanDebugSessions ────────────────────────────────────────────────────────
259
264
  /**
260
- * 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.
261
275
  * Open = status NOT in ['resolved', 'complete'].
262
- * Ignores the resolved/ subdirectory.
276
+ * Ignores the resolved/ subdirectory and the debugger's knowledge base.
263
277
  */
264
- function scanDebugSessions(planDir) {
265
- const debugDir = node_path_1.default.join(planDir, 'debug');
266
- if (!node_fs_1.default.existsSync(debugDir))
278
+ function scanDebugSessions(debugPath) {
279
+ if (!node_fs_1.default.existsSync(debugPath))
267
280
  return { items: [], acknowledged: 0 };
268
281
  const results = [];
269
282
  let acknowledged = 0;
270
283
  let files;
271
284
  try {
272
- files = node_fs_1.default.readdirSync(debugDir, { withFileTypes: true });
285
+ files = node_fs_1.default.readdirSync(debugPath, { withFileTypes: true });
273
286
  }
274
287
  catch {
275
288
  return { items: [{ scan_error: true, slug: '', status: '', updated: '', hypothesis: '' }], acknowledged: 0 };
@@ -279,10 +292,12 @@ function scanDebugSessions(planDir) {
279
292
  continue;
280
293
  if (!entry.name.endsWith('.md'))
281
294
  continue;
282
- 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);
283
298
  let safeFilePath;
284
299
  try {
285
- 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);
286
301
  }
287
302
  catch {
288
303
  continue;
@@ -291,9 +306,9 @@ function scanDebugSessions(planDir) {
291
306
  // document at this read boundary, same seam as `src/uat.cts`'s
292
307
  // `readNormalizedDocument` — `platformReadSync` performs no line-ending
293
308
  // normalization itself, and extractFrontmatter/status-derivation below
294
- // degrade a lone-CR file's frontmatter to `unknown`, which every scan
295
- // in this module treats as "not open" (fail-open, the permissive
296
- // 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.
297
312
  const rawContent = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
298
313
  if (rawContent === null)
299
314
  continue;
@@ -591,9 +606,11 @@ function scanTodos(todosBase) {
591
606
  }
592
607
  const displayFiles = openFiles.slice(0, 5);
593
608
  for (const { entry, content, fm } of displayFiles) {
594
- // Extract first line of body after frontmatter
595
- const bodyMatch = content.replace(/^---[\s\S]*?---\r?\n?/, '');
596
- 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] || '';
597
614
  const summary = (0, security_cjs_1.sanitizeForDisplay)(firstLine.slice(0, 100));
598
615
  results.push({
599
616
  filename: (0, security_cjs_1.sanitizeLabel)(entry.name),
@@ -816,9 +833,9 @@ function scanUatGaps(planDir, cwd) {
816
833
  // document at this read boundary, same seam as `src/uat.cts`'s
817
834
  // `readNormalizedDocument` — `platformReadSync` performs no line-ending
818
835
  // normalization itself, and extractFrontmatter/status-derivation below
819
- // degrade a lone-CR file's frontmatter to `unknown`, which every scan
820
- // in this module treats as "not open" (fail-open, the permissive
821
- // 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.
822
839
  const rawContent = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
823
840
  if (rawContent === null)
824
841
  continue;
@@ -897,8 +914,10 @@ function scanVerificationGaps(planDir, cwd) {
897
914
  continue;
898
915
  const content = normalizeLineEndings(rawContent);
899
916
  const fm = extractFrontmatter(content, safeFilePath);
900
- const status = (fm.status || 'unknown').toLowerCase();
901
- 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)
902
921
  continue;
903
922
  if (isAuditItemAcknowledged(fm, { snapshotKey: 'status', currentValue: status })) {
904
923
  acknowledged++;
@@ -1074,8 +1093,10 @@ function scanDeferredItems(planDir, cwd) {
1074
1093
  function auditOpenArtifacts(cwd) {
1075
1094
  const planDir = planningDir(cwd);
1076
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.
1077
1098
  try {
1078
- return scanDebugSessions(planDir);
1099
+ return scanDebugSessions(debugDir(cwd));
1079
1100
  }
1080
1101
  catch {
1081
1102
  return { items: [{ scan_error: true, slug: '', status: '', updated: '', hypothesis: '' }], acknowledged: 0 };
@@ -1098,7 +1119,7 @@ function auditOpenArtifacts(cwd) {
1098
1119
  }
1099
1120
  })();
1100
1121
  const todos = (() => {
1101
- // #4256: the ONE root-scoped category — todos are shared project state,
1122
+ // #4256: todos are shared project state, like debug sessions (#5042),
1102
1123
  // so the close gate reads todosDir(cwd) (the root), not the workstream-
1103
1124
  // scoped planDir every other scan below receives. Reading planDir here
1104
1125
  // made audit-open print "All artifact types clear. Safe to proceed."
@@ -1130,7 +1151,11 @@ function auditOpenArtifacts(cwd) {
1130
1151
  try {
1131
1152
  return scanVerificationGaps(planDir, cwd);
1132
1153
  }
1133
- 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;
1134
1159
  return { items: [{ scan_error: true, phase: '', file: '', status: '' }], acknowledged: 0 };
1135
1160
  }
1136
1161
  })();
@@ -1399,6 +1424,26 @@ function resolvePhaseTargetDir(planDir, cwd, phase, archivedMilestone) {
1399
1424
  * artifact identifier that resolves outside the project is refused before
1400
1425
  * any read or write is attempted.
1401
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
+ }
1402
1447
  function cmdAuditAcknowledge(cwd, args, raw) {
1403
1448
  // args already has the family + subcommand tokens stripped by the caller
1404
1449
  // (audit-command-router.cts:147 passes `hubArgs.slice(2)`), so validation
@@ -1418,7 +1463,9 @@ function cmdAuditAcknowledge(cwd, args, raw) {
1418
1463
  // All declared flags above are value flags, so each resolves to `string |
1419
1464
  // null` at runtime; the cast narrows away the `boolean` arm of
1420
1465
  // ParsedNamedArgs's value type that this call site never produces.
1421
- 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();
1422
1469
  const planDir = planningDir(cwd);
1423
1470
  const markerBase = { milestone: milestone, at };
1424
1471
  // #3078-CR MEDIUM 2: every `fs.readFileSync` in this function (below, and
@@ -1479,13 +1526,6 @@ function cmdAuditAcknowledge(cwd, args, raw) {
1479
1526
  }
1480
1527
  const content = node_fs_1.default.readFileSync(safeFilePath, 'utf-8');
1481
1528
  const fm = extractFrontmatter(content, safeFilePath);
1482
- // #4802: an unparseable frontmatter block is NOT an empty one — splicing
1483
- // the marker-marked object over the file would discard every field the
1484
- // author actually wrote. Refuse and name the file (the write-path
1485
- // counterpart of the read-side FRONTMATTER_UNPARSEABLE contract).
1486
- if (fm[FRONTMATTER_UNPARSEABLE] === true) {
1487
- ioError(`refusing to acknowledge — the frontmatter of "${file}" is not parseable YAML (splicing would discard every other frontmatter field); fix the YAML syntax error first, then re-run`);
1488
- }
1489
1529
  // Mixed-frame fix (security review, 4th instance on this branch): the
1490
1530
  // splice above and below stays keyed to RAW `content` (raw byte offsets
1491
1531
  // must not shift), but `scanUatGaps`/`scanContextQuestions` now derive
@@ -1516,7 +1556,7 @@ function cmdAuditAcknowledge(cwd, args, raw) {
1516
1556
  currentValue = deriveOpenQuestionsDigest(deriveOpenQuestions(normalizedContent, fm));
1517
1557
  }
1518
1558
  fm.audit_acknowledged = { ...markerBase, [snapshotKey]: currentValue };
1519
- const newContent = spliceFrontmatter(content, fm);
1559
+ const newContent = spliceAcknowledgement(content, fm, file);
1520
1560
  (0, shell_command_projection_cjs_2.platformWriteSync)(safeFilePath, newContent);
1521
1561
  output({ acknowledged: true, category, phase, file, [snapshotKey]: currentValue }, raw, 'true');
1522
1562
  return;
@@ -1645,18 +1685,12 @@ function cmdAuditAcknowledge(cwd, args, raw) {
1645
1685
  return; // unreachable — ioError throws — satisfies TS control-flow analysis
1646
1686
  }
1647
1687
  const presenceOnly = category === 'todos';
1648
- const fm = createIfMissing ? fmForCreate : extractFrontmatter(node_fs_1.default.readFileSync(safeFilePath, 'utf-8'), safeFilePath);
1649
- // #4802: same unparseable-frontmatter refusal as the phase-scoped branch —
1650
- // createIfMissing never reaches this extract (it only fires when the file is
1651
- // absent), so an existing file with broken YAML refuses instead of splicing
1652
- // a near-empty object over every field the author wrote.
1653
- if (!createIfMissing && fm[FRONTMATTER_UNPARSEABLE] === true) {
1654
- ioError(`refusing to acknowledge — the frontmatter of "${safeFilePath}" is not parseable YAML (splicing would discard every other frontmatter field); fix the YAML syntax error first, then re-run`);
1655
- }
1688
+ const existingContent = createIfMissing ? '' : node_fs_1.default.readFileSync(safeFilePath, 'utf-8');
1689
+ const fm = createIfMissing ? fmForCreate : extractFrontmatter(existingContent, safeFilePath);
1656
1690
  fm.audit_acknowledged = presenceOnly ? { ...markerBase } : { ...markerBase, [snapshotKey]: currentValue };
1657
- const newContent = createIfMissing
1658
- ? spliceFrontmatter('', fm)
1659
- : 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);
1660
1694
  (0, shell_command_projection_cjs_2.platformWriteSync)(safeFilePath, newContent);
1661
1695
  output({ acknowledged: true, category, ...(presenceOnly ? {} : { [snapshotKey]: currentValue }) }, raw, 'true');
1662
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
  }