@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
@@ -55,14 +55,14 @@ Verify the work is ready to ship:
55
55
  # The gate decides on ONE read. --pick takes a single field, so the two
56
56
  # human-facing fields are read only on the blocking path below — never on the
57
57
  # passing path — rather than issuing three queries up front (#2589).
58
- STATUS=$(gsd_run query verification.status "${PHASE_DIR}" --pick status 2>/dev/null || echo "")
58
+ STATUS=$(gsd_run query verification.status "${PHASE_DIR}" --pick status 2>/dev/null)
59
59
  ```
60
60
  Only `passed` may ship. If `$STATUS` is `passed`, verification is complete — continue to the next preflight check; do not read any further verification field.
61
61
 
62
62
  Any other value (including `gaps_found`, `human_needed`, `missing`, and `unknown`) blocks with `PHASE_VERIFICATION_INCOMPLETE`. Only then, read the two message fields:
63
63
  ```bash
64
- NEXT_ACTION=$(gsd_run query verification.status "${PHASE_DIR}" --pick next_action 2>/dev/null || echo "")
65
- NEXT_COMMAND=$(gsd_run query verification.status "${PHASE_DIR}" --pick next_command 2>/dev/null || echo "")
64
+ NEXT_ACTION=$(gsd_run query verification.status "${PHASE_DIR}" --pick next_action 2>/dev/null)
65
+ NEXT_COMMAND=$(gsd_run query verification.status "${PHASE_DIR}" --pick next_command 2>/dev/null)
66
66
  ```
67
67
  Present `$NEXT_ACTION` to the user and, when `$NEXT_COMMAND` is non-empty, show it as the command to run next. These two are message text only — the block/allow decision has already been made from `$STATUS`, so a concurrent write between the reads cannot change the gate's verdict. The query already handles missing files and unexpected values, so no per-status arm is needed.
68
68
 
@@ -91,9 +91,9 @@ Verify the work is ready to ship:
91
91
  ```
92
92
  If `gh` not found or not authenticated: provide setup instructions and exit.
93
93
 
94
- 6. **Security ship gate (capability-driven).**
94
+ 6. **Capability ship gates (generic dispatch).**
95
95
 
96
- Resolve active `ship:pre` gate hooks from the capability registry — the registry evaluates each hook's `when` condition, so do **not** read `workflow.security_enforcement` directly:
96
+ Resolve active `ship:pre` gate hooks from the capability registry — the registry evaluates each hook's `when` condition, so do **not** read `workflow.security_enforcement` or `workflow.windows_enforce` directly:
97
97
 
