@opengsd/gsd-core 1.9.1 → 1.11.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 (426) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -3
  3. package/.opencode/plugins/gsd-core.js +8 -1
  4. package/agents/gsd-code-fixer.md +27 -3
  5. package/agents/gsd-debug-session-manager.md +11 -0
  6. package/agents/gsd-debugger.md +12 -246
  7. package/agents/gsd-doc-synthesizer.md +2 -4
  8. package/agents/gsd-executor.md +12 -10
  9. package/agents/gsd-integration-checker.md +3 -0
  10. package/agents/gsd-mempalace-curator.md +5 -2
  11. package/agents/gsd-phase-researcher.md +20 -1
  12. package/agents/gsd-plan-checker.md +46 -0
  13. package/agents/gsd-planner.md +49 -54
  14. package/agents/gsd-roadmapper.md +21 -3
  15. package/agents/gsd-user-profiler.md +3 -0
  16. package/agents/gsd-verifier.md +26 -73
  17. package/bin/install.js +1272 -1238
  18. package/bin/lib/ui-safety-gate.cjs +2 -0
  19. package/commands/gsd/code-review.md +1 -1
  20. package/commands/gsd/execute-phase.md +1 -1
  21. package/commands/gsd/map-codebase.md +1 -1
  22. package/commands/gsd/mempalace-capture.md +2 -2
  23. package/commands/gsd/mempalace-recall.md +1 -1
  24. package/commands/gsd/new-milestone.md +2 -2
  25. package/commands/gsd/plan-phase.md +1 -1
  26. package/commands/gsd/quick.md +1 -1
  27. package/commands/gsd/review-backlog.md +2 -1
  28. package/commands/gsd/verify-work.md +1 -1
  29. package/gsd-core/bin/gsd-tools.cjs +1009 -115
  30. package/gsd-core/bin/lib/active-workstream-store.cjs +153 -12
  31. package/gsd-core/bin/lib/agent-install-check.cjs +268 -38
  32. package/gsd-core/bin/lib/api-coverage.cjs +123 -5
  33. package/gsd-core/bin/lib/artifacts.cjs +3 -0
  34. package/gsd-core/bin/lib/assumption-delta.cjs +2 -4
  35. package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
  36. package/gsd-core/bin/lib/audit.cjs +926 -202
  37. package/gsd-core/bin/lib/broken-windows.cjs +36 -6
  38. package/gsd-core/bin/lib/capability-consent.cjs +149 -15
  39. package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
  40. package/gsd-core/bin/lib/capability-registry.cjs +608 -148
  41. package/gsd-core/bin/lib/capability-source.cjs +92 -0
  42. package/gsd-core/bin/lib/capability-trust.cjs +444 -25
  43. package/gsd-core/bin/lib/capability-validator.cjs +507 -24
  44. package/gsd-core/bin/lib/capability-writer.cjs +3 -2
  45. package/gsd-core/bin/lib/check-command-router.cjs +114 -38
  46. package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
  47. package/gsd-core/bin/lib/codex-agent-toml.cjs +329 -0
  48. package/gsd-core/bin/lib/command-aliases.cjs +94 -0
  49. package/gsd-core/bin/lib/command-roster.cjs +44 -1
  50. package/gsd-core/bin/lib/commands.cjs +665 -99
  51. package/gsd-core/bin/lib/commonjs-marker.cjs +142 -0
  52. package/gsd-core/bin/lib/complexity-trigger.cjs +1172 -0
  53. package/gsd-core/bin/lib/config-loader.cjs +76 -0
  54. package/gsd-core/bin/lib/config.cjs +22 -2
  55. package/gsd-core/bin/lib/context-composer.cjs +278 -0
  56. package/gsd-core/bin/lib/context-predicates.cjs +506 -0
  57. package/gsd-core/bin/lib/core-utils.cjs +217 -40
  58. package/gsd-core/bin/lib/decisions.cjs +23 -0
  59. package/gsd-core/bin/lib/docs.cjs +3 -2
  60. package/gsd-core/bin/lib/external-job.cjs +19 -4
  61. package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
  62. package/gsd-core/bin/lib/frontmatter.cjs +239 -32
  63. package/gsd-core/bin/lib/gap-checker.cjs +68 -7
  64. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +57 -6
  65. package/gsd-core/bin/lib/git-base-branch.cjs +160 -15
  66. package/gsd-core/bin/lib/graphify.cjs +142 -27
  67. package/gsd-core/bin/lib/gsd2-import.cjs +37 -5
  68. package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
  69. package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
  70. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +145 -0
  71. package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
  72. package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
  73. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
  74. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +265 -0
  75. package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
  76. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
  77. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +173 -0
  78. package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
  79. package/gsd-core/bin/lib/health-diagnostic.cjs +431 -0
  80. package/gsd-core/bin/lib/host-integration.cjs +13 -1
  81. package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
  82. package/gsd-core/bin/lib/init-command-router.cjs +83 -8
  83. package/gsd-core/bin/lib/init.cjs +1325 -169
  84. package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
  85. package/gsd-core/bin/lib/install-engine.cjs +805 -264
  86. package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
  87. package/gsd-core/bin/lib/install-model-override-resolver.cjs +203 -0
  88. package/gsd-core/bin/lib/install-profiles.cjs +160 -57
  89. package/gsd-core/bin/lib/install-scope.cjs +270 -0
  90. package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
  91. package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
  92. package/gsd-core/bin/lib/installer-migration-authoring.cjs +3 -1
  93. package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
  94. package/gsd-core/bin/lib/installer-migrations/007-retire-config-root-commonjs-marker.cjs +149 -0
  95. package/gsd-core/bin/lib/installer-migrations/008-cursor-retire-commands-surface.cjs +55 -0
  96. package/gsd-core/bin/lib/installer-migrations/009-pi-retire-reserved-hooks-dir.cjs +199 -0
  97. package/gsd-core/bin/lib/installer-migrations.cjs +206 -13
  98. package/gsd-core/bin/lib/io.cjs +38 -3
  99. package/gsd-core/bin/lib/markdown-sectionizer.cjs +8 -1
  100. package/gsd-core/bin/lib/markdown-table.cjs +133 -20
  101. package/gsd-core/bin/lib/mcp-catalog.cjs +518 -0
  102. package/gsd-core/bin/lib/mcp-server.cjs +135 -3
  103. package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
  104. package/gsd-core/bin/lib/milestone.cjs +821 -109
  105. package/gsd-core/bin/lib/model-catalog.cjs +59 -1
  106. package/gsd-core/bin/lib/model-resolver.cjs +183 -40
  107. package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
  108. package/gsd-core/bin/lib/pattern.cjs +122 -0
  109. package/gsd-core/bin/lib/phase-estimation.cjs +1 -1
  110. package/gsd-core/bin/lib/phase-id.cjs +507 -36
  111. package/gsd-core/bin/lib/phase-lifecycle.cjs +28 -3
  112. package/gsd-core/bin/lib/phase-locator.cjs +258 -58
  113. package/gsd-core/bin/lib/phase.cjs +891 -156
  114. package/gsd-core/bin/lib/plan-dependency-graph.cjs +303 -0
  115. package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
  116. package/gsd-core/bin/lib/plan-scan.cjs +86 -2
  117. package/gsd-core/bin/lib/planning-scope.cjs +31 -0
  118. package/gsd-core/bin/lib/planning-snapshot.cjs +890 -0
  119. package/gsd-core/bin/lib/planning-workspace.cjs +60 -6
  120. package/gsd-core/bin/lib/probe-core.cjs +1 -1
  121. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  122. package/gsd-core/bin/lib/prompt-budget.cjs +128 -165
  123. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +740 -0
  124. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +85 -0
  125. package/gsd-core/bin/lib/review-lane-descriptor.cjs +108 -0
  126. package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
  127. package/gsd-core/bin/lib/review-lane-runner.cjs +447 -68
  128. package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
  129. package/gsd-core/bin/lib/roadmap-command-router.cjs +76 -9
  130. package/gsd-core/bin/lib/roadmap-parser.cjs +1035 -194
  131. package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
  132. package/gsd-core/bin/lib/roadmap.cjs +405 -84
  133. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +795 -100
  134. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
  135. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +440 -57
  136. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
  137. package/gsd-core/bin/lib/runtime-homes.cjs +220 -41
  138. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +220 -44
  139. package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
  140. package/gsd-core/bin/lib/runtime-slash.cjs +27 -9
  141. package/gsd-core/bin/lib/section-manifest.cjs +209 -0
  142. package/gsd-core/bin/lib/security.cjs +104 -5
  143. package/gsd-core/bin/lib/shell-command-projection.cjs +388 -30
  144. package/gsd-core/bin/lib/smart-entry.cjs +154 -22
  145. package/gsd-core/bin/lib/state-command-router.cjs +5 -1
  146. package/gsd-core/bin/lib/state-document.cjs +152 -8
  147. package/gsd-core/bin/lib/state-transition.cjs +424 -105
  148. package/gsd-core/bin/lib/state.cjs +1927 -401
  149. package/gsd-core/bin/lib/surface.cjs +35 -10
  150. package/gsd-core/bin/lib/text-lines.cjs +80 -0
  151. package/gsd-core/bin/lib/token-scanner.cjs +76 -0
  152. package/gsd-core/bin/lib/uat-predicate.cjs +20 -4
  153. package/gsd-core/bin/lib/uat.cjs +706 -64
  154. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
  155. package/gsd-core/bin/lib/ui-safety-gate.cjs +14 -5
  156. package/gsd-core/bin/lib/unusable-input.cjs +33 -0
  157. package/gsd-core/bin/lib/update-context.cjs +8 -2
  158. package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
  159. package/gsd-core/bin/lib/validate.cjs +20 -6
  160. package/gsd-core/bin/lib/vendor/README.md +37 -0
  161. package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
  162. package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
  163. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  164. package/gsd-core/bin/lib/verification.cjs +287 -20
  165. package/gsd-core/bin/lib/verify.cjs +368 -880
  166. package/gsd-core/bin/lib/workflow-fragments.cjs +557 -0
  167. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +203 -19
  168. package/gsd-core/bin/lib/workstream-inventory.cjs +576 -31
  169. package/gsd-core/bin/lib/workstream.cjs +8 -2
  170. package/gsd-core/bin/lib/worktree-base-ref.cjs +50 -6
  171. package/gsd-core/bin/lib/worktree-safety.cjs +450 -125
  172. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  173. package/gsd-core/bin/shared/config-schema.manifest.json +9 -1
  174. package/gsd-core/references/agent-contracts.md +43 -26
  175. package/gsd-core/references/artifact-types.md +10 -3
  176. package/gsd-core/references/autonomous-ui-design-contract.md +42 -0
  177. package/gsd-core/references/checkpoints.md +2 -2
  178. package/gsd-core/references/context-budget.md +1 -1
  179. package/gsd-core/references/debugger-techniques.md +255 -0
  180. package/gsd-core/references/dispatch-isolation-gate.md +138 -0
  181. package/gsd-core/references/doc-conflict-engine.md +1 -1
  182. package/gsd-core/references/execute-mvp-tdd.md +3 -3
  183. package/gsd-core/references/execute-phase-between-wave-reset.md +6 -2
  184. package/gsd-core/references/execute-phase-context-guard.md +1 -1
  185. package/gsd-core/references/execute-phase-response-language.md +1 -1
  186. package/gsd-core/references/execute-phase-wave-guard.md +6 -2
  187. package/gsd-core/references/gate-prompts.md +1 -1
  188. package/gsd-core/references/git-planning-commit.md +2 -1
  189. package/gsd-core/references/loop-hook-dispatch.md +39 -2
  190. package/gsd-core/references/model-profiles.md +12 -4
  191. package/gsd-core/references/mvp-concepts.md +9 -9
  192. package/gsd-core/references/planner-guidance.md +3 -9
  193. package/gsd-core/references/planner-preconditions.md +1 -1
  194. package/gsd-core/references/planner-reviews.md +1 -1
  195. package/gsd-core/references/planning-config.md +8 -6
  196. package/gsd-core/references/research-documentation-lookup.md +5 -3
  197. package/gsd-core/references/revision-loop.md +1 -1
  198. package/gsd-core/references/specless-probe-fallback.md +8 -7
  199. package/gsd-core/references/universal-anti-patterns.md +3 -3
  200. package/gsd-core/references/verifier-phase-gates.md +192 -0
  201. package/gsd-core/references/verifier-wiring-patterns.md +100 -0
  202. package/gsd-core/references/verify-mvp-mode.md +1 -1
  203. package/gsd-core/references/workstream-flag.md +22 -6
  204. package/gsd-core/references/worktree-branch-check.md +2 -2
  205. package/gsd-core/templates/discussion-log.md +1 -1
  206. package/gsd-core/templates/phase-prompt.md +2 -4
  207. package/gsd-core/templates/state.md +4 -4
  208. package/gsd-core/templates/summary-complex.md +2 -0
  209. package/gsd-core/templates/summary-minimal.md +2 -0
  210. package/gsd-core/templates/summary-standard.md +2 -0
  211. package/gsd-core/templates/summary.md +2 -0
  212. package/gsd-core/templates/verification-report.md +9 -1
  213. package/gsd-core/workflows/ai-integration-phase.md +9 -11
  214. package/gsd-core/workflows/audit-milestone.md +3 -0
  215. package/gsd-core/workflows/autonomous/steps/converge-banner.md +1 -0
  216. package/gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md +11 -0
  217. package/gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md +7 -0
  218. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +21 -0
  219. package/gsd-core/workflows/autonomous/steps/converge-loop.md +7 -0
  220. package/gsd-core/workflows/autonomous.md +33 -70
  221. package/gsd-core/workflows/cleanup.md +62 -3
  222. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +39 -0
  223. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +93 -0
  224. package/gsd-core/workflows/code-review-fix.md +37 -10
  225. package/gsd-core/workflows/code-review.md +74 -166
  226. package/gsd-core/workflows/complete-milestone/steps/git-tag.md +29 -0
  227. package/gsd-core/workflows/complete-milestone.md +160 -95
  228. package/gsd-core/workflows/debug.md +16 -17
  229. package/gsd-core/workflows/diagnose-issues.md +56 -8
  230. package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -1
  231. package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
  232. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +15 -0
  233. package/gsd-core/workflows/discuss-phase-assumptions.md +7 -17
  234. package/gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md +51 -0
  235. package/gsd-core/workflows/docs-update.md +8 -51
  236. package/gsd-core/workflows/edit-phase.md +26 -1
  237. package/gsd-core/workflows/eval-review.md +3 -5
  238. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +64 -7
  239. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +50 -0
  240. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +31 -0
  241. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
  242. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +21 -0
  243. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +42 -0
  244. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +43 -37
  245. package/gsd-core/workflows/execute-phase.md +103 -187
  246. package/gsd-core/workflows/execute-plan.md +36 -4
  247. package/gsd-core/workflows/explore.md +131 -4
  248. package/gsd-core/workflows/fast.md +10 -2
  249. package/gsd-core/workflows/health.md +73 -4
  250. package/gsd-core/workflows/help/modes/full.md +6 -1
  251. package/gsd-core/workflows/import.md +4 -4
  252. package/gsd-core/workflows/ingest-docs.md +7 -6
  253. package/gsd-core/workflows/mvp-phase.md +6 -3
  254. package/gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md +16 -0
  255. package/gsd-core/workflows/new-milestone/steps/reset-phase-safety.md +19 -0
  256. package/gsd-core/workflows/new-milestone.md +35 -47
  257. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +176 -0
  258. package/gsd-core/workflows/new-project/steps/auto-mode-detection.md +32 -0
  259. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +18 -0
  260. package/gsd-core/workflows/new-project.md +27 -240
  261. package/gsd-core/workflows/next.md +12 -0
  262. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +15 -0
  263. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +110 -0
  264. package/gsd-core/workflows/plan-phase/steps/prd-express-gate.md +8 -0
  265. package/gsd-core/workflows/plan-phase/steps/research-only-early-exit.md +17 -0
  266. package/gsd-core/workflows/plan-phase/steps/research-only-modifiers.md +16 -0
  267. package/gsd-core/workflows/plan-phase/steps/reviews-prerequisite.md +17 -0
  268. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +149 -0
  269. package/gsd-core/workflows/plan-phase.md +89 -209
  270. package/gsd-core/workflows/plan-review-convergence.md +50 -2
  271. package/gsd-core/workflows/progress/steps/forensic-audit.md +125 -0
  272. package/gsd-core/workflows/progress/steps/mvp-display.md +18 -0
  273. package/gsd-core/workflows/progress.md +45 -159
  274. package/gsd-core/workflows/quick/steps/discussion-phase.md +124 -0
  275. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +111 -0
  276. package/gsd-core/workflows/quick/steps/quick-verification.md +67 -0
  277. package/gsd-core/workflows/quick/steps/research-phase.md +72 -0
  278. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +37 -0
  279. package/gsd-core/workflows/quick.md +55 -405
  280. package/gsd-core/workflows/resume-project.md +3 -0
  281. package/gsd-core/workflows/review/steps/reviewer-instances-note-1.md +4 -0
  282. package/gsd-core/workflows/review/steps/reviewer-instances-note-2.md +3 -0
  283. package/gsd-core/workflows/review.md +41 -13
  284. package/gsd-core/workflows/section-manifest.json +219 -0
  285. package/gsd-core/workflows/secure-phase.md +1 -1
  286. package/gsd-core/workflows/session-report.md +2 -1
  287. package/gsd-core/workflows/settings.md +66 -2
  288. package/gsd-core/workflows/ship.md +104 -44
  289. package/gsd-core/workflows/sketch.md +1 -1
  290. package/gsd-core/workflows/spec-phase.md +41 -20
  291. package/gsd-core/workflows/spike-wrap-up.md +20 -5
  292. package/gsd-core/workflows/spike.md +50 -16
  293. package/gsd-core/workflows/sync-skills.md +106 -13
  294. package/gsd-core/workflows/transition/steps/workstream-collision-check.md +17 -0
  295. package/gsd-core/workflows/transition.md +53 -31
  296. package/gsd-core/workflows/ui-phase.md +13 -12
  297. package/gsd-core/workflows/ui-review.md +2 -2
  298. package/gsd-core/workflows/update/steps/channel-banner.md +7 -0
  299. package/gsd-core/workflows/update.md +19 -8
  300. package/gsd-core/workflows/validate-phase.md +1 -1
  301. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +36 -0
  302. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +21 -0
  303. package/gsd-core/workflows/verify-work.md +17 -65
  304. package/hooks/dist/gsd-agent-isolation-guard.js +517 -0
  305. package/hooks/dist/gsd-check-update-worker.js +64 -12
  306. package/hooks/dist/gsd-check-update.js +19 -1
  307. package/hooks/dist/gsd-cursor-pre-tool.js +0 -3
  308. package/hooks/dist/gsd-cursor-subagent-start.js +607 -26
  309. package/hooks/dist/gsd-cursor-subagent-stop.js +3 -2
  310. package/hooks/dist/gsd-prompt-guard.js +21 -20
  311. package/hooks/dist/gsd-read-injection-scanner.js +45 -24
  312. package/hooks/dist/gsd-statusline.js +90 -6
  313. package/hooks/dist/gsd-update-banner.js +22 -1
  314. package/hooks/dist/gsd-workflow-guard.js +134 -36
  315. package/hooks/dist/gsd-worktree-path-guard.js +2 -1
  316. package/hooks/dist/gsd-write-guard.js +359 -0
  317. package/hooks/dist/lib/git-cmd.js +92 -59
  318. package/hooks/dist/lib/injection-patterns.js +45 -0
  319. package/hooks/dist/lib/isolation-deny-reason.js +39 -0
  320. package/hooks/dist/lib/isolation-sentinel.js +277 -0
  321. package/hooks/dist/managed-hooks-registry.cjs +2 -0
  322. package/hooks/gsd-agent-isolation-guard.js +517 -0
  323. package/hooks/gsd-check-update-worker.js +64 -12
  324. package/hooks/gsd-check-update.js +19 -1
  325. package/hooks/gsd-cursor-pre-tool.js +0 -3
  326. package/hooks/gsd-cursor-subagent-start.js +607 -26
  327. package/hooks/gsd-cursor-subagent-stop.js +3 -2
  328. package/hooks/gsd-prompt-guard.js +21 -20
  329. package/hooks/gsd-read-injection-scanner.js +45 -24
  330. package/hooks/gsd-statusline.js +90 -6
  331. package/hooks/gsd-update-banner.js +22 -1
  332. package/hooks/gsd-workflow-guard.js +134 -36
  333. package/hooks/gsd-worktree-path-guard.js +2 -1
  334. package/hooks/gsd-write-guard.js +359 -0
  335. package/hooks/hooks.json +12 -0
  336. package/hooks/lib/git-cmd.js +92 -59
  337. package/hooks/lib/injection-patterns.js +45 -0
  338. package/hooks/lib/isolation-deny-reason.js +39 -0
  339. package/hooks/lib/isolation-sentinel.js +277 -0
  340. package/hooks/managed-hooks-registry.cjs +2 -0
  341. package/package.json +31 -10
  342. package/pi/gsd.cjs +71 -12
  343. package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
  344. package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
  345. package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
  346. package/scripts/build-hooks.js +9 -0
  347. package/scripts/changeset/lint.cjs +68 -6
  348. package/scripts/changeset/serialize.cjs +5 -1
  349. package/scripts/check-alias-drift.cjs +7 -43
  350. package/scripts/check-contract-drift.cjs +297 -0
  351. package/scripts/ci-test-scope.cjs +19 -2
  352. package/scripts/command-contract-helpers.cjs +903 -1
  353. package/scripts/gen-adr-index.cjs +728 -38
  354. package/scripts/gen-capability-matrix.cjs +1 -1
  355. package/scripts/gen-capability-registry.cjs +3 -15
  356. package/scripts/gen-context-index.cjs +439 -0
  357. package/scripts/gen-health-docs.cjs +390 -0
  358. package/scripts/gen-inventory-manifest.cjs +150 -4
  359. package/scripts/gen-loop-host-contract.cjs +4 -24
  360. package/scripts/gen-prompt-budget-parity-corpus.cjs +645 -0
  361. package/scripts/gen-registry.cjs +3 -14
  362. package/scripts/gen-section-manifest.cjs +638 -0
  363. package/scripts/generate-package-identity.cjs +4 -2
  364. package/scripts/lib/alias-drift-families.cjs +46 -0
  365. package/scripts/lib/drift-scan.cjs +278 -0
  366. package/scripts/lint-allow-test-rule-refs.allowlist.json +15 -54
  367. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
  368. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
  369. package/scripts/lint-canary-version-leak.cjs +73 -0
  370. package/scripts/lint-command-contract.cjs +96 -13
  371. package/scripts/lint-compiled-artifact-sync.cjs +6 -1
  372. package/scripts/lint-completion-predicate-drift.cjs +933 -0
  373. package/scripts/lint-completion-ratio-drift.cjs +214 -0
  374. package/scripts/lint-default-flip-documentation.cjs +193 -0
  375. package/scripts/lint-docs-command-form.cjs +195 -0
  376. package/scripts/lint-docs-required.cjs +9 -1
  377. package/scripts/lint-emitted-drift-ack.cjs +215 -20
  378. package/scripts/lint-eslint-glob-coverage.allowlist.json +34 -0
  379. package/scripts/lint-eslint-glob-coverage.cjs +340 -0
  380. package/scripts/lint-example-parser-parity.cjs +395 -0
  381. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
  382. package/scripts/lint-health-diagnostic-rule-table.cjs +404 -0
  383. package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
  384. package/scripts/lint-milestone-window-drift.cjs +468 -0
  385. package/scripts/lint-phase-enumeration-drift.cjs +479 -0
  386. package/scripts/lint-plan-count-drift.cjs +318 -0
  387. package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
  388. package/scripts/lint-planning-prompt-drift.cjs +434 -0
  389. package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
  390. package/scripts/lint-regression-test-names.cjs +15 -13
  391. package/scripts/lint-removed-but-needed.cjs +320 -0
  392. package/scripts/lint-state-field-drift.cjs +805 -0
  393. package/scripts/lint-state-write-path-drift.cjs +1045 -0
  394. package/scripts/lint-test-file-count.allowlist.json +40 -3
  395. package/scripts/lint-unreachable-guard-drift.cjs +843 -0
  396. package/scripts/lint-vendored-deps.cjs +124 -0
  397. package/scripts/mutation-matrix.cjs +13 -0
  398. package/scripts/pr-changed-files.cjs +63 -0
  399. package/scripts/pr-template-policy.cjs +14 -4
  400. package/scripts/prompt-injection-scan.sh +52 -6
  401. package/scripts/require-issue-link-policy.cjs +192 -0
  402. package/scripts/state-write-path-drift-baseline.json +19 -0
  403. package/scripts/sync-runtime-launcher.cjs +2 -4
  404. package/skills/gsd-autonomous/SKILL.md +0 -1
  405. package/skills/gsd-code-review/SKILL.md +1 -1
  406. package/skills/gsd-execute-phase/SKILL.md +1 -2
  407. package/skills/gsd-map-codebase/SKILL.md +1 -1
  408. package/skills/gsd-mempalace-capture/SKILL.md +2 -2
  409. package/skills/gsd-mempalace-recall/SKILL.md +1 -1
  410. package/skills/gsd-new-milestone/SKILL.md +2 -2
  411. package/skills/gsd-next/SKILL.md +0 -1
  412. package/skills/gsd-plan-phase/SKILL.md +1 -2
  413. package/skills/gsd-progress/SKILL.md +0 -1
  414. package/skills/gsd-quick/SKILL.md +1 -1
  415. package/skills/gsd-review-backlog/SKILL.md +2 -1
  416. package/skills/gsd-stats/SKILL.md +0 -1
  417. package/skills/gsd-verify-work/SKILL.md +1 -1
  418. package/vscode/package.json +1 -1
  419. package/gsd-core/workflows/discovery-phase.md +0 -298
  420. package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
  421. package/gsd-core/workflows/verify-phase.md +0 -577
  422. package/scripts/affected-tests-lib.cjs +0 -554
  423. package/scripts/gen-emitted-baseline.cjs +0 -145
  424. package/scripts/lint-allow-test-rule-refs.cjs +0 -162
  425. package/scripts/run-affected-tests.cjs +0 -7
  426. package/scripts/run-tests.cjs +0 -1050
