@opengsd/gsd-core 1.15.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (487) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +85 -5
  4. package/agents/gsd-code-fixer.compact.md +1 -1
  5. package/agents/gsd-code-fixer.md +1 -1
  6. package/agents/gsd-code-reviewer.compact.md +5 -3
  7. package/agents/gsd-code-reviewer.md +8 -6
  8. package/agents/gsd-debug-session-manager.compact.md +1 -1
  9. package/agents/gsd-debug-session-manager.md +1 -1
  10. package/agents/gsd-debugger.md +2 -2
  11. package/agents/gsd-eval-auditor.compact.md +1 -1
  12. package/agents/gsd-eval-auditor.md +1 -1
  13. package/agents/gsd-executor.md +4 -4
  14. package/agents/gsd-intel-updater.compact.md +1 -1
  15. package/agents/gsd-intel-updater.md +1 -1
  16. package/agents/gsd-mempalace-curator.md +2 -2
  17. package/agents/gsd-phase-researcher.md +1 -1
  18. package/agents/gsd-plan-checker.md +7 -2
  19. package/agents/gsd-planner.md +3 -3
  20. package/agents/gsd-project-researcher.compact.md +1 -1
  21. package/agents/gsd-project-researcher.md +1 -1
  22. package/agents/gsd-research-synthesizer.compact.md +1 -1
  23. package/agents/gsd-research-synthesizer.md +1 -1
  24. package/agents/gsd-ui-auditor.compact.md +21 -30
  25. package/agents/gsd-ui-auditor.md +42 -51
  26. package/agents/gsd-ui-researcher.compact.md +1 -1
  27. package/agents/gsd-ui-researcher.md +1 -1
  28. package/agents/gsd-verifier.md +31 -9
  29. package/bin/install.js +126 -196
  30. package/commands/gsd/add-tests.md +6 -1
  31. package/commands/gsd/ai-integration-phase.md +6 -1
  32. package/commands/gsd/audit-fix.md +5 -0
  33. package/commands/gsd/audit-milestone.md +6 -1
  34. package/commands/gsd/autonomous.md +5 -0
  35. package/commands/gsd/capture.md +8 -4
  36. package/commands/gsd/code-review.md +7 -2
  37. package/commands/gsd/complete-milestone.md +4 -0
  38. package/commands/gsd/config.md +7 -3
  39. package/commands/gsd/debug.md +11 -7
  40. package/commands/gsd/discuss-phase.md +7 -3
  41. package/commands/gsd/docs-update.md +12 -7
  42. package/commands/gsd/eval-review.md +6 -1
  43. package/commands/gsd/execute-phase.md +12 -7
  44. package/commands/gsd/extract-learnings.md +5 -0
  45. package/commands/gsd/fast.md +4 -0
  46. package/commands/gsd/forensics.md +5 -1
  47. package/commands/gsd/graphify.md +10 -6
  48. package/commands/gsd/health.md +5 -0
  49. package/commands/gsd/help.md +7 -2
  50. package/commands/gsd/import.md +7 -3
  51. package/commands/gsd/inbox.md +5 -0
  52. package/commands/gsd/ingest-docs.md +5 -1
  53. package/commands/gsd/manager.md +6 -1
  54. package/commands/gsd/map-codebase.md +7 -3
  55. package/commands/gsd/mempalace-capture.md +5 -1
  56. package/commands/gsd/mempalace-recall.md +5 -1
  57. package/commands/gsd/milestone-summary.md +5 -1
  58. package/commands/gsd/mvp-phase.md +8 -3
  59. package/commands/gsd/new-milestone.md +6 -1
  60. package/commands/gsd/new-project.md +5 -0
  61. package/commands/gsd/next.md +6 -1
  62. package/commands/gsd/ns-context.md +4 -0
  63. package/commands/gsd/ns-ideate.md +4 -0
  64. package/commands/gsd/ns-manage.md +4 -0
  65. package/commands/gsd/ns-project.md +4 -0
  66. package/commands/gsd/ns-review.md +4 -0
  67. package/commands/gsd/ns-workflow.md +4 -0
  68. package/commands/gsd/onboard.md +6 -1
  69. package/commands/gsd/pause-work.md +5 -1
  70. package/commands/gsd/phase.md +8 -4
  71. package/commands/gsd/plan-phase.md +6 -1
  72. package/commands/gsd/plan-review-convergence.md +5 -1
  73. package/commands/gsd/pr-branch.md +4 -0
  74. package/commands/gsd/profile-user.md +5 -1
  75. package/commands/gsd/progress.md +6 -1
  76. package/commands/gsd/quick-batch.md +20 -8
  77. package/commands/gsd/quick.md +12 -7
  78. package/commands/gsd/review.md +5 -1
  79. package/commands/gsd/secure-phase.md +6 -1
  80. package/commands/gsd/ship.md +5 -0
  81. package/commands/gsd/sketch.md +7 -2
  82. package/commands/gsd/spec-phase.md +5 -1
  83. package/commands/gsd/spike.md +8 -3
  84. package/commands/gsd/surface.md +5 -1
  85. package/commands/gsd/thread.md +4 -0
  86. package/commands/gsd/ui-phase.md +6 -1
  87. package/commands/gsd/ui-review.md +6 -1
  88. package/commands/gsd/ultraplan-phase.md +5 -1
  89. package/commands/gsd/undo.md +5 -1
  90. package/commands/gsd/update.md +6 -2
  91. package/commands/gsd/validate-phase.md +6 -1
  92. package/commands/gsd/verify-work.md +6 -1
  93. package/commands/gsd/workspace.md +7 -3
  94. package/gsd-core/bin/gsd-tools.cjs +142 -56
  95. package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
  96. package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
  97. package/gsd-core/bin/lib/audit.cjs +78 -44
  98. package/gsd-core/bin/lib/broken-windows.cjs +13 -13
  99. package/gsd-core/bin/lib/capability-activation.cjs +9 -4
  100. package/gsd-core/bin/lib/capability-registry.cjs +183 -103
  101. package/gsd-core/bin/lib/capability-validator.cjs +16 -0
  102. package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
  103. package/gsd-core/bin/lib/check-command-router.cjs +164 -1712
  104. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
  105. package/gsd-core/bin/lib/cli-exit.cjs +12 -0
  106. package/gsd-core/bin/lib/codex-agent-toml.cjs +11 -8
  107. package/gsd-core/bin/lib/command-aliases.cjs +7 -0
  108. package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
  109. package/gsd-core/bin/lib/commands.cjs +173 -170
  110. package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
  111. package/gsd-core/bin/lib/config.cjs +43 -12
  112. package/gsd-core/bin/lib/core-utils.cjs +6 -1
  113. package/gsd-core/bin/lib/coverage.cjs +4 -8
  114. package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
  115. package/gsd-core/bin/lib/drift.cjs +177 -42
  116. package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
  117. package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
  118. package/gsd-core/bin/lib/frontmatter.cjs +413 -234
  119. package/gsd-core/bin/lib/gap-checker.cjs +72 -29
  120. package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
  121. package/gsd-core/bin/lib/gate-args.cjs +53 -0
  122. package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
  123. package/gsd-core/bin/lib/gate-config.cjs +46 -0
  124. package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
  125. package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
  126. package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
  127. package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
  128. package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
  129. package/gsd-core/bin/lib/gate-exit.cjs +27 -0
  130. package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
  131. package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
  132. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
  133. package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
  134. package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
  135. package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
  136. package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
  137. package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
  138. package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
  139. package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
  140. package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
  141. package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
  142. package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
  143. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
  144. package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
  145. package/gsd-core/bin/lib/init.cjs +162 -96
  146. package/gsd-core/bin/lib/install-engine.cjs +19 -35
  147. package/gsd-core/bin/lib/install-profiles.cjs +7 -4
  148. package/gsd-core/bin/lib/io.cjs +122 -3
  149. package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
  150. package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
  151. package/gsd-core/bin/lib/milestone.cjs +19 -1
  152. package/gsd-core/bin/lib/model-resolver.cjs +18 -18
  153. package/gsd-core/bin/lib/observability/event.cjs +1 -1
  154. package/gsd-core/bin/lib/observability/logger.cjs +46 -1
  155. package/gsd-core/bin/lib/pattern.cjs +10 -0
  156. package/gsd-core/bin/lib/phase-command-router.cjs +11 -4
  157. package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
  158. package/gsd-core/bin/lib/phase-id.cjs +1 -1
  159. package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
  160. package/gsd-core/bin/lib/phase-status.cjs +360 -0
  161. package/gsd-core/bin/lib/phase.cjs +280 -80
  162. package/gsd-core/bin/lib/plan-document.cjs +93 -19
  163. package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
  164. package/gsd-core/bin/lib/planning-document.cjs +273 -40
  165. package/gsd-core/bin/lib/planning-inspect.cjs +42 -8
  166. package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
  167. package/gsd-core/bin/lib/planning-workspace.cjs +76 -53
  168. package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
  169. package/gsd-core/bin/lib/profile-output.cjs +6 -3
  170. package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
  171. package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
  172. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
  173. package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
  174. package/gsd-core/bin/lib/report-parser.cjs +269 -0
  175. package/gsd-core/bin/lib/roadmap-command-router.cjs +13 -15
  176. package/gsd-core/bin/lib/roadmap-parser.cjs +82 -15
  177. package/gsd-core/bin/lib/roadmap-upgrade.cjs +127 -65
  178. package/gsd-core/bin/lib/roadmap.cjs +169 -72
  179. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +91 -157
  180. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +2 -1
  181. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
  182. package/gsd-core/bin/lib/runtime-homes.cjs +13 -10
  183. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +307 -591
  184. package/gsd-core/bin/lib/runtime-name-policy.cjs +142 -27
  185. package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
  186. package/gsd-core/bin/lib/shell-command-projection.cjs +37 -2
  187. package/gsd-core/bin/lib/smart-entry.cjs +19 -3
  188. package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
  189. package/gsd-core/bin/lib/state-contract.cjs +15 -18
  190. package/gsd-core/bin/lib/state-document.cjs +100 -22
  191. package/gsd-core/bin/lib/state.cjs +214 -105
  192. package/gsd-core/bin/lib/surface.cjs +2 -1
  193. package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -152
  194. package/gsd-core/bin/lib/uat-predicate.cjs +313 -35
  195. package/gsd-core/bin/lib/uat.cjs +424 -7
  196. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +94 -58
  197. package/gsd-core/bin/lib/vendor/README.md +31 -9
  198. package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
  199. package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
  200. package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
  201. package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
  202. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  203. package/gsd-core/bin/lib/verification.cjs +1165 -314
  204. package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
  205. package/gsd-core/bin/lib/verify.cjs +286 -567
  206. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
  207. package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
  208. package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
  209. package/gsd-core/bin/lib/workstream.cjs +11 -2
  210. package/gsd-core/bin/shared/config-defaults.manifest.json +5 -0
  211. package/gsd-core/bin/shared/config-schema.manifest.json +4 -0
  212. package/gsd-core/references/autonomous-smart-discuss.md +2 -1
  213. package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
  214. package/gsd-core/references/execute-mvp-tdd.md +5 -10
  215. package/gsd-core/references/execute-phase-between-wave-reset.md +3 -0
  216. package/gsd-core/references/execute-phase-response-language.md +1 -1
  217. package/gsd-core/references/gsd-run-resolver.md +1 -1
  218. package/gsd-core/references/loop-hook-dispatch.md +7 -1
  219. package/gsd-core/references/offer-next.md +1 -1
  220. package/gsd-core/references/planning-config.md +1 -1
  221. package/gsd-core/references/spidr-splitting.md +1 -1
  222. package/gsd-core/references/tdd.md +10 -4
  223. package/gsd-core/references/verifier-phase-gates.md +5 -2
  224. package/gsd-core/references/verify-mvp-mode.md +2 -2
  225. package/gsd-core/references/workstream-flag.md +33 -3
  226. package/gsd-core/templates/README.md +1 -1
  227. package/gsd-core/templates/UAT.md +17 -1
  228. package/gsd-core/templates/config.json +2 -11
  229. package/gsd-core/templates/verification-report.md +1 -1
  230. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  231. package/gsd-core/workflows/add-backlog.md +1 -1
  232. package/gsd-core/workflows/add-phase.md +8 -7
  233. package/gsd-core/workflows/add-tests.md +3 -2
  234. package/gsd-core/workflows/add-todo.md +4 -3
  235. package/gsd-core/workflows/ai-integration-phase.md +3 -2
  236. package/gsd-core/workflows/audit-fix.md +1 -1
  237. package/gsd-core/workflows/audit-milestone.md +4 -3
  238. package/gsd-core/workflows/audit-uat.md +1 -1
  239. package/gsd-core/workflows/autonomous.md +28 -18
  240. package/gsd-core/workflows/check-todos.md +6 -5
  241. package/gsd-core/workflows/cleanup.md +1 -1
  242. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
  243. package/gsd-core/workflows/code-review-fix.md +5 -4
  244. package/gsd-core/workflows/code-review.md +84 -90
  245. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
  246. package/gsd-core/workflows/complete-milestone.md +12 -7
  247. package/gsd-core/workflows/debug.md +30 -5
  248. package/gsd-core/workflows/diagnose-issues.md +3 -2
  249. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  250. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  251. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  252. package/gsd-core/workflows/discuss-phase.md +4 -3
  253. package/gsd-core/workflows/do.md +1 -1
  254. package/gsd-core/workflows/docs-update.md +4 -3
  255. package/gsd-core/workflows/edit-phase.md +4 -3
  256. package/gsd-core/workflows/eval-review.md +5 -3
  257. package/gsd-core/workflows/execute-phase/detail/elaboration.md +1 -1
  258. package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +4 -2
  259. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
  260. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
  261. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +1 -1
  262. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
  263. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
  264. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  265. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
  266. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +1 -1
  267. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
  268. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
  269. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
  270. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
  271. package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
  272. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
  273. package/gsd-core/workflows/execute-phase.md +78 -170
  274. package/gsd-core/workflows/execute-plan.md +13 -19
  275. package/gsd-core/workflows/explore.md +2 -2
  276. package/gsd-core/workflows/extract-learnings.md +3 -2
  277. package/gsd-core/workflows/fast.md +1 -1
  278. package/gsd-core/workflows/forensics.md +1 -1
  279. package/gsd-core/workflows/graduation.md +1 -1
  280. package/gsd-core/workflows/health.md +2 -1
  281. package/gsd-core/workflows/import.md +3 -2
  282. package/gsd-core/workflows/inbox.md +1 -1
  283. package/gsd-core/workflows/ingest-docs.md +1 -1
  284. package/gsd-core/workflows/insert-phase.md +4 -3
  285. package/gsd-core/workflows/list-seeds.md +1 -1
  286. package/gsd-core/workflows/list-workspaces.md +1 -1
  287. package/gsd-core/workflows/manager.md +5 -3
  288. package/gsd-core/workflows/map-codebase.md +4 -3
  289. package/gsd-core/workflows/milestone-summary.md +3 -2
  290. package/gsd-core/workflows/mvp-phase.md +14 -14
  291. package/gsd-core/workflows/new-milestone.md +10 -10
  292. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  293. package/gsd-core/workflows/new-project.md +1 -1
  294. package/gsd-core/workflows/new-workspace.md +1 -1
  295. package/gsd-core/workflows/next.md +1 -1
  296. package/gsd-core/workflows/pause-work.md +2 -2
  297. package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
  298. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
  299. package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
  300. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  301. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +1 -1
  302. package/gsd-core/workflows/plan-phase.md +27 -18
  303. package/gsd-core/workflows/plan-review-convergence.md +1 -1
  304. package/gsd-core/workflows/plant-seed.md +1 -1
  305. package/gsd-core/workflows/pr-branch.md +1 -1
  306. package/gsd-core/workflows/profile-user.md +1 -1
  307. package/gsd-core/workflows/progress.md +19 -49
  308. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -2
  309. package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
  310. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
  311. package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
  312. package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
  313. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
  314. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
  315. package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
  316. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
  317. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
  318. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
  319. package/gsd-core/workflows/quick-batch.md +15 -10
  320. package/gsd-core/workflows/quick.md +42 -31
  321. package/gsd-core/workflows/remove-phase.md +3 -2
  322. package/gsd-core/workflows/remove-workspace.md +1 -1
  323. package/gsd-core/workflows/resume-project.md +3 -2
  324. package/gsd-core/workflows/review.md +3 -2
  325. package/gsd-core/workflows/scan.md +3 -2
  326. package/gsd-core/workflows/secure-phase.md +11 -12
  327. package/gsd-core/workflows/settings-advanced.md +1 -1
  328. package/gsd-core/workflows/settings-integrations.md +1 -1
  329. package/gsd-core/workflows/settings.md +1 -1
  330. package/gsd-core/workflows/ship.md +12 -12
  331. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  332. package/gsd-core/workflows/sketch.md +1 -1
  333. package/gsd-core/workflows/smart-entry.md +1 -1
  334. package/gsd-core/workflows/spec-phase.md +1 -1
  335. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  336. package/gsd-core/workflows/spike.md +1 -1
  337. package/gsd-core/workflows/stats.md +1 -1
  338. package/gsd-core/workflows/sync-skills.md +1 -1
  339. package/gsd-core/workflows/thread.md +2 -2
  340. package/gsd-core/workflows/transition.md +13 -23
  341. package/gsd-core/workflows/ui-phase.md +5 -4
  342. package/gsd-core/workflows/ui-review.md +4 -3
  343. package/gsd-core/workflows/ultraplan-phase.md +3 -2
  344. package/gsd-core/workflows/undo.md +1 -1
  345. package/gsd-core/workflows/validate-phase.md +10 -12
  346. package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
  347. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
  348. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
  349. package/gsd-core/workflows/verify-work.md +68 -59
  350. package/hooks/dist/gsd-agent-isolation-guard.js +8 -0
  351. package/hooks/dist/gsd-check-update-worker.js +8 -0
  352. package/hooks/dist/gsd-check-update.js +8 -0
  353. package/hooks/dist/gsd-context-monitor.js +31 -8
  354. package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
  355. package/hooks/dist/gsd-secret-read-guard.js +147 -16
  356. package/hooks/dist/gsd-statusline.js +15 -7
  357. package/hooks/dist/gsd-update-banner.js +8 -0
  358. package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
  359. package/hooks/dist/gsd-workflow-guard.js +5 -4
  360. package/hooks/dist/gsd-worktree-path-guard.js +6 -2
  361. package/hooks/dist/lib/cli-exit.js +12 -0
  362. package/hooks/dist/lib/git-probe.js +17 -1
  363. package/hooks/dist/lib/isolation-sentinel.js +2 -2
  364. package/hooks/gsd-agent-isolation-guard.js +8 -0
  365. package/hooks/gsd-check-update-worker.js +8 -0
  366. package/hooks/gsd-check-update.js +8 -0
  367. package/hooks/gsd-context-monitor.js +31 -8
  368. package/hooks/gsd-cursor-subagent-start.js +8 -0
  369. package/hooks/gsd-secret-read-guard.js +147 -16
  370. package/hooks/gsd-statusline.js +15 -7
  371. package/hooks/gsd-update-banner.js +8 -0
  372. package/hooks/gsd-windsurf-pre-write.js +11 -2
  373. package/hooks/gsd-workflow-guard.js +5 -4
  374. package/hooks/gsd-worktree-path-guard.js +6 -2
  375. package/hooks/hooks.json +5 -5
  376. package/hooks/lib/cli-exit.js +12 -0
  377. package/hooks/lib/git-probe.js +17 -1
  378. package/hooks/lib/isolation-sentinel.js +2 -2
  379. package/package.json +21 -4
  380. package/scripts/changeset/parse.cjs +52 -4
  381. package/scripts/ci-timeout-report.cjs +770 -4
  382. package/scripts/command-contract-helpers.cjs +12 -8
  383. package/scripts/docs-guard-registry.cjs +6 -0
  384. package/scripts/gen-features.cjs +13 -8
  385. package/scripts/gen-hooks-cli-exit.cjs +12 -28
  386. package/scripts/gen-loop-host-contract.cjs +10 -1
  387. package/scripts/gen-platform-conformance-tier.cjs +187 -1
  388. package/scripts/gen-plugin-skills.cjs +87 -1
  389. package/scripts/gen-research-agents.cjs +24 -31
  390. package/scripts/gen-scripts-cli-exit.cjs +30 -3
  391. package/scripts/gen-test-timings.cjs +32 -7
  392. package/scripts/lib/cli-exit.cjs +12 -0
  393. package/scripts/lib/macos-conformance-tier.generated.cjs +20 -2
  394. package/scripts/lib/ndjson-reporter.cjs +28 -3
  395. package/scripts/lib/platform-conformance-tier.generated.cjs +34 -5
  396. package/scripts/lib/registration-ledger-preload.cjs +155 -0
  397. package/scripts/lib/vendor-bundle.cjs +59 -0
  398. package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
  399. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  400. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  401. package/scripts/lint-completion-predicate-drift.cjs +18 -19
  402. package/scripts/lint-descriptions.cjs +7 -3
  403. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +10 -0
  404. package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
  405. package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
  406. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
  407. package/scripts/lint-phase-enumeration-drift.cjs +12 -8
  408. package/scripts/lint-phase-id-drift.cjs +29 -0
  409. package/scripts/lint-planning-document-positive-control.cjs +329 -0
  410. package/scripts/lint-response-language-coverage.cjs +3 -0
  411. package/scripts/lint-skill-deps.cjs +7 -3
  412. package/scripts/lint-test-file-count.allowlist.json +11 -1
  413. package/scripts/lint-test-file-count.cjs +34 -1
  414. package/scripts/lint-vendored-deps.cjs +41 -5
  415. package/scripts/lint-workflow-shellcheck-baseline.json +10 -10
  416. package/scripts/mutation-matrix.cjs +50 -5
  417. package/scripts/require-issue-link-policy.cjs +6 -2
  418. package/scripts/sync-runtime-launcher.cjs +184 -2
  419. package/scripts/verify-npm-publish.cjs +76 -20
  420. package/skills/gsd-add-tests/SKILL.md +6 -1
  421. package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
  422. package/skills/gsd-audit-fix/SKILL.md +5 -0
  423. package/skills/gsd-audit-milestone/SKILL.md +6 -1
  424. package/skills/gsd-autonomous/SKILL.md +5 -0
  425. package/skills/gsd-capture/SKILL.md +8 -4
  426. package/skills/gsd-code-review/SKILL.md +7 -2
  427. package/skills/gsd-complete-milestone/SKILL.md +4 -0
  428. package/skills/gsd-config/SKILL.md +8 -4
  429. package/skills/gsd-debug/SKILL.md +11 -7
  430. package/skills/gsd-discuss-phase/SKILL.md +7 -3
  431. package/skills/gsd-docs-update/SKILL.md +12 -7
  432. package/skills/gsd-eval-review/SKILL.md +6 -1
  433. package/skills/gsd-execute-phase/SKILL.md +12 -7
  434. package/skills/gsd-extract-learnings/SKILL.md +5 -0
  435. package/skills/gsd-fast/SKILL.md +4 -0
  436. package/skills/gsd-forensics/SKILL.md +5 -1
  437. package/skills/gsd-graphify/SKILL.md +10 -6
  438. package/skills/gsd-health/SKILL.md +5 -0
  439. package/skills/gsd-help/SKILL.md +7 -2
  440. package/skills/gsd-import/SKILL.md +7 -3
  441. package/skills/gsd-inbox/SKILL.md +5 -0
  442. package/skills/gsd-ingest-docs/SKILL.md +5 -1
  443. package/skills/gsd-manager/SKILL.md +6 -1
  444. package/skills/gsd-map-codebase/SKILL.md +7 -3
  445. package/skills/gsd-mempalace-capture/SKILL.md +5 -1
  446. package/skills/gsd-mempalace-recall/SKILL.md +5 -1
  447. package/skills/gsd-milestone-summary/SKILL.md +5 -1
  448. package/skills/gsd-mvp-phase/SKILL.md +8 -3
  449. package/skills/gsd-new-milestone/SKILL.md +6 -1
  450. package/skills/gsd-new-project/SKILL.md +5 -0
  451. package/skills/gsd-next/SKILL.md +6 -1
  452. package/skills/gsd-ns-context/SKILL.md +4 -0
  453. package/skills/gsd-ns-ideate/SKILL.md +4 -0
  454. package/skills/gsd-ns-manage/SKILL.md +4 -0
  455. package/skills/gsd-ns-project/SKILL.md +4 -0
  456. package/skills/gsd-ns-review/SKILL.md +4 -0
  457. package/skills/gsd-ns-workflow/SKILL.md +4 -0
  458. package/skills/gsd-onboard/SKILL.md +6 -1
  459. package/skills/gsd-pause-work/SKILL.md +5 -1
  460. package/skills/gsd-phase/SKILL.md +8 -4
  461. package/skills/gsd-plan-phase/SKILL.md +6 -1
  462. package/skills/gsd-plan-review-convergence/SKILL.md +5 -1
  463. package/skills/gsd-pr-branch/SKILL.md +4 -0
  464. package/skills/gsd-profile-user/SKILL.md +5 -1
  465. package/skills/gsd-progress/SKILL.md +6 -1
  466. package/skills/gsd-quick/SKILL.md +16 -10
  467. package/skills/gsd-quick-batch/SKILL.md +20 -8
  468. package/skills/gsd-review/SKILL.md +5 -1
  469. package/skills/gsd-review-backlog/SKILL.md +3 -2
  470. package/skills/gsd-secure-phase/SKILL.md +6 -1
  471. package/skills/gsd-ship/SKILL.md +5 -0
  472. package/skills/gsd-sketch/SKILL.md +7 -2
  473. package/skills/gsd-spec-phase/SKILL.md +5 -1
  474. package/skills/gsd-spike/SKILL.md +8 -3
  475. package/skills/gsd-surface/SKILL.md +5 -1
  476. package/skills/gsd-thread/SKILL.md +4 -0
  477. package/skills/gsd-ui-phase/SKILL.md +6 -1
  478. package/skills/gsd-ui-review/SKILL.md +6 -1
  479. package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
  480. package/skills/gsd-undo/SKILL.md +5 -1
  481. package/skills/gsd-update/SKILL.md +6 -2
  482. package/skills/gsd-validate-phase/SKILL.md +6 -1
  483. package/skills/gsd-verify-work/SKILL.md +6 -1
  484. package/skills/gsd-workspace/SKILL.md +7 -3
  485. package/skills/gsd-workstreams/SKILL.md +6 -6
  486. package/vscode/package.json +1 -1
  487. package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +0 -24
