@opengsd/gsd-core 1.10.0 → 1.12.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 (544) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/agents/gsd-code-fixer.md +1 -1
  4. package/agents/gsd-debug-session-manager.md +12 -1
  5. package/agents/gsd-debugger.md +1 -1
  6. package/agents/gsd-doc-synthesizer.md +2 -4
  7. package/agents/gsd-dom-verifier.md +169 -0
  8. package/agents/gsd-eval-auditor.md +1 -1
  9. package/agents/gsd-executor.md +22 -14
  10. package/agents/gsd-framework-selector.md +1 -3
  11. package/agents/gsd-intel-updater.md +1 -1
  12. package/agents/gsd-mempalace-curator.md +5 -3
  13. package/agents/gsd-pattern-mapper.md +11 -0
  14. package/agents/gsd-phase-researcher.md +23 -2
  15. package/agents/gsd-plan-checker.md +50 -53
  16. package/agents/gsd-planner.md +50 -50
  17. package/agents/gsd-project-researcher.md +1 -1
  18. package/agents/gsd-research-synthesizer.md +2 -2
  19. package/agents/gsd-roadmapper.md +15 -11
  20. package/agents/gsd-ui-checker.md +63 -4
  21. package/agents/gsd-ui-researcher.md +41 -3
  22. package/agents/gsd-user-profiler.md +3 -0
  23. package/agents/gsd-verifier.md +13 -4
  24. package/bin/install.js +1448 -1103
  25. package/commands/gsd/code-review.md +1 -1
  26. package/commands/gsd/discuss-phase.md +1 -1
  27. package/commands/gsd/execute-phase.md +1 -1
  28. package/commands/gsd/import.md +1 -1
  29. package/commands/gsd/map-codebase.md +1 -1
  30. package/commands/gsd/mempalace-capture.md +1 -1
  31. package/commands/gsd/mempalace-recall.md +1 -1
  32. package/commands/gsd/new-milestone.md +1 -1
  33. package/commands/gsd/quick.md +9 -5
  34. package/commands/gsd/review-backlog.md +2 -1
  35. package/commands/gsd/verify-work.md +1 -1
  36. package/gsd-core/bin/gsd-tools.cjs +1035 -138
  37. package/gsd-core/bin/lib/active-workstream-store.cjs +146 -22
  38. package/gsd-core/bin/lib/adr-parser.cjs +13 -7
  39. package/gsd-core/bin/lib/agent-install-check.cjs +392 -32
  40. package/gsd-core/bin/lib/api-coverage.cjs +33 -14
  41. package/gsd-core/bin/lib/artifacts.cjs +5 -0
  42. package/gsd-core/bin/lib/assumption-delta.cjs +32 -15
  43. package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
  44. package/gsd-core/bin/lib/audit.cjs +1026 -268
  45. package/gsd-core/bin/lib/broken-windows.cjs +306 -28
  46. package/gsd-core/bin/lib/capability-consent.cjs +149 -15
  47. package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
  48. package/gsd-core/bin/lib/capability-lock.cjs +10 -4
  49. package/gsd-core/bin/lib/capability-registry.cjs +845 -130
  50. package/gsd-core/bin/lib/capability-source.cjs +92 -0
  51. package/gsd-core/bin/lib/capability-state.cjs +18 -3
  52. package/gsd-core/bin/lib/capability-trust.cjs +444 -25
  53. package/gsd-core/bin/lib/capability-validator.cjs +700 -40
  54. package/gsd-core/bin/lib/capability-writer.cjs +3 -2
  55. package/gsd-core/bin/lib/check-command-router.cjs +216 -42
  56. package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
  57. package/gsd-core/bin/lib/cli-exit.cjs +496 -10
  58. package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
  59. package/gsd-core/bin/lib/codex-agent-toml.cjs +735 -0
  60. package/gsd-core/bin/lib/command-aliases.cjs +22 -0
  61. package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
  62. package/gsd-core/bin/lib/command-roster.cjs +44 -1
  63. package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
  64. package/gsd-core/bin/lib/commands.cjs +1172 -108
  65. package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
  66. package/gsd-core/bin/lib/complexity-trigger.cjs +1192 -0
  67. package/gsd-core/bin/lib/config-loader.cjs +187 -23
  68. package/gsd-core/bin/lib/config.cjs +102 -3
  69. package/gsd-core/bin/lib/configuration.cjs +129 -37
  70. package/gsd-core/bin/lib/core-utils.cjs +208 -33
  71. package/gsd-core/bin/lib/decisions.cjs +23 -0
  72. package/gsd-core/bin/lib/edge-probe.cjs +9 -1
  73. package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
  74. package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
  75. package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
  76. package/gsd-core/bin/lib/frontmatter.cjs +899 -229
  77. package/gsd-core/bin/lib/gap-checker.cjs +95 -10
  78. package/gsd-core/bin/lib/git-base-branch.cjs +276 -39
  79. package/gsd-core/bin/lib/gsd2-import.cjs +10 -1
  80. package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
  81. package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
  82. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +149 -0
  83. package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
  84. package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
  85. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
  86. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +268 -0
  87. package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
  88. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
  89. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +187 -0
  90. package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
  91. package/gsd-core/bin/lib/health-diagnostic.cjs +451 -0
  92. package/gsd-core/bin/lib/host-integration.cjs +39 -6
  93. package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
  94. package/gsd-core/bin/lib/init-command-router.cjs +118 -21
  95. package/gsd-core/bin/lib/init.cjs +439 -168
  96. package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
  97. package/gsd-core/bin/lib/install-engine.cjs +811 -259
  98. package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
  99. package/gsd-core/bin/lib/install-model-override-resolver.cjs +235 -0
  100. package/gsd-core/bin/lib/install-profiles.cjs +212 -61
  101. package/gsd-core/bin/lib/install-scope.cjs +270 -0
  102. package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
  103. package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
  104. package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
  105. package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
  106. package/gsd-core/bin/lib/installer-migrations.cjs +148 -38
  107. package/gsd-core/bin/lib/intel.cjs +101 -26
  108. package/gsd-core/bin/lib/io.cjs +170 -15
  109. package/gsd-core/bin/lib/learnings.cjs +85 -14
  110. package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
  111. package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
  112. package/gsd-core/bin/lib/markdown-table.cjs +183 -22
  113. package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
  114. package/gsd-core/bin/lib/milestone.cjs +842 -73
  115. package/gsd-core/bin/lib/model-catalog.cjs +232 -16
  116. package/gsd-core/bin/lib/model-resolver.cjs +193 -68
  117. package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
  118. package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
  119. package/gsd-core/bin/lib/pattern.cjs +122 -0
  120. package/gsd-core/bin/lib/phase-estimation.cjs +18 -9
  121. package/gsd-core/bin/lib/phase-id.cjs +514 -40
  122. package/gsd-core/bin/lib/phase-lifecycle.cjs +52 -19
  123. package/gsd-core/bin/lib/phase-locator.cjs +262 -34
  124. package/gsd-core/bin/lib/phase.cjs +1038 -214
  125. package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
  126. package/gsd-core/bin/lib/plan-document.cjs +263 -0
  127. package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
  128. package/gsd-core/bin/lib/plan-scan.cjs +98 -3
  129. package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
  130. package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
  131. package/gsd-core/bin/lib/planning-scope.cjs +31 -0
  132. package/gsd-core/bin/lib/planning-snapshot.cjs +894 -0
  133. package/gsd-core/bin/lib/planning-workspace.cjs +112 -6
  134. package/gsd-core/bin/lib/probe-core.cjs +5 -2
  135. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  136. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
  137. package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
  138. package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
  139. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +766 -0
  140. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
  141. package/gsd-core/bin/lib/review-lane-descriptor.cjs +22 -13
  142. package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
  143. package/gsd-core/bin/lib/review-lane-runner.cjs +421 -66
  144. package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
  145. package/gsd-core/bin/lib/roadmap-command-router.cjs +59 -11
  146. package/gsd-core/bin/lib/roadmap-parser.cjs +1006 -184
  147. package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
  148. package/gsd-core/bin/lib/roadmap.cjs +442 -96
  149. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +702 -52
  150. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
  151. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +459 -55
  152. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
  153. package/gsd-core/bin/lib/runtime-homes.cjs +69 -3
  154. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +402 -58
  155. package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
  156. package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
  157. package/gsd-core/bin/lib/runtime-slash.cjs +96 -8
  158. package/gsd-core/bin/lib/security.cjs +104 -5
  159. package/gsd-core/bin/lib/shell-command-projection.cjs +342 -7
  160. package/gsd-core/bin/lib/smart-entry.cjs +133 -23
  161. package/gsd-core/bin/lib/spec-section.cjs +12 -7
  162. package/gsd-core/bin/lib/state-command-router.cjs +52 -19
  163. package/gsd-core/bin/lib/state-contract.cjs +359 -0
  164. package/gsd-core/bin/lib/state-document.cjs +338 -8
  165. package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
  166. package/gsd-core/bin/lib/state-transition.cjs +846 -176
  167. package/gsd-core/bin/lib/state.cjs +2589 -369
  168. package/gsd-core/bin/lib/surface.cjs +33 -11
  169. package/gsd-core/bin/lib/task-command-router.cjs +111 -1
  170. package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
  171. package/gsd-core/bin/lib/teams-status.cjs +4 -1
  172. package/gsd-core/bin/lib/text-lines.cjs +80 -0
  173. package/gsd-core/bin/lib/token-scanner.cjs +76 -0
  174. package/gsd-core/bin/lib/uat-predicate.cjs +67 -23
  175. package/gsd-core/bin/lib/uat.cjs +1761 -167
  176. package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
  177. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
  178. package/gsd-core/bin/lib/ui-safety-gate.cjs +51 -12
  179. package/gsd-core/bin/lib/unusable-input.cjs +37 -0
  180. package/gsd-core/bin/lib/update-context.cjs +8 -2
  181. package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
  182. package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
  183. package/gsd-core/bin/lib/validate.cjs +20 -6
  184. package/gsd-core/bin/lib/vendor/README.md +75 -0
  185. package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
  186. package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
  187. package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
  188. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  189. package/gsd-core/bin/lib/verification.cjs +272 -9
  190. package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
  191. package/gsd-core/bin/lib/verify.cjs +453 -918
  192. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +53 -32
  193. package/gsd-core/bin/lib/workstream-inventory.cjs +63 -10
  194. package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
  195. package/gsd-core/bin/lib/workstream.cjs +2 -2
  196. package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
  197. package/gsd-core/bin/lib/worktree-safety.cjs +341 -18
  198. package/gsd-core/bin/shared/config-defaults.manifest.json +8 -1
  199. package/gsd-core/bin/shared/config-schema.manifest.json +12 -1
  200. package/gsd-core/bin/shared/exit-codes.json +8 -0
  201. package/gsd-core/bin/shared/exit-codes.sh +20 -0
  202. package/gsd-core/bin/shared/model-catalog.json +8 -1
  203. package/gsd-core/references/agent-contracts.md +44 -26
  204. package/gsd-core/references/api-coverage.md +24 -2
  205. package/gsd-core/references/autonomous-smart-discuss.md +3 -3
  206. package/gsd-core/references/checkpoints.md +39 -21
  207. package/gsd-core/references/context-budget.md +1 -1
  208. package/gsd-core/references/decimal-phase-calculation.md +5 -5
  209. package/gsd-core/references/dispatch-isolation-gate.md +138 -0
  210. package/gsd-core/references/doc-conflict-engine.md +1 -1
  211. package/gsd-core/references/edge-probe.md +8 -0
  212. package/gsd-core/references/execute-mvp-tdd.md +4 -6
  213. package/gsd-core/references/execute-phase-between-wave-reset.md +15 -14
  214. package/gsd-core/references/execute-phase-context-guard.md +1 -1
  215. package/gsd-core/references/execute-phase-response-language.md +1 -1
  216. package/gsd-core/references/execute-phase-wave-guard.md +17 -11
  217. package/gsd-core/references/failing-direction.md +78 -0
  218. package/gsd-core/references/gate-prompts.md +1 -1
  219. package/gsd-core/references/git-integration.md +5 -5
  220. package/gsd-core/references/git-planning-commit.md +5 -4
  221. package/gsd-core/references/gsd-run-resolver.md +1 -1
  222. package/gsd-core/references/loop-hook-dispatch.md +61 -2
  223. package/gsd-core/references/model-profiles.md +12 -4
  224. package/gsd-core/references/mvp-concepts.md +9 -9
  225. package/gsd-core/references/nyquist-compliance.md +74 -0
  226. package/gsd-core/references/offer-next.md +3 -5
  227. package/gsd-core/references/phase-argument-parsing.md +3 -3
  228. package/gsd-core/references/planner-failing-direction.md +53 -0
  229. package/gsd-core/references/planner-guidance.md +3 -9
  230. package/gsd-core/references/planner-human-verify-mode.md +15 -1
  231. package/gsd-core/references/planner-preconditions.md +1 -1
  232. package/gsd-core/references/planner-reviews.md +1 -1
  233. package/gsd-core/references/planner-revision.md +1 -1
  234. package/gsd-core/references/planner-verify-command-grounding.md +17 -0
  235. package/gsd-core/references/planning-config.md +44 -13
  236. package/gsd-core/references/reviewer-instances.md +31 -0
  237. package/gsd-core/references/revision-loop.md +1 -1
  238. package/gsd-core/references/runtime-aware-dispatch.md +1 -1
  239. package/gsd-core/references/specless-probe-fallback.md +1 -1
  240. package/gsd-core/references/tdd.md +1 -3
  241. package/gsd-core/references/ui-brand.md +65 -21
  242. package/gsd-core/references/ui-consideration-probe.md +1 -1
  243. package/gsd-core/references/universal-anti-patterns.md +5 -5
  244. package/gsd-core/references/verifier-phase-gates.md +192 -0
  245. package/gsd-core/references/verify-command-path-resolvability.md +42 -0
  246. package/gsd-core/references/verify-mvp-mode.md +2 -2
  247. package/gsd-core/references/workstream-flag.md +33 -17
  248. package/gsd-core/templates/README.md +1 -1
  249. package/gsd-core/templates/SECURITY.md +3 -3
  250. package/gsd-core/templates/UI-SPEC.md +25 -3
  251. package/gsd-core/templates/VALIDATION.md +3 -3
  252. package/gsd-core/templates/discussion-log.md +1 -1
  253. package/gsd-core/templates/phase-prompt.md +5 -4
  254. package/gsd-core/templates/state.md +11 -4
  255. package/gsd-core/templates/verification-report.md +9 -1
  256. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  257. package/gsd-core/workflows/add-backlog.md +1 -1
  258. package/gsd-core/workflows/add-phase.md +3 -3
  259. package/gsd-core/workflows/add-tests.md +3 -8
  260. package/gsd-core/workflows/add-todo.md +1 -1
  261. package/gsd-core/workflows/ai-integration-phase.md +13 -20
  262. package/gsd-core/workflows/audit-fix.md +12 -3
  263. package/gsd-core/workflows/audit-milestone.md +9 -9
  264. package/gsd-core/workflows/audit-uat.md +17 -2
  265. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
  266. package/gsd-core/workflows/autonomous.md +11 -27
  267. package/gsd-core/workflows/check-todos.md +1 -1
  268. package/gsd-core/workflows/cleanup.md +64 -5
  269. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +14 -4
  270. package/gsd-core/workflows/code-review-fix.md +38 -11
  271. package/gsd-core/workflows/code-review.md +159 -52
  272. package/gsd-core/workflows/complete-milestone.md +151 -23
  273. package/gsd-core/workflows/debug.md +12 -8
  274. package/gsd-core/workflows/diagnose-issues.md +47 -15
  275. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  276. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -8
  277. package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
  278. package/gsd-core/workflows/discuss-phase/modes/text.md +1 -1
  279. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
  280. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  281. package/gsd-core/workflows/discuss-phase.md +1 -1
  282. package/gsd-core/workflows/do.md +3 -6
  283. package/gsd-core/workflows/docs-update.md +5 -4
  284. package/gsd-core/workflows/edit-phase.md +27 -2
  285. package/gsd-core/workflows/eval-review.md +7 -14
  286. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
  287. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +142 -15
  288. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  289. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  290. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
  291. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +24 -4
  292. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
  293. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
  294. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -2
  295. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
  296. package/gsd-core/workflows/execute-phase.md +72 -100
  297. package/gsd-core/workflows/execute-plan.md +52 -15
  298. package/gsd-core/workflows/explore.md +131 -4
  299. package/gsd-core/workflows/extract-learnings.md +1 -1
  300. package/gsd-core/workflows/fast.md +10 -2
  301. package/gsd-core/workflows/forensics.md +1 -1
  302. package/gsd-core/workflows/graduation.md +5 -5
  303. package/gsd-core/workflows/health.md +76 -10
  304. package/gsd-core/workflows/import.md +18 -15
  305. package/gsd-core/workflows/inbox.md +4 -5
  306. package/gsd-core/workflows/ingest-docs.md +49 -16
  307. package/gsd-core/workflows/insert-phase.md +5 -5
  308. package/gsd-core/workflows/list-seeds.md +5 -3
  309. package/gsd-core/workflows/list-workspaces.md +1 -1
  310. package/gsd-core/workflows/manager.md +12 -23
  311. package/gsd-core/workflows/map-codebase.md +1 -1
  312. package/gsd-core/workflows/milestone-summary.md +1 -1
  313. package/gsd-core/workflows/mvp-phase.md +8 -5
  314. package/gsd-core/workflows/new-milestone.md +22 -29
  315. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  316. package/gsd-core/workflows/new-project.md +26 -40
  317. package/gsd-core/workflows/new-workspace.md +1 -1
  318. package/gsd-core/workflows/next.md +14 -2
  319. package/gsd-core/workflows/pause-work.md +1 -1
  320. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
  321. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
  322. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -4
  323. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +3 -3
  324. package/gsd-core/workflows/plan-phase.md +162 -59
  325. package/gsd-core/workflows/plan-review-convergence.md +96 -11
  326. package/gsd-core/workflows/plant-seed.md +2 -2
  327. package/gsd-core/workflows/pr-branch.md +187 -51
  328. package/gsd-core/workflows/profile-user.md +16 -14
  329. package/gsd-core/workflows/progress.md +61 -18
  330. package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
  331. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +5 -7
  332. package/gsd-core/workflows/quick/steps/quick-verification.md +28 -9
  333. package/gsd-core/workflows/quick/steps/research-phase.md +4 -6
  334. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
  335. package/gsd-core/workflows/quick.md +55 -44
  336. package/gsd-core/workflows/remove-phase.md +4 -4
  337. package/gsd-core/workflows/remove-workspace.md +2 -2
  338. package/gsd-core/workflows/resume-project.md +8 -12
  339. package/gsd-core/workflows/review.md +219 -20
  340. package/gsd-core/workflows/scan.md +1 -1
  341. package/gsd-core/workflows/secure-phase.md +3 -3
  342. package/gsd-core/workflows/session-report.md +2 -1
  343. package/gsd-core/workflows/settings-advanced.md +7 -9
  344. package/gsd-core/workflows/settings-integrations.md +64 -31
  345. package/gsd-core/workflows/settings.md +69 -7
  346. package/gsd-core/workflows/ship.md +116 -50
  347. package/gsd-core/workflows/sketch-wrap-up.md +11 -17
  348. package/gsd-core/workflows/sketch.md +12 -18
  349. package/gsd-core/workflows/smart-entry.md +3 -5
  350. package/gsd-core/workflows/spec-phase.md +53 -13
  351. package/gsd-core/workflows/spike-wrap-up.md +7 -11
  352. package/gsd-core/workflows/spike.md +20 -31
  353. package/gsd-core/workflows/stats.md +2 -2
  354. package/gsd-core/workflows/sync-skills.md +64 -9
  355. package/gsd-core/workflows/thread.md +11 -7
  356. package/gsd-core/workflows/transition.md +49 -14
  357. package/gsd-core/workflows/ui-phase.md +15 -21
  358. package/gsd-core/workflows/ui-review.md +8 -12
  359. package/gsd-core/workflows/ultraplan-phase.md +5 -13
  360. package/gsd-core/workflows/undo.md +8 -16
  361. package/gsd-core/workflows/update.md +7 -11
  362. package/gsd-core/workflows/validate-phase.md +3 -3
  363. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
  364. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  365. package/gsd-core/workflows/verify-work.md +66 -25
  366. package/hooks/dist/gsd-agent-isolation-guard.js +158 -30
  367. package/hooks/dist/gsd-check-update-worker.js +56 -13
  368. package/hooks/dist/gsd-check-update.js +19 -1
  369. package/hooks/dist/gsd-config-reload.js +18 -12
  370. package/hooks/dist/gsd-context-monitor.js +19 -10
  371. package/hooks/dist/gsd-cursor-post-tool.js +3 -1
  372. package/hooks/dist/gsd-cursor-pre-tool.js +2 -3
  373. package/hooks/dist/gsd-cursor-session-start.js +2 -1
  374. package/hooks/dist/gsd-cursor-stop.js +2 -1
  375. package/hooks/dist/gsd-cursor-subagent-start.js +83 -3
  376. package/hooks/dist/gsd-cursor-subagent-stop.js +6 -3
  377. package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
  378. package/hooks/dist/gsd-graphify-update.sh +22 -18
  379. package/hooks/dist/gsd-node-runner.sh +76 -0
  380. package/hooks/dist/gsd-phase-boundary.sh +1 -0
  381. package/hooks/dist/gsd-prompt-guard.js +37 -27
  382. package/hooks/dist/gsd-read-guard.js +16 -7
  383. package/hooks/dist/gsd-read-injection-scanner.js +55 -32
  384. package/hooks/dist/gsd-session-state.sh +1 -0
  385. package/hooks/dist/gsd-statusline.js +231 -24
  386. package/hooks/dist/gsd-update-banner.js +22 -1
  387. package/hooks/dist/gsd-validate-commit.sh +80 -6
  388. package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
  389. package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
  390. package/hooks/dist/gsd-workflow-guard.js +162 -46
  391. package/hooks/dist/gsd-worktree-path-guard.js +36 -21
  392. package/hooks/dist/gsd-write-guard.js +35 -25
  393. package/hooks/dist/lib/cli-exit.js +560 -0
  394. package/hooks/dist/lib/exit-code-registry.js +98 -0
  395. package/hooks/dist/lib/git-cmd.js +92 -59
  396. package/hooks/dist/lib/git-probe.js +84 -0
  397. package/hooks/dist/lib/hook-exit.js +81 -0
  398. package/hooks/dist/lib/injection-patterns.js +45 -0
  399. package/hooks/dist/lib/isolation-deny-reason.js +39 -0
  400. package/hooks/dist/lib/isolation-sentinel.js +9 -0
  401. package/hooks/dist/managed-hooks-registry.cjs +3 -0
  402. package/hooks/gsd-agent-isolation-guard.js +158 -30
  403. package/hooks/gsd-check-update-worker.js +56 -13
  404. package/hooks/gsd-check-update.js +19 -1
  405. package/hooks/gsd-config-reload.js +18 -12
  406. package/hooks/gsd-context-monitor.js +19 -10
  407. package/hooks/gsd-cursor-post-tool.js +3 -1
  408. package/hooks/gsd-cursor-pre-tool.js +2 -3
  409. package/hooks/gsd-cursor-session-start.js +2 -1
  410. package/hooks/gsd-cursor-stop.js +2 -1
  411. package/hooks/gsd-cursor-subagent-start.js +83 -3
  412. package/hooks/gsd-cursor-subagent-stop.js +6 -3
  413. package/hooks/gsd-ensure-canonical-path.js +2 -1
  414. package/hooks/gsd-graphify-update.sh +22 -18
  415. package/hooks/gsd-node-runner.sh +76 -0
  416. package/hooks/gsd-phase-boundary.sh +1 -0
  417. package/hooks/gsd-prompt-guard.js +37 -27
  418. package/hooks/gsd-read-guard.js +16 -7
  419. package/hooks/gsd-read-injection-scanner.js +55 -32
  420. package/hooks/gsd-session-state.sh +1 -0
  421. package/hooks/gsd-statusline.js +231 -24
  422. package/hooks/gsd-update-banner.js +22 -1
  423. package/hooks/gsd-validate-commit.sh +80 -6
  424. package/hooks/gsd-windsurf-pre-command.js +16 -11
  425. package/hooks/gsd-windsurf-pre-write.js +22 -13
  426. package/hooks/gsd-workflow-guard.js +162 -46
  427. package/hooks/gsd-worktree-path-guard.js +36 -21
  428. package/hooks/gsd-write-guard.js +35 -25
  429. package/hooks/lib/cli-exit.js +560 -0
  430. package/hooks/lib/exit-code-registry.js +98 -0
  431. package/hooks/lib/git-cmd.js +92 -59
  432. package/hooks/lib/git-probe.js +84 -0
  433. package/hooks/lib/hook-exit.js +81 -0
  434. package/hooks/lib/injection-patterns.js +45 -0
  435. package/hooks/lib/isolation-deny-reason.js +39 -0
  436. package/hooks/lib/isolation-sentinel.js +9 -0
  437. package/hooks/managed-hooks-registry.cjs +3 -0
  438. package/package.json +28 -11
  439. package/pi/gsd.cjs +19 -5
  440. package/scripts/base64-scan.sh +74 -12
  441. package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
  442. package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
  443. package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
  444. package/scripts/build-hooks.js +5 -0
  445. package/scripts/changeset/lint.cjs +60 -5
  446. package/scripts/check-alias-drift.cjs +7 -43
  447. package/scripts/check-contract-drift.cjs +297 -0
  448. package/scripts/check-glossary-refs.cjs +77 -15
  449. package/scripts/check-mutation-score-ratchet.cjs +156 -0
  450. package/scripts/ci-check-job-near-cap.cjs +49 -0
  451. package/scripts/ci-pr-mergeability.cjs +262 -0
  452. package/scripts/ci-test-scope.cjs +64 -14
  453. package/scripts/ci-timeout-report.cjs +230 -0
  454. package/scripts/command-contract-helpers.cjs +903 -1
  455. package/scripts/docs-guard-registry.cjs +396 -0
  456. package/scripts/gen-adr-index.cjs +728 -38
  457. package/scripts/gen-capability-registry.cjs +11 -21
  458. package/scripts/gen-context-index.cjs +2 -11
  459. package/scripts/gen-exit-code-docs.cjs +318 -0
  460. package/scripts/gen-exit-code-registry.cjs +891 -0
  461. package/scripts/gen-features.cjs +836 -0
  462. package/scripts/gen-health-docs.cjs +390 -0
  463. package/scripts/gen-hooks-cli-exit.cjs +239 -0
  464. package/scripts/gen-install-tree-fixtures.cjs +2 -2
  465. package/scripts/gen-inventory-manifest.cjs +50 -4
  466. package/scripts/gen-loop-host-contract.cjs +138 -25
  467. package/scripts/gen-registry.cjs +3 -14
  468. package/scripts/gen-scripts-cli-exit.cjs +185 -0
  469. package/scripts/gen-state-md-docs.cjs +727 -0
  470. package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
  471. package/scripts/lib/alias-drift-families.cjs +46 -0
  472. package/scripts/lib/ci-job-timing.cjs +72 -0
  473. package/scripts/lib/cli-exit.cjs +546 -44
  474. package/scripts/lib/drift-scan.cjs +308 -0
  475. package/scripts/lib/exit-code-registry.cjs +98 -0
  476. package/scripts/lib/ndjson-reporter.cjs +119 -0
  477. package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -26
  478. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
  479. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
  480. package/scripts/lint-canary-version-leak.cjs +73 -0
  481. package/scripts/lint-command-contract.cjs +96 -13
  482. package/scripts/lint-completion-predicate-drift.cjs +933 -0
  483. package/scripts/lint-completion-ratio-drift.cjs +214 -0
  484. package/scripts/lint-default-flip-documentation.cjs +193 -0
  485. package/scripts/lint-docs-guard-registration.cjs +495 -0
  486. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +193 -0
  487. package/scripts/lint-eslint-glob-coverage.allowlist.json +38 -0
  488. package/scripts/lint-eslint-glob-coverage.cjs +340 -0
  489. package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
  490. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
  491. package/scripts/lint-health-diagnostic-rule-table.cjs +461 -0
  492. package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
  493. package/scripts/lint-milestone-window-drift.cjs +468 -0
  494. package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
  495. package/scripts/lint-phase-enumeration-drift.cjs +492 -0
  496. package/scripts/lint-plan-count-drift.cjs +318 -0
  497. package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
  498. package/scripts/lint-planning-prompt-drift.cjs +471 -0
  499. package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
  500. package/scripts/lint-regression-test-names.cjs +15 -13
  501. package/scripts/lint-removed-but-needed.cjs +488 -0
  502. package/scripts/lint-seam-enforcement.cjs +182 -0
  503. package/scripts/lint-slug-derivation-drift.cjs +921 -0
  504. package/scripts/lint-source-test-name-collision.cjs +241 -0
  505. package/scripts/lint-state-field-drift.cjs +805 -0
  506. package/scripts/lint-state-write-path-drift.cjs +950 -0
  507. package/scripts/lint-test-file-count.allowlist.json +137 -8
  508. package/scripts/lint-test-file-count.cjs +25 -3
  509. package/scripts/lint-unreachable-guard-drift.cjs +830 -0
  510. package/scripts/lint-vendored-deps.cjs +297 -0
  511. package/scripts/mutation-matrix.cjs +599 -50
  512. package/scripts/pr-changed-files.cjs +63 -0
  513. package/scripts/pr-template-policy.cjs +14 -4
  514. package/scripts/prompt-injection-scan.sh +100 -14
  515. package/scripts/require-issue-link-policy.cjs +192 -0
  516. package/scripts/secret-scan.sh +75 -13
  517. package/scripts/select-docs-guards.cjs +56 -0
  518. package/scripts/sync-runtime-launcher.cjs +24 -7
  519. package/skills/gsd-autonomous/SKILL.md +0 -1
  520. package/skills/gsd-code-review/SKILL.md +1 -1
  521. package/skills/gsd-discuss-phase/SKILL.md +1 -1
  522. package/skills/gsd-execute-phase/SKILL.md +1 -2
  523. package/skills/gsd-import/SKILL.md +1 -1
  524. package/skills/gsd-map-codebase/SKILL.md +1 -1
  525. package/skills/gsd-mempalace-capture/SKILL.md +1 -1
  526. package/skills/gsd-mempalace-recall/SKILL.md +1 -1
  527. package/skills/gsd-new-milestone/SKILL.md +1 -1
  528. package/skills/gsd-next/SKILL.md +0 -1
  529. package/skills/gsd-plan-phase/SKILL.md +0 -1
  530. package/skills/gsd-progress/SKILL.md +0 -1
  531. package/skills/gsd-quick/SKILL.md +9 -5
  532. package/skills/gsd-review-backlog/SKILL.md +2 -1
  533. package/skills/gsd-stats/SKILL.md +0 -1
  534. package/skills/gsd-verify-work/SKILL.md +1 -1
  535. package/vscode/package.json +1 -1
  536. package/bin/lib/ui-safety-gate.cjs +0 -107
  537. package/gsd-core/workflows/discovery-phase.md +0 -298
  538. package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
  539. package/gsd-core/workflows/verify-phase.md +0 -574
  540. package/scripts/affected-tests-lib.cjs +0 -554
  541. package/scripts/lint-allow-test-rule-refs.cjs +0 -162
  542. package/scripts/lint-emitted-drift-ack.cjs +0 -344
  543. package/scripts/run-affected-tests.cjs +0 -7
  544. package/scripts/run-tests.cjs +0 -1051