98
98
  ```bash
99
99
  SHIP_PRE_HOOKS_JSON=$(gsd_run loop render-hooks ship:pre --raw)
@@ -102,57 +102,83 @@ Verify the work is ready to ship:
102
102
 
103
103
  Read the `activeHooks` array from `SHIP_PRE_HOOKS_JSON` in-context (do NOT pipe it through a shell parser).
104
104
 
105
- If an active entry exists with `kind == "gate"`, `capId == "security"`, and `blocking == true`, enforce its predicate (`SECURITY.md` frontmatter `threats_open == 0`) before shipping:
105
+ **If `activeHooks` is empty or absent:** skip this check silently and continue to the next preflight step. A capability whose `when` is off contributes no entry, and one that failed to load fails OPEN with its own warning from the resolver — neither is a block.
106
106
 
107
- - **`SECURITY_FILE` is empty** → block with `SECURITY_SHIP_GATE_NO_REVIEW`:
108
- ```
109
- ⚠ Security enforcement is enabled but no SECURITY.md exists for this phase.
110
- Run /gsd:secure-phase {phase} and resolve findings before shipping.
111
- ```
112
- - **`SECURITY_FILE` exists** → read its frontmatter `threats_open`. The gate passes **only** when `threats_open` is exactly `0`. For any other value — `threats_open` > 0, or a missing / non-numeric / unparsable field — **fail closed and block** with `SECURITY_SHIP_GATE_OPEN_THREATS` (the predicate is strict equality to `0`; never ship on an ambiguous value):
113
- ```
114
- ⚠ Security ship gate: SECURITY.md does not assert threats_open == 0 (found: {threats_open|unset}).
115
- Resolve open threats (or re-run /gsd:secure-phase {phase}) before shipping.
116
- ```
107
+ **For each active entry where `kind == "gate"`** (process in array order), following `gsd-core/references/loop-hook-dispatch.md`. Entries of any other `kind` are not gates and are not enforced here. Every gate is visited exactly once by this loop — the named branches below are specializations *within* it, never a separate pass, so no gate is evaluated twice.
117
108
 
118
- If no active security `ship:pre` gate hook is present (security enforcement off), skip this check silently.
109
+ **Step 1 — evaluate the gate's `check`.** Dispatch by check shape; read the hook's `check` object in-context to pick the branch (the registry validates exactly one of `query`/`predicate`/`agentVerdict`). Two capability IDs carry a bespoke evaluation whose fail-closed semantics the declared predicate alone does not reproduce — take their branch, then rejoin at step 2:
119
110
 
120
- 7. **Broken-windows ship gate (capability-driven, issue #1950).**
111
+ - **`capId == "security"`** — enforce against `SECURITY_FILE`:
112
+ - **`SECURITY_FILE` is empty** → `block: true`, `SECURITY_SHIP_GATE_NO_REVIEW`:
113
+ ```
114
+ ⚠ Security enforcement is enabled but no SECURITY.md exists for this phase.
115
+ Run /gsd:secure-phase {phase} and resolve findings before shipping.
116
+ ```
117
+ - **`SECURITY_FILE` exists** → read its frontmatter `threats_open`. The gate passes **only** when `threats_open` is exactly `0`. For any other value — `threats_open` > 0, or a missing / non-numeric / unparsable field — **fail closed** with `block: true` and `SECURITY_SHIP_GATE_OPEN_THREATS` (the predicate is strict equality to `0`; never ship on an ambiguous value):
118
+ ```
119
+ ⚠ Security ship gate: SECURITY.md does not assert threats_open == 0 (found: {threats_open|unset}).
120
+ Resolve open threats (or re-run /gsd:secure-phase {phase}) before shipping.
121
+ ```
121
122
 
122
- The `SHIP_PRE_HOOKS_JSON` resolved in step 6 already includes any `broken-windows` gate. Inspect `activeHooks` for an entry with `capId == "broken-windows"` and `kind == "gate"`:
123
+ - **`capId == "broken-windows"`** (issue #1950) — enforce against the ledger's typed status. The ledger lives at the **project root** (cross-phase, not phase-scoped):
123
124
 
124
- ```bash
125
- WINDOWS_GATE_ACTIVE=$(printf '%s' "$SHIP_PRE_HOOKS_JSON" | jq -r \
126
- '.activeHooks[]? | select(.capId == "broken-windows" and .kind == "gate" and .blocking == true) | .capId' \
127
- 2>/dev/null | head -1)
128
- ```
125
+ ```bash
126
+ WINDOWS_STATUS_JSON=$(gsd_run windows status --raw 2>/dev/null || echo '')
127
+ WINDOWS_OPEN_COUNT=$(printf '%s' "$WINDOWS_STATUS_JSON" | jq -r '.ledger.open_count // "?"' 2>/dev/null || echo '?')
128
+ ```
129
129
 
130
- If `$WINDOWS_GATE_ACTIVE` is non-empty, enforce the gate by reading the ledger's typed status. The ledger lives at the **project root** (cross-phase, not phase-scoped):
130
+ - **`WINDOWS_OPEN_COUNT == "0"`** → `block: false`; the gate passes.
131
+ - **`WINDOWS_OPEN_COUNT` is a positive integer** → `block: true`, `WINDOWS_SHIP_GATE_OPEN`:
132
+ ```
133
+ ⚠ Broken-windows ship gate: WINDOWS.md has {WINDOWS_OPEN_COUNT} open window(s).
134
+ Resolve each entry before shipping, or explicitly waive with a recorded reason:
135
+ gsd_run windows fixed <id> # defect resolved
136
+ gsd_run windows waive <id> "<reason>" # justified deferral (reason required)
137
+ Then re-run /gsd:ship.
138
+ ```
139
+ - **`WINDOWS_OPEN_COUNT` is `"?"`, empty, or non-numeric** → **fail closed** with `block: true` and `WINDOWS_SHIP_GATE_READ_FAILED` (the gate is strict equality to `0`; never ship on an unreadable ledger):
140
+ ```
141
+ ⚠ Broken-windows ship gate: could not read open_count from .planning/WINDOWS.md.
142
+ Inspect the file or run `gsd_run windows status --raw` to diagnose. The ledger
143
+ may be malformed; fix it before shipping (an unparseable ledger is a broken window).
144
+ ```
145
+
146
+ The ledger is **optional and backward-compatible**: on a project where `gsd_run windows status` returns `open_count: 0` (no `.planning/WINDOWS.md` yet, or an empty ledger), the gate passes silently. It only blocks when at least one entry is `open`.
147
+
148
+ - **Every other `capId`** — run the gate's own declared check through the generic evaluator. This arm is what makes a third-party capability's declared gate enforceable at all (#3559); before it existed, a gate whose `capId` was not named above was resolved and then silently dropped.
149
+
150
+ ⚠ **Validate `check` before shell use** (third-party manifest input) — `loop-hook-dispatch.md` § `gate`.
151
+
152
+ For a named-query gate (only a value that has passed validation is run):
153
+ ```bash
154
+ GATE_RESULT=$(gsd_run check ${hook.check.query} "${PHASE_DIR}" --raw)
155
+ CHECK_EXIT=$?
156
+ ```
131
157
 
132
- ```bash
133
- WINDOWS_STATUS_JSON=$(gsd_run windows status --raw 2>/dev/null || echo '')
134
- WINDOWS_OPEN_COUNT=$(printf '%s' "$WINDOWS_STATUS_JSON" | jq -r '.ledger.open_count // "?"' 2>/dev/null || echo '?')
135
- ```
158
+ (The named-query argument convention — a single `"${PHASE_DIR}"` positional — mirrors `verify-work.md`'s `verify:pre` arm verbatim. No capability declares a `check.query` gate at `ship:pre` today; the arm exists so the documented check contract is complete rather than half-implemented.)
136
159
 
137
- - **`WINDOWS_OPEN_COUNT == "0"`** → gate passes; continue to the next preflight check.
138
- - **`WINDOWS_OPEN_COUNT` is a positive integer** → block with `WINDOWS_SHIP_GATE_OPEN`:
160
+ For a `predicate` gate (ADR-2008 / #2008), serialize `hook.check.predicate` to compact JSON and pass it as a **single argv element**:
161
+ ```bash
162
+ GATE_RESULT=$(gsd_run check predicate --predicate '<hook.check.predicate as JSON>' --phase-dir "${PHASE_DIR}" --phase-number "${PHASE_NUMBER}" --raw)
163
+ CHECK_EXIT=$?
139
164
  ```
140
- ⚠ Broken-windows ship gate: WINDOWS.md has {WINDOWS_OPEN_COUNT} open window(s).
141
- Resolve each entry before shipping, or explicitly waive with a recorded reason:
142
- gsd_run windows fixed <id> # defect resolved
143
- gsd_run windows waive <id> "<reason>" # justified deferral (reason required)
144
- Then re-run /gsd:ship.
145
- ```
146
- - **`WINDOWS_OPEN_COUNT` is `"?"`, empty, or non-numeric** → **fail closed and block** with `WINDOWS_SHIP_GATE_READ_FAILED` (the gate is strict equality to `0`; never ship on an unreadable ledger):
165
+ A gate carrying neither — including an `agentVerdict` check, which has no runner at `ship:pre` — cannot be evaluated here. Record a warning naming the `capId` and treat it as a check-command failure routed per step 1a, **never** as a silent pass.
166
+
167
+ **Step 1a — did the CHECK COMMAND itself fail?** (non-zero `CHECK_EXIT`, empty output, or unparseable JSON). The two named branches above cannot reach this state — their failure modes are already folded into a fail-closed `block: true`.
168
+ - **`onError == "halt"`** → stop the ship. Do NOT push, do NOT create a PR. Surface: `⚠ Gate check command failed ({hook.capId}): command error. Resolve before shipping.`
169
+ - **`onError == "skip"`** → record a warning naming the `capId`, then continue to the next gate. Do NOT read `GATE_RESULT.block`.
170
+
171
+ **Step 2 — read the gate's `block` decision.** Only reached when the check produced a verdict.
172
+
173
+ - **`blocking == true` and `block == true`** → HALT the ship — do NOT push, do NOT create a PR — surfacing that gate's own message:
147
174
  ```
148
- ⚠ Broken-windows ship gate: could not read open_count from .planning/WINDOWS.md.
149
- Inspect the file or run `gsd_run windows status --raw` to diagnose. The ledger
150
- may be malformed; fix it before shipping (an unparseable ledger is a broken window).
175
+ ⚠ Ship blocked by capability gate ({hook.capId}): {message}
151
176
  ```