@@ -45,16 +45,18 @@ const { loadConfig: loadConfigForScope } = configLoaderForScope;
45
45
  const scanPhasePlans = require("./plan-scan.cjs");
46
46
  // eslint-disable-next-line @typescript-eslint/no-require-imports
47
47
  const coreUtils = require("./core-utils.cjs");
48
- const { countMatchedSummaries, findUnsummarizedPlans } = coreUtils;
48
+ const { findUnsummarizedPlans } = coreUtils;
49
49
  // eslint-disable-next-line @typescript-eslint/no-require-imports
50
50
  const frontmatter = require("./frontmatter.cjs");
51
- const { extractFrontmatter, parseMustHavesBlock } = frontmatter;
51
+ const { extractFrontmatter, frontmatterRegion, parseMustHavesBlock } = frontmatter;
52
52
  // eslint-disable-next-line @typescript-eslint/no-require-imports
53
53
  const verificationMod = require("./verification.cjs");
54
- const { isPhaseComplete } = verificationMod;
54
+ const { isPhaseComplete, failOnVerificationStatusError, firstStatusError } = verificationMod;
55
55
  // #4906 Phase 2 (#4917/ADR-4910): the PlanningDoc parse -> mutate -> serialize
56
56
  // seam, mirroring phase.cts's already-migrated `writePlansField` site.