@@ -0,0 +1,265 @@
1
+ "use strict";
2
+ /**
3
+ * Health Diagnostic — ROADMAP/disk consistency rules (Phase 11, #3309,
4
+ * ADR-3180 §8.2/§8.3/§8.5).
5
+ *
6
+ * Group: "ROADMAP/disk consistency" (design doc, "Rule table organization"
7
+ * table) — W006, W007.
8
+ *
9
+ * Ported behavior-preserving from `cmdValidateHealth`
10
+ * (`src/verify.cts:2029-2101`, the exact call sites for W006/W007).
11
+ *
12
+ * Both rules share ONE matcher — `matchPhaseDirs` + `normalizePhaseName`
13
+ * (`src/phase-id.cts`), the same canonical directory-resolution owner
14
+ * `verify.cts:2060/2073` already calls (its own #2528 comment explains why:
15
+ * pairing roadmap phases against disk by intersecting independently-derived
16
+ * TOKEN SETS mislabels digit-leading slugs like `05-80-20-cleanup` in BOTH
17
+ * directions at once — phase 5 reads as missing a directory (W006) AND that
18
+ * directory reads as not in the roadmap (W007) — so both rules here resolve
19
+ * through `matchPhaseDirs`, never a hand-rolled string/token comparison, and
20
+ * `dirsForPhase` below is the single call site both go through, so they
21
+ * cannot independently drift on what "matches" means (#2528's own bug
22
+ * class).
23
+ *
24
+ * DISK-SIDE SOURCE — `allPhaseDirNames`, NOT `phaseDirs` (found while
25
+ * implementing this file, fixed inline rather than deferred).
26
+ * `snapshot.phaseDirs` (Phase 10, `listMilestonePhaseDirs`) is WINDOWED: its
27
+ * `inWindow` filter (`getMilestonePhaseFilter`, `src/roadmap-parser.cts:1220`)
28
+ * admits a directory only when its phase id is a MEMBER of the roadmap's
29
+ * current-milestone-declared phase set (`isDirInMilestone`). That makes
30
+ * `phaseDirs.value` a subset that, by construction, can never contain a
31
+ * directory the roadmap does NOT declare — exactly the directory W007 exists
32
+ * to find. Sourced from `phaseDirs`, W007 would be structurally inert: every
33
+ * member of the set is already provably claimable. Verified empirically
34
+ * (`node -e` trace against a real `buildPlanningSnapshot`): a genuine orphan
35
+ * directory (`04-extra`, no roadmap entry) was silently absent from
36
+ * `phaseDirs.value` and W007 fired zero diagnostics. `phaseDirs`'s windowing
37
+ * also risks a W006 false positive for a phase declared in a NON-current
38
+ * milestone section (`roadmapDeclaredPhases` is built from the FULL raw
39
+ * ROADMAP, all milestones — `src/planning-snapshot.cts:398-436` — while
40
+ * `phaseDirs` is scoped to the current milestone only), so both rules here
41
+ * use the new, additive `allPhaseDirNames` field
42
+ * (`src/planning-snapshot.cts`) instead: every directory actually present
43
+ * under the active `phases/` root, unfiltered by roadmap declaration.
44
+ * Archived-milestone directory names (`verify.cts:2050`,
45
+ * `collectArchivedPhaseDirNames`) are still not exposed as directory NAMES
46
+ * on `PlanningSnapshot`, but the equivalent TOKEN set is: `checkW006` below
47
+ * additionally consults `snapshot.archivedPhaseTokens` (added for the
48
+ * W002/state-consistency group's #3652 fix, reused verbatim here — see that
49
+ * field's own doc comment) so a phase whose only directory lives in a
50
+ * milestone archive (shipped OR the current milestone's own archive layout)
51
+ * no longer reads as W006-missing (Bug 1, found post-migration: the archived
52
+ * fixtures under `tests/milestone-archive.test.cjs` and
53
+ * `tests/verify-health.test.cjs` regressed against the pre-migration
54
+ * `verify.cts` behavior). W007 still never scans archived dirs (its loop is
55
+ * `allPhaseDirNames.value`, the active `phases/` root only), so an archived
56
+ * dir still cannot spuriously read as W007-orphaned either — unchanged.
57
+ *
58
+ * Bug 2 (found alongside Bug 1): `dirsForPhase` below also runs a
59
+ * `phaseVariants()`-based fallback when `matchPhaseDirs` finds nothing — see
60
+ * its own doc comment. Pre-migration, `verify.cts:2071-2073`/`2092-2093` ran
61
+ * this as a SECOND, independent check the migrated matchPhaseDirs-only path
62
+ * had dropped, causing a false W006/W007 whenever ROADMAP and disk spelled
63
+ * the same phase with a different zero-padding (e.g. ROADMAP "01A" vs disk
64
+ * "1A-...").
65
+ *
66
+ * Not-started exclusion (verify.cts:2065/2075-2076,
67
+ * `buildNotStartedPhaseVariants`, `src/validate.cts:160`): the design doc's
68
+ * field table assigns this group only `roadmapDeclaredPhases`/`phaseDirs`,
69
+ * and `roadmapDeclaredPhases` (`src/planning-snapshot.cts:398-436`) does
70
+ * NOT filter not-started phases out — it returns every heading- and
71
+ * checklist-declared phase id regardless of checked state (confirmed by
72
+ * direct read: its `buildRoadmapPhaseVariants` call includes BOTH `[x]` and
73
+ * `[ ]` checklist entries). Omitting the exclusion here would regress a
74
+ * COMMON case: `gsd-core/templates/roadmap.md`'s "Initial Roadmap" shape
75
+ * declares every phase as an unchecked `- [ ] **Phase N: [Name]**` checklist
76
+ * item before any phase directory exists, so a freshly created ROADMAP.md
77
+ * would immediately spam one W006 per phase. `snapshot.roadmapPhaseCheckboxes`
78
+ * (`src/planning-snapshot.cts:457-480`, backs W011 in the STATE.md-consistency
79
+ * group) already parses exactly this `[x]`/`[ ]` state — `check(snapshot)`'s
80
+ * signature grants the full snapshot, not just this group's assigned column,
81
+ * so `isPhaseNotStarted` below reads it directly rather than re-deriving a
82
+ * third independent regex over raw ROADMAP text (forbidden by §8.1 rule 2).
83
+ * KNOWN GAP, disclosed rather than silently dropped: `roadmapPhaseCheckboxes`
84
+ * is keyed by `PHASE_NUMBER_TOKEN_SOURCE` (`phase-id.cts:54`, no dash), so a
85
+ * milestone-dash-prefixed phase id ("2-01") can never match a checkbox key —
86
+ * unlike the original `buildNotStartedPhaseVariants`, which captures the
87
+ * fuller `[\w][\w.-]*` grammar (dashes included). For that id shape only,
88
+ * this rule's not-started exclusion silently no-ops (never excludes), which
89
+ * is the conservative direction (a possible false W006, not a suppressed
90
+ * true one).
91
+ *
92
+ * Design: .gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md
93
+ *
94
+ * ADR-457 build-at-publish: source in
95
+ * src/health-diagnostic-rules/roadmap-disk-consistency.cts, compiled to
96
+ * gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs
97
+ * (gitignored).
98
+ */
99
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
100
+ const healthDiagnosticMod = require("../health-diagnostic-types.cjs");
101
+ const { SEVERITY, adviseRemedy } = healthDiagnosticMod;
102
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
103
+ const planningScopeMod = require("../planning-scope.cjs");
104
+ const { SCOPE } = planningScopeMod;
105
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
106
+ const phaseIdMod = require("../phase-id.cjs");
107
+ const { matchPhaseDirs, normalizePhaseName, extractPhaseToken, isSentinelPhaseId } = phaseIdMod;
108
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
109
+ const validateMod = require("../validate.cjs");
110
+ const { phaseVariants } = validateMod;
111
+ // ─── Shared matcher — the single call site both W006 and W007 go through ───
112
+ /**
113
+ * Every on-disk directory (from `allPhaseDirNames.value`) that `phaseId`
114
+ * resolves to via the canonical `matchPhaseDirs` selection. Both `checkW006`
115
+ * (does ANY directory resolve) and `computeClaimedDirs` (which directories
116
+ * does the roadmap claim, for W007) call this — one matcher, reused, per the
117
+ * file-level comment.
118
+ */
119
+ function dirsForPhase(dirs, phaseId) {
120
+ const canonical = matchPhaseDirs(dirs, normalizePhaseName(phaseId)).matches;
121
+ if (canonical.length > 0)
122
+ return canonical;
123
+ // Bug 2 (#3309 W006/W007 migration cluster, found while fixing the
124
+ // originally-reported archived-directory gap): `matchPhaseDirs`'s
125
+ // `phaseTokenMatches` compares `extractPhaseToken(dir)` (the directory's
126
+ // LITERAL, un-normalized digit run — e.g. "1A" for `1A-suffix-phase`)
127
+ // against `normalizePhaseName(phaseId)` (which PADS — "01A") case-
128
+ // insensitively, but never unifies a padding/letter-suffix mismatch
129
+ // BETWEEN the two sides: "1A" !== "01A" even though they name the same
130
+ // phase. Pre-migration, `verify.cts:2071-2073`/`2092-2093` ran a SECOND,
131
+ // independent check here — `[...phaseVariants(p)].some((v) =>
132
+ // diskPhases.has(v))` — that the migrated matchPhaseDirs-only path
133
+ // dropped. `phaseVariants` (`validate.cts:101`) is symmetric
134
+ // (padded<->unpadded, letter-suffix preserved both ways), so generating
135
+ // variants from `phaseId` and checking raw-disk-token membership is
136
+ // equivalent to intersecting `phaseVariants(phaseId)` with
137
+ // `phaseVariants(diskToken)` — variants always include their own input
138
+ // verbatim, so this fallback catches exactly the cases `matchPhaseDirs`
139
+ // alone misses without re-deriving a second matcher.
140
+ const variants = phaseVariants(phaseId);
141
+ return dirs.filter((d) => {
142
+ const token = extractPhaseToken(d).toUpperCase();
143
+ for (const variant of variants) {
144
+ if (token === variant.toUpperCase())
145
+ return true;
146
+ }
147
+ return false;
148
+ });
149
+ }
150
+ /**
151
+ * True when `phaseId` has an unchecked (`[ ]`) checklist entry in
152
+ * `roadmapPhaseCheckboxes` under any of its padding/case variants
153
+ * (`phaseVariants`, `src/validate.cts:101` — the same variant-expansion
154
+ * owner `verify.cts:2071/2075` uses for this exact exclusion). See the
155
+ * file-level comment for the KNOWN GAP on dash-shaped ids.
156
+ */
157
+ function isPhaseNotStarted(phaseId, checkboxes) {
158
+ for (const variant of phaseVariants(phaseId)) {
159
+ if (Object.prototype.hasOwnProperty.call(checkboxes, variant) && checkboxes[variant] === false) {
160
+ return true;
161
+ }
162
+ }
163
+ return false;
164
+ }
165
+ // ─── W006 — ROADMAP.md declares a phase with no directory on disk ─────────
166
+ // (verify.cts:2067-2084)
167
+ function checkW006(snapshot) {
168
+ // Mirrors verify.cts:2029's `if (fs.existsSync(roadmapPath))` guard: ROADMAP.md
169
+ // absent or unreadable means the field degrades to `{value: [], scope:
170
+ // UNREADABLE}` (`src/planning-snapshot.cts:401-403/407-409`) and NEITHER
171
+ // W006 nor W007 evaluates — an empty declared-phase list must not be
172
+ // mistaken for "the roadmap legitimately declares zero phases" here.
173
+ if (snapshot.roadmapDeclaredPhases.scope !== SCOPE.COMPLETE)
174
+ return [];
175
+ const dirs = snapshot.allPhaseDirNames.value;
176
+ const archivedTokens = new Set(snapshot.archivedPhaseTokens.value);
177
+ const checkboxes = snapshot.roadmapPhaseCheckboxes.value;
178
+ const diagnostics = [];
179
+ for (const { phaseId } of snapshot.roadmapDeclaredPhases.value) {
180
+ // #3225: sentinel phase ids (999.x/0.x) are never-on-roadmap by
181
+ // convention; a sentinel heading shouldn't demand a directory.
182
+ if (isSentinelPhaseId(phaseId))
183
+ continue;
184
+ if (dirsForPhase(dirs, phaseId).length > 0)
185
+ continue;
186
+ // Bug 1 (#3309 W006/W007 migration cluster): a phase whose ONLY
187
+ // directory lives under a milestone archive
188
+ // (`.planning/milestones/vX.Y-phases/<phase>/`, shipped OR the current
189
+ // milestone's own archive layout) must not read as "no directory on
190
+ // disk" — mirrors `verify.cts:2038`'s
191
+ // `forEachArchivedPhaseToken(planBase, (token) => diskPhases.add(token))`
192
+ // feeding the archived-phase token set into this exact existence check.
193
+ // `snapshot.archivedPhaseTokens` (`src/planning-snapshot.cts`) is the
194
+ // same token set, reused verbatim from the W002/state-consistency
195
+ // group's own fix for the analogous gap — not a re-derivation.
196
+ if ([...phaseVariants(phaseId)].some((v) => archivedTokens.has(v)))
197
+ continue;
198
+ if (isPhaseNotStarted(phaseId, checkboxes))
199
+ continue;
200
+ diagnostics.push({
201
+ code: 'W006',
202
+ severity: SEVERITY.WARNING,
203
+ message: `Phase ${phaseId} in ROADMAP.md but no directory on disk`,
204
+ remedy: adviseRemedy('Create phase directory or remove from roadmap'),
205
+ });
206
+ }
207
+ return diagnostics;
208
+ }
209
+ // ─── W007 — an on-disk phase directory has no matching ROADMAP entry ──────
210
+ // (verify.cts:2086-2101)
211
+ /** Every directory in `dirs` that ANY declared roadmap phase resolves to. */
212
+ function computeClaimedDirs(dirs, declaredPhases) {
213
+ const claimed = new Set();
214
+ for (const { phaseId } of declaredPhases) {
215
+ for (const dir of dirsForPhase(dirs, phaseId))
216
+ claimed.add(dir);
217
+ }
218
+ return claimed;
219
+ }
220
+ function checkW007(snapshot) {
221
+ // Same guard as W006 — see its comment.
222
+ if (snapshot.roadmapDeclaredPhases.scope !== SCOPE.COMPLETE)
223
+ return [];
224
+ const dirs = snapshot.allPhaseDirNames.value;
225
+ const claimedDirs = computeClaimedDirs(dirs, snapshot.roadmapDeclaredPhases.value);
226
+ const diagnostics = [];
227
+ for (const dirName of dirs) {
228
+ // `extractPhaseToken` is the phase-id.cts owner `PHASE_TOKEN_FROM_DIR_RE`
229
+ // (`src/validate.cts:73-76`) is documented to match exactly
230
+ // (verify.cts's original `p` key from `collectDiskPhaseEntries`,
231
+ // `verify.cts:1373-1397`) — same token, relocated read, not reinvented.
232
+ const token = extractPhaseToken(dirName);
233
+ // #3225: a sentinel dir on disk (999-interim, 0-drafts) is defined as
234
+ // never-on-roadmap; it must not trigger W007.
235
+ if (isSentinelPhaseId(token))
236
+ continue;
237
+ if (claimedDirs.has(dirName))
238
+ continue;
239
+ diagnostics.push({
240
+ code: 'W007',
241
+ severity: SEVERITY.WARNING,
242
+ message: `Phase ${token} exists on disk but not in ROADMAP.md`,
243
+ remedy: adviseRemedy('Add to roadmap or remove directory'),
244
+ });
245
+ }
246
+ return diagnostics;
247
+ }
248
+ // ─── Exports ────────────────────────────────────────────────────────────────
249
+ const RULES = [
250
+ {
251
+ code: 'W006',
252
+ severity: SEVERITY.WARNING,
253
+ description: 'Phase in ROADMAP but no directory',
254
+ repairable: false,
255
+ check: checkW006,
256
+ },
257
+ {
258
+ code: 'W007',
259
+ severity: SEVERITY.WARNING,
260
+ description: 'Phase on disk but not in ROADMAP',
261
+ repairable: false,
262
+ check: checkW007,
263
+ },
264
+ ];
265
+ module.exports = { RULES };
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ /**
3
+ * Health Diagnostic — Root existence + PROJECT.md rules (Phase 11, #3309,
4
+ * ADR-3180 §8.2/§8.3/§8.5).
5
+ *
6
+ * Group: "Root existence + PROJECT.md" (design doc, "Rule table organization"
7
+ * table) — E002, E003, E004, W001. E001 (the `.planning/` root missing guard)
8
+ * stays OUTSIDE the rule table entirely per the design doc's "Two guards that
9
+ * stay OUTSIDE the rule table entirely" section — it is not a row here.
10
+ *
11
+ * Ported behavior-preserving from `cmdValidateHealth`
12
+ * (`src/verify.cts:1681-1705`), the exact call sites for E002/E003/E004/W001.
13
+ *
14
+ * E002's original message interpolates `${slash('new-project')}`
15
+ * (`verify.cts:1682`, ``Run ${slash('new-project')} to create``) and E003's
16
+ * interpolates `${slash('new-milestone')}` (`verify.cts:1694`, ``Run
17
+ * ${slash('new-milestone')} to create roadmap``) — both per-project
18
+ * runtime-resolved values (`formatGsdSlash`, `src/runtime-slash.cts`) this
19
+ * rule's `(snapshot) => Diagnostic[]` signature has no access to (§8.1 rule
20
+ * 1 forbids ambient I/O, including `cwd`, inside `check`). Hardcodes the
21
+ * canonical `/gsd-new-project`/`/gsd-new-milestone` hyphen form instead,
22
+ * mirroring the sibling "config.json validation" group's W016 rule
23
+ * (`src/health-diagnostic-rules/config-validation.cts`), which hardcodes
24
+ * `/gsd-ai-integration-phase` the same way for the identical reason.
25
+ *
26
+ * Design: .gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md
27
+ *
28
+ * ADR-457 build-at-publish: source in src/health-diagnostic-rules/root-existence.cts,
29
+ * compiled to gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs (gitignored).
30
+ */
31
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
32
+ const healthDiagnosticMod = require("../health-diagnostic-types.cjs");
33
+ const { SEVERITY, REMEDY_ACTION, REMEDY_RISK, adviseRemedy } = healthDiagnosticMod;
34
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
35
+ const planningScopeMod = require("../planning-scope.cjs");
36
+ const { SCOPE } = planningScopeMod;
37
+ // ─── E002 — PROJECT.md not found (verify.cts:1682) ─────────────────────────
38
+ function checkE002(snapshot) {
39
+ if (snapshot.projectSections.exists)
40
+ return [];
41
+ return [
42
+ {
43
+ code: 'E002',
44
+ severity: SEVERITY.ERROR,
45
+ message: 'PROJECT.md not found',
46
+ remedy: adviseRemedy('/gsd-new-project'),
47
+ },
48
+ ];
49
+ }
50
+ // ─── E003 — ROADMAP.md not found (verify.cts:1694) ─────────────────────────
51
+ //
52
+ // Condition uses `snapshot.milestone.scope === SCOPE.UNREADABLE`
53
+ // (`getMilestoneInfo`, `src/roadmap-parser.cts`). KNOWN AMBIGUITY (flagged in
54
+ // this batch's report, not silently papered over): `getMilestoneInfo` returns
55
+ // `SCOPE.UNREADABLE` for TWO distinct causes it does not otherwise
56
+ // distinguish — (1) ROADMAP.md absent (`platformReadSync` returns `null` ->
57
+ // synthetic `Error('missing')`, no errno, `reportUnreadableRoadmap` finds no
58
+ // `.code` and stays silent) and (2) ROADMAP.md present but unreadable (a real
59
+ // read fault, e.g. EACCES/EISDIR, which DOES carry an errno and fires
60
+ // `warnUnusableInput(ROADMAP_UNREADABLE)`). Unlike `config`/`projectSections`,
61
+ // `milestone` carries no `exists` discriminator, so this rule cannot tell the
62
+ // two apart from the snapshot alone without adding cwd/fs access to `check`
63
+ // (forbidden by §8.1 rule 1). This is a best-effort port of the pre-migration
64
+ // condition (`!fs.existsSync(roadmapPath)`), which itself only asked "does
65
+ // the file exist" — this rule now also fires (message-mismatched, but
66
+ // error-preserving) on a present-but-corrupt ROADMAP.md.
67
+ function checkE003(snapshot) {
68
+ if (snapshot.milestone.scope !== SCOPE.UNREADABLE)
69
+ return [];
70
+ return [
71
+ {
72
+ code: 'E003',
73
+ severity: SEVERITY.ERROR,
74
+ message: 'ROADMAP.md not found',
75
+ remedy: adviseRemedy('/gsd-new-milestone'),
76
+ },
77
+ ];
78
+ }
79
+ // ─── E004 — STATE.md not found (verify.cts:1697) ───────────────────────────
80
+ //
81
+ // Condition uses `snapshot.currentPhaseLabel.scope === SCOPE.UNREADABLE`
82
+ // (`buildStateFields`, `src/planning-snapshot.cts:210-249`). KNOWN GAP
83
+ // (flagged in this batch's report): `buildStateFields` collapses TWO distinct
84
+ // causes into the same `UNREADABLE` scope with no discriminator field at
85
+ // all — STATE.md absent (`platformReadSync` returns `null`, a real
86
+ // non-answer, `warnUnusableInput` NOT called) and STATE.md present but
87
+ // unreadable (any other read error, e.g. EISDIR, corruption,
88
+ // `warnUnusableInput(STATE_UNREADABLE)` fires). Unlike `config`, there is no
89
+ // `exists` flag on `currentPhaseLabel` (or on `PlanningSnapshot` generally)
90
+ // to distinguish "STATE.md was never created" from "STATE.md exists but
91
+ // could not be read" — this is a REAL gap in the current 15-field
92
+ // `PlanningSnapshot` shape, not something this rule can work around without
93
+ // extending that snapshot (out of this batch's scope per the brief). This
94
+ // rule is therefore a best-effort port: it fires E004 ("STATE.md not found")
95
+ // for both causes, exactly mirroring what `snapshot.currentPhaseLabel.scope`
96
+ // can express today.
97
+ //
98
+ // Remedy is `regenerateState`, one of the two DESTRUCTIVE-risk actions (loses
99
+ // session history, design doc "Risk assignment" section) — per §8.3 rule 3
100
+ // `--repair` will refuse to auto-apply it once `applyRepairs`'s dispatch
101
+ // wires this rule in; the remedy is still described (ADVISE-shaped for
102
+ // display, per `applyRepairs`'s own contract) but never executed.
103
+ function checkE004(snapshot) {
104
+ if (snapshot.currentPhaseLabel.scope !== SCOPE.UNREADABLE)
105
+ return [];
106
+ return [
107
+ {
108
+ code: 'E004',
109
+ severity: SEVERITY.ERROR,
110
+ message: 'STATE.md not found',
111
+ remedy: {
112
+ action: REMEDY_ACTION.REGENERATE_STATE,
113
+ risk: REMEDY_RISK.DESTRUCTIVE,
114
+ args: {},
115
+ },
116
+ },
117
+ ];
118
+ }
119
+ // ─── W001 — PROJECT.md missing a required section (verify.cts:1684-1690) ──
120
+ //
121
+ // `REQUIRED_SECTIONS` carries the exact `## `-prefixed strings
122
+ // `verify.cts:1685` uses in its message text; membership is tested against
123
+ // `snapshot.projectSections.value`, which `buildProjectSectionsField`
124
+ // (`src/planning-snapshot.cts:367-381`) stores WITHOUT the `##` prefix (its
125
+ // `/^##\s+(.+)$/gm` capture group), so each required string's own `## `
126
+ // prefix is stripped before the membership check. `projectSections.value ===
127
+ // null` (PROJECT.md absent OR unreadable) emits zero diagnostics — E002
128
+ // already reports absence; this rule does not double-report it.
129
+ const REQUIRED_SECTIONS = ['## What This Is', '## Core Value', '## Requirements'];
130
+ function checkW001(snapshot) {
131
+ const { value } = snapshot.projectSections;
132
+ if (value === null)
133
+ return [];
134
+ const diagnostics = [];
135
+ for (const required of REQUIRED_SECTIONS) {
136
+ const heading = required.replace(/^##\s+/, '');
137
+ if (!value.includes(heading)) {
138
+ diagnostics.push({
139
+ code: 'W001',
140
+ severity: SEVERITY.WARNING,
141
+ message: `PROJECT.md missing section: ${required}`,
142
+ remedy: adviseRemedy('Add section manually'),
143
+ });
144
+ }
145
+ }
146
+ return diagnostics;
147
+ }
148
+ // ─── Exports ────────────────────────────────────────────────────────────────
149
+ const RULES = [
150
+ { code: 'E002', severity: SEVERITY.ERROR, description: 'PROJECT.md not found', repairable: false, check: checkE002 },
151
+ { code: 'E003', severity: SEVERITY.ERROR, description: 'ROADMAP.md not found', repairable: false, check: checkE003 },
152
+ { code: 'E004', severity: SEVERITY.ERROR, description: 'STATE.md not found', repairable: false, check: checkE004 },
153
+ {
154
+ code: 'W001',
155
+ severity: SEVERITY.WARNING,
156
+ description: 'PROJECT.md missing required section',
157
+ repairable: false,
158
+ check: checkW001,
159
+ },
160
+ ];
161
+ module.exports = { RULES };