@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
@@ -0,0 +1,303 @@
1
+ "use strict";
2
+ /**
3
+ * Health Diagnostic Rules — STATE.md consistency group (Phase 11, #3309,
4
+ * ADR-3180 §8.2/§8.3/§8.5).
5
+ *
6
+ * Five rules, each a near-mechanical extraction of an already-working
7
+ * `addIssue` call site in `cmdValidateHealth` (Gall's Law, design doc "Rule
8
+ * table organization" / "Laws applied"):
9
+ *
10
+ * - W024 (`verify.cts:1709-1729`) — STATE.md `state_head` commit-age
11
+ * freshness vs. git HEAD. GENUINE GAP, deliberately NOT migrated — see the
12
+ * `RULE_W024` comment below for exactly why.
13
+ * - W002 (`verify.cts:1731-1774`) — STATE.md references a phase token not
14
+ * declared anywhere (disk or ROADMAP).
15
+ * - W011 (`verify.cts:2104-2134`) — STATE's current-phase status disagrees
16
+ * with ROADMAP's `[x]` checkbox for that same phase.
17
+ * - W021 (`verify.cts:2270-2299`, the FIRST `addIssue('warning', 'W021', ...)`
18
+ * call site) — under the `'milestone-prefixed'` `phase_id_convention`, a
19
+ * phase's integer prefix implies a different milestone than the ROADMAP
20
+ * section it is actually listed under.
21
+ * - W026 (`verify.cts:2356-2399`, the SECOND `addIssue('warning', 'W021', ...)`
22
+ * call site — split off per the design doc's "New codes for the two split
23
+ * subjects" section, since one code covering two unrelated subjects is a
24
+ * genuine conflation) — STATE says the milestone is complete/archived, but
25
+ * ROADMAP (scoped to that same milestone) still lists a phase with no
26
+ * matching disk directory.
27
+ *
28
+ * - W002's original message interpolates `${slash('health')}`
29
+ * (`verify.cts:1770`) and W011's interpolates `${slash('progress')}`
30
+ * (`verify.cts:2126`) — both per-project runtime-resolved values
31
+ * (`formatGsdSlash`, `src/runtime-slash.cts`) this rule's
32
+ * `(snapshot) => Diagnostic[]` signature has no access to. Hardcodes the
33
+ * canonical `/gsd-health`/`/gsd-progress` hyphen form instead, mirroring
34
+ * the sibling "config.json validation" group's W016 rule
35
+ * (`src/health-diagnostic-rules/config-validation.cts`), which hardcodes
36
+ * `/gsd-ai-integration-phase` the same way for the identical reason.
37
+ *
38
+ * Design: .gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md
39
+ */
40
+ // Runtime values (SEVERITY/REMEDY_ACTION/REMEDY_RISK) are needed here, not
41
+ // just types, so this is a normal (non type-only) `import ... = require(...)`
42
+ // — unlike `health-diagnostic.cts`'s own type-only import of
43
+ // `planning-snapshot.cjs`, which never touches that module's runtime values.
44
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- export= CommonJS module
45
+ const healthDiagnosticMod = require("../health-diagnostic-types.cjs");
46
+ const { SEVERITY, adviseRemedy } = healthDiagnosticMod;
47
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
48
+ const phaseIdMod = require("../phase-id.cjs");
49
+ const { getMilestoneFromPhaseId, matchPhaseDirs, normalizePhaseName, extractPhaseToken, PHASE_NUMBER_TOKEN_SOURCE } = phaseIdMod;
50
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- the single owner of the persisted status vocabulary
51
+ const stateDocumentMod = require("../state-document.cjs");
52
+ const { normalizeStateStatus } = stateDocumentMod;
53
+ // ─── W024 — STATE.md commit-age freshness (DELIBERATELY INERT) ─────────────
54
+ /**
55
+ * W024's real check (`verify.cts:1709-1729`) calls
56
+ * `readStateHeadFreshness(cwd, fm['state_head'])`, which shells out to `git
57
+ * log` to count commits between the frontmatter's `state_head` and the
58
+ * current HEAD. That is ambient I/O (git history), not `.planning/` content —
59
+ * confirmed against `src/planning-snapshot.cts`'s full 15-field
60
+ * `PlanningSnapshot` interface: no field wraps `readStateHeadFreshness` or
61
+ * exposes a commits-behind count.
62
+ *
63
+ * §8.1 rule 1 requires a rule's signature to be `(snapshot) => Diagnostic[]`
64
+ * with no ambient I/O inside `check` — so this rule does NOT call
65
+ * `readStateHeadFreshness` itself (that would violate the constraint the
66
+ * skeleton's own `Rule.check` type exists to enforce). Adding a 16th
67
+ * `PlanningSnapshot` field (e.g. `stateHeadFreshness: {value:
68
+ * {commitsBehind, stateHead}, scope}`) is the fix, but is out of this
69
+ * group's scope (`src/planning-snapshot.cts` is a shared file this task was
70
+ * not dispatched to extend).
71
+ *
72
+ * Registered here, `check` always returning `[]`, so the code table stays
73
+ * complete per §8.2's 1:1 invariant (every code the old `verify.cts` emitted
74
+ * has exactly one `Rule` entry) rather than silently dropping W024 from the
75
+ * table. This is a documented, deliberate deferral pending the 16th snapshot
76
+ * field — flagged prominently rather than quietly ported as a no-op.
77
+ */
78
+ const RULE_W024 = {
79
+ code: 'W024',
80
+ severity: SEVERITY.WARNING,
81
+ description: 'STATE.md was written many commits ago — treat its contents as approximate',
82
+ repairable: false,
83
+ check: (_snapshot) => [],
84
+ };
85
+ // ─── W002 — STATE.md references an undeclared phase token ──────────────────
86
+ /**
87
+ * The "valid phase" set the original code builds from
88
+ * `collectDiskPhases(planBase)` (disk dir tokens) + ROADMAP heading tokens +
89
+ * `forEachArchivedPhaseToken` (archived milestone-phase-dir tokens,
90
+ * `verify.cts:1748`). This rebuilds the disk+ROADMAP two-thirds from parsed
91
+ * snapshot fields only: `phaseDirs.value` (disk dir names, tokenized the same
92
+ * way `collectDiskPhaseEntries` does — via `extractPhaseToken`) and
93
+ * `roadmapDeclaredPhases.value.map(p => p.phaseId)` (ROADMAP-declared phase
94
+ * ids). Archived-phase-token coverage is NOT included — no
95
+ * `PlanningSnapshot` field exposes archived milestone-phase-dir tokens
96
+ * (confirmed against the 15-field interface). Omitting it makes this valid
97
+ * set a SUBSET of the original's, which can only make MORE STATE.md phase
98
+ * tokens look "invalid" (never fewer) — a conservative, safe direction; a
99
+ * project with archived phases still referenced from STATE.md is the
100
+ * fixture shape that would expose a false positive, and none of this
101
+ * group's fixtures exercise archives, so this gap is disclosed rather than
102
+ * silently absorbed.
103
+ *
104
+ * UPDATE (#3652): archived-phase-token coverage IS now included, via the
105
+ * additive `snapshot.archivedPhaseTokens` field
106
+ * (`src/planning-snapshot.cts`, added for this fix) — the disclosed gap
107
+ * above is closed; the paragraph is kept for the "conservative direction"
108
+ * reasoning, which still explains why every OTHER omission in this
109
+ * function is safe.
110
+ */
111
+ function buildValidPhaseSet(snapshot) {
112
+ const valid = new Set();
113
+ for (const dir of snapshot.phaseDirs.value) {
114
+ const token = extractPhaseToken(dir);
115
+ if (token)
116
+ valid.add(token);
117
+ }
118
+ for (const entry of snapshot.roadmapDeclaredPhases.value) {
119
+ valid.add(entry.phaseId);
120
+ }
121
+ for (const token of snapshot.archivedPhaseTokens.value) {
122
+ valid.add(token);
123
+ }
124
+ return valid;
125
+ }
126
+ /** Mirrors `verify.cts:1749-1758`'s zero-padding normalization exactly. */
127
+ function normalizePhaseTokenSet(valid) {
128
+ const normalized = new Set();
129
+ for (const p of valid) {
130
+ normalized.add(p);
131
+ const dotIdx = p.indexOf('.');
132
+ const head = dotIdx === -1 ? p : p.slice(0, dotIdx);
133
+ const tail = dotIdx === -1 ? '' : p.slice(dotIdx);
134
+ if (/^\d+$/.test(head)) {
135
+ normalized.add(head.padStart(2, '0') + tail);
136
+ }
137
+ }
138
+ return normalized;
139
+ }
140
+ const RULE_W002 = {
141
+ code: 'W002',
142
+ severity: SEVERITY.WARNING,
143
+ description: 'STATE.md references invalid phase',
144
+ repairable: false,
145
+ check: (snapshot) => {
146
+ const validPhases = buildValidPhaseSet(snapshot);
147
+ // Mirrors `verify.cts:1765`'s `if (normalizedValid.size > 0)` guard
148
+ // exactly — a project with zero declared phases emits nothing, never a
149
+ // false positive on every STATE.md phase mention.
150
+ if (validPhases.size === 0)
151
+ return [];
152
+ const normalizedValid = normalizePhaseTokenSet(validPhases);
153
+ const sortedValid = [...validPhases].sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
154
+ const diagnostics = [];
155
+ for (const ref of snapshot.statePhaseTokens.value) {
156
+ const dotIdx = ref.indexOf('.');
157
+ const head = dotIdx === -1 ? ref : ref.slice(0, dotIdx);
158
+ const tail = dotIdx === -1 ? '' : ref.slice(dotIdx);
159
+ const padded = /^\d+$/.test(head) ? head.padStart(2, '0') + tail : ref;
160
+ if (normalizedValid.has(ref) || normalizedValid.has(padded))
161
+ continue;
162
+ diagnostics.push({
163
+ code: 'W002',
164
+ severity: SEVERITY.WARNING,
165
+ message: `STATE.md references phase ${ref}, but only phases ${sortedValid.join(', ')} are declared`,
166
+ remedy: adviseRemedy('Review STATE.md manually before changing it; /gsd-health --repair will not overwrite an existing STATE.md for phase mismatches'),
167
+ });
168
+ }
169
+ return diagnostics;
170
+ },
171
+ };
172
+ // ─── W011 — STATE current-phase status vs. ROADMAP checkbox disagree ───────
173
+ /**
174
+ * `currentPhaseLabel.value` is a prose string (e.g. `"3 of 8 (User Auth)"`),
175
+ * not a clean phase id — the leading integer (optionally letter-suffixed /
176
+ * dotted, the same `PHASE_NUMBER_TOKEN_SOURCE` grammar) is the "current
177
+ * phase" proxy the original `verify.cts:2109-2113` derives via its own
178
+ * `**Current Phase:**`/`Current Phase:` regex + `.replace(/^0+/, '')`. That
179
+ * literal field name does not exist in the current `state.md` template
180
+ * (which uses `Phase: [X] of [Y] ([Phase name])` under `## Current
181
+ * Position`) — `currentPhaseLabel` is the parsed owner of that exact field,
182
+ * so extracting its leading number is the equivalent-intent read against
183
+ * the template STATE.md actually ships. #3280: the label's ladder
184
+ * (`buildStateFields`, `src/planning-snapshot.cts`) now leads with the
185
+ * frontmatter `current_phase` scalar — the key `gsd-tools state update` /
186
+ * `state begin-phase` persist — so a bare `"2"` is the expected value on
187
+ * the machine-readable format, and this leading-number extraction handles
188
+ * it identically.
189
+ */
190
+ function currentPhaseIdFromLabel(label) {
191
+ if (!label)
192
+ return null;
193
+ const m = label.match(new RegExp(`^0*(${PHASE_NUMBER_TOKEN_SOURCE})`));
194
+ return m ? m[1] : null;
195
+ }
196
+ const RULE_W011 = {
197
+ code: 'W011',
198
+ severity: SEVERITY.WARNING,
199
+ description: 'STATE.md current-phase status disagrees with ROADMAP.md checkbox',
200
+ repairable: false,
201
+ check: (snapshot) => {
202
+ const phaseId = currentPhaseIdFromLabel(snapshot.currentPhaseLabel.value);
203
+ if (phaseId === null)
204
+ return [];
205
+ const checked = snapshot.roadmapPhaseCheckboxes.value[phaseId];
206
+ if (checked !== true)
207
+ return [];
208
+ // #3280: the state writer persists `status` through `normalizeStateStatus`
209
+ // (`state.cts`'s syncStateFrontmatter), whose completion token is
210
+ // `completed` — an exact `'complete' || 'done'` comparison rejects the
211
+ // exact vocabulary the product writes and turns every legitimately
212
+ // completed frontmatter STATE.md into a false positive. Route the
213
+ // comparison through the same seam that owns the vocabulary
214
+ // (`state-document.cjs`'s `normalizeStateStatus`) rather than growing a
215
+ // second bespoke token list here.
216
+ const statusVal = (snapshot.stateStatus.value ?? '').trim();
217
+ if (normalizeStateStatus(statusVal, null) === 'completed')
218
+ return [];
219
+ return [
220
+ {
221
+ code: 'W011',
222
+ severity: SEVERITY.WARNING,
223
+ message: `STATE.md says current phase is ${phaseId} (status: ${statusVal.toLowerCase() || 'unknown'}) but ROADMAP.md shows it as [x] complete — state files may be out of sync`,
224
+ remedy: adviseRemedy('Run /gsd-progress to re-derive current position, or manually update STATE.md'),
225
+ },
226
+ ];
227
+ },
228
+ };
229
+ // ─── W021 — phase_id_convention integer-prefix/milestone mismatch ──────────
230
+ const RULE_W021 = {
231
+ code: 'W021',
232
+ severity: SEVERITY.WARNING,
233
+ description: "Phase's integer prefix implies a different milestone than its ROADMAP section (phase_id_convention: milestone-prefixed)",
234
+ repairable: false,
235
+ check: (snapshot) => {
236
+ const convention = snapshot.config.value?.['phase_id_convention'];
237
+ if (convention !== 'milestone-prefixed')
238
+ return [];
239
+ const diagnostics = [];
240
+ for (const entry of snapshot.roadmapDeclaredPhases.value) {
241
+ // `entry.milestone === null` means the builder never found this phase
242
+ // heading inside any versioned (`v\d+\.\d+`) section — the original
243
+ // `checkMilestonePrefixMismatches` only ever iterates phases found
244
+ // WITHIN a section, so a phase outside any section is equivalently
245
+ // never checked here.
246
+ if (entry.milestone === null)
247
+ continue;
248
+ const expectedMilestone = getMilestoneFromPhaseId(entry.phaseId);
249
+ if (expectedMilestone === null || expectedMilestone === entry.milestone)
250
+ continue;
251
+ diagnostics.push({
252
+ code: 'W021',
253
+ severity: SEVERITY.WARNING,
254
+ message: `Phase ${entry.phaseId}: integer prefix implies ${expectedMilestone} but listed under ${entry.milestone}`,
255
+ remedy: adviseRemedy('gsd-tools roadmap upgrade --convention milestone-prefixed'),
256
+ });
257
+ }
258
+ return diagnostics;
259
+ },
260
+ };
261
+ // ─── W026 — STATE says milestone complete but ROADMAP lists unstarted phase ─
262
+ const RULE_W026 = {
263
+ code: 'W026',
264
+ severity: SEVERITY.WARNING,
265
+ description: 'STATE says milestone complete but ROADMAP lists an unstarted phase for that milestone',
266
+ repairable: false,
267
+ check: (snapshot) => {
268
+ const statusVal = (snapshot.stateStatus.value ?? '').trim().toLowerCase();
269
+ if (!/milestone complete|archived/.test(statusVal))
270
+ return [];
271
+ // `currentMilestoneRoadmapPhaseIds` is already scoped to the current
272
+ // milestone (`extractCurrentMilestone(roadmapRaw, cwd)`, the same
273
+ // `<details>`/`<summary>`-tolerant owner `verify.cts:2364` used) — no
274
+ // separate `currentMilestone` resolution/filter needed here (see the
275
+ // field's own doc comment on `PlanningSnapshot` for why
276
+ // `roadmapDeclaredPhases`'s `milestone` attribution is the wrong fit).
277
+ const unstarted = [];
278
+ for (const phaseId of snapshot.currentMilestoneRoadmapPhaseIds.value) {
279
+ const normalized = normalizePhaseName(phaseId);
280
+ // `allPhaseDirNames` — every directory under `phases/`, UNWINDOWED by
281
+ // ROADMAP-declaration membership — mirrors the original's own
282
+ // unwindowed `phaseDirNames2` (`verify.cts:2372-2382`, a direct
283
+ // `readdirSync` of the phases dir), not the current-milestone-windowed
284
+ // `phaseDirs`.
285
+ const hasDirectory = matchPhaseDirs(snapshot.allPhaseDirNames.value, normalized).matches.length > 0;
286
+ if (!hasDirectory)
287
+ unstarted.push(phaseId);
288
+ }
289
+ if (unstarted.length === 0)
290
+ return [];
291
+ return [
292
+ {
293
+ code: 'W026',
294
+ severity: SEVERITY.WARNING,
295
+ message: `STATE says milestone complete but ROADMAP lists ${unstarted.length} unstarted phase(s) (e.g. Phase ${unstarted[0]})`,
296
+ remedy: adviseRemedy('Run validate consistency or re-run complete-milestone after verifying all phases are done'),
297
+ },
298
+ ];
299
+ },
300
+ };
301
+ // ─── Exports ────────────────────────────────────────────────────────────────
302
+ const RULES = [RULE_W024, RULE_W002, RULE_W011, RULE_W021, RULE_W026];
303
+ module.exports = { RULES };
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ /**
3
+ * Health Diagnostic — Worktree health rules (Phase 11, #3309, ADR-3180
4
+ * §8.2/§8.3/§8.5).
5
+ *
6
+ * Group: "Worktree health" (design doc, "Rule table organization" table) —
7
+ * W020 (×3 internal conditions, one subject: "the worktree health scan
8
+ * itself is degraded", design doc "Rejected alternatives" §3), W017 (orphan
9
+ * worktree), W027 (NEW — the split-off "stale worktree" subject, design
10
+ * doc's "New codes for the two split subjects" section).
11
+ *
12
+ * Ported behavior-preserving from `cmdValidateHealth`
13
+ * (`src/verify.cts:2193-2268`), the exact call sites for W020/W017/W027 (the
14
+ * pre-migration source still names the split-off stale-worktree site
15
+ * 'W017' — this batch is what actually applies the W027 split).
16
+ *
17
+ * W020's original THREE conditions were git_timed_out / git_list_failed / a
18
+ * per-finding 'unverified' kind, each with its own message. The first two
19
+ * are scan-level failures reported by `inspectWorktreeHealth`'s own `reason`
20
+ * field ('git_timed_out' vs 'git_list_failed' vs 'not_a_git_repo') —
21
+ * `planning-snapshot.cts`'s `buildWorktreeHealthField` now carries `reason`
22
+ * straight through on `PlanningSnapshot.worktreeHealth`, so `checkW020`
23
+ * below reproduces the original's exact branch-per-reason messages instead
24
+ * of collapsing them (a prior version of this file collapsed both into one
25
+ * message AND, worse, warned on 'not_a_git_repo' too — a regression, since
26
+ * the original silently skips a non-git cwd; see `verify.cts:2202-2217`).
27
+ *
28
+ * W027 restores the pre-migration active-worktree exclusion
29
+ * (`verify.cts:2233-2242`) via `PlanningSnapshot.cwd` — see `checkW027`'s own
30
+ * comment below for the mechanism.
31
+ *
32
+ * Design: .gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md
33
+ *
34
+ * ADR-457 build-at-publish: source in
35
+ * src/health-diagnostic-rules/worktree-health.cts, compiled to
36
+ * gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs (gitignored).
37
+ */
38
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
39
+ const shellCmdProjection = require("../shell-command-projection.cjs");
40
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
41
+ const healthDiagnosticMod = require("../health-diagnostic-types.cjs");
42
+ const { SEVERITY, adviseRemedy } = healthDiagnosticMod;
43
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
44
+ const planningScopeMod = require("../planning-scope.cjs");
45
+ const { SCOPE } = planningScopeMod;
46
+ // ─── W020 — worktree health scan itself is degraded (verify.cts:2193-2264) ─
47
+ //
48
+ // ONE rule, THREE internal conditions, all the same subject ("the worktree
49
+ // health scan itself is degraded" — design doc "Rejected alternatives" §3):
50
+ // (a) `git worktree list` timed out (verify.cts:2202-2209), (b) `git
51
+ // worktree list` failed outright (verify.cts:2210-2217), (c) a specific
52
+ // 'unverified' finding (existsSync ok, statSync threw,
53
+ // verify.cts:2256-2263). A fourth `!ok` reason, 'not_a_git_repo', and a
54
+ // thrown exception ('exception') are DELIBERATELY silent — the original's
55
+ // `if` ladder never matches 'not_a_git_repo', and the outer try/catch around
56
+ // the whole block is commented "git worktree not available or not a git
57
+ // repo — skip silently".
58
+ function checkW020(snapshot) {
59
+ const diagnostics = [];
60
+ const { scope, reason } = snapshot.worktreeHealth;
61
+ const degraded = scope === SCOPE.UNREADABLE;
62
+ // (a) — git worktree list timed out (verify.cts:2202-2209).
63
+ if (degraded && reason === 'git_timed_out') {
64
+ diagnostics.push({
65
+ code: 'W020',
66
+ severity: SEVERITY.WARNING,
67
+ message: 'Worktree health check degraded: git worktree list timed out after 10s — orphan/stale worktrees could not be inspected',
68
+ remedy: adviseRemedy('Run: git worktree list --porcelain to diagnose; check for .git/index.lock or a hung git process'),
69
+ });
70
+ }
71
+ // (b) — git worktree list failed outright (verify.cts:2210-2217).
72
+ if (degraded && reason === 'git_list_failed') {
73
+ diagnostics.push({
74
+ code: 'W020',
75
+ severity: SEVERITY.WARNING,
76
+ message: 'Worktree health check degraded: git worktree list failed — orphan/stale worktrees could not be inspected',
77
+ remedy: adviseRemedy('Run: git worktree list --porcelain to diagnose; check git repository state and permissions'),
78
+ });
79
+ }
80
+ // (c) — per-finding 'unverified' (existsSync ok, statSync threw).
81
+ for (const finding of snapshot.worktreeHealth.value) {
82
+ if (finding.kind !== 'unverified')
83
+ continue;
84
+ diagnostics.push({
85
+ code: 'W020',
86
+ severity: SEVERITY.WARNING,
87
+ message: `Worktree health check degraded: could not stat ${finding.path} — presence/staleness could not be verified`,
88
+ remedy: adviseRemedy('Check filesystem permissions on the worktree path, or investigate why statSync failed for it'),
89
+ });
90
+ }
91
+ return diagnostics;
92
+ }
93
+ // ─── W017 — orphan git worktree (verify.cts:2222-2229) ─────────────────────
94
+ //
95
+ // `finding.kind === 'orphan'` — path no longer exists on disk. One
96
+ // Diagnostic per orphan finding. Remedy mirrors the exact original literal
97
+ // fix, `verify.cts:2227`: `'Run: git worktree prune'`.
98
+ function checkW017(snapshot) {
99
+ const diagnostics = [];
100
+ for (const finding of snapshot.worktreeHealth.value) {
101
+ if (finding.kind !== 'orphan')
102
+ continue;
103
+ diagnostics.push({
104
+ code: 'W017',
105
+ severity: SEVERITY.WARNING,
106
+ message: `Orphan git worktree: ${finding.path} (path no longer exists on disk)`,
107
+ remedy: adviseRemedy('git worktree prune'),
108
+ });
109
+ }
110
+ return diagnostics;
111
+ }
112
+ // ─── W027 — stale git worktree (verify.cts:2232-2249, the split-off half of
113
+ // the pre-migration 'W017' site) ─────────────────────────────────────────
114
+ //
115
+ // `finding.kind === 'stale'` — age-based. Excludes the active session's own
116
+ // worktree, restored via `snapshot.cwd` (see module doc, gap 2 — RESOLVED):
117
+ // a 'stale' finding is skipped when `snapshot.cwd` equals the finding's path
118
+ // or is nested under it, the exact comparison `verify.cts:2238-2241` made
119
+ // against `process.cwd()`. Per this batch's brief: the interpolated command
120
+ // (with the real path) lives in `message`; `remedy.args.command` stays a
121
+ // static `<path>` template, mirroring the split the brief specifies.
122
+ // ─── #3663 — path-comparison provenance helper ─────────────────────────────
123
+ //
124
+ // snapshot.cwd is raw process-cwd-derived — path.resolve() normalizes
125
+ // separators and relative segments but NOT casing, and a process launched via
126
+ // a differently-cased path echoes that spelling back. finding.path is
127
+ // `git worktree list`-derived, which self-normalizes to the canonical
128
+ // on-disk casing (forward slashes). Comparing those two spellings strictly
129
+ // misclassifies the ACTIVE worktree as stale on win32 — so the comparison
130
+ // folds case ONLY on win32 (case-insensitive filesystem, via the Shell
131
+ // Command Projection seam's toComparablePathKey — the platform-conditional
132
+ // fold policy lives there, not per call site) and stays case-sensitive on
133
+ // POSIX, where differently-cased paths are genuinely different directories.
134
+ // No realpath resolution — that would change symlink matching behavior.
135
+ function isActiveWorktreePath(activeCwd, worktreePath, platform = process.platform) {
136
+ const active = shellCmdProjection.toComparablePathKey(activeCwd, platform);
137
+ const worktree = shellCmdProjection.toComparablePathKey(worktreePath, platform);
138
+ return active === worktree || active.startsWith(worktree + '/');
139
+ }
140
+ function checkW027(snapshot) {
141
+ const diagnostics = [];
142
+ const activeCwd = snapshot.cwd;
143
+ for (const finding of snapshot.worktreeHealth.value) {
144
+ if (finding.kind !== 'stale')
145
+ continue;
146
+ if (isActiveWorktreePath(activeCwd, finding.path))
147
+ continue;
148
+ diagnostics.push({
149
+ code: 'W027',
150
+ severity: SEVERITY.WARNING,
151
+ // #3280: staleness is a pure mtime heuristic and carries no information
152
+ // about whether the tree is clean — git's own refusal of a non-forced
153
+ // removal on a dirty tree is the safety net, so the remediation must
154
+ // direct the operator (or an agent executing this literally) to check
155
+ // for uncommitted work FIRST and keep `--force` an explicit discard
156
+ // opt-in, never the default instruction.
157
+ message: `Stale git worktree: ${finding.path} (last modified ${finding.ageMinutes} minutes ago). Inspect uncommitted work first: git -C ${finding.path} status --porcelain; if clean run: git worktree remove ${finding.path}; only add --force to discard changes`,
158
+ remedy: adviseRemedy('git -C <path> status --porcelain; if clean: git worktree remove <path>; add --force only to discard changes'),
159
+ });
160
+ }
161
+ return diagnostics;
162
+ }
163
+ // ─── Exports ────────────────────────────────────────────────────────────────
164
+ const RULES = [
165
+ {
166
+ code: 'W020',
167
+ severity: SEVERITY.WARNING,
168
+ description: 'Worktree health scan degraded — git worktree list timed out, failed, or a finding could not be verified',
169
+ repairable: false,
170
+ check: checkW020,
171
+ },
172
+ {
173
+ code: 'W017',
174
+ severity: SEVERITY.WARNING,
175
+ description: 'Orphan git worktree (path no longer exists on disk)',
176
+ repairable: false,
177
+ check: checkW017,
178
+ },
179
+ {
180
+ code: 'W027',
181
+ severity: SEVERITY.WARNING,
182
+ description: 'Stale git worktree (not modified in a long time)',
183
+ repairable: false,
184
+ check: checkW027,
185
+ },
186
+ ];
187
+ module.exports = { RULES, isActiveWorktreePath };
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ /**
3
+ * Health Diagnostic Types — shared, dependency-free rule-table types (Phase
4
+ * 11, #3309, ADR-3180 §8.2/§8.3/§8.5).
5
+ *
6
+ * Split out from `src/health-diagnostic.cts` to break a CJS circular
7
+ * dependency between the evaluator and its own rule-group files
8
+ * (`src/health-diagnostic-rules/*.cts`): those files need the frozen
9
+ * `SEVERITY`/`REMEDY_ACTION`/`REMEDY_RISK` enums and the `Diagnostic`/
10
+ * `Remedy`/`Rule` shapes, but the evaluator (`health-diagnostic.cts`) also
11
+ * needs to `require()` every rule-group file to populate its `RULES` array —
12
+ * a rule-group file requiring `health-diagnostic.cjs` back, mid-load, reads
13
+ * `module.exports` before it is assigned, so the destructured enums come
14
+ * back `undefined`. This leaf has NO runtime dependency on anything in that
15
+ * cycle, so both sides can depend on it directly.
16
+ *
17
+ * Design: .gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md
18
+ * Test matrix: .gsd/phase/refactor-3309-health-diagnostic-rule-table/50-test-matrix.md
19
+ *
20
+ * ADR-457 build-at-publish: source in src/health-diagnostic-types.cts,
21
+ * compiled to gsd-core/bin/lib/health-diagnostic-types.cjs (gitignored).
22
+ */
23
+ // ─── Severity ───────────────────────────────────────────────────────────────
24
+ const SEVERITY = Object.freeze({
25
+ ERROR: 'error',
26
+ WARNING: 'warning',
27
+ INFO: 'info',
28
+ });
29
+ // ─── Remedy action / risk ───────────────────────────────────────────────────
30
+ // Harvested from health.md's published table + the corrected 6-action
31
+ // implementation (`src/verify.cts:2405-2553`) — not 5; `addAiIntegrationPhaseKey`
32
+ // (verify.cts:1860/2481-2502) was live in code, missing from docs (design
33
+ // doc, "Ground truth vs. issue #3309's claims" section).
34
+ const REMEDY_ACTION = Object.freeze({
35
+ CREATE_CONFIG: 'createConfig',
36
+ RESET_CONFIG: 'resetConfig',
37
+ REGENERATE_STATE: 'regenerateState',
38
+ ADD_NYQUIST_KEY: 'addNyquistKey',
39
+ ADD_AI_INTEGRATION_PHASE_KEY: 'addAiIntegrationPhaseKey',
40
+ BACKFILL_MILESTONES: 'backfillMilestones',
41
+ // §8.3 rule 5 — every non-repairable finding's `fix` string becomes an
42
+ // ADVISE payload; ADVISE never acts, only describes.
43
+ ADVISE: 'advise',
44
+ });
45
+ const REMEDY_RISK = Object.freeze({
46
+ NONE: 'none',
47
+ DESTRUCTIVE: 'destructive',
48
+ });
49
+ // ─── adviseRemedy — shared ADVISE-remedy builder ───────────────────────────
50
+ /**
51
+ * Every rule-group file needs the same `{action: ADVISE, risk: NONE, args:
52
+ * {command}}` shape for a non-repairable finding's `fix` string (§8.3 rule
53
+ * 5). Was defined identically in `config-validation.cts` and
54
+ * `agent-install.cts`, and repeated inline elsewhere — moved to this shared,
55
+ * dependency-free leaf so every rule-group file imports one implementation
56
+ * instead of duplicating it.
57
+ */
58
+ function adviseRemedy(command) {
59
+ return { action: REMEDY_ACTION.ADVISE, risk: REMEDY_RISK.NONE, args: { command } };
60
+ }
61
+ // ─── Exports ────────────────────────────────────────────────────────────────
62
+ const healthDiagnosticTypes = {
63
+ SEVERITY,
64
+ REMEDY_ACTION,
65
+ REMEDY_RISK,
66
+ adviseRemedy,
67
+ };
68
+ module.exports = healthDiagnosticTypes;