57
57
  const planning_document_cjs_1 = require("./planning-document.cjs");
58
+ // #5060: the Phase Status Module owns the ladder; roadmap.cts is a consumer.
59
+ const phase_status_cjs_1 = require("./phase-status.cjs");
58
60
  // ─── coerceTruthToString ──────────────────────────────────────────────────────
59
61
  /**
60
62
  * Coerce an arbitrary YAML scalar/object into a string for cross-cutting
@@ -212,7 +214,8 @@ function searchPhaseInContent(content, escapedPhase, phaseNum, convention) {
212
214
  * Returns the phase section string if found, null if ROADMAP.md is missing,
213
215
  * or throws if ROADMAP.md read fails.
214
216
  *
215
- * Used by check-command-router (computeUiPlanGate) so ui-plan-gate uses the SAME
217
+ * Used by the shared gate phase context (lookupRoadmapPhase in gate-phase-context.cts, which
218
+ * computeUiPlanGate in gate-ui-plan.cts calls) so ui-plan-gate uses the SAME
216
219
  * phase resolution as `roadmap.get-phase` — not a milestone-only subset.
217
220
  */
218
221
  function getRoadmapPhaseWithFallback(cwd, phaseNum) {
@@ -310,6 +313,14 @@ function cmdRoadmapGetPhase(cwd, phaseNum, raw) {
310
313
  error('Failed to read ROADMAP.md: ' + e.message);
311
314
  }
312
315
  }