@@ -13,7 +13,7 @@
13
13
  const cjsCommandRouterAdapter = require("./cjs-command-router-adapter.cjs");
14
14
  const { routeCjsCommandFamily } = cjsCommandRouterAdapter;
15
15
  // ─── Implementation ───────────────────────────────────────────────────────────
16
- const VERIFICATION_SUBCOMMANDS = ['status'];
16
+ const VERIFICATION_SUBCOMMANDS = ['status', 'resolve-file'];
17
17
  function routeVerificationCommand({ verification, args, cwd, raw, error, }) {
18
18
  routeCjsCommandFamily({
19
19
  args,
@@ -23,6 +23,7 @@ function routeVerificationCommand({ verification, args, cwd, raw, error, }) {
23
23
  unknownMessage: (_subcommand, available) => `Unknown verification subcommand. Available: ${available.join(', ')}`,
24
24
  handlers: {
25
25
  status: () => verification.cmdVerificationStatus(cwd, args[2], raw),
26
+ 'resolve-file': () => verification.cmdVerificationResolveFile(cwd, args[2], raw),
26
27
  },
27
28
  });
28
29
  }
@@ -40,11 +40,17 @@ const phaseId = require("./phase-id.cjs");
40
40
  const frontmatterMod = require("./frontmatter.cjs");
41
41
  // eslint-disable-next-line @typescript-eslint/no-require-imports -- plan-scan.cjs is an export= CommonJS module
42
42
  const scanPhasePlans = require("./plan-scan.cjs");
43
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- core-utils.cjs is an export= CommonJS module
44
+ const coreUtilsMod = require("./core-utils.cjs");
45
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- planning-scope.cjs is an export= CommonJS module
46
+ const planningScopeMod = require("./planning-scope.cjs");
43
47
  const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
44
48
  const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
45
49
  const { output, error } = io;
46
- const { extractPhaseToken } = phaseId;
50
+ const { extractPhaseToken, scopeToPhase } = phaseId;
47
51
  const { extractFrontmatter } = frontmatterMod;
52
+ const { normalizeLineEndings } = coreUtilsMod;
53
+ const { SCOPE } = planningScopeMod;
48
54
  // ─── Constants ────────────────────────────────────────────────────────────────
49
55
  /** The set of status values that the gsd-verifier agent emits. */
50
56
  const VERIFIER_STATUSES = ['passed', 'gaps_found', 'human_needed'];
@@ -100,7 +106,7 @@ const VERIFICATION_ROUTING_TABLE = {
100
106
  // the file has no parseable frontmatter status. Never emitted by the verifier.
101
107
  missing: {
102
108
  status: 'missing',
103
- next_action: 'No verification report found — the verify step never completed. Re-run execute-phase.',
109
+ next_action: 'No verification report found — the verify step never completed. Running execute-phase is safe here: it resumes at the verification gates and does not re-run plans that already have a SUMMARY.md (see #2868).',
104
110
  next_command: 'execute-phase',
105
111
  },
106
112
  // INTERNAL SENTINEL: constructed when the file has a status value not in
@@ -211,6 +217,145 @@ function missingResult(runtime, phaseArg) {
211
217
  next_command: projectNextCommand(route.next_command, runtime, phaseArg),
212
218
  };
213
219
  }
220
+ /**
221
+ * #3518: the shared phase-pinned artifact-selection core BOTH single-pick
222
+ * resolvers (`resolveVerificationFile` for `*-VERIFICATION.md`,
223
+ * `resolveUatFile` for `*-UAT.md`) delegate to — one rule, not two grammars
224
+ * that agree today and drift tomorrow (epic #3473 F2's defect class).
225
+ *
226
+ * `bareName` is the artifact filename WITHOUT the leading dash (`'UAT.md'`);
227
+ * a "dashed" candidate is any entry ending `-${bareName}`.
228
+ *
229
+ * Selection order:
230
+ * 1. `options.phaseToken` given and `<phaseToken>-${bareName}` is among
231
+ * the candidates — that exact file always wins: it is THIS phase's own
232
+ * artifact, and no other candidate (whichever phase's token it carries)
233
+ * can outrank it (#3492 / #3518).
234
+ * 2. Fallback — no exact phase-token match (or no token given): alphabetically
235
+ * first of the dashed candidates that are THIS phase's own, per
236
+ * `scopeToPhase(candidates, options.phaseDirName)` (#3511 reconciliation,
237
+ * below). Load-bearing: a phase whose only artifact is non-canonically
238
+ * named must keep resolving to it, not to null — this fix must not turn
239
+ * "found an artifact" into "found nothing" for anyone. A
240
+ * non-canonically-named artifact of THIS phase (e.g.
241
+ * `03-CORRECTION-VERIFICATION.md` in `03-foo`) still passes
242
+ * `isPhaseArtifact` (it names phase 03, same as the directory), so it
243
+ * is still returned here.
244
+ * 3. `options.allowBare` only — a bare `${bareName}`, ranked BELOW both
245
+ * of the above. Rationale: a dashed file names its phase, a bare one
246
+ * does not, so a dashed file (canonical or not) is always the better
247
+ * answer when both exist. Reached when neither (1) nor (2) found any
248
+ * candidate — including when (2)'s scoping filtered every dashed
249
+ * candidate out as belonging to some OTHER phase.
250
+ *
251
+ * #3511 RECONCILIATION with `isPhaseArtifact` (`src/phase-id.cts`): that
252
+ * predicate's own docblock used to flag this fallback as an open gap — its
253
+ * aggregate scans exclude a cross-phase stray, but this single-pick resolver
254
+ * did not, so it could return a stray as THE artifact while the aggregate
255
+ * scans correctly ignored it. Closed by scoping step (2) above through
256
+ * `scopeToPhase` (`src/phase-id.cts`, itself built on `isPhaseArtifact`):
257
+ * `options.phaseDirName` threads the phase directory's basename in, and the
258
+ * fallback now filters candidates through `scopeToPhase(candidates,
259
+ * phaseDirName)` before picking alphabetically-first. This does NOT reopen
260
+ * the #3357 guarantee — that guarantee is "a phase whose only report is
261
+ * non-canonically named must keep working", and a non-canonically-named
262
+ * artifact of THIS phase still passes `isPhaseArtifact` (it is membership by
263
+ * phase number, not by canonical shape), so it is still returned. Only a
264
+ * file belonging to a DIFFERENT phase is now excluded — and excluding it is
265
+ * correct: returning another phase's artifact as this phase's own is worse
266
+ * than reporting none (confidently wrong beats honestly empty).
267
+ * The fail-safe now lives entirely inside `isPhaseArtifact`, not in
268
+ * `scopeToPhase` (which is a plain filter with no unfiltered fallback):
269
+ * (a) when phase-number membership cannot be determined for `phaseDirName` at
270
+ * all (no reliable token — the zero-token directory case), every candidate is
271
+ * treated as belonging to the phase; (b) the `firstLetterPrefixed`
272
+ * bracket-ambiguity case, where a letter-prefixed-decimal dir is
273
+ * string-indistinguishable from a bracket-dir token, also includes
274
+ * everything rather than guess; (c) a token-less filename (bare
275
+ * `${bareName}`) is accepted by directory containment alone. Outside
276
+ * those cases, when scoping DOES remove every dashed candidate — a real
277
+ * cross-phase stray, or a phase whose own artifact is genuinely absent — the
278
+ * fallback below correctly falls through to `allowBare`/`null`: reporting no
279
+ * artifact, not another phase's. `options.phaseDirName` omitted entirely skips
280
+ * the filter outright (the ternary below), which is unscoped, pre-#3511
281
+ * behavior.
282
+ *
283
+ * Pure — takes an already-read directory listing and does no I/O of its own,
284
+ * so every call site keeps its existing `fsImpl` seam and no-throw contract
285
+ * untouched.
286
+ */
287
+ function resolvePhaseArtifactFile(entries, bareName, options = {}) {
288
+ const candidates = entries.filter((f) => f.endsWith(`-${bareName}`)).sort();
289
+ if (candidates.length > 0) {
290
+ if (options.phaseToken) {
291
+ const thisPhaseFile = `${options.phaseToken}-${bareName}`;
292
+ if (candidates.includes(thisPhaseFile))
293
+ return thisPhaseFile;
294
+ }
295
+ // #3511: scope the fallback to files that belong to THIS phase, so a
296
+ // stray cross-phase file can no longer outrank a return of null.
297
+ // `phaseDirName` omitted, or membership undeterminable for it, →
298
+ // unscoped `candidates` (pre-#3511 behavior); otherwise strays are
299
+ // filtered out, and if that leaves nothing the code falls through to
300
+ // `allowBare`/`null` deliberately.
301
+ const scoped = options.phaseDirName
302
+ ? scopeToPhase(candidates, options.phaseDirName)
303
+ : candidates;
304
+ if (scoped.length > 0)
305
+ return scoped[0];
306
+ }
307
+ if (options.allowBare && entries.includes(bareName))
308
+ return bareName;
309
+ return null;
310
+ }
311
+ /**
312
+ * Resolve which `*-VERIFICATION.md` entry in a phase directory's listing IS
313
+ * the phase's verification report, when more than one such file exists.
314
+ *
315
+ * #3357: a phase dir can legitimately hold more than one `*-VERIFICATION.md`
316
+ * — the real per-phase report (`03-VERIFICATION.md`) alongside an ad-hoc plan
317
+ * worksheet (`03-CORRECTION-VERIFICATION.md`). Picking "alphabetically first"
318
+ * (`'C' < 'V'`) silently chose the worksheet, which usually has no
319
+ * frontmatter `status:`, so a phase with a PASSING report read as `missing`.
320
+ * This was two independent hand-rolled `.sort()[0]` picks
321
+ * (findStaleVerificationSummary and readVerificationStatus) — this is the
322
+ * single resolver both now call (#3473 F2).
323
+ *
324
+ * Selection order: see `resolvePhaseArtifactFile` (the shared core this
325
+ * delegates to since #3518, itself phase-scoped since #3511) —
326
+ * phase-token-pinned, then phase-scoped alphabetically-first dashed
327
+ * fallback, then (allowBare only) a bare `VERIFICATION.md`. #3518 extracted
328
+ * this into the shared core without changing behavior; #3511's
329
+ * `phaseDirName` scoping now lives inside that shared core rather than here.
330
+ */
331
+ function resolveVerificationFile(entries, options = {}) {
332
+ return resolvePhaseArtifactFile(entries, 'VERIFICATION.md', options);
333
+ }
334
+ /**
335
+ * #3518: resolve which `*-UAT.md` entry in a phase directory's listing IS
336
+ * the phase's UAT artifact, when more than one such file exists — the UAT
337
+ * counterpart of `resolveVerificationFile`, sharing its exact selection rule
338
+ * via `resolvePhaseArtifactFile`.
339
+ *
340
+ * The bug this closes: both `uat_path` projectors in `src/init.cts` picked
341
+ * with a bare `.find((f) => f.endsWith('-UAT.md') || f === 'UAT.md')` over an
342
+ * unsorted `readdir` listing — no phase-membership check and no ordering — so
343
+ * a stray or cross-phase `04-UAT.md` sitting in phase 03's directory could
344
+ * become phase 03's `uat_path`, and WHICH file won was filesystem-dependent
345
+ * (creation order on APFS, hash order on ext4/XFS): two machines on the same
346
+ * commit could emit different `uat_path` values for the same phase. `uat_path`
347
+ * is consumed downstream by workflows that then read the named file, so a
348
+ * wrong path routes UAT state from another phase.
349
+ *
350
+ * Deterministic by construction: same answer on every machine. Phase-scoped
351
+ * (#3511): passing `options.phaseDirName` filters the alphabetically-first
352
+ * fallback (tier 2) to artifacts that belong to THIS phase — see
353
+ * `resolvePhaseArtifactFile` for the full selection order and scoping
354
+ * rationale.
355
+ */
356
+ function resolveUatFile(entries, options = {}) {
357
+ return resolvePhaseArtifactFile(entries, 'UAT.md', options);
358
+ }
214
359
  function findStaleVerificationSummary(phaseDir, fsImpl = node_fs_1.default, phaseCleanCommitTimesMs = defaultPhaseCleanCommitTimesMs) {
215
360
  // FS errors (TOCTOU: a SUMMARY listed by scanPhasePlans then removed before statSync;
216
361
  // unreadable dir; broken symlink; file->dir swap) must degrade rather than throw
@@ -223,7 +368,13 @@ function findStaleVerificationSummary(phaseDir, fsImpl = node_fs_1.default, phas
223
368
  // this function only reports what it actually knows.
224
369
  try {
225
370
  const phaseFiles = fsImpl.readdirSync(phaseDir);
226
- const verificationFile = phaseFiles.filter((f) => f.endsWith('-VERIFICATION.md')).sort()[0];
371
+ // #3492: pin selection to THIS phase's own token so a stray cross-phase
372
+ // or sentinel-numbered canonically-shaped file cannot outrank this
373
+ // phase's own (possibly non-canonical) report. #3511: phaseDirName scopes
374
+ // the fallback path to this same phase (see resolveVerificationFile docs).
375
+ const phaseDirName = node_path_1.default.basename(phaseDir);
376
+ const phaseToken = extractPhaseToken(phaseDirName);
377
+ const verificationFile = resolveVerificationFile(phaseFiles, { phaseToken, phaseDirName });
227
378
  if (!verificationFile)
228
379
  return { determined: true, stale: false };
229
380
  const summaryFiles = scanPhasePlans(phaseDir).summaryFiles
@@ -261,8 +412,10 @@ function findStaleVerificationSummary(phaseDir, fsImpl = node_fs_1.default, phas
261
412
  * phaseDir and return the routing result.
262
413
  *
263
414
  * Behavior:
264
- * 1. Find the first file matching `*-VERIFICATION.md` (sorted, take first).
265
- * If none → status 'missing'.
415
+ * 1. Find the phase's verification report via `resolveVerificationFile`
416
+ * (canonical `<phase-token>-VERIFICATION.md` preferred; falls back to the
417
+ * alphabetically-first `*-VERIFICATION.md` that belongs to THIS phase when
418
+ * none is canonical — #3357/#3511). If none → status 'missing'.
266
419
  * 2. Extract `status` from FRONTMATTER ONLY via the shared extractFrontmatter
267
420
  * parser (DEFECT.FRONTMATTER-SCALAR-BROAD-GREP fix — parser anchors at byte 0).
268
421
  * If no frontmatter block or no `status` key → status 'missing'.
@@ -299,8 +452,12 @@ function readVerificationStatus(phaseDir, opts = {}) {
299
452
  let verificationFile = null;
300
453
  try {
301
454
  const entries = fsImpl.readdirSync(phaseDir);
302
- const candidates = entries.filter((f) => f.endsWith('-VERIFICATION.md')).sort();
303
- verificationFile = candidates.length > 0 ? candidates[0] : null;
455
+ // #3492: pin selection to THIS phase's own token (already derived above
456
+ // for the routed command argument) so a stray cross-phase or
457
+ // sentinel-numbered canonically-shaped file cannot outrank this phase's
458
+ // own (possibly non-canonical) report. #3511: baseName also scopes the
459
+ // fallback path to this same phase (see resolveVerificationFile docs).
460
+ verificationFile = resolveVerificationFile(entries, { phaseToken, phaseDirName: baseName });
304
461
  }
305
462
  catch {
306
463
  // Directory unreadable → treat as missing
@@ -314,7 +471,17 @@ function readVerificationStatus(phaseDir, opts = {}) {
314
471
  const filePath = node_path_1.default.join(phaseDir, verificationFile);
315
472
  let rawStatus = null;
316
473
  try {
317
- const content = fsImpl.readFileSync(filePath, 'utf-8');
474
+ // #3707-CR follow-up MINOR 1: normalize line endings at this read
475
+ // boundary — this function's own `readFileSync` is the equivalent seam
476
+ // `planning.inspect`'s `buildUatRows`/`readDocument` route through for
477
+ // UAT/REQUIREMENTS documents, but `readVerificationStatus` had no such
478
+ // normalization of its own. A lone-CR VERIFICATION.md's `---\r...\r---`
479
+ // frontmatter fence never matched `extractFrontmatter`'s byte-0
480
+ // `---\n`/`---\r\n` check, so `status: passed` was read as absent and
481
+ // this function reported 'missing' — under-reporting a completed
482
+ // verification as if the step never ran, the fail-safe direction but the
483
+ // same root cause as the false-clean class fixed elsewhere in #3707-CR.
484
+ const content = normalizeLineEndings(fsImpl.readFileSync(filePath, 'utf-8'));
318
485
  const fm = extractFrontmatter(content, filePath);
319
486
  const statusVal = fm['status'];
320
487
  // status is always a scalar string in a well-formed VERIFICATION.md frontmatter;
@@ -374,11 +541,63 @@ function readVerificationStatus(phaseDir, opts = {}) {
374
541
  const unknownRoute = VERIFICATION_ROUTING_TABLE['unknown'];
375
542
  return {
376
543
  status: unknownRoute.status,
377
- next_action: `Unexpected verification status '${rawStatus}'. Re-run execute-phase verification.`,
544
+ next_action: `Unexpected verification status '${rawStatus}'. If this is an intentional non-standard marker (e.g. a hand-set failed/superseded state), no action is needed. Otherwise, run execute-phase to regenerate verification — it will not re-run plans that already have a SUMMARY.md.`,
378
545
  next_command: projectNextCommand(unknownRoute.next_command, runtime, phaseArg),
379
546
  ...(staleCheckIndeterminate ? { staleCheckIndeterminate: true } : {}),
380
547
  };
381
548
  }
549
+ /**
550
+ * isPhaseComplete — the single canonical owner of "is phase P complete?"
551
+ * (ADR-3180 §7.4, Decision 1). Sited beside readVerificationStatus, which it
552
+ * wraps.
553
+ *
554
+ * DISK-STRICT (#2957, maintainer decision 2026-08-08; ADR-3180 §7.4 amended
555
+ * af92fd4c9): readVerificationStatus is called UNCONDITIONALLY here — plan
556
+ * count is NOT a precondition. A phase with zero plans and a passing
557
+ * `*-VERIFICATION.md` is complete (#3168). A ROADMAP checkbox has no machine
558
+ * authority and is never consulted — this function never reads ROADMAP.md.
559
+ *
560
+ * `complete` is exactly `verification.status === 'passed'`. `verification`
561
+ * carries the FULL routing result (status/next_action/next_command), so a
562
+ * caller can distinguish a failing verdict (`gaps_found`/`human_needed`/
563
+ * `stale`/`unknown`) from an absent one (`missing`) — both are "not
564
+ * complete", but they are not the same non-answer.
565
+ *
566
+ * `scope` is UNREADABLE when `phaseDir` itself could not be listed — this is
567
+ * INDEPENDENT of readVerificationStatus's own no-throw fail-open contract for
568
+ * a missing `*-VERIFICATION.md` file (a well-formed answer,
569
+ * `verification.status === 'missing'`, scope COMPLETE): a caller must not
570
+ * read `value.complete: false` here as a confident "not complete" the way it
571
+ * can for a genuinely-checked missing file.
572
+ *
573
+ * Does NOT import scanPhasePlans / plan-scan.cjs — the owner consumes plan
574
+ * counts from its caller when a caller needs them for a different question
575
+ * (e.g. buildPhaseCompletionProjection's own `implementation_complete`); it
576
+ * never re-derives or requires them itself.
577
+ */
578
+ function isPhaseComplete(phaseDir, deps = {}) {
579
+ const fsImpl = deps.fs ?? node_fs_1.default;
580
+ let readable = true;
581
+ try {
582
+ fsImpl.readdirSync(phaseDir);
583
+ }
584
+ catch {
585
+ readable = false;
586
+ }
587
+ const verification = readVerificationStatus(phaseDir, {
588
+ fs: deps.fs,
589
+ phaseCleanCommitTimesMs: deps.phaseCleanCommitTimesMs,
590
+ runtime: deps.runtime,
591
+ phaseNumber: deps.phaseNumber,
592
+ });
593
+ return {
594
+ value: {
595
+ complete: verification.status === 'passed',
596
+ verification,
597
+ },
598
+ scope: readable ? SCOPE.COMPLETE : SCOPE.UNREADABLE,
599
+ };
600
+ }
382
601
  /**
383
602
  * CLI command handler: resolve phaseDir against cwd, call readVerificationStatus,
384
603
  * emit via io.output().
@@ -396,11 +615,55 @@ function cmdVerificationStatus(cwd, phaseDirArg, raw) {
396
615
  const result = readVerificationStatus(phaseDir, { runtime: (0, runtime_slash_cjs_1.resolveRuntime)(cwd) });
397
616
  output(result, raw);
398
617
  }
618
+ /**
619
+ * CLI command handler: resolve which `*-VERIFICATION.md` in `phaseDirArg` is
620
+ * the phase's own report, via the shared `resolveVerificationFile` seam, and
621
+ * emit its absolute path.
622
+ *
623
+ * #3492 F3: the ONE seam shell callers (verify-work.md's writer, transition.md's
624
+ * awk reader) route through instead of hand-rolling `ls *-VERIFICATION.md |
625
+ * head -1` / an awk glob scan — both of which pick alphabetically-first and so
626
+ * diverge from every JS reader now pinned to the phase's own token.
627
+ *
628
+ * Emits `{ verification_file: "<absolute path>" | "" }` (empty when no
629
+ * candidate resolves, including an unreadable directory). `raw` emits the
630
+ * bare path string (possibly empty) so `VAR=$(gsd_run query
631
+ * verification.resolve-file "$PHASE_DIR" --raw)` is directly assignable.
632
+ *
633
+ * @param cwd - Current working directory (used to resolve phaseDirArg).
634
+ * @param phaseDirArg - Phase directory path (absolute or relative to cwd).
635
+ * @param raw - Whether to emit raw (non-JSON) output.
636
+ */
637
+ function cmdVerificationResolveFile(cwd, phaseDirArg, raw) {
638
+ if (!phaseDirArg) {
639
+ error('phase directory required for verification.resolve-file');
640
+ return;
641
+ }
642
+ const phaseDir = node_path_1.default.resolve(cwd, phaseDirArg);
643
+ let verificationPath = '';
644
+ try {
645
+ const entries = node_fs_1.default.readdirSync(phaseDir);
646
+ const phaseDirName = node_path_1.default.basename(phaseDir);
647
+ const phaseToken = extractPhaseToken(phaseDirName);
648
+ const verificationFile = resolveVerificationFile(entries, { allowBare: true, phaseToken, phaseDirName });
649
+ if (verificationFile) {
650
+ verificationPath = node_path_1.default.join(phaseDir, verificationFile);
651
+ }
652
+ }
653
+ catch {
654
+ verificationPath = '';
655
+ }
656
+ output({ verification_file: verificationPath }, raw, verificationPath);
657
+ }
399
658
  module.exports = {
400
659
  VERIFIER_STATUSES,
401
660
  VERIFICATION_ROUTING_TABLE,
402
661
  defaultPhaseCleanCommitTimesMs,
662
+ resolveVerificationFile,
663
+ resolveUatFile,
403
664
  findStaleVerificationSummary,
404
665
  readVerificationStatus,
666
+ isPhaseComplete,
405
667
  cmdVerificationStatus,
668
+ cmdVerificationResolveFile,
406
669
  };