@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
@@ -46,14 +46,19 @@ const planDocument = require("./plan-document.cjs");
46
46
  const state_document_cjs_1 = require("./state-document.cjs");
47
47
  const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
48
48
  const host_runtime_detection_cjs_1 = require("./host-runtime-detection.cjs");
49
- // eslint-disable-next-line @typescript-eslint/no-require-imports -- commands.cjs is an export= CommonJS module
50
- const commandsMod = require("./commands.cjs");
51
49
  const security_cjs_1 = require("./security.cjs");
52
50
  const runtime_homes_cjs_1 = require("./runtime-homes.cjs");
53
51
  // eslint-disable-next-line @typescript-eslint/no-require-imports -- frontmatter.cjs is an export= CommonJS module
54
52
  const frontmatterMod = require("./frontmatter.cjs");
55
53
  // eslint-disable-next-line @typescript-eslint/no-require-imports -- verification.cjs is an export= CommonJS module
56
54
  const verificationMod = require("./verification.cjs");
55
+ // #5060: Phase Status Module — the single owner of "what state is phase P
56
+ // in?" (ADR-5057 §1/§2). Replaces this file's own determinePhaseStatus/
57
+ // projectCompletionStatus derivations, and cmdInitMilestoneOp's
58
+ // summary-count-only completion check (the former listPhaseSummaryFiles
59
+ // helper, since removed). listPhasePlanFiles (below) is unrelated — it backs
60
+ // only the STATE.md disk-plan-count validation, not a completion verdict.
61
+ const phase_status_cjs_1 = require("./phase-status.cjs");
57
62
  // eslint-disable-next-line @typescript-eslint/no-require-imports -- uat-predicate.cjs is an export= CommonJS module
58
63
  const uatPredicateMod = require("./uat-predicate.cjs");
59
64
  // eslint-disable-next-line @typescript-eslint/no-require-imports -- agent-install-check.cjs is an export= CommonJS module
@@ -91,10 +96,9 @@ const { getRoadmapPhaseInternal, getMilestoneInfo, stripShippedMilestones, extra
91
96
  const { pathExistsInternal, generateSlugInternal, toPosixPath } = coreUtils;
92
97
  const { comparePhaseNum, normalizePhaseName, stripProjectCodePrefix, PHASE_NUMBER_TOKEN_SOURCE, PHASE_DEP_REF_SOURCE, isForeignPrefixedPhaseQuery, isSentinelPhaseId, extractPhaseToken, scopeToPhase, renderPhaseBranchName, parsePhaseId, renderPhaseId, phaseHeadingPrefixSrcFor, PHASE_HEADING_BASELINE, buildPhaseHeadingScanRegex, } = phaseId;
93
98
  const { pruneOrphanedWorktrees } = worktreeSafety;
94
- const { planningPaths, planningDir, planningRoot, todosDir, listAvailableWorkstreams, peekActiveWorkstream, resolveEnvWorkstream, diagnoseUnresolvedActiveWorkstream, describeUnresolvedWorkstreamReason, findContextMdIn, resolvePhaseIdConvention, } = planningWorkspace;
95
- const { determinePhaseStatus } = commandsMod;
96
- const { extractFrontmatter } = frontmatterMod;
97
- const { isPhaseComplete, resolveVerificationFile, resolveUatFile } = verificationMod;
99
+ const { planningPaths, planningDir, planningRoot, todosDir, listAvailableWorkstreams, peekActiveWorkstream, resolveEnvWorkstream, diagnoseUnresolvedActiveWorkstream, describeUnresolvedWorkstreamReason, findContextMdIn, resolvePhaseIdConvention, worktreesOptedOut, } = planningWorkspace;
100
+ const { extractFrontmatter, frontmatterBlock } = frontmatterMod;
101
+ const { isPhaseComplete, resolveVerificationFile, resolveUatFile, VERIFICATION_STATUS, VerificationStatusError } = verificationMod;
98
102
  const { evaluateUatPassed } = uatPredicateMod;
99
103
  const { resolveLoopHooks } = loopResolverMod;
100
104
  const { loadRegistry } = capabilityLoaderMod;
@@ -153,6 +157,24 @@ function slugifyPhaseName(phaseName) {
153
157
  // the same reported phase_slug.
154
158
  return phaseName ? coreUtils.generateSlugInternal(phaseName, null) : null;
155
159
  }
160
+ /**
161
+ * #4854: the one place that decides which name an `init` verb emits as
162
+ * `phase_name`. When a phase directory exists, `searchPhaseInDir` derives
163
+ * `phaseInfo.phase_name` from the directory-name remainder — already slugified
164
+ * (`phase.add` writes `${num}-${slug}` dirs), so it comes out byte-identical to
165
+ * `phase_slug`. The ROADMAP carries the curated display name
166
+ * (`### Phase N: <Name>`), so it wins; the disk-derived name is the fallback
167
+ * for a phase the ROADMAP does not describe, then `null`. #3171 fixed this
168
+ * inline for `init execute-phase` only; plan-phase (whose `phase_name` reaches
169
+ * STATE.md through `state planned-phase --name`), verify-work, code-review,
170
+ * discuss-phase-assumptions and phase-op read the raw disk value. `phase_slug`
171
+ * is deliberately not routed through here — it stays disk-derived.
172
+ */
173
+ function resolvePhaseDisplayName(phaseInfo, roadmapPhase) {
174
+ return roadmapPhase?.['phase_name']
175
+ || phaseInfo?.['phase_name']
176
+ || null;
177
+ }
156
178
  /**
157
179
  * #2994 (review finding, DEFECT.GENERATIVE-FIX): shared archived/not-found
158
180
  * fallback applied identically by `cmdInitExecutePhase`, `cmdInitPlanPhase`,
@@ -160,10 +182,11 @@ function slugifyPhaseName(phaseName) {
160
182
  * `cmdInitDiscussPhaseAssumptions` — 6 call sites previously reproducing the
161
183
  * exact same two-branch control flow verbatim (only the synthetic
162
184
  * replacement object's field set differs per caller, supplied here via
163
- * `buildFallback`). `cmdInitPhaseOp` is deliberately left untouched (CRITICAL
164
- * blast radius, 179 dependents) even though it follows the same shape, since
165
- * its own fallback object differs by one field (`has_reviews` absent) and is
166
- * not a byte-identical copy.
185
+ * `buildFallback`). `cmdInitPhaseOp` does not use this helper (its own fallback
186
+ * object differs by one field, `has_reviews` absent, so it is not a
187
+ * byte-identical copy), but since #4854 it resolves `roadmapPhase` once up
188
+ * front like the others, so `resolvePhaseDisplayName` sees it in the ordinary
189
+ * case too.
167
190
  *
168
191
  * Behavior-preserving by construction: every original call site either (a)
169
192
  * unconditionally computed `roadmapPhase` once up front and then applied
@@ -186,20 +209,10 @@ function applyRoadmapFallback(phaseInfo, roadmapPhase, buildFallback) {
186
209
  }
187
210
  return phaseInfo;
188
211
  }
189
- function listPhaseSummaryFiles(phaseDir) {
190
- return scanPhasePlans(phaseDir)['summaryFiles'];
191
- }
192
212
  function listPhasePlanFiles(phaseDir) {
193
213
  return scanPhasePlans(phaseDir)['planFiles'];
194
214
  }
195
- function projectCompletionStatus(implementationComplete, phaseComplete) {
196
- if (phaseComplete)
197
- return 'complete';
198
- if (implementationComplete)
199
- return 'executed';
200
- return 'incomplete';
201
- }
202
- function buildPhaseCompletionProjection(cwd, phaseNumber, phaseDir, planCount, summaryCount, slashRuntime) {
215
+ function buildPhaseCompletionProjection(cwd, phaseNumber, phaseDir, planCount, summaryCount, slashRuntime, convention) {
203
216
  // ADR-3180 §7.4 (issue #3186) / DO-NOT-MIGRATE exemption
204
217
  // (scripts/lint-completion-predicate-drift.cjs FUNCTION_SCOPED_EXEMPTIONS,
205
218
  // declared deviation): `implementation_complete` answers "are the plans
@@ -219,20 +232,35 @@ function buildPhaseCompletionProjection(cwd, phaseNumber, phaseDir, planCount, s
219
232
  // #2617: the router still owns both the message content and the runtime
220
233
  // projection; init passes the phase number it already knows (its phaseDir
221
234
  // is unresolved in some branches, where the router could not derive one).
222
- const completionResult = isPhaseComplete(phaseFullDir, { runtime: slashRuntime, phaseNumber });
235
+ const completionResult = isPhaseComplete(phaseFullDir, { runtime: slashRuntime, phaseNumber, convention });
236
+ // #5118: the owner carried an out-of-set report status in its result
237
+ // (`statusError`, `verification.status: null`); an init bundle is never
238
+ // assembled over a report the owner refused — the carried error is raised
239
+ // here and every `init *` surface built on this projection fails with the
240
+ // error's own reason (the CLI entry seam), printing nothing.
241
+ if (completionResult.value.statusError)
242
+ throw completionResult.value.statusError;
223
243
  const verificationStatus = completionResult.value.verification;
224
244
  const projectedVerificationStatus = verificationStatus.status;
225
245
  const projectedVerificationAction = verificationStatus.next_action;
226
- const verificationPassed = projectedVerificationStatus === 'passed';
246
+ const verificationPassed = projectedVerificationStatus === VERIFICATION_STATUS.PASSED;
227
247
  const phaseComplete = completionResult.value.complete;
228
248
  return {
229
249
  implementation_complete: implementationComplete,
230
250
  verification_status: projectedVerificationStatus,
231
251
  verification_passed: verificationPassed,
232
252
  phase_complete: phaseComplete,
233
- completion_status: projectCompletionStatus(implementationComplete, phaseComplete),
253
+ // #5060: Phase Status Module — the single owner of "what state is phase P
254
+ // in?" (ADR-5057 §1/§2).
255
+ completion_status: (0, phase_status_cjs_1.toCompletionStatus)((0, phase_status_cjs_1.phaseStatusFromFacts)({
256
+ planCount,
257
+ summaryCount,
258
+ complete: phaseComplete,
259
+ verificationStatus: projectedVerificationStatus,
260
+ })),
234
261
  verification_next_action: projectedVerificationAction,
235
262
  verification_next_command: verificationStatus.next_command,
263
+ verification_route: verificationStatus.route,
236
264
  // #3057 B3: readVerificationStatus's result carries this flag when its
237
265
  // internal staleness check could not run to completion.
238
266
  verification_stale_check_indeterminate: 'staleCheckIndeterminate' in verificationStatus
@@ -479,7 +507,8 @@ function detectHasPriorPhases(cwd, phaseInfo) {
479
507
  * `false` — strict `=== true`, never coerced, mirrors `detectHasPriorPhases`'s
480
508
  * degrade-to-false discipline. `keyPath` is always a fixed literal supplied
481
509
  * by this module, never attacker/user input, so a plain bracket traversal
482
- * carries no prototype hazard here.
510
+ * carries no prototype hazard here. Only for keys whose default is OFF — a
511
+ * default-ON key read here silently inverts its unset value (#4977).
483
512
  */
484
513
  function readConfigJsonBoolean(cwd, keyPath) {
485
514
  try {
@@ -727,7 +756,13 @@ function buildSectionManifestField(cwd, phaseInfo, options, workflow, overrides
727
756
  flags,
728
757
  phaseNumber,
729
758
  hasPriorPhases: detectHasPriorPhases(cwd, phaseInfo),
730
- worktreesEnabled: readConfigJsonBoolean(cwd, ['workflow', 'use_worktrees']),
759
+ // #4977: `workflow.use_worktrees` defaults ON, so this fact must come from
760
+ // the #3972 owner `query dispatch-isolation` and the isolation guard
761
+ // already share — not `readConfigJsonBoolean`, whose absent ⇒ false
762
+ // polarity (right for the opt-in keys around it) excluded the quick
763
+ // pre-dispatch plan commit while the executor was still dispatched
764
+ // isolated. The ladder also brings root→workstream inheritance along.
765
+ worktreesEnabled: !worktreesOptedOut(cwd),
731
766
  phaseMvpMode: detectPhaseMvpMode(cwd, phaseNumber),
732
767
  needsCodebaseMap: overrides.needsCodebaseMap,
733
768
  chunkedMode,
@@ -908,7 +943,7 @@ function cmdInitExecutePhase(cwd, phase, raw, options = {}) {
908
943
  // the human-curated display name (`### Phase N: <Name>`); prefer it,
909
944
  // matching the no-disk fallback above. phase_slug stays disk-derived — it
910
945
  // correctly feeds branch-name construction below and is unchanged here.
911
- phase_name: (roadmapPhase?.['phase_name']) || (phaseInfo?.['phase_name']) || null,
946
+ phase_name: resolvePhaseDisplayName(phaseInfo, roadmapPhase),
912
947
  phase_slug: phaseInfo?.['phase_slug'] || null,
913
948
  phase_req_ids,
914
949
  plans: phaseInfo?.['plans'] || [],
@@ -1027,7 +1062,7 @@ function cmdInitPlanPhase(cwd, phase, raw, options = {}) {
1027
1062
  const phase_req_ids = reqExtracted && reqExtracted !== 'TBD' ? reqExtracted : null;
1028
1063
  const phaseDirPlan = phaseInfo?.['directory'] || null;
1029
1064
  const phaseNumberPlan = phaseInfo?.['phase_number'] || null;
1030
- const phaseNamePlan = phaseInfo?.['phase_name'] || null;
1065
+ const phaseNamePlan = resolvePhaseDisplayName(phaseInfo, roadmapPhase);
1031
1066
  const rawProjectCodePlan = config.project_code || '';
1032
1067
  let expectedPhaseDirPlan = null;
1033
1068
  if (!phaseDirPlan && phaseNumberPlan && phaseNamePlan) {
@@ -1075,8 +1110,10 @@ function cmdInitPlanPhase(cwd, phase, raw, options = {}) {
1075
1110
  phase_slug: phaseInfo?.['phase_slug'] || null,
1076
1111
  padded_phase: phaseNumberPlan ? normalizePhaseName(phaseNumberPlan) : null,
1077
1112
  phase_req_ids,
1113
+ // #5060: Phase Status Module — the single owner of "what state is phase P
1114
+ // in?" (ADR-5057 §1/§2).
1078
1115
  phase_status: phaseDirPlan
1079
- ? determinePhaseStatus(phaseInfo?.['plans']?.length || 0, phaseInfo?.['summaries']?.length || 0, node_path_1.default.join(cwd, phaseDirPlan), 'Pending')
1116
+ ? (0, phase_status_cjs_1.toDisplayLabel)((0, phase_status_cjs_1.phaseStatus)(node_path_1.default.join(cwd, phaseDirPlan), { convention: resolvePhaseIdConvention(cwd) }).value.status, { pendingWord: 'Pending' })
1080
1117
  : 'Pending',
1081
1118
  has_research: phaseInfo?.['has_research'] || false,
1082
1119
  has_context: phaseInfo?.['has_context'] || false,
@@ -1273,12 +1310,15 @@ function buildInitCompletenessFields(cwd) {
1273
1310
  }
1274
1311
  function cmdInitNewProject(cwd, raw, options = {}) {
1275
1312
  const config = loadConfig(cwd);
1276
- const homedir = node_os_1.default.homedir();
1277
- const braveKeyFile = node_path_1.default.join(homedir, '.gsd', 'brave_api_key');
1313
+ // #4976: probe the GSD-owned store the config loader resolves
1314
+ // (`GSD_HOME || homedir()`), so these flags agree with config-new-project's
1315
+ // key probes in the same /gsd-new-project run.
1316
+ const gsdHome = process.env['GSD_HOME'] || node_os_1.default.homedir();
1317
+ const braveKeyFile = node_path_1.default.join(gsdHome, '.gsd', 'brave_api_key');
1278
1318
  const hasBraveSearch = !!(process.env['BRAVE_API_KEY'] || node_fs_1.default.existsSync(braveKeyFile));
1279
- const firecrawlKeyFile = node_path_1.default.join(homedir, '.gsd', 'firecrawl_api_key');
1319
+ const firecrawlKeyFile = node_path_1.default.join(gsdHome, '.gsd', 'firecrawl_api_key');
1280
1320
  const hasFirecrawl = !!(process.env['FIRECRAWL_API_KEY'] || node_fs_1.default.existsSync(firecrawlKeyFile));
1281
- const exaKeyFile = node_path_1.default.join(homedir, '.gsd', 'exa_api_key');
1321
+ const exaKeyFile = node_path_1.default.join(gsdHome, '.gsd', 'exa_api_key');
1282
1322
  const hasExaSearch = !!(process.env['EXA_API_KEY'] || node_fs_1.default.existsSync(exaKeyFile));
1283
1323
  const hasCode = hasCodeFilesInternal(cwd);
1284
1324
  const hasPackageFile = hasPackageFileInternal(cwd);
@@ -1638,9 +1678,21 @@ function cmdInitVerifyWork(cwd, phase, raw) {
1638
1678
  };
1639
1679
  });
1640
1680
  const phaseDir = phaseInfo?.['directory'] || null;
1641
- const planCount = phaseInfo?.['plans']?.length || 0;
1642
- const summaryCount = phaseInfo?.['summaries']?.length || 0;
1643
- const completion = buildPhaseCompletionProjection(cwd, phaseInfo?.['phase_number'] || phase, phaseDir, planCount, summaryCount, _slashRuntime);
1681
+ // #5060: Phase Status Module — matched counts from the §7.5 owner
1682
+ // (scanPhasePlans via phaseStatus), not phaseInfo's raw plans/summaries
1683
+ // arrays, so this projection's counts agree with buildPhaseCompletionProjection's
1684
+ // own isPhaseComplete call below (see the convention thread there).
1685
+ const verifyWorkConvention = resolvePhaseIdConvention(cwd);
1686
+ const verifyWorkPs = phaseDir
1687
+ ? (0, phase_status_cjs_1.phaseStatus)(node_path_1.default.join(cwd, phaseDir), { convention: verifyWorkConvention })
1688
+ : null;
1689
+ const planCount = verifyWorkPs
1690
+ ? verifyWorkPs.value.planCount
1691
+ : phaseInfo?.['plans']?.length || 0;
1692
+ const summaryCount = verifyWorkPs
1693
+ ? verifyWorkPs.value.summaryCount
1694
+ : phaseInfo?.['summaries']?.length || 0;
1695
+ const completion = buildPhaseCompletionProjection(cwd, phaseInfo?.['phase_number'] || phase, phaseDir, planCount, summaryCount, _slashRuntime, verifyWorkConvention);
1644
1696
  const uatReport = phaseDir
1645
1697
  ? evaluateUatPassed(node_path_1.default.join(cwd, phaseDir), {
1646
1698
  policy: { requireVerification: true },
@@ -1656,7 +1708,7 @@ function cmdInitVerifyWork(cwd, phase, raw) {
1656
1708
  // itself stays relative — evaluateUatPassed above still joins it against cwd.
1657
1709
  phase_dir: phaseDir ? toPosixPath(node_path_1.default.join(cwd, phaseDir)) : null,
1658
1710
  phase_number: phaseInfo?.['phase_number'] || null,
1659
- phase_name: phaseInfo?.['phase_name'] || null,
1711
+ phase_name: resolvePhaseDisplayName(phaseInfo, roadmapPhase),
1660
1712
  // #2376: verify-work.md's plan_gap_closure step reads these instead of
1661
1713
  // hardcoding '.planning/STATE.md' / '.planning/ROADMAP.md' literals.
1662
1714
  state_path: toPosixPath(node_path_1.default.join(planningDir(cwd), 'STATE.md')),
@@ -1728,7 +1780,7 @@ function cmdInitCodeReview(cwd, phase, raw, options = {}) {
1728
1780
  });
1729
1781
  const phaseDir = phaseInfo?.['directory'] || null;
1730
1782
  const phaseNumber = phaseInfo?.['phase_number'] || null;
1731
- const phaseName = phaseInfo?.['phase_name'] || null;
1783
+ const phaseName = resolvePhaseDisplayName(phaseInfo, roadmapPhase);
1732
1784
  const fallow = detectFallowConfig(cwd);
1733
1785
  const result = {
1734
1786
  commit_docs: config.commit_docs,
@@ -1857,7 +1909,7 @@ function cmdInitDiscussPhaseAssumptions(cwd, phase, raw, options = {}) {
1857
1909
  });
1858
1910
  const phaseDir = phaseInfo?.['directory'] || null;
1859
1911
  const phaseNumber = phaseInfo?.['phase_number'] || null;
1860
- const phaseName = phaseInfo?.['phase_name'] || null;
1912
+ const phaseName = resolvePhaseDisplayName(phaseInfo, roadmapPhase);
1861
1913
  // #2994: mirrors discuss-phase-assumptions.md's own auto_advance step
1862
1914
  // resolver — `--auto` flag OR the consolidated `check auto-mode --pick
1863
1915
  // active` fact (workflow._auto_chain_active OR workflow.auto_advance).
@@ -1909,8 +1961,10 @@ function cmdInitPhaseOp(cwd, phase, raw) {
1909
1961
  output(withProjectRoot(cwd, result), raw);
1910
1962
  return;
1911
1963
  }
1964
+ // #4854: resolved once, up front (a pure read — guardedGetRoadmapPhase has no side effects),
1965
+ // so the ordinary case (phase dir on disk, not archived) also sees the ROADMAP display name.
1966
+ const roadmapPhase = guardedGetRoadmapPhase(cwd, phase, config.project_code);
1912
1967
  if (phaseInfo?.['archived']) {
1913
- const roadmapPhase = guardedGetRoadmapPhase(cwd, phase, config.project_code);
1914
1968
  if (roadmapPhase?.['found']) {
1915
1969
  const phaseName = roadmapPhase['phase_name'];
1916
1970
  phaseInfo = {
@@ -1933,7 +1987,6 @@ function cmdInitPhaseOp(cwd, phase, raw) {
1933
1987
  }
1934
1988
  }
1935
1989
  if (!phaseInfo) {
1936
- const roadmapPhase = guardedGetRoadmapPhase(cwd, phase, config.project_code);
1937
1990
  if (roadmapPhase?.['found']) {
1938
1991
  const phaseName = roadmapPhase['phase_name'];
1939
1992
  phaseInfo = {
@@ -1957,7 +2010,7 @@ function cmdInitPhaseOp(cwd, phase, raw) {
1957
2010
  }
1958
2011
  const phaseDir = phaseInfo?.['directory'] || null;
1959
2012
  const phaseNumber = phaseInfo?.['phase_number'] || null;
1960
- const phaseName = phaseInfo?.['phase_name'] || null;
2013
+ const phaseName = resolvePhaseDisplayName(phaseInfo, roadmapPhase);
1961
2014
  const rawProjectCode = config.project_code || '';
1962
2015
  let expectedPhaseDir = null;
1963
2016
  if (!phaseDir && phaseNumber && phaseName) {
@@ -2314,6 +2367,12 @@ function cmdInitTodos(cwd, area, raw) {
2314
2367
  function cmdInitMilestoneOp(cwd, raw) {
2315
2368
  const config = loadConfig(cwd);
2316
2369
  const milestone = milestoneRecord(cwd);
2370
+ // #5060: Phase Status Module — the single owner of "what state is phase P
2371
+ // in?" (ADR-5057 §1/§2). A phase counts as completed only when the ladder
2372
+ // itself says COMPLETE, not "has any *-SUMMARY.md" (a counts-only verdict
2373
+ // that bypasses isPhaseComplete and disagrees with every other completion
2374
+ // consumer on a stale `passed` report).
2375
+ const milestoneOpConvention = resolvePhaseIdConvention(cwd);
2317
2376
  let phaseCount = 0;
2318
2377
  let completedPhases = 0;
2319
2378
  const phasesDir = node_path_1.default.join(planningDir(cwd), 'phases');
@@ -2325,7 +2384,7 @@ function cmdInitMilestoneOp(cwd, raw) {
2325
2384
  // #1729: `(?:\s*\([^)\n]{0,200}\))?` tolerates a pre-colon ( ) tag, owned by
2326
2385
  // buildPhaseHeadingScanRegex (phase-id.cts) so this scan also recognizes
2327
2386
  // bracket-convention headings instead of hand-rolling a literal `Phase\s+`.
2328
- const { regex: phasePattern, phaseNumGroup } = buildPhaseHeadingScanRegex(PHASE_HEADING_BASELINE.ANY_BRACKET, resolvePhaseIdConvention(cwd));
2387
+ const { regex: phasePattern, phaseNumGroup } = buildPhaseHeadingScanRegex(PHASE_HEADING_BASELINE.ANY_BRACKET, milestoneOpConvention);
2329
2388
  let m;
2330
2389
  while ((m = phasePattern.exec(currentSection)) !== null) {
2331
2390
  // #3185: canonical sentinel predicate (SENTINEL_RANGES [0,999]) — this was a local 999-only literal that admitted Phase 0.
@@ -2366,8 +2425,8 @@ function cmdInitMilestoneOp(cwd, raw) {
2366
2425
  if (!dirName)
2367
2426
  continue;
2368
2427
  try {
2369
- const hasSummary = listPhaseSummaryFiles(node_path_1.default.join(phasesDir, dirName)).length > 0;
2370
- if (hasSummary)
2428
+ const isComplete = (0, phase_status_cjs_1.phaseStatus)(node_path_1.default.join(phasesDir, dirName), { convention: milestoneOpConvention }).value.status === phase_status_cjs_1.PHASE_STATUS.COMPLETE;
2429
+ if (isComplete)
2371
2430
  completedPhases++;
2372
2431
  }
2373
2432
  catch {
@@ -2386,8 +2445,8 @@ function cmdInitMilestoneOp(cwd, raw) {
2386
2445
  phaseCount = dirs.length;
2387
2446
  for (const dir of dirs) {
2388
2447
  try {
2389
- const hasSummary = listPhaseSummaryFiles(node_path_1.default.join(phasesDir, dir)).length > 0;
2390
- if (hasSummary)
2448
+ const isComplete = (0, phase_status_cjs_1.phaseStatus)(node_path_1.default.join(phasesDir, dir), { convention: milestoneOpConvention }).value.status === phase_status_cjs_1.PHASE_STATUS.COMPLETE;
2449
+ if (isComplete)
2391
2450
  completedPhases++;
2392
2451
  }
2393
2452
  catch {
@@ -2493,11 +2552,23 @@ function cmdInitManager(cwd, raw) {
2493
2552
  // getMilestonePhaseFilter window check (which also never excluded
2494
2553
  // sentinels, unlike the owner).
2495
2554
  const _checkboxStates = new Map();
2496
- const _cbPattern = new RegExp(`-\\s*\\[(x| )\\]\\s*.*${phaseHeadingPrefix}(${PHASE_NUMBER_TOKEN_SOURCE})[:\\s]`, 'gi');
2555
+ // #4982: anchored (`^`, `m`) so the phase label must be the FIRST thing
2556
+ // after the checkbox (tolerating only an optional `**` bold marker) —
2557
+ // the prior unanchored `\s*.*` let the greedy `.*` bind to the LAST
2558
+ // "Phase N" mentioned anywhere in the line's prose instead of the line's
2559
+ // own phase. First-match-wins (`if (!_checkboxStates.has(...))` below)
2560
+ // additionally guards against a later anchored line (e.g. a per-plan
2561
+ // sub-entry self-titled "Phase N ...") overwriting an already-recorded
2562
+ // phase's own (first) checkbox — anchoring alone does not fully close
2563
+ // that "last-match-wins" composition defect.
2564
+ const _cbPattern = new RegExp(`^[ \\t]*-[ \\t]*\\[(x| )\\][ \\t]*(?:\\*\\*)?${phaseHeadingPrefix}(${PHASE_NUMBER_TOKEN_SOURCE})[:\\s]`, 'gim');
2497
2565
  let _cbMatch;
2498
2566
  while ((_cbMatch = _cbPattern.exec(content)) !== null) {
2499
2567
  const phaseGroup = capturesBracketId ? 3 : 2;
2500
- _checkboxStates.set(_cbMatch[phaseGroup], _cbMatch[1].toLowerCase() === 'x');
2568
+ const _cbKey = _cbMatch[phaseGroup];
2569
+ if (!_checkboxStates.has(_cbKey)) {
2570
+ _checkboxStates.set(_cbKey, _cbMatch[1].toLowerCase() === 'x');
2571
+ }
2501
2572
  }
2502
2573
  // #1729: `(?:\s*\([^)\n]{0,200}\))?` tolerates a pre-colon ( ) tag (literal mirror of OPTIONAL_PHASE_TAG_SOURCE).
2503
2574
  const phasePattern = new RegExp(`#{2,4}\\s*${phaseHeadingPrefix}(${PHASE_NUMBER_TOKEN_SOURCE})(?:\\s*\\([^)\\n]{0,200}\\))?\\s*:\\s*([^\\n]+)`, 'gi');
@@ -2529,7 +2600,7 @@ function cmdInitManager(cwd, raw) {
2529
2600
  const goal = roadmapParser.extractPhaseFieldMultiline(section, 'Goal');
2530
2601
  const dependsMatch = section.match(/\*\*Depends on(?::\*\*|\*\*:)\s*([^\n]+)/i);
2531
2602
  const depends_on = dependsMatch ? dependsMatch[1].trim() : null;
2532
- let diskStatus = 'no_directory';
2603
+ let diskStatus = phase_status_cjs_1.DISK_STATUS.NO_DIRECTORY;
2533
2604
  let planCount = 0;
2534
2605
  let summaryCount = 0;
2535
2606
  let hasContext = false;
@@ -2539,7 +2610,7 @@ function cmdInitManager(cwd, raw) {
2539
2610
  // #4014 (epic #3473 B4-unreadable): default COMPLETE — no directory at
2540
2611
  // all (dirMatch not found) is a genuine, not-unreadable answer.
2541
2612
  let contextScope = SCOPE.COMPLETE;
2542
- let completion = buildPhaseCompletionProjection(cwd, phaseNum, null, planCount, summaryCount, _slashRuntime);
2613
+ let completion = buildPhaseCompletionProjection(cwd, phaseNum, null, planCount, summaryCount, _slashRuntime, phaseIdConvention);
2543
2614
  try {
2544
2615
  // #4801: resolve through the canonical locator instead of a private
2545
2616
  // current-milestone-only scan. findPhaseInternal searches the live
@@ -2570,8 +2641,11 @@ function cmdInitManager(cwd, raw) {
2570
2641
  // only, the failure control-flow is untouched.
2571
2642
  contextScope = findContextMdIn(fullDir).scope;
2572
2643
  const phaseFiles = node_fs_1.default.readdirSync(fullDir);
2573
- planCount = listPhasePlanFiles(fullDir).length;
2574
- summaryCount = listPhaseSummaryFiles(fullDir).length;
2644
+ // #5060: Phase Status Module — the single owner of "what state is
2645
+ // phase P in?" (ADR-5057 §1/§2).
2646
+ const ps = (0, phase_status_cjs_1.phaseStatus)(fullDir, { convention: phaseIdConvention });
2647
+ planCount = ps.value.planCount;
2648
+ summaryCount = ps.value.summaryCount;
2575
2649
  // #3511-class: scope the raw listing to THIS phase's own artifacts
2576
2650
  // before the hasContext/hasResearch predicates run, so a stray
2577
2651
  // cross-phase `-CONTEXT.md`/`-RESEARCH.md` sitting in this directory
@@ -2579,21 +2653,8 @@ function cmdInitManager(cwd, raw) {
2579
2653
  const scopedFiles = scopeToPhase(phaseFiles, dirMatch);
2580
2654
  hasContext = findContextMdIn(scopedFiles) !== null;
2581
2655
  hasResearch = scopedFiles.some((f) => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
2582
- completion = buildPhaseCompletionProjection(cwd, phaseNum, phaseDirRel, planCount, summaryCount, _slashRuntime);
2583
- if (completion.phase_complete)
2584
- diskStatus = 'complete';
2585
- else if (completion.implementation_complete)
2586
- diskStatus = 'executed';
2587
- else if (summaryCount > 0)
2588
- diskStatus = 'partial';
2589
- else if (planCount > 0)
2590
- diskStatus = 'planned';
2591
- else if (hasResearch)
2592
- diskStatus = 'researched';
2593
- else if (hasContext)
2594
- diskStatus = 'discussed';
2595
- else
2596
- diskStatus = 'empty';
2656
+ completion = buildPhaseCompletionProjection(cwd, phaseNum, phaseDirRel, planCount, summaryCount, _slashRuntime, phaseIdConvention);
2657
+ diskStatus = (0, phase_status_cjs_1.toDiskStatus)(ps.value.status, { hasResearch, hasContext });
2597
2658
  const nowMs = clock_cjs_1.realClock.now();
2598
2659
  let newestMtime = 0;
2599
2660
  for (const f of phaseFiles) {
@@ -2751,7 +2812,7 @@ function cmdInitManager(cwd, raw) {
2751
2812
  }
2752
2813
  for (const phase of phases) {
2753
2814
  phase['is_next_to_discuss'] =
2754
- (phase['disk_status'] === 'empty' || phase['disk_status'] === 'no_directory') &&
2815
+ (phase['disk_status'] === phase_status_cjs_1.DISK_STATUS.EMPTY || phase['disk_status'] === phase_status_cjs_1.DISK_STATUS.NO_DIRECTORY) &&
2755
2816
  phase['deps_satisfied'];
2756
2817
  }
2757
2818
  let waitingSignal = null;
@@ -2773,12 +2834,12 @@ function cmdInitManager(cwd, raw) {
2773
2834
  }
2774
2835
  const recommendedActions = [];
2775
2836
  for (const phase of phases) {
2776
- if (phase['disk_status'] === 'complete')
2837
+ if (phase['disk_status'] === phase_status_cjs_1.DISK_STATUS.COMPLETE)
2777
2838
  continue;
2778
2839
  // #3185: canonical sentinel predicate (SENTINEL_RANGES [0,999]) — this was a local 999-only literal that admitted Phase 0.
2779
2840
  if (isSentinelPhaseId(phase['number']))
2780
2841
  continue;
2781
- if (phase['disk_status'] === 'executed') {
2842
+ if (phase['disk_status'] === phase_status_cjs_1.DISK_STATUS.EXECUTED) {
2782
2843
  recommendedActions.push({
2783
2844
  phase: phase['number'],
2784
2845
  phase_name: phase['name'],
@@ -2787,7 +2848,7 @@ function cmdInitManager(cwd, raw) {
2787
2848
  command: phase['verification_next_command'],
2788
2849
  });
2789
2850
  }
2790
- else if (phase['disk_status'] === 'planned' && phase['deps_satisfied']) {
2851
+ else if (phase['disk_status'] === phase_status_cjs_1.DISK_STATUS.PLANNED && phase['deps_satisfied']) {
2791
2852
  recommendedActions.push({
2792
2853
  phase: phase['number'],
2793
2854
  phase_name: phase['name'],
@@ -2796,8 +2857,8 @@ function cmdInitManager(cwd, raw) {
2796
2857
  command: `${(0, runtime_slash_cjs_1.formatGsdSlash)('execute-phase', _slashRuntime)} ${phase['number']}`,
2797
2858
  });
2798
2859
  }
2799
- else if (phase['disk_status'] === 'discussed' ||
2800
- phase['disk_status'] === 'researched') {
2860
+ else if (phase['disk_status'] === phase_status_cjs_1.DISK_STATUS.DISCUSSED ||
2861
+ phase['disk_status'] === phase_status_cjs_1.DISK_STATUS.RESEARCHED) {
2801
2862
  recommendedActions.push({
2802
2863
  phase: phase['number'],
2803
2864
  phase_name: phase['name'],
@@ -2806,7 +2867,7 @@ function cmdInitManager(cwd, raw) {
2806
2867
  command: `${(0, runtime_slash_cjs_1.formatGsdSlash)('plan-phase', _slashRuntime)} ${phase['number']}`,
2807
2868
  });
2808
2869
  }
2809
- else if ((phase['disk_status'] === 'empty' || phase['disk_status'] === 'no_directory') &&
2870
+ else if ((phase['disk_status'] === phase_status_cjs_1.DISK_STATUS.EMPTY || phase['disk_status'] === phase_status_cjs_1.DISK_STATUS.NO_DIRECTORY) &&
2810
2871
  phase['is_next_to_discuss']) {
2811
2872
  recommendedActions.push({
2812
2873
  phase: phase['number'],
@@ -2817,10 +2878,10 @@ function cmdInitManager(cwd, raw) {
2817
2878
  });
2818
2879
  }
2819
2880
  }
2820
- const activeExecuting = phases.filter((p) => p['disk_status'] === 'partial' ||
2821
- (p['disk_status'] === 'planned' && p['is_active']));
2881
+ const activeExecuting = phases.filter((p) => p['disk_status'] === phase_status_cjs_1.DISK_STATUS.PARTIAL ||
2882
+ (p['disk_status'] === phase_status_cjs_1.DISK_STATUS.PLANNED && p['is_active']));
2822
2883
  const activePlanning = phases.filter((p) => p['is_active'] &&
2823
- (p['disk_status'] === 'discussed' || p['disk_status'] === 'researched'));
2884
+ (p['disk_status'] === phase_status_cjs_1.DISK_STATUS.DISCUSSED || p['disk_status'] === phase_status_cjs_1.DISK_STATUS.RESEARCHED));
2824
2885
  const filteredActions = recommendedActions.filter((action) => {
2825
2886
  if (action['action'] === 'execute' && activeExecuting.length > 0) {
2826
2887
  return activeExecuting.every((active) => !hasDepRelationship(action['phase'], active['number']));
@@ -2863,7 +2924,7 @@ function cmdInitManager(cwd, raw) {
2863
2924
  phases,
2864
2925
  phase_count: phases.length,
2865
2926
  completed_count: completedCount,
2866
- in_progress_count: phases.filter((p) => ['executed', 'partial', 'planned', 'discussed', 'researched'].includes(p['disk_status'])).length,
2927
+ in_progress_count: phases.filter((p) => [phase_status_cjs_1.DISK_STATUS.EXECUTED, phase_status_cjs_1.DISK_STATUS.PARTIAL, phase_status_cjs_1.DISK_STATUS.PLANNED, phase_status_cjs_1.DISK_STATUS.DISCUSSED, phase_status_cjs_1.DISK_STATUS.RESEARCHED].includes(p['disk_status'])).length,
2867
2928
  recommended_actions: filteredActions,
2868
2929
  waiting_signal: waitingSignal,
2869
2930
  all_complete: completedCount === nonBacklogPhases.length && nonBacklogPhases.length > 0,
@@ -3213,10 +3274,34 @@ function cmdInitProgress(cwd, raw, options = {}) {
3213
3274
  // uncounted LABEL_ONLY consumer to init.cts's pinned
3214
3275
  // tests/adr-612-bracket-heading-selection.test.cjs census.
3215
3276
  // phase-id-owner: deliberately unmigrated (#4984 revert) — see comment above.
3216
- const cbPattern = new RegExp(`-\\s*\\[(x| )\\]\\s*.*Phase\\s+(${PHASE_NUMBER_TOKEN_SOURCE})[:\\s]`, 'gi');
3277
+ // #4982: anchored (`^`, `m`) — the phase label must be the FIRST thing
3278
+ // after the checkbox (tolerating only an optional `**` bold marker) — so
3279
+ // the greedy `.*` this replaces can no longer bind a line's checkbox to
3280
+ // the LAST "Phase N" mentioned anywhere in that line's prose. This value
3281
+ // feeds `roadmap_complete` AND directly gates next_phase/current_phase
3282
+ // selection below, so getting the wrong phase here is load-bearing, not
3283
+ // metadata-only (contrast the `_cbPattern` site in cmdInitManager).
3284
+ // First-match-wins (`if (!roadmapCheckboxStates.has(...))`) additionally
3285
+ // guards against a later anchored line (e.g. a per-plan sub-entry
3286
+ // self-titled "Phase N ...") overwriting an already-recorded phase's own
3287
+ // (first) checkbox — anchoring alone does not fully close that
3288
+ // "last-match-wins" composition defect.
3289
+ // `(?:\[[^\]\n]{0,200}\]\s*)?` tolerates an optional leading bracket tag
3290
+ // (literal mirror of BASE_ANY_BRACKET_HEADING_PREFIX_SRC, phase-id.cts)
3291
+ // BEFORE the literal "Phase" word — decoration tolerance only, no capture
3292
+ // group, no convention gating. Without it the anchor fix above regresses
3293
+ // a checklist line combining a bracket tag with literal "Phase N" wording
3294
+ // (e.g. `**[GSD.02] Phase 3: ...**`), which the old unanchored `.*`
3295
+ // matched (by absorbing the bracket text). This does NOT migrate the site
3296
+ // onto phaseHeadingPrefixSrcFor / the bracket convention — that stays
3297
+ // out of scope per the comment above (#4984 revert, pinned census).
3298
+ const cbPattern = new RegExp(`^[ \\t]*-[ \\t]*\\[(x| )\\][ \\t]*(?:\\*\\*)?(?:\\[[^\\]\\n]{0,200}\\]\\s*)?Phase\\s+(${PHASE_NUMBER_TOKEN_SOURCE})[:\\s]`, 'gim');
3217
3299
  let cbm;
3218
3300
  while ((cbm = cbPattern.exec(roadmapContent)) !== null) {
3219
- roadmapCheckboxStates.set(cbm[2], cbm[1].toLowerCase() === 'x');
3301
+ const cbKey = cbm[2];
3302
+ if (!roadmapCheckboxStates.has(cbKey)) {
3303
+ roadmapCheckboxStates.set(cbKey, cbm[1].toLowerCase() === 'x');
3304
+ }
3220
3305
  }
3221
3306
  }
3222
3307
  catch {
@@ -3238,8 +3323,9 @@ function cmdInitProgress(cwd, raw, options = {}) {
3238
3323
  seenPhaseNums.add(phaseNumber.replace(/^0+/, '') || '0');
3239
3324
  const phasePath = node_path_1.default.join(phasesDir, dir);
3240
3325
  const phaseFiles = node_fs_1.default.readdirSync(phasePath);
3241
- const plans = listPhasePlanFiles(phasePath);
3242
- const summaries = listPhaseSummaryFiles(phasePath);
3326
+ // #5060: Phase Status Module — the single owner of "what state is
3327
+ // phase P in?" (ADR-5057 §1/§2).
3328
+ const ps = (0, phase_status_cjs_1.phaseStatus)(phasePath, { convention: resolvePhaseIdConvention(cwd) });
3243
3329
  // #3511-class: scope the raw listing to THIS phase's own artifacts
3244
3330
  // before the hasResearch predicate runs, so a stray cross-phase
3245
3331
  // `-RESEARCH.md` sitting in this directory cannot win this phase's
@@ -3247,16 +3333,8 @@ function cmdInitProgress(cwd, raw, options = {}) {
3247
3333
  const scopedPhaseFiles = scopeToPhase(phaseFiles, dir);
3248
3334
  const hasResearch = scopedPhaseFiles.some((f) => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
3249
3335
  const phaseDirRel = toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'phases', dir)));
3250
- const completion = buildPhaseCompletionProjection(cwd, phaseNumber, phaseDirRel, plans.length, summaries.length, _slashRuntime);
3251
- const status = completion.phase_complete
3252
- ? 'complete'
3253
- : completion.implementation_complete
3254
- ? 'executed'
3255
- : plans.length > 0
3256
- ? 'in_progress'
3257
- : hasResearch
3258
- ? 'researched'
3259
- : 'pending';
3336
+ const completion = buildPhaseCompletionProjection(cwd, phaseNumber, phaseDirRel, ps.value.planCount, ps.value.summaryCount, _slashRuntime, resolvePhaseIdConvention(cwd));
3337
+ const status = (0, phase_status_cjs_1.toProgressStatus)(ps.value.status, { hasResearch });
3260
3338
  const phaseInfo = {
3261
3339
  number: phaseNumber,
3262
3340
  name: phaseName,
@@ -3265,30 +3343,37 @@ function cmdInitProgress(cwd, raw, options = {}) {
3265
3343
  // above still joins it against cwd.
3266
3344
  directory: toPosixPath(node_path_1.default.join(cwd, phaseDirRel)),
3267
3345
  status,
3268
- plan_count: plans.length,
3269
- summary_count: summaries.length,
3346
+ plan_count: ps.value.planCount,
3347
+ summary_count: ps.value.summaryCount,
3270
3348
  has_research: hasResearch,
3271
3349
  ...completion,
3272
3350
  };
3273
3351
  phases.push(phaseInfo);
3274
- if (!currentPhase && (status === 'executed' || status === 'in_progress' || status === 'researched')) {
3352
+ if (!currentPhase && (status === phase_status_cjs_1.PROGRESS_STATUS.EXECUTED || status === phase_status_cjs_1.PROGRESS_STATUS.IN_PROGRESS || status === phase_status_cjs_1.PROGRESS_STATUS.RESEARCHED)) {
3275
3353
  currentPhase = phaseInfo;
3276
3354
  }
3277
- if (!nextPhase && status === 'pending') {
3355
+ if (!nextPhase && status === phase_status_cjs_1.PROGRESS_STATUS.PENDING) {
3278
3356
  nextPhase = phaseInfo;
3279
3357
  }
3280
3358
  }
3281
3359
  }
3282
- catch {
3283
- /* intentionally empty */
3360
+ catch (err) {
3361
+ // #5118: the owner's out-of-set report error is not a scan failure to
3362
+ // degrade over — the bundle is never assembled over a refused report.
3363
+ if (err instanceof VerificationStatusError)
3364
+ throw err;
3365
+ /* otherwise intentionally empty */
3284
3366
  }
3285
3367
  for (const [num, name] of roadmapPhaseNames) {
3286
3368
  const stripped = num.replace(/^0+/, '') || '0';
3287
3369
  if (!seenPhaseNums.has(stripped)) {
3288
3370
  const checkboxComplete = roadmapCheckboxStates.get(num) === true ||
3289
3371
  roadmapCheckboxStates.get(stripped) === true;
3290
- const completion = buildPhaseCompletionProjection(cwd, num, null, 0, 0, _slashRuntime);
3291
- const status = 'not_started';
3372
+ const completion = buildPhaseCompletionProjection(cwd, num, null, 0, 0, _slashRuntime, resolvePhaseIdConvention(cwd));
3373
+ // #5060: this synthetic row has no phase directory at all — the
3374
+ // roadmap heading exists but no `seenPhaseNums` disk match was found —
3375
+ // so it is the ladder's own NOT_STARTED word, not a derived guess.
3376
+ const status = phase_status_cjs_1.PROGRESS_STATUS.NOT_STARTED;
3292
3377
  const phaseInfo = {
3293
3378
  number: num,
3294
3379
  // #3883 (ADR-3473 §8.3): delegate to the canonical slug formula
@@ -3325,7 +3410,7 @@ function cmdInitProgress(cwd, raw, options = {}) {
3325
3410
  {
3326
3411
  const frontier = phases.find((p) => {
3327
3412
  const st = p['status'];
3328
- return (st === 'pending' || st === 'not_started') && p['roadmap_complete'] !== true;
3413
+ return (st === phase_status_cjs_1.PROGRESS_STATUS.PENDING || st === phase_status_cjs_1.PROGRESS_STATUS.NOT_STARTED) && p['roadmap_complete'] !== true;
3329
3414
  });
3330
3415
  if (frontier)
3331
3416
  nextPhase = frontier;
@@ -3362,8 +3447,8 @@ function cmdInitProgress(cwd, raw, options = {}) {
3362
3447
  milestone_name: milestone['name'] ?? null,
3363
3448
  phases,
3364
3449
  phase_count: phases.length,
3365
- completed_count: phases.filter((p) => p['status'] === 'complete').length,
3366
- in_progress_count: phases.filter((p) => ['executed', 'in_progress'].includes(p['status'])).length,
3450
+ completed_count: phases.filter((p) => p['status'] === phase_status_cjs_1.PROGRESS_STATUS.COMPLETE).length,
3451
+ in_progress_count: phases.filter((p) => [phase_status_cjs_1.PROGRESS_STATUS.EXECUTED, phase_status_cjs_1.PROGRESS_STATUS.IN_PROGRESS].includes(p['status'])).length,
3367
3452
  current_phase: currentPhase,
3368
3453
  next_phase: nextPhase,
3369
3454
  paused_at: pausedAt,
@@ -3955,10 +4040,11 @@ function buildSkillManifest(cwd, skillsDir = null) {
3955
4040
  seenNamesInRoot.add(name);
3956
4041
  const description = frontmatter['description'] || '';
3957
4042
  const triggers = [];
3958
- const bodyMatch = content.match(/^---[\s\S]*?---\s*\r?\n([\s\S]*)$/);
3959
- if (bodyMatch) {
3960
- const body = bodyMatch[1];
3961
- const triggerLines = body.match(/^TRIGGER\s+when:\s*(.+)$/gmi);
4043
+ // TRIGGER lines are read from the body after the block `extractFrontmatter` read (the
4044
+ // one fence owner), so a `---` inside a frontmatter value cannot start the body early.
4045
+ const block = frontmatterBlock(content);
4046
+ if (block) {
4047
+ const triggerLines = block.rest.match(/^TRIGGER\s+when:\s*(.+)$/gmi);
3962
4048
  if (triggerLines) {
3963
4049
  for (const line of triggerLines) {
3964
4050
  const m = line.match(/^TRIGGER\s+when:\s*(.+)$/i);