316
+ /**
317
+ * #4757: the phase records whose `roadmap_complete` was READ from a ROADMAP
318
+ * checkbox. Table rows and headings with no checklist entry also report
319
+ * `roadmap_complete: false`, but there is no checkbox behind it, so they must
320
+ * not be compared against disk status by `checkbox_conflict`. A WeakSet keeps
321
+ * this out of the emitted `phases[]` shape.
322
+ */
323
+ const PHASES_WITH_CHECKBOX = new WeakSet();
313
324
  // #612 composes the convention-qualified sentinel reading with upstream's
314
325
  // canonical legacy sentinel owner. A reserved bracket milestone OR a reserved
315
326
  // phase token excludes the occurrence.
@@ -373,6 +384,7 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
373
384
  // The caller needs the exact occurrence identities from the same scan that
374
385
  // built `phases`; returning them together also keeps fallback rescans atomic.
375
386
  const detailKeys = new Set();
387
+ let statusError;
376
388
  while ((match = phasePattern.exec(content)) !== null) {
377
389
  const bracketId = G ? match[1] : undefined;
378
390
  const phaseNum = match[1 + G];
@@ -402,7 +414,7 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
402
414
  const depends_on = dependsMatch ? dependsMatch[1].trim() : null;
403
415
  // Check completion on disk
404
416
  const normalized = normalizePhaseName(phaseNum);
405
- let diskStatus = 'no_directory';
417
+ let diskStatus = phase_status_cjs_1.DISK_STATUS.NO_DIRECTORY;
406
418
  let planCount = 0;
407
419
  let summaryCount = 0;
408
420
  let hasContext = false;
@@ -446,33 +458,32 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
446
458
  hasResearch = counts.hasResearch;
447
459
  contextReadError = counts.contextReadError;
448
460
  contextScope = counts.scope;
449
- // ADR-3180 §7.4 (issue #3186, disk-strict, #3168 fix): route "is this
450
- // phase complete" through the canonical owner (`isPhaseComplete`),
451
- // which calls readVerificationStatus UNCONDITIONALLY — plan count is
452
- // NOT a precondition, so a zero-plan phase with a passing
453
- // `*-VERIFICATION.md` reports complete here too, not just via
454
- // `phase.complete`.
455
- // #612: `convention` (a parameter of this function, same thread as
456
- // matchPhaseDirs above) rides into completion so a bracket phase dir
457
- // resolves and scopes its verification report like its legacy twin.
458
- const completionResult = isPhaseComplete(node_path_1.default.join(phasesDir, dirMatch), { convention });
459
- if (completionResult.value.complete)
460
- diskStatus = 'complete';
461
- else if (summaryCount > 0)
462
- diskStatus = 'partial';
463
- else if (planCount > 0)
464
- diskStatus = 'planned';
465
- else if (hasResearch)
466
- diskStatus = 'researched';
467
- else if (hasContext)
468
- diskStatus = 'discussed';
469
- else
470
- diskStatus = 'empty';
461
+ // #5060: route the disk-status ladder through the Phase Status Module's
462
+ // single owner (`phaseStatus`/`toDiskStatus`) rather than a local
463
+ // if/else re-derivation. `convention` still threads through so a
464
+ // bracket phase's verification report resolves and scopes like its
465
+ // legacy twin (#612).
466
+ const ps = (0, phase_status_cjs_1.phaseStatus)(node_path_1.default.join(phasesDir, dirMatch), { convention });
467
+ statusError = firstStatusError(statusError, ps.value.statusError);
468
+ diskStatus = (0, phase_status_cjs_1.toDiskStatus)(ps.value.status, { hasResearch, hasContext });
471
469
  }
472
- // Check ROADMAP checkbox status. #3537: padding-tolerant fragment — the
473
- // heading discovered above may use a different padding than the
474
- // summary-bullet checkbox below it (mixed padding inside one ROADMAP is
475
- // legal and seen in real projects).
470
+ // Check ROADMAP checkbox status. #4965: line-anchored, label-first — the
471
+ // old fragment allowed `\s*.*` between the checkbox and the label, which
472
+ // let "Phase N" match ANYWHERE in any checklist line's free-form
473
+ // description (not just this phase's own line), and `content.match`
474
+ // returns only the first hit in the document — so an earlier, unrelated
475
+ // line whose prose merely mentioned "Phase N" shadowed that phase's own
476
+ // checkbox state (both a false negative and a false positive were
477
+ // reported against real ROADMAPs). The label must now be the first thing
478
+ // after the checkbox, tolerating only an optional `**` bold marker and
479
+ // horizontal whitespace — matching `cmdRoadmapAnalyze`'s own
480
+ // `checklistPattern` (the missing-detail-section scan a bit further down
481
+ // in this file), which already hard-requires `\*\*` immediately after the
482
+ // checkbox for the same reason. A decoration the old `.*` used to tolerate
483
+ // by accident — a blockquoted bullet, an emoji/badge before the label —
484
+ // now resolves to `roadmap_complete: false` instead of matching; this is
485
+ // the deliberate, precedent-consistent narrowing (see 10-diagnosis.md's
486
+ // "Negative space" note), not a new gap.
476
487
  //
477
488
  // ADR-3180 §7.4 (disk-strict, #2957, maintainer decision 2026-08-08):
478
489
  // `roadmapComplete` is reported below as metadata ONLY — it carries NO
@@ -483,10 +494,10 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
483
494
  // checkbox — no passing `*-VERIFICATION.md`, plans outstanding — now
484
495
  // reports incomplete; this is the deliberate Tier-2 break (ADR-3180 §7.4
485
496
  // Decision 3).
486
- const checkboxPattern = new RegExp(`-\\s*\\[(x| )\\]\\s*.*${phaseHeadingPrefixSrcFor(PHASE_HEADING_BASELINE.LABEL_ONLY, convention)}${phaseMarkdownRegexSource(phaseNum)}${OPTIONAL_PHASE_TAG_SOURCE}[:\\s]`, 'i');
497
+ const checkboxPattern = new RegExp(`^[ \\t]*-[ \\t]*\\[(x| )\\][ \\t]*(?:\\*\\*)?${phaseHeadingPrefixSrcFor(PHASE_HEADING_BASELINE.LABEL_ONLY, convention)}${phaseMarkdownRegexSource(phaseNum)}${OPTIONAL_PHASE_TAG_SOURCE}[:\\s]`, 'im');
487
498
  const checkboxMatch = content.match(checkboxPattern);