177
+ This halt is **not** bypassed by `onError` — `onError` covers check-command failure (step 1a), never the gate's block decision.
178
+ - **`blocking == false`** (advisory) → never halts. If `block == true` or the result carries a non-empty message, print `⚠ {hook.capId} advisory: {message}`, then continue.
179
+ - **`blocking == true` and `block == false`** → continue silently.
152
180
 
153
- The ledger is **optional and backward-compatible**: on a project where `gsd_run windows status` returns `open_count: 0` (no `.planning/WINDOWS.md` yet, or an empty ledger), the gate passes silently. The gate only blocks when at least one entry is `open`.
154
-
155
- If no active `broken-windows` `ship:pre` gate hook is present (gate disabled via `workflow.windows_enforce=false`, the default — tracking continues but the gate is opt-in), skip this check silently.
181
+ **When every active gate has been processed without a halt:** continue to the next preflight check.
156
182
  </step>
157
183
 
158
184
  <step name="push_branch">
@@ -455,7 +481,41 @@ would otherwise trigger (GitHub honors `[ci skip]` / `[skip ci]`):
455
481
 
456
482
  ```bash
457
483
  gsd_run query commit "docs(${padded_phase}): ship phase ${PHASE_NUMBER} — PR #${PR_NUMBER} [ci skip]" --files .planning/STATE.md
484
+ SHIP_NOTE_SHA=$(git rev-parse HEAD)
458
485
  git push origin ${CURRENT_BRANCH} 2>&1 || echo "⚠ track_shipping: ship-note push failed — it is local-only; rerun: git push origin ${CURRENT_BRANCH}"
486
+
487
+ # Preserve the skip-token optimization for repositories without a required-check
488
+ # wedge; only synthesize a second CI-triggering commit when GitHub reports one (#2783).
489
+ # Poll mergeStateStatus with backoff to avoid racing GitHub's async state computation.
490
+ # Note: Skip tokens recognized by GitHub Actions are [skip ci], [ci skip], [no ci], [skip actions], [actions skip], and skip-checks:true.
491
+ # The recovery commit message MUST NOT contain any of these tokens.
492
+
493
+ STATUS="UNKNOWN"
494
+ CHECKS=0
495
+ REVIEW_DECISION=""
496
+ for i in {1..5}; do
497
+ PR_STATE=$(gh pr view ${PR_NUMBER} --json headRefOid,mergeStateStatus,statusCheckRollup,reviewDecision -q '{head: .headRefOid, status: .mergeStateStatus, checks: ((.statusCheckRollup // []) | length), review: (.reviewDecision // "")}' 2>/dev/null || echo '{"head":"","status":"UNKNOWN","checks":0,"review":""}')
498
+ HEAD_OID=$(echo "$PR_STATE" | jq -r .head)
499
+ if [ "$HEAD_OID" = "$SHIP_NOTE_SHA" ]; then
500
+ STATUS=$(echo "$PR_STATE" | jq -r .status)
501
+ CHECKS=$(echo "$PR_STATE" | jq -r .checks)
502
+ REVIEW_DECISION=$(echo "$PR_STATE" | jq -r .review)
503
+ fi
504
+ if [ "$HEAD_OID" = "$SHIP_NOTE_SHA" ] && [ "$STATUS" != "UNKNOWN" ]; then
505
+ break
506
+ fi
507
+ sleep 3
508
+ done
509
+
510
+ if [ "$STATUS" = "BLOCKED" ] && [ "$CHECKS" = "0" ] && [ "$REVIEW_DECISION" != "REVIEW_REQUIRED" ] && [ "$REVIEW_DECISION" != "CHANGES_REQUESTED" ] && git log -1 --format=%B "$SHIP_NOTE_SHA" | grep -q '\[ci skip\]'; then
511
+ echo "⚠ PR is BLOCKED with zero checks. The [ci skip] trailer wedged the PR due to required checks."
512
+ echo "Pushing an empty commit to trigger the required pipelines..."
513
+ # gsd_run query commit requires a file list; use git directly for this intentionally empty commit.
514
+ git commit --allow-empty -m "chore: trigger CI (recover from ship-note skip-token)"
515
+ git push origin ${CURRENT_BRANCH} 2>&1 || echo "⚠ track_shipping: recovery push failed — rerun: git push origin ${CURRENT_BRANCH}"
516
+ elif [ "$STATUS" = "UNKNOWN" ]; then
517
+ echo "⚠ track_shipping: PR mergeStateStatus is UNKNOWN after polling; PR may require manual check re-trigger."
518
+ fi
459
519
  ```
460
520
  </step>
461
521
 
@@ -134,7 +134,7 @@ If spikes exist for this project, read them to ground the sketches in reality. M
134
134
 
135
135
  **a.** Glob for `./.claude/skills/spike-findings-*/SKILL.md` and read any that exist, plus their `references/*.md`. These contain validated patterns and requirements.
136
136
 
137
- **b.** Read `.planning/spikes/MANIFEST.md` if it exists — check the Requirements section for non-negotiable design constraints (e.g., "must support streaming", "must render markdown"). These requirements should be visible in the mockup even though the mockup doesn't implement them for real.
137
+ **b.** Read `.planning/spikes/MANIFEST.md` if it exists — it may hold separate `### {idea-key}` sections for several unrelated ideas. Check the Requirements list of the idea key relevant to this sketch's design direction (or all of them if none clearly matches) for non-negotiable design constraints (e.g., "must support streaming", "must render markdown"). These requirements should be visible in the mockup even though the mockup doesn't implement them for real.
138
138
 
139
139
  **c.** Read `.planning/spikes/CONVENTIONS.md` if it exists — the established stack informs what's buildable and what interaction patterns are idiomatic.
140
140
 
@@ -126,7 +126,7 @@ Acceptance Criteria:[score 0.0–1.0]
126
126
  Ambiguity: [score] ([calculate])