488
499
  const roadmapComplete = checkboxMatch ? checkboxMatch[1] === 'x' : false;
489
- phases.push({
500
+ const headingPhase = {
490
501
  number: phaseNum,
491
502
  name: phaseName,
492
503
  goal,
@@ -500,7 +511,10 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
500
511
  roadmap_complete: roadmapComplete,
501
512
  context_read_error: contextReadError,
502
513
  context_scope: contextScope,
503
- });
514
+ };
515
+ if (checkboxMatch)
516
+ PHASES_WITH_CHECKBOX.add(headingPhase);
517
+ phases.push(headingPhase);
504
518
  }
505
519
  // #3577: markdown-table row declarations join the enumeration — same
506
520
  // enrichment contract as headings (disk counts when the directory exists),
@@ -514,7 +528,7 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
514
528
  detailKeys.add(occurrenceKey(tr.id));
515
529
  if (seen.has(stripPadA(tr.id)))
516
530
  continue;
517
- const dirMatchA = matchPhaseDirs(phaseDirNames, normalizePhaseName(tr.id)).matches[0];
531
+ const dirMatchA = matchPhaseDirs(phaseDirNames, normalizePhaseName(tr.id), convention).matches[0];
518
532
  let tPlanCount = 0;
519
533
  let tSummaryCount = 0;
520
534
  let tHasContext = false;
@@ -523,8 +537,9 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
523
537
  // #4014 (epic #3473 B4): additive sibling, same default rule as the
524
538
  // heading-declared branch above.
525
539
  let tContextScope = SCOPE.COMPLETE;
540
+ let tDiskStatus = phase_status_cjs_1.DISK_STATUS.NO_DIRECTORY;
526
541
  if (dirMatchA) {
527
- const counts = countPhasePlansAndSummaries(node_path_1.default.join(phasesDir, dirMatchA));
542
+ const counts = countPhasePlansAndSummaries(node_path_1.default.join(phasesDir, dirMatchA), convention);
528
543
  tPlanCount = counts.planCount;
529
544
  tSummaryCount = counts.summaryCount;
530
545
  tHasContext = node_fs_1.default.existsSync(node_path_1.default.join(phasesDir, dirMatchA, 'CONTEXT.md'));
@@ -535,6 +550,11 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
535
550
  // an unreadable phase directory is still surfaced via the sibling call.
536
551
  tContextReadError = counts.contextReadError;
537
552
  tContextScope = counts.scope;
553
+ // #5060: route through the Phase Status Module's owner rather than the
554
+ // fixed 'ok' sentinel this row used to emit.
555
+ const tps = (0, phase_status_cjs_1.phaseStatus)(node_path_1.default.join(phasesDir, dirMatchA), { convention });
556
+ statusError = firstStatusError(statusError, tps.value.statusError);
557
+ tDiskStatus = (0, phase_status_cjs_1.toDiskStatus)(tps.value.status, { hasResearch: tHasResearch, hasContext: tHasContext });
538
558
  }
539
559
  phases.push({
540
560
  number: tr.id,
@@ -546,13 +566,13 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
546
566
  summary_count: tSummaryCount,
547
567
  has_context: tHasContext,
548
568
  has_research: tHasResearch,
549
- disk_status: dirMatchA ? 'ok' : 'no_directory',
569
+ disk_status: tDiskStatus,
550
570
  roadmap_complete: false,
551
571
  context_read_error: tContextReadError,
552
572
  context_scope: tContextScope,
553
573
  });
554
574
  }
555
- return { phases, detailKeys };
575
+ return { phases, detailKeys, statusError };
556
576
  }
557
577
  function cmdRoadmapAnalyze(cwd, raw) {
558
578
  const roadmapPath = planningPaths(cwd).roadmap;
@@ -588,6 +608,8 @@ function cmdRoadmapAnalyze(cwd, raw) {
588
608
  let collected = collectAnalyzePhases(content, phasesDir, _phaseDirNames, convention);
589
609
  let phases = collected.phases;
590
610
  let detailKeys = collected.detailKeys;
611
+ // #5118: carried from every phaseStatus read this command makes.
612
+ let statusError = collected.statusError;
591
613
  // `effectiveContent` is what the downstream checklist scan (missing_details)
592
614
  // iterates. Defaults to the scoped window; switched to the fallback document
593
615
  // when the recovery path below fires, so a phase found via fallback is not
@@ -614,6 +636,7 @@ function cmdRoadmapAnalyze(cwd, raw) {
614
636
  collected = fallbackCollection;
615
637
  phases = collected.phases;
616
638
  detailKeys = collected.detailKeys;
639
+ statusError = firstStatusError(statusError, collected.statusError);
617
640
  effectiveContent = fallbackContent;
618
641
  }
619
642
  }
@@ -626,12 +649,12 @@ function cmdRoadmapAnalyze(cwd, raw) {
626
649
  version: m.version,
627
650
  }));
628
651
  // Find current and next phase
629
- const currentPhase = phases.find(p => p.disk_status === 'planned' || p.disk_status === 'partial') || null;
630
- const nextPhase = phases.find(p => p.disk_status === 'empty' || p.disk_status === 'no_directory' || p.disk_status === 'discussed' || p.disk_status === 'researched') || null;
652
+ const currentPhase = phases.find(p => p.disk_status === phase_status_cjs_1.DISK_STATUS.PLANNED || p.disk_status === phase_status_cjs_1.DISK_STATUS.PARTIAL || p.disk_status === phase_status_cjs_1.DISK_STATUS.EXECUTED) || null;
653
+ const nextPhase = phases.find(p => p.disk_status === phase_status_cjs_1.DISK_STATUS.EMPTY || p.disk_status === phase_status_cjs_1.DISK_STATUS.NO_DIRECTORY || p.disk_status === phase_status_cjs_1.DISK_STATUS.DISCUSSED || p.disk_status === phase_status_cjs_1.DISK_STATUS.RESEARCHED) || null;
631
654
  // Aggregated stats
632
655
  const totalPlans = phases.reduce((sum, p) => sum + p.plan_count, 0);
633
656
  const totalSummaries = phases.reduce((sum, p) => sum + p.summary_count, 0);
634
- const completedPhases = phases.filter(p => p.disk_status === 'complete').length;
657
+ const completedPhases = phases.filter(p => p.disk_status === phase_status_cjs_1.DISK_STATUS.COMPLETE).length;
635
658
  // Detect phases in summary list without detail sections (malformed ROADMAP).
636
659
  // The char class must allow `-` (not just `.`) so dash-separated milestone-prefixed
637
660
  // IDs (e.g. `1-01`) match the detail-heading scanner above; otherwise they truncate
@@ -718,21 +741,12 @@ function cmdRoadmapAnalyze(cwd, raw) {
718
741
  hasResearch = counts.hasResearch;
719
742
  contextReadError = counts.contextReadError;
720
743
  contextScope = counts.scope;
721
- const completionResult = isPhaseComplete(node_path_1.default.join(phasesDir, dirMatch), { convention });
722
- if (completionResult.value.complete)
723
- diskStatus = 'complete';
724
- else if (summaryCount > 0)
725
- diskStatus = 'partial';
726
- else if (planCount > 0)
727
- diskStatus = 'planned';
728
- else if (hasResearch)
729
- diskStatus = 'researched';
730
- else if (hasContext)
731
- diskStatus = 'discussed';
732
- else
733
- diskStatus = 'empty';
744
+ // #5060: same owner call as the heading branch above.
745
+ const ps = (0, phase_status_cjs_1.phaseStatus)(node_path_1.default.join(phasesDir, dirMatch), { convention });
746
+ statusError = firstStatusError(statusError, ps.value.statusError);
747
+ diskStatus = (0, phase_status_cjs_1.toDiskStatus)(ps.value.status, { hasResearch, hasContext });
734
748
  }
735
- phases.push({
749
+ const synthesized = {
736
750
  number: occ.token,
737
751
  name: `Phase ${occ.token}`,
738
752
  goal: null,
@@ -746,7 +760,9 @@ function cmdRoadmapAnalyze(cwd, raw) {
746
760
  roadmap_complete: occ.checked,
747
761
  context_read_error: contextReadError,
748
762
  context_scope: contextScope,
749
- });
763
+ };
764
+ PHASES_WITH_CHECKBOX.add(synthesized);
765
+ phases.push(synthesized);
750
766
  }
751
767
  }
752
768
  // The EMITTED value stays the bare token, unchanged: `phases[].number` is a
@@ -790,6 +806,29 @@ function cmdRoadmapAnalyze(cwd, raw) {
790
806
  const progressPercent = progressScope === SCOPE.COMPLETE
791
807
  ? (0, phase_lifecycle_cjs_1.clampPercent)(scopedTotalSummaries, scopedTotalPlans)
792
808
  : null;
809
+ // #4757: `current_phase` / `next_phase` / `completed_phases` are disk-
810
+ // authoritative (ADR-3180 §7.4, #2957 — a ticked ROADMAP checkbox carries no
811
+ // machine authority), so a phase whose checkbox disagrees with its disk
812
+ // status can be handed back as the phase to work on while the operator has
813
+ // already ticked it (a backfilled phase with a SUMMARY and no PLAN reads
814
+ // `empty`; an all-summarized phase with no VERIFICATION reads `executed`), or
815
+ // withheld from `completed_phases` while ticked-complete. The selectors stay
816
+ // disk-authoritative; the disagreement is SURFACED here rather than silently
817
+ // resolved either way. Computed after the heading/table/checklist phase
818
+ // enumeration is final so synthesized phases are covered too. Only phases
819
+ // that HAVE a checkbox can conflict: a progress-table row or a heading with
820
+ // no checklist entry reports `roadmap_complete: false` because there is no
821
+ // checkbox to read, not because one is unticked.
822
+ const checkboxConflict = phases
823
+ .filter(p => PHASES_WITH_CHECKBOX.has(p)
824
+ && p.roadmap_complete !== (p.disk_status === phase_status_cjs_1.DISK_STATUS.COMPLETE))
825
+ .map(p => ({
826
+ number: p.number,
827
+ roadmap_complete: p.roadmap_complete,
828
+ disk_status: p.disk_status,
829
+ plan_count: p.plan_count,
830
+ summary_count: p.summary_count,
831
+ }));
793
832
  const result = {
794
833
  milestones,
795
834
  phases,
@@ -817,6 +856,9 @@ function cmdRoadmapAnalyze(cwd, raw) {
817
856
  progress_scope: progressScope,
818
857
  current_phase: currentPhase ? currentPhase.number : null,
819
858
  next_phase: nextPhase ? nextPhase.number : null,
859
+ // #4757: phases whose ROADMAP checkbox disagrees with `disk_status`
860
+ // (`roadmap_complete` vs `disk_status === "complete"`); always an array.
861
+ checkbox_conflict: checkboxConflict,
820
862
  missing_phase_details: missingDetails.length > 0 ? missingDetails : null,
821
863
  // #3184/#3165: distinguishes a genuinely empty milestone (`scope:
822
864
  // "complete"`, `phase_count: 0`) from a window that could not be fully
@@ -824,6 +866,10 @@ function cmdRoadmapAnalyze(cwd, raw) {
824
866
  // were previously output-identical.
825
867
  scope,
826
868
  };
869
+ // #5118: a read-only aggregate over a refused report prints nothing and
870
+ // fails with the error's own reason.
871
+ if (statusError)
872
+ failOnVerificationStatusError(statusError);
827
873
  output(result, raw, undefined);
828
874
  }
829
875
  // ─── cmdRoadmapMilestoneScope ────────────────────────────────────────────────
@@ -867,11 +913,11 @@ function cmdRoadmapMilestoneScope(cwd, raw) {
867
913
  phaseIdConvention = undefined;
868
914
  }
869
915
  if (phaseIdConvention === undefined || phaseIdConvention === null) {
870
- // Bounded per local/no-unbounded-quantifier (#2128): frontmatter is a
871
- // short header block — 4KB is orders of magnitude beyond any real one.
872
- const fmMatch = rawContent.match(/^---\r?\n([\s\S]{0,4000}?)\r?\n---/);
873
- if (fmMatch) {
874
- const kvMatch = fmMatch[1].match(/^phase_id_convention:\s*(.*)$/m);
916
+ // The block is the one the one fence owner finds (`frontmatterRegion`), the same one
917
+ // `roadmap validate` reads, so the two cannot disagree on where it ends (#3641 NEW-1).
918
+ const found = frontmatterRegion(rawContent);
919
+ if (found?.terminated) {
920
+ const kvMatch = found.region.match(/^phase_id_convention:\s*(.*)$/m);
875
921
  if (kvMatch) {
876
922
  const val = kvMatch[1].trim();
877
923
  if (val !== 'null' && val !== '') {
@@ -928,11 +974,20 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
928
974
  if (!phaseInfo) {
929
975
  error(`Phase ${phaseNum} not found`);
930
976
  }
931
- const planCount = phaseInfo.plans.length;
932
- // Count only summaries that pair with a real plan (#1988): stray non-plan
933
- // summaries (30-FIX-CR02-SUMMARY.md, 30-GAPCLOSURE-SUMMARY.md, …) must not
934
- // inflate summary_count and silently flip the phase to Complete.
935
- const summaryCount = countMatchedSummaries(phaseInfo.plans, phaseInfo.summaries);
977
+ const phaseDir = node_path_1.default.join(cwd, phaseInfo.directory);
978
+ // #5060: ONE count source for this verb — `scanPhasePlans` (the ADR-3180
979
+ // §7.5 count owner) — rather than `phaseInfo.plans.length` /
980
+ // `countMatchedSummaries(phaseInfo.plans, phaseInfo.summaries)`. The two
981
+ // diverge when a plan's frontmatter declares `status: superseded`:
982
+ // scanPhasePlans excludes it (and its summary) from both counts (#2349),
983
+ // the phaseInfo-based counts do not. Using scanPhasePlans everywhere in
984
+ // this verb — the `planCount === 0` decline, the `Plans Complete` cell,
985
+ // the `Plans:` line, the checkbox gate, and the JSON output — keeps every
986
+ // one of those in agreement with the Status-cell ladder below, which
987
+ // already read scanPhasePlans's counts.
988
+ const coverageScan = scanPhasePlans(phaseDir);
989
+ const planCount = coverageScan.planCount;
990
+ const summaryCount = coverageScan.summaryCount;
936
991
  if (planCount === 0) {
937
992
  declineNoOp(raw, 'updated', 'No plans found', 'roadmap update-plan-progress skipped — no plans found for this phase. ROADMAP.md was left unchanged.', { plan_count: 0, summary_count: 0 });
938
993
  return;
@@ -949,12 +1004,15 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
949
1004
  // agrees with `roadmap analyze` / `init manager` / `phase complete` for
950
1005
  // the same phase (ADR-3180 §7.4's headline: one predicate for the read
951
1006
  // path and the write path).
952
- const phaseDir = node_path_1.default.join(cwd, phaseInfo.directory);
953
1007
  // ADR-3180 §7.4 read/write-path symmetry with the threaded site at ~583:
954
1008
  // thread convention here too, so this write path's completion reading
955
1009
  // agrees with the read path's under the bracket convention.
956
1010
  const convention = resolvePhaseIdConvention(cwd);
957
1011
  const completionResult = isPhaseComplete(phaseDir, { convention });
1012
+ // #5118: no write before the error — a report whose `status` is outside the
1013
+ // closed set fails this writer before ROADMAP.md is touched.
1014
+ if (completionResult.value.statusError)
1015
+ failOnVerificationStatusError(completionResult.value.statusError);
958
1016
  const verificationResult = completionResult.value.verification;
959
1017
  // #2648 precedent, applied at this write site (ADR-3180 §7.4 / #3186):
960
1018
  // `isPhaseComplete` deliberately carries NO plan-count precondition — the
@@ -970,14 +1028,29 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
970
1028
  // (phase.cts:~1995, #2648: "a coverage gate that passes when it cannot
971
1029
  // read the plans is no gate at all"), composed explicitly here rather than
972
1030
  // folded into the predicate: complete AND all plans executed.
973
- const coverageScan = scanPhasePlans(phaseDir);
1031
+ // #5060: `coverageScan` (declared above, before the `planCount === 0`
1032
+ // decline) is now this verb's ONE count source — the `Plans Complete`
1033
+ // cell, the `Plans:` line, the checkbox gate, the JSON output, and the
1034
+ // Status-cell ladder below all read `planCount`/`summaryCount` from it, so
1035
+ // a phase with a `status: superseded` plan (#2349) reports the same
1036
+ // counts everywhere instead of diverging between the ladder and the rest
1037
+ // of this verb's output.
974
1038
  const unsummarizedPlans = findUnsummarizedPlans(coverageScan.planFiles, coverageScan.summaryFiles);
975
1039
  const isComplete = completionResult.value.complete && unsummarizedPlans.length === 0;
976
1040
  // #3057 B3: routing above is unchanged (an indeterminate staleness check
977
1041
  // still routes as if nothing were stale) — this only makes the fact visible
978
1042
  // to whatever reads this command's JSON output.
979
- const verificationStaleCheckIndeterminate = verificationResult.staleCheckIndeterminate === true;
980
- const status = isComplete ? 'Complete' : summaryCount > 0 ? 'In Progress' : 'Planned';
1043
+ const verificationStaleCheckIndeterminate = 'staleCheckIndeterminate' in verificationResult && verificationResult.staleCheckIndeterminate === true;
1044
+ // #5060: route the Status-cell token through the Phase Status Module's
1045
+ // owner ladder rather than a local if/else, over the same `planCount`/
1046
+ // `summaryCount` (from `coverageScan`) every other output in this verb
1047
+ // uses.
1048
+ const status = (0, phase_status_cjs_1.toRoadmapStatusCell)((0, phase_status_cjs_1.phaseStatusFromFacts)({
1049
+ planCount,
1050
+ summaryCount,
1051
+ complete: isComplete,
1052
+ verificationStatus: verificationResult.status,
1053
+ }));
981
1054
  const today = clock_cjs_1.realClock.localToday();
982
1055
  if (!node_fs_1.default.existsSync(roadmapPath)) {
983
1056
  declineNoOp(raw, 'updated', 'ROADMAP.md not found', 'roadmap update-plan-progress skipped — ROADMAP.md not found.', { plan_count: planCount, summary_count: summaryCount });
@@ -1068,7 +1141,29 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
1068
1141
  text = plansResult.value;
1069
1142
  tableRowFound = true;
1070
1143
  }
1071
- const statusResult = (0, markdown_table_cjs_1.updateTableCell)(text, rowMatch, 'Status', ` ${status.padEnd(11)}`);
1144
+ // #4925: the verb owns the Status cell's leading status TOKEN only — the
1145
+ // same split #2853/#3584 made for the `Plans:` line below. It used to
1146
+ // overwrite the whole cell with ` ${status.padEnd(11)}` (no trailing
1147
+ // space), discarding any operator prose kept after the token. Three arms:
1148
+ // 1. empty or a dash placeholder → write the token, padded exactly as
1149
+ // phase complete writes ` Complete ` (phase.cts).
1150
+ // 2. a leading status token → rewrite the token only and keep the prose
1151
+ // after it; an unchanged token leaves the cell byte-identical.
1152
+ // 3. freeform prose with no leading token → operator-owned, untouched.
1153
+ // #5060: routed through the Phase Status Module's `matchRoadmapStatusCell`
1154
+ // owner rather than a local statusTokenRe. `ROADMAP_STATUS_TOKEN.DEFERRED`
1155
+ // is now a recognized token (the old regex never matched "deferred" at
1156
+ // all, so a Deferred cell fell through to arm 3 unchanged) — the DEFERRED
1157
+ // guard below preserves that same "leave it alone" outcome explicitly.
1158
+ const statusResult = (0, markdown_table_cjs_1.updateTableCell)(text, rowMatch, 'Status', (current) => {
1159
+ if (current === '' || /^[-–—]$/.test(current))
1160
+ return ` ${status.padEnd(11)} `;
1161
+ const m = (0, phase_status_cjs_1.matchRoadmapStatusCell)(current);
1162
+ if (!m || m.token === phase_status_cjs_1.ROADMAP_STATUS_TOKEN.DEFERRED || m.text === status)
1163
+ return current;
1164
+ const rest = current.slice(m.text.length);
1165
+ return rest === '' ? ` ${status.padEnd(11)} ` : ` ${(0, markdown_table_cjs_1.escapeCell)(status + rest)} `;
1166
+ });
1072
1167
  if (statusResult.ok) {
1073
1168
  text = statusResult.value;
1074
1169
  tableRowFound = true;
@@ -1085,7 +1180,9 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
1085
1180
  if (isComplete) {
1086
1181
  return dateShape.test(current.trim()) ? current : ` ${today} `;
1087
1182
  }
1088
- return ' ';
1183
+ // #4925: only a stale ISO completion date — this verb's own stamp — is
1184
+ // cleared; a `-` placeholder or operator text stays byte-identical.
1185
+ return dateShape.test(current) ? ' ' : current;
1089
1186
  });
1090
1187
  if (completedResult.ok) {
1091
1188
  text = completedResult.value;