127
127
  ```
128
128
 
129
- **If `--auto` and initial ambiguity already ≤ 0.20 with all minimums met:** Skip interview — derive SPEC.md directly from roadmap + requirements. Log: `[auto] Phase requirements are already sufficiently clear — generating SPEC.md from existing context.` Jump to Step 6.
129
+ **If `--auto` and initial ambiguity already ≤ 0.20 with all minimums met:** Skip interview — derive SPEC.md directly from roadmap + requirements. Log: `[auto] Phase requirements are already sufficiently clear — generating SPEC.md from existing context.` Jump to Step 5.5.
130
130
 
131
131
  **Otherwise:** Continue to Step 4.
132
132
 
@@ -159,15 +159,15 @@ After round [N]:
159
159
 
160
160
  If gate passes (ambiguity ≤ 0.20 AND all minimums met):
161
161
 
162
- **If `--auto`:** Jump to Step 6.
162
+ **If `--auto`:** Jump to Step 5.5.
163
163
 
164
164
  **Otherwise:** AskUserQuestion:
165
165
  - header: "Spec Gate Passed"
166
166
  - question: "Ambiguity is [score] — requirements are clear enough to write SPEC.md. Proceed?"
167
167
  - options:
168
- - "Yes — write SPEC.md" → Jump to Step 6
168
+ - "Yes — write SPEC.md" → Jump to Step 5.5
169
169
  - "One more round" → Continue interview
170
- - "Done talking — write it" → Jump to Step 6
170
+ - "Done talking — write it" → Jump to Step 5.5
171
171
 
172
172
  **If max rounds reached (6) and gate not passed:**
173
173
 
@@ -251,8 +251,11 @@ if ! node -e 'const a=require(process.argv[1]);if(!Array.isArray(a)||a.length===
251
251
  exit 1
252
252
  fi
253
253
  # Invoke the compiled engine and CAPTURE its report — it computes which categories apply per
254
- # requirement. The covered/backstop/dismissed/unresolved rows in $COVERAGE drive the
255
- # resolution loop below (canonical taxonomy compute, NOT LLM re-derivation from prose).
254
+ # requirement. The report is RENDERED into context below (#3102); its resolved/dismissed/
255
+ # unresolved rows (resolved items carry verification: explicit|backstop) are the deterministic
256
+ # FLOOR the resolution loop consumes and unions with its own classification — the loop no longer
257
+ # re-derives the taxonomy from prose unaided. Floor, never ceiling: the classifier has a measured
258
+ # recall gap (ADR-857 §98 / ADR-550 D7b), so the model still ADDS any category the engine missed.
256
259
  # The engine FAILS CLOSED (exit 2) on an invalid authored shape or bad input — so the capture
257
260
  # MUST be exit-checked. A bare `COVERAGE=$(node …)` swallows that exit code, leaves $COVERAGE
258
261
  # empty, and lets the workflow fall through to prose re-derivation: fail-OPEN at the boundary
@@ -269,6 +272,16 @@ if ! printf '%s' "$COVERAGE" | node -e 'let s="";process.stdin.on("data",d=>s+=d
269
272
  echo "ERROR: edge-probe produced an unparseable or malformed coverage report — refusing to proceed with the resolution loop." >&2
270
273
  exit 1
271
274
  fi
275
+ # Render the validated report into the model's visible context (#3102). Until here $COVERAGE was
276
+ # captured, shape-checked, and reduced to coverage.applicable — the engine's per-requirement
277
+ # items[] never reached the model, so the resolution loop below re-derived edge categories from
278
+ # requirement PROSE (the data-flow twin of #2733's control-flow discard). These rows are the
279
+ # deterministic FLOOR the resolution loop consumes. Printed RAW (not a bespoke table) so this
280
+ # step holds NO knowledge of the item schema: an ADR-550 D7a-style re-cut of the item/coverage
281
+ # shape cannot silently desync a hand-rolled renderer here — the engine stays the single source.
282
+ echo "### Edge-probe coverage report (deterministic proposals — the FLOOR for the resolution loop below):"
283
+ printf '%s\n' "$COVERAGE"
284
+ echo "### (end edge-probe coverage report)"
272
285
  # Zero-applicable guard: a report where the engine proposed NO applicable edge across ANY
273
286
  # requirement is far more likely a shape-classification miss (or malformed requirements) than
274
287
  # a genuinely edge-free spec — the same fail-open shape as an invalid shape yielding
@@ -286,23 +299,29 @@ edge-free spec, or should we revisit the requirement wording / authored shapes?"
286
299
  an empty `## Edge Coverage` section after explicit confirmation.
287
300
 
288
301
  For each Requirement gathered so far:
289
- 1. Classify its shape and raise only applicable edge categories (relevance filter — see
290
- the taxonomy in the reference). Reuse any edges the Round-4 Failure Analyst already
291
- surfaced as pre-`covered`.
302
+ 1. Start from the edge-probe rows RENDERED above — the deterministic `items[]` are the FLOOR:
303
+ every proposed `(requirement_id, category)` MUST be resolved below (Specify / Dismiss-with-
304
+ reason / Backstop / Defer), none silently dropped. Then raise any applicable category the
305
+ engine MISSED — the rows are a floor, never a ceiling: the classifier has a measured recall
306
+ gap on terse prose (ADR-857 §98 / ADR-550 D7b), e.g. a CSV-export requirement whose
307
+ `encoding` edge the shape cue under-fires. Union the engine's rows with your own
308
+ classification (relevance filter — see the taxonomy in the reference); do not narrow to them.
309
+ Reuse any edges the Round-4 Failure Analyst already surfaced as pre-resolved.
292
310
  2. For each raised category, propose a CONCRETE candidate edge (not "consider
293
311
  boundaries" — e.g. "R2 merges intervals; what about `[[1,2],[2,3]]` that only touch?").
294
312
  3. Resolve each with the user (AskUserQuestion; text mode → numbered list):
295
313
  - **Specify it** → write a new pass/fail line into Acceptance Criteria AND mark the
296
- edge `covered`.
314
+ edge `resolved` with `verification: explicit`.
297
315
  - **Dismiss (reason)** → mark `dismissed` with a required non-empty reason.
298
- - **Backstop with a test** → mark `backstop`; note "held-out edge test" for plan-phase.
316
+ - **Backstop with a test** → mark `resolved` with `verification: backstop`; note
317
+ "held-out edge test" for plan-phase.
299
318
  - **Defer** → leave `unresolved`.
300
319
  - An `unclassified` row (probe `unclassified — review manually`) means the requirement's
301
320
  prose matched no shape cue (#1110) — treat it like any other candidate (**Specify**,
302
321
  **Dismiss (reason)**, or **Defer**). A manual-review nudge, not a hard block.
303
322
 
304
323
  **Soft gate (after resolving):**
305
- - All applicable edges resolved → proceed to Step 6.
324
+ - All applicable edges resolved → proceed to Step 5.6.
306
325
  - Any `unresolved` → AskUserQuestion:
307
326
  - header: "Edge Coverage"
308
327
  - question: "[N] edge(s) are unresolved: [list]. What do you want to do?"
@@ -311,13 +330,16 @@ For each Requirement gathered so far:
311
330
  - On "anyway": write SPEC.md with those rows marked `⚠ Edge unresolved — planner must
312
331
  treat as assumption`.
313
332
 
314
- **`--auto` mode:** auto-`covered` where a defensible acceptance criterion can be written;
315
- otherwise auto-`backstop` (never auto-dismiss — a wrong dismissal is the exact silent
316
- failure being eliminated). Log: `[auto] edge coverage: C covered, B backstop, U unresolved`.
333
+ **`--auto` mode:** resolve over the **same rendered floor** (#3102) — every engine-proposed row
334
+ from Step 5.5's report (step 1) plus any category the classifier missed, never a narrower set.
335
+ For each: auto-`resolved` (verification: explicit) where a defensible acceptance criterion can be
336
+ written; otherwise auto-`resolved` (verification: backstop) (never auto-dismiss — a wrong
337
+ dismissal is the exact silent failure being eliminated). Log:
338
+ `[auto] edge coverage: E explicit, B backstop, U unresolved`.
317
339
 
318
340
  **`unclassified` exception (#1110):** `--auto` leaves an `unclassified` candidate
319
341
  **`unresolved`** (the soft gate surfaces it as a flagged planner assumption) — it never
320
- auto-`backstop`s it. A missing shape is not evidence an edge exists, so minting a held-out
342
+ auto-resolves it with `verification: backstop`. A missing shape is not evidence an edge exists, so minting a held-out
321
343
  edge obligation on a requirement that may be genuinely edge-free would be a false claim and
322
344
  risks a vacuous edge test. Leaving it `unresolved` keeps the zero-cue requirement visible
323
345
  (never a silent drop) without fabricating an edge — which is exactly #1110's purpose: surface
@@ -425,7 +447,7 @@ downstream rather than blocking authoring.
425
447
 
426
448
  Use the SPEC.md template from @~/.claude/gsd-core/templates/spec.md.
427
449
 
428
- - Populate the **Edge Coverage** section from Step 5.5 (covered/dismissed/backstop/unresolved rows).
450
+ - Populate the **Edge Coverage** section from Step 5.5 (resolved/dismissed/unresolved rows; resolved items carry `verification: explicit|backstop`).
429
451
  - Populate the **Prohibitions** section from Step 5.6 (resolved/dismissed/unresolved rows with the test|judgment tier).
430
452
 
431
453
  **Requirements for every requirement entry:**
@@ -455,11 +477,10 @@ Write to: `{phase_dir}/{padded_phase}-SPEC.md`
455
477
  ## Step 7: Commit
456
478
 
457
479
  ```bash
458
- git add "${phase_dir}/${padded_phase}-SPEC.md"
459
- git commit -m "spec(phase-${phase_number}): add SPEC.md for ${phase_name} — ${requirement_count} requirements (#2213)" -- "${phase_dir}/${padded_phase}-SPEC.md"
480
+ gsd_run query commit "spec(phase-${phase_number}): add SPEC.md for ${phase_name} — ${requirement_count} requirements (#2213)" --files "${phase_dir}/${padded_phase}-SPEC.md"
460
481
  ```
461
482
 
462
- If `commit_docs` is false: Skip commit. Note that SPEC.md was written but not committed.
483
+ If `commit_docs` is false the CLI returns `skipped`; SPEC.md is written, not committed.
463
484
 
464
485
  ## Step 8: Wrap Up
465
486
 
@@ -22,8 +22,12 @@ Read all files referenced by the invoking prompt's execution_context before star
22
22
  <step name="gather">
23
23
  ## Gather Spike Inventory
24
24
 
25
- 1. Read `.planning/spikes/MANIFEST.md` for the overall idea context and requirements
26
- 2. Glob `.planning/spikes/*/README.md` and parse YAML frontmatter from each
25
+ 1. Read `.planning/spikes/MANIFEST.md` for the `## Ideas` sections (each idea's paragraph and
26
+ its own scoped Requirements list) and the `## Spikes` table (its Idea column tells you which
27
+ idea key each spike row belongs to).
28
+ 2. Glob `.planning/spikes/*/README.md` and parse YAML frontmatter from each — each spike's
29
+ `idea:` field is the idea key that owns it. If a README predates #1700 and has no `idea:`
30
+ field, resolve its idea key from the matching `## Spikes` table row's Idea column instead.
27
31
  3. Check if `./.claude/skills/spike-findings-*/SKILL.md` exists for this project
28
32
  - If yes: read its `processed_spikes` list from the metadata section and filter those out
29
33
  - If no: all spikes are candidates
@@ -101,7 +105,12 @@ For each feature-area group, write a reference file at `references/[feature-area
101
105
 
102
106
  ## Requirements
103
107
 
104
- [Non-negotiable design decisions from MANIFEST.md Requirements section that apply to this feature area. These MUST be honored in the real build. E.g., "Must use streaming JSON output", "Must support reconnection".]
108
+ [Non-negotiable design decisions pulled ONLY from the Requirements list of the idea key(s) that
109
+ own the spikes in this feature-area group — match each spike's `idea:` frontmatter (or Idea
110
+ column) to its `### {idea-key}` Requirements list in MANIFEST.md. These MUST be honored in the
111
+ real build. E.g., "Must use streaming JSON output", "Must support reconnection".
112
+
113
+ Never include a requirement from an idea key that has no spike in this group.]
105
114
 
106
115
  ## How to Build It
107
116
 
@@ -136,7 +145,8 @@ description: Implementation blueprint from spike experiments. Requirements, prov
136
145
  <context>
137
146
  ## Project: [project-dir-name]
138
147
 
139
- [One paragraph from MANIFEST.md describing the overall idea]
148
+ [One paragraph per idea key represented among the wrapped spikes, taken from that idea's
149
+ `### {idea-key}` section in MANIFEST.md — not the whole MANIFEST.md if it holds unrelated ideas.]
140
150
 
141
151
  Spike sessions wrapped: [date(s)]
142
152
  </context>
@@ -144,7 +154,11 @@ Spike sessions wrapped: [date(s)]
144
154
  <requirements>
145
155
  ## Requirements
146
156
 
147
- [Copied directly from MANIFEST.md Requirements section. These are non-negotiable design decisions that emerged from the user's choices during spiking. Every feature area reference must honor these.]
157
+ [Union of the Requirements lists for every idea key represented among the spikes being wrapped
158
+ in this session — never the whole MANIFEST.md. These are non-negotiable design decisions that
159
+ emerged from the user's choices while spiking those specific idea(s). Every feature area
160
+ reference must honor these. If this wrap-up spans more than one idea key, group the list by
161
+ idea key so a future reader can tell which requirement belongs to which idea.]
148
162
 
149
163
  - [requirement 1]
150
164
  - [requirement 2]
@@ -299,6 +313,7 @@ After the summary, present next-step options:
299
313
  - [ ] Spikes grouped by feature area
300
314
  - [ ] Spike-findings skill exists at `./.claude/skills/` with SKILL.md (including requirements), references/, sources/
301
315
  - [ ] Reference files are implementation blueprints with Requirements, How to Build It, What to Avoid, Constraints
316
+ - [ ] Requirements in each reference file and in SKILL.md are scoped to the idea key(s) actually represented among the wrapped spikes — never blended with an unrelated idea's requirements
302
317
  - [ ] `.planning/spikes/CONVENTIONS.md` created or updated with recurring stack/structure/pattern choices
303
318
  - [ ] `.planning/spikes/WRAP-UP-SUMMARY.md` written for project history
304
319
  - [ ] Project CLAUDE.md has auto-load routing line
@@ -53,7 +53,8 @@ If no `.planning/spikes/` directory exists, tell the user there's nothing to ana
53
53
 
54
54
  Otherwise, load in this order:
55
55
 
56
- **a. MANIFEST.md** — the overall idea, requirements, and spike table with verdicts.
56
+ **a. MANIFEST.md** — every idea section under `## Ideas` (each idea's paragraph and its own
57
+ scoped Requirements) and the `## Spikes` table with verdicts (each row tagged by idea).
57
58
 
58
59
  **b. Findings skills** — glob `./.claude/skills/spike-findings-*/SKILL.md` and read any that exist, plus their `references/*.md`. These contain curated knowledge from prior wrap-ups.
59
60
 
@@ -74,7 +75,8 @@ If integration risks exist, present them as concrete proposed spikes with names
74
75
 
75
76
  ### Analyze for Frontier Spikes
76
77
 
77
- Think laterally about the overall idea from MANIFEST.md and what's been proven so far. Consider:
78
+ Think laterally about every idea section from MANIFEST.md and what's been proven so far for
79
+ each. Consider:
78
80
 
79
81
  - **Gaps in the vision:** Capabilities assumed but unproven.
80
82
  - **Discovered dependencies:** Findings that reveal new questions.
@@ -86,7 +88,7 @@ Present frontier spikes as concrete proposals numbered from the highest existing
86
88
 
87
89
  ### Get Alignment and Execute
88
90
 
89
- Present all integration and frontier candidates, then ask which to run. When the user picks spikes, write definitions into `.planning/spikes/MANIFEST.md` (appending to existing table) and proceed directly to building them starting at `research`.
91
+ Present all integration and frontier candidates, then ask which to run. When the user picks spikes, write definitions into `.planning/spikes/MANIFEST.md` (appending to the existing table, with each row's Idea column set to the idea key(s) it extends or validates) and proceed directly to building them starting at `research`.
90
92
  </step>
91
93
 
92
94
  <step name="setup_directory">
@@ -212,33 +214,63 @@ If 2+ credible approaches exist, plan to build quick variants within the spike a
212
214
  </step>
213
215
 
214
216
  <step name="create_manifest">
215
- Create or update `.planning/spikes/MANIFEST.md`:
217
+ Create or update `.planning/spikes/MANIFEST.md`.
218
+
219
+ **Assign an idea key.** Derive a short, stable, kebab-case slug (2-4 words) summarizing the
220
+ idea being spiked right now, e.g. `realtime-llm-streaming`. Reuse the exact same idea key for
221
+ every spike in this session and any later session that continues the same idea. Only mint a
222
+ new idea key when the current idea is not a continuation of one already indexed in
223
+ MANIFEST.md — never reuse an existing idea key for an unrelated idea, and never merge two
224
+ different ideas under one key.
225
+
226
+ If `.planning/spikes/MANIFEST.md` doesn't exist, create it:
216
227
 
217
228
  ```markdown
218
229
  # Spike Manifest
219
230
 
220
- ## Idea
221
- [One paragraph describing the overall idea being explored]
231
+ ## Ideas
232
+
233
+ ### {idea-key}
234
+ [One paragraph describing this idea]
222
235
 
223
- ## Requirements
224
- [Design decisions that emerged from the user's choices during spiking. Non-negotiable for the real build. Updated as spikes progress.]
236
+ **Requirements:**
237
+ [Design decisions that emerged from the user's choices while spiking THIS idea. Non-negotiable
238
+ for the real build of this idea. Updated as spikes progress. Never copy or merge requirements
239
+ from a different idea key into this list.]
225
240
 
226
241
  - [e.g., "Must use streaming JSON output, not single-response"]
227
242
  - [e.g., "Must support reconnection on network failure"]
228
243
 
229
244
  ## Spikes
230
245
 
231
- | # | Name | Type | Validates | Verdict | Tags |
232
- |---|------|------|-----------|---------|------|
246
+ | # | Idea | Name | Type | Validates | Verdict | Tags |
247
+ |---|------|------|------|-----------|---------|------|
233
248
  ```
234
249
 
235
- **Track requirements as they emerge.** When the user expresses a preference during spiking, add it to the Requirements section immediately.
250
+ If `.planning/spikes/MANIFEST.md` already exists:
251
+
252
+ - **Same idea key already has a `### {idea-key}` section under `## Ideas`:** append to that
253
+ section's Requirements list as new requirements emerge. Never overwrite or rewrite its
254
+ `## Idea` paragraph.
255
+ - **New idea key, not yet present:** append a new `### {idea-key}` subsection under `## Ideas`,
256
+ after any existing idea sections. Never touch, merge into, or delete another idea's section.
257
+ - **A pre-#1700 MANIFEST.md with the old flat shape** (a single top-level `## Idea` / `##
258
+ Requirements` pair, no `## Ideas` heading): treat its existing content as one implicit idea.
259
+ Derive an idea key from its `## Idea` paragraph, migrate it in place to `## Ideas` >
260
+ `### {idea-key}` — preserving the paragraph and every existing Requirements bullet and
261
+ Spikes row verbatim — then continue as above. Do this migration once; do not repeat it once
262
+ `## Ideas` exists.
263
+
264
+ Every row appended to `## Spikes` carries an **Idea** column set to the idea key it belongs to.
265
+
266
+ **Track requirements as they emerge.** When the user expresses a preference during spiking, add
267
+ it to the current idea's Requirements list immediately — never to a different idea's list.
236
268
  </step>
237
269
 
238
270
  <step name="reground">
239
271
  ## Re-Ground Before Each Spike
240
272
 
241
- Before starting each spike (not just the first), re-read `.planning/spikes/MANIFEST.md` and `.planning/spikes/CONVENTIONS.md` to prevent drift within long sessions. Check the Requirements section — make sure the spike doesn't contradict any established requirements.
273
+ Before starting each spike (not just the first), re-read `.planning/spikes/MANIFEST.md` and `.planning/spikes/CONVENTIONS.md` to prevent drift within long sessions. Check the current idea's `### {idea-key}` Requirements list — make sure the spike doesn't contradict any established requirement for this idea. Do not apply another idea's requirements.
242
274
  </step>
243
275
 
244
276
  <step name="build_spikes">
@@ -287,6 +319,7 @@ Multiple files per spike are expected for complex questions (e.g., `test-basic.j
287
319
  ```markdown
288
320
  ---
289
321
  spike: NNN
322
+ idea: {idea-key}
290
323
  name: descriptive-name
291
324
  type: standard
292
325
  validates: "Given [precondition], when [action], then [expected outcome]"
@@ -337,7 +370,8 @@ tags: [tag1, tag2]
337
370
  → Does this match what you expected? Describe what you see.
338
371
  ──────────────────────────────────────────────────────────────
339
372
 
340
- **h.** Update `.planning/spikes/MANIFEST.md` with the spike's row.
373
+ **h.** Update `.planning/spikes/MANIFEST.md` with the spike's row, setting the Idea column to
374
+ this spike's idea key.
341
375
 
342
376
  **i.** Commit (if `COMMIT_DOCS` is true):
343
377
  ```bash
@@ -450,10 +484,10 @@ gsd_run query commit "docs(spikes): update conventions" --files .planning/spikes
450
484
  - [ ] Depth over speed — edge cases tested, surprising findings followed, investigation trail documented
451
485
  - [ ] Comparison spikes built back-to-back with head-to-head verdict
452
486
  - [ ] Spikes needing human interaction have forensic log layer
453
- - [ ] Requirements tracked in MANIFEST.md as they emerge from user choices
487
+ - [ ] Requirements tracked in MANIFEST.md, scoped to the idea key that produced them, as they emerge from user choices
454
488
  - [ ] CONVENTIONS.md created or updated with patterns that emerged
455
- - [ ] Each spike README has complete frontmatter, Investigation Trail, and Results
456
- - [ ] MANIFEST.md is current (with Type column and Requirements section)
489
+ - [ ] Each spike README has complete frontmatter (including its idea key), Investigation Trail, and Results
490
+ - [ ] MANIFEST.md is current (with Idea and Type columns, and each idea's own scoped Requirements section)
457
491
  - [ ] Commits use `docs(spike-NNN): [VERDICT]` format
458
492
  - [ ] Consolidated report presented with next-step routing
459
493
  </success_criteria>