@opengsd/gsd-core 1.14.0 → 1.16.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 (551) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +85 -5
  4. package/README.ja-JP.md +3 -3
  5. package/README.ko-KR.md +3 -3
  6. package/README.pt-BR.md +3 -3
  7. package/README.zh-CN.md +3 -3
  8. package/agents/gsd-code-fixer.compact.md +7 -6
  9. package/agents/gsd-code-fixer.md +9 -8
  10. package/agents/gsd-code-reviewer.compact.md +5 -3
  11. package/agents/gsd-code-reviewer.md +8 -6
  12. package/agents/gsd-debug-session-manager.compact.md +17 -2
  13. package/agents/gsd-debug-session-manager.md +17 -2
  14. package/agents/gsd-debugger.md +3 -3
  15. package/agents/gsd-eval-auditor.compact.md +1 -1
  16. package/agents/gsd-eval-auditor.md +1 -1
  17. package/agents/gsd-executor.md +17 -12
  18. package/agents/gsd-intel-updater.compact.md +1 -1
  19. package/agents/gsd-intel-updater.md +1 -1
  20. package/agents/gsd-mempalace-curator.md +2 -2
  21. package/agents/gsd-phase-researcher.md +19 -11
  22. package/agents/gsd-plan-checker.md +15 -9
  23. package/agents/gsd-planner.md +15 -11
  24. package/agents/gsd-project-researcher.compact.md +1 -1
  25. package/agents/gsd-project-researcher.md +1 -1
  26. package/agents/gsd-research-synthesizer.compact.md +1 -1
  27. package/agents/gsd-research-synthesizer.md +1 -1
  28. package/agents/gsd-ui-auditor.compact.md +21 -30
  29. package/agents/gsd-ui-auditor.md +166 -37
  30. package/agents/gsd-ui-researcher.compact.md +1 -1
  31. package/agents/gsd-ui-researcher.md +1 -1
  32. package/agents/gsd-verifier.md +37 -14
  33. package/bin/install.js +764 -287
  34. package/commands/gsd/add-tests.md +6 -1
  35. package/commands/gsd/ai-integration-phase.md +6 -1
  36. package/commands/gsd/audit-fix.md +5 -0
  37. package/commands/gsd/audit-milestone.md +6 -1
  38. package/commands/gsd/autonomous.md +7 -2
  39. package/commands/gsd/capture.md +9 -5
  40. package/commands/gsd/code-review.md +7 -2
  41. package/commands/gsd/complete-milestone.md +4 -0
  42. package/commands/gsd/config.md +7 -3
  43. package/commands/gsd/debug.md +11 -7
  44. package/commands/gsd/discuss-phase.md +7 -3
  45. package/commands/gsd/docs-update.md +12 -7
  46. package/commands/gsd/eval-review.md +6 -1
  47. package/commands/gsd/execute-phase.md +12 -7
  48. package/commands/gsd/extract-learnings.md +5 -0
  49. package/commands/gsd/fast.md +4 -0
  50. package/commands/gsd/forensics.md +5 -1
  51. package/commands/gsd/graphify.md +10 -6
  52. package/commands/gsd/health.md +5 -0
  53. package/commands/gsd/help.md +7 -2
  54. package/commands/gsd/import.md +7 -3
  55. package/commands/gsd/inbox.md +5 -0
  56. package/commands/gsd/ingest-docs.md +5 -1
  57. package/commands/gsd/manager.md +6 -1
  58. package/commands/gsd/map-codebase.md +7 -3
  59. package/commands/gsd/mempalace-capture.md +12 -4
  60. package/commands/gsd/mempalace-recall.md +5 -1
  61. package/commands/gsd/milestone-summary.md +5 -1
  62. package/commands/gsd/mvp-phase.md +8 -3
  63. package/commands/gsd/new-milestone.md +6 -1
  64. package/commands/gsd/new-project.md +5 -0
  65. package/commands/gsd/next.md +6 -1
  66. package/commands/gsd/ns-context.md +4 -0
  67. package/commands/gsd/ns-ideate.md +4 -0
  68. package/commands/gsd/ns-manage.md +4 -0
  69. package/commands/gsd/ns-project.md +4 -0
  70. package/commands/gsd/ns-review.md +4 -0
  71. package/commands/gsd/ns-workflow.md +4 -0
  72. package/commands/gsd/onboard.md +6 -1
  73. package/commands/gsd/pause-work.md +5 -1
  74. package/commands/gsd/phase.md +8 -4
  75. package/commands/gsd/plan-phase.md +6 -1
  76. package/commands/gsd/plan-review-convergence.md +11 -7
  77. package/commands/gsd/pr-branch.md +4 -0
  78. package/commands/gsd/profile-user.md +5 -1
  79. package/commands/gsd/progress.md +7 -2
  80. package/commands/gsd/quick-batch.md +21 -9
  81. package/commands/gsd/quick.md +12 -7
  82. package/commands/gsd/review.md +7 -4
  83. package/commands/gsd/secure-phase.md +6 -1
  84. package/commands/gsd/ship.md +5 -0
  85. package/commands/gsd/sketch.md +7 -2
  86. package/commands/gsd/spec-phase.md +5 -1
  87. package/commands/gsd/spike.md +8 -3
  88. package/commands/gsd/surface.md +5 -1
  89. package/commands/gsd/thread.md +4 -0
  90. package/commands/gsd/ui-phase.md +6 -1
  91. package/commands/gsd/ui-review.md +6 -1
  92. package/commands/gsd/ultraplan-phase.md +5 -1
  93. package/commands/gsd/undo.md +5 -1
  94. package/commands/gsd/update.md +6 -2
  95. package/commands/gsd/validate-phase.md +6 -1
  96. package/commands/gsd/verify-work.md +6 -1
  97. package/commands/gsd/workspace.md +7 -3
  98. package/gsd-core/bin/gsd-tools.cjs +477 -78
  99. package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
  100. package/gsd-core/bin/lib/adr-parser.cjs +3 -1
  101. package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
  102. package/gsd-core/bin/lib/audit.cjs +144 -42
  103. package/gsd-core/bin/lib/broken-windows.cjs +13 -13
  104. package/gsd-core/bin/lib/capability-activation.cjs +9 -4
  105. package/gsd-core/bin/lib/capability-registry.cjs +197 -222
  106. package/gsd-core/bin/lib/capability-validator.cjs +16 -1
  107. package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
  108. package/gsd-core/bin/lib/check-command-router.cjs +164 -1625
  109. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
  110. package/gsd-core/bin/lib/cli-exit.cjs +12 -0
  111. package/gsd-core/bin/lib/codex-agent-toml.cjs +32 -33
  112. package/gsd-core/bin/lib/command-aliases.cjs +7 -0
  113. package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
  114. package/gsd-core/bin/lib/commands.cjs +343 -207
  115. package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
  116. package/gsd-core/bin/lib/config-loader.cjs +65 -4
  117. package/gsd-core/bin/lib/config.cjs +76 -19
  118. package/gsd-core/bin/lib/core-utils.cjs +6 -1
  119. package/gsd-core/bin/lib/coverage.cjs +4 -8
  120. package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
  121. package/gsd-core/bin/lib/decisions.cjs +30 -14
  122. package/gsd-core/bin/lib/drift.cjs +177 -42
  123. package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
  124. package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
  125. package/gsd-core/bin/lib/frontmatter.cjs +426 -234
  126. package/gsd-core/bin/lib/gap-checker.cjs +72 -29
  127. package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
  128. package/gsd-core/bin/lib/gate-args.cjs +53 -0
  129. package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
  130. package/gsd-core/bin/lib/gate-config.cjs +46 -0
  131. package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
  132. package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
  133. package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
  134. package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
  135. package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
  136. package/gsd-core/bin/lib/gate-exit.cjs +27 -0
  137. package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
  138. package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
  139. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
  140. package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
  141. package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
  142. package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
  143. package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
  144. package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
  145. package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
  146. package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
  147. package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
  148. package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
  149. package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
  150. package/gsd-core/bin/lib/graphify.cjs +10 -2
  151. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
  152. package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
  153. package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
  154. package/gsd-core/bin/lib/init.cjs +364 -132
  155. package/gsd-core/bin/lib/install-engine.cjs +30 -33
  156. package/gsd-core/bin/lib/install-profiles.cjs +7 -4
  157. package/gsd-core/bin/lib/installer-migrations.cjs +8 -1
  158. package/gsd-core/bin/lib/io.cjs +122 -3
  159. package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
  160. package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
  161. package/gsd-core/bin/lib/milestone.cjs +37 -6
  162. package/gsd-core/bin/lib/model-resolver.cjs +171 -62
  163. package/gsd-core/bin/lib/observability/event.cjs +1 -1
  164. package/gsd-core/bin/lib/observability/logger.cjs +46 -1
  165. package/gsd-core/bin/lib/pattern.cjs +10 -0
  166. package/gsd-core/bin/lib/phase-command-router.cjs +20 -5
  167. package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
  168. package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
  169. package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
  170. package/gsd-core/bin/lib/phase-id.cjs +110 -8
  171. package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
  172. package/gsd-core/bin/lib/phase-locator.cjs +29 -10
  173. package/gsd-core/bin/lib/phase-status.cjs +360 -0
  174. package/gsd-core/bin/lib/phase.cjs +489 -88
  175. package/gsd-core/bin/lib/plan-document.cjs +142 -20
  176. package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
  177. package/gsd-core/bin/lib/planning-document.cjs +692 -0
  178. package/gsd-core/bin/lib/planning-inspect.cjs +60 -9
  179. package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
  180. package/gsd-core/bin/lib/planning-workspace.cjs +83 -55
  181. package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
  182. package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
  183. package/gsd-core/bin/lib/probe-core.cjs +7 -1
  184. package/gsd-core/bin/lib/profile-output.cjs +6 -3
  185. package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
  186. package/gsd-core/bin/lib/project-root.cjs +41 -2
  187. package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
  188. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
  189. package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
  190. package/gsd-core/bin/lib/report-parser.cjs +269 -0
  191. package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
  192. package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
  193. package/gsd-core/bin/lib/roadmap-command-router.cjs +25 -19
  194. package/gsd-core/bin/lib/roadmap-parser.cjs +242 -15
  195. package/gsd-core/bin/lib/roadmap-upgrade.cjs +1653 -65
  196. package/gsd-core/bin/lib/roadmap.cjs +405 -88
  197. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +373 -187
  198. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +5 -2
  199. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
  200. package/gsd-core/bin/lib/runtime-homes.cjs +14 -7
  201. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +522 -624
  202. package/gsd-core/bin/lib/runtime-name-policy.cjs +246 -21
  203. package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
  204. package/gsd-core/bin/lib/shell-command-projection.cjs +47 -8
  205. package/gsd-core/bin/lib/smart-entry.cjs +19 -3
  206. package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
  207. package/gsd-core/bin/lib/state-contract.cjs +15 -18
  208. package/gsd-core/bin/lib/state-document.cjs +100 -22
  209. package/gsd-core/bin/lib/state-transition.cjs +39 -2
  210. package/gsd-core/bin/lib/state.cjs +256 -105
  211. package/gsd-core/bin/lib/surface.cjs +19 -2
  212. package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -79
  213. package/gsd-core/bin/lib/uat-predicate.cjs +359 -38
  214. package/gsd-core/bin/lib/uat.cjs +432 -7
  215. package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
  216. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +167 -40
  217. package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
  218. package/gsd-core/bin/lib/vendor/README.md +31 -9
  219. package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
  220. package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
  221. package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
  222. package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
  223. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  224. package/gsd-core/bin/lib/verification.cjs +1378 -274
  225. package/gsd-core/bin/lib/verify-command-grounding.cjs +46 -2
  226. package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
  227. package/gsd-core/bin/lib/verify.cjs +357 -531
  228. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
  229. package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
  230. package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
  231. package/gsd-core/bin/lib/workstream.cjs +11 -2
  232. package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
  233. package/gsd-core/bin/lib/worktree-safety.cjs +784 -51
  234. package/gsd-core/bin/shared/config-defaults.manifest.json +8 -0
  235. package/gsd-core/bin/shared/config-schema.manifest.json +5 -0
  236. package/gsd-core/references/autonomous-smart-discuss.md +2 -1
  237. package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
  238. package/gsd-core/references/checkpoints.md +5 -3
  239. package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
  240. package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
  241. package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
  242. package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
  243. package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
  244. package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
  245. package/gsd-core/references/edge-probe.md +195 -21
  246. package/gsd-core/references/execute-mvp-tdd.md +5 -10
  247. package/gsd-core/references/execute-phase-between-wave-reset.md +10 -6
  248. package/gsd-core/references/execute-phase-response-language.md +1 -1
  249. package/gsd-core/references/execute-phase-wave-guard.md +22 -11
  250. package/gsd-core/references/gsd-run-resolver.md +1 -1
  251. package/gsd-core/references/loop-hook-dispatch.md +7 -1
  252. package/gsd-core/references/model-profiles.md +1 -1
  253. package/gsd-core/references/offer-next.md +1 -1
  254. package/gsd-core/references/phase-argument-parsing.md +9 -7
  255. package/gsd-core/references/phase-id-convention.md +28 -0
  256. package/gsd-core/references/planner-gap-closure.md +2 -0
  257. package/gsd-core/references/planner-load-graph-context.md +24 -13
  258. package/gsd-core/references/planner-verify-command-grounding.md +14 -0
  259. package/gsd-core/references/planning-config.md +12 -3
  260. package/gsd-core/references/spidr-splitting.md +1 -1
  261. package/gsd-core/references/tdd.md +37 -8
  262. package/gsd-core/references/ui-consideration-probe.md +10 -5
  263. package/gsd-core/references/verifier-phase-gates.md +5 -2
  264. package/gsd-core/references/verify-command-path-resolvability.md +10 -2
  265. package/gsd-core/references/verify-mvp-mode.md +2 -2
  266. package/gsd-core/references/workstream-flag.md +33 -3
  267. package/gsd-core/references/worktree-path-safety.md +321 -0
  268. package/gsd-core/templates/README.md +1 -1
  269. package/gsd-core/templates/UAT.md +17 -1
  270. package/gsd-core/templates/config.json +2 -11
  271. package/gsd-core/templates/verification-report.md +1 -1
  272. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  273. package/gsd-core/workflows/add-backlog.md +1 -1
  274. package/gsd-core/workflows/add-phase.md +8 -7
  275. package/gsd-core/workflows/add-tests.md +4 -3
  276. package/gsd-core/workflows/add-todo.md +6 -5
  277. package/gsd-core/workflows/ai-integration-phase.md +13 -4
  278. package/gsd-core/workflows/audit-fix.md +1 -1
  279. package/gsd-core/workflows/audit-milestone.md +4 -3
  280. package/gsd-core/workflows/audit-uat.md +1 -1
  281. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
  282. package/gsd-core/workflows/autonomous.md +43 -23
  283. package/gsd-core/workflows/check-todos.md +7 -6
  284. package/gsd-core/workflows/cleanup.md +2 -2
  285. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
  286. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
  287. package/gsd-core/workflows/code-review-fix.md +112 -25
  288. package/gsd-core/workflows/code-review.md +146 -135
  289. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
  290. package/gsd-core/workflows/complete-milestone.md +13 -8
  291. package/gsd-core/workflows/debug.md +32 -7
  292. package/gsd-core/workflows/diagnose-issues.md +3 -2
  293. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  294. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  295. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  296. package/gsd-core/workflows/discuss-phase.md +4 -3
  297. package/gsd-core/workflows/do.md +2 -2
  298. package/gsd-core/workflows/docs-update.md +6 -5
  299. package/gsd-core/workflows/edit-phase.md +4 -3
  300. package/gsd-core/workflows/eval-review.md +14 -5
  301. package/gsd-core/workflows/execute-phase/detail/elaboration.md +2 -2
  302. package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1019 -0
  303. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
  304. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
  305. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +37 -3
  306. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
  307. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
  308. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  309. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
  310. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
  311. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
  312. package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
  313. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
  314. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
  315. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
  316. package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
  317. package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
  318. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
  319. package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
  320. package/gsd-core/workflows/execute-phase.md +96 -178
  321. package/gsd-core/workflows/execute-plan.md +18 -23
  322. package/gsd-core/workflows/explore.md +4 -4
  323. package/gsd-core/workflows/extract-learnings.md +4 -2
  324. package/gsd-core/workflows/fast.md +1 -1
  325. package/gsd-core/workflows/forensics.md +1 -1
  326. package/gsd-core/workflows/graduation.md +1 -1
  327. package/gsd-core/workflows/health.md +3 -2
  328. package/gsd-core/workflows/help/modes/full.compact.md +3 -3
  329. package/gsd-core/workflows/help/modes/full.md +5 -5
  330. package/gsd-core/workflows/help/modes/topic.md +15 -5
  331. package/gsd-core/workflows/import.md +4 -3
  332. package/gsd-core/workflows/inbox.md +2 -2
  333. package/gsd-core/workflows/ingest-docs.md +3 -3
  334. package/gsd-core/workflows/insert-phase.md +4 -3
  335. package/gsd-core/workflows/list-seeds.md +1 -1
  336. package/gsd-core/workflows/list-workspaces.md +1 -1
  337. package/gsd-core/workflows/manager.md +6 -4
  338. package/gsd-core/workflows/map-codebase.md +5 -4
  339. package/gsd-core/workflows/milestone-summary.md +3 -2
  340. package/gsd-core/workflows/mvp-phase.md +14 -14
  341. package/gsd-core/workflows/new-milestone.md +11 -11
  342. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
  343. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
  344. package/gsd-core/workflows/new-project.md +7 -7
  345. package/gsd-core/workflows/new-workspace.md +2 -2
  346. package/gsd-core/workflows/next.md +1 -1
  347. package/gsd-core/workflows/note.md +1 -1
  348. package/gsd-core/workflows/onboard.md +1 -1
  349. package/gsd-core/workflows/pause-work.md +2 -2
  350. package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
  351. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
  352. package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
  353. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  354. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
  355. package/gsd-core/workflows/plan-phase.md +50 -24
  356. package/gsd-core/workflows/plan-review-convergence.md +21 -5
  357. package/gsd-core/workflows/plant-seed.md +62 -20
  358. package/gsd-core/workflows/pr-branch.md +113 -13
  359. package/gsd-core/workflows/profile-user.md +2 -2
  360. package/gsd-core/workflows/progress.md +19 -49
  361. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +27 -0
  362. package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
  363. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
  364. package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
  365. package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
  366. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
  367. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
  368. package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
  369. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
  370. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
  371. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
  372. package/gsd-core/workflows/quick-batch.md +15 -10
  373. package/gsd-core/workflows/quick.md +62 -39
  374. package/gsd-core/workflows/reapply-patches.md +9 -3
  375. package/gsd-core/workflows/remove-phase.md +3 -2
  376. package/gsd-core/workflows/remove-workspace.md +2 -2
  377. package/gsd-core/workflows/resume-project.md +3 -2
  378. package/gsd-core/workflows/review.md +33 -17
  379. package/gsd-core/workflows/scan.md +3 -2
  380. package/gsd-core/workflows/secure-phase.md +13 -13
  381. package/gsd-core/workflows/settings-advanced.md +30 -10
  382. package/gsd-core/workflows/settings-integrations.md +2 -3
  383. package/gsd-core/workflows/settings.md +4 -4
  384. package/gsd-core/workflows/ship.md +14 -13
  385. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  386. package/gsd-core/workflows/sketch.md +1 -1
  387. package/gsd-core/workflows/smart-entry.md +2 -2
  388. package/gsd-core/workflows/spec-phase.md +15 -5
  389. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  390. package/gsd-core/workflows/spike.md +1 -1
  391. package/gsd-core/workflows/stats.md +1 -1
  392. package/gsd-core/workflows/sync-skills.md +5 -5
  393. package/gsd-core/workflows/thread.md +2 -2
  394. package/gsd-core/workflows/transition.md +13 -23
  395. package/gsd-core/workflows/ui-phase.md +48 -11
  396. package/gsd-core/workflows/ui-review.md +21 -6
  397. package/gsd-core/workflows/ultraplan-phase.md +3 -2
  398. package/gsd-core/workflows/undo.md +339 -20
  399. package/gsd-core/workflows/update.md +7 -7
  400. package/gsd-core/workflows/validate-phase.md +12 -13
  401. package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
  402. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
  403. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
  404. package/gsd-core/workflows/verify-work.md +129 -55
  405. package/hooks/dist/gsd-agent-isolation-guard.js +32 -0
  406. package/hooks/dist/gsd-check-update-worker.js +8 -0
  407. package/hooks/dist/gsd-check-update.js +8 -0
  408. package/hooks/dist/gsd-context-monitor.js +31 -8
  409. package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
  410. package/hooks/dist/gsd-secret-read-guard.js +161 -4
  411. package/hooks/dist/gsd-statusline.js +85 -20
  412. package/hooks/dist/gsd-update-banner.js +8 -0
  413. package/hooks/dist/gsd-validate-commit.sh +63 -4
  414. package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
  415. package/hooks/dist/gsd-workflow-guard.js +5 -4
  416. package/hooks/dist/gsd-worktree-path-guard.js +6 -2
  417. package/hooks/dist/lib/cli-exit.js +12 -0
  418. package/hooks/dist/lib/git-probe.js +17 -1
  419. package/hooks/dist/lib/isolation-sentinel.js +2 -2
  420. package/hooks/gsd-agent-isolation-guard.js +32 -0
  421. package/hooks/gsd-check-update-worker.js +8 -0
  422. package/hooks/gsd-check-update.js +8 -0
  423. package/hooks/gsd-context-monitor.js +31 -8
  424. package/hooks/gsd-cursor-subagent-start.js +8 -0
  425. package/hooks/gsd-secret-read-guard.js +161 -4
  426. package/hooks/gsd-statusline.js +85 -20
  427. package/hooks/gsd-update-banner.js +8 -0
  428. package/hooks/gsd-validate-commit.sh +63 -4
  429. package/hooks/gsd-windsurf-pre-write.js +11 -2
  430. package/hooks/gsd-workflow-guard.js +5 -4
  431. package/hooks/gsd-worktree-path-guard.js +6 -2
  432. package/hooks/hooks.json +5 -5
  433. package/hooks/lib/cli-exit.js +12 -0
  434. package/hooks/lib/git-probe.js +17 -1
  435. package/hooks/lib/isolation-sentinel.js +2 -2
  436. package/package.json +22 -4
  437. package/scripts/build-hooks.js +15 -6
  438. package/scripts/changeset/parse.cjs +52 -4
  439. package/scripts/check-contract-drift.cjs +127 -11
  440. package/scripts/ci-timeout-report.cjs +770 -4
  441. package/scripts/command-contract-helpers.cjs +15 -8
  442. package/scripts/docs-guard-registry.cjs +34 -0
  443. package/scripts/gen-features.cjs +13 -8
  444. package/scripts/gen-hooks-cli-exit.cjs +12 -28
  445. package/scripts/gen-loop-host-contract.cjs +79 -1
  446. package/scripts/gen-platform-conformance-tier.cjs +187 -1
  447. package/scripts/gen-plugin-skills.cjs +87 -1
  448. package/scripts/gen-research-agents.cjs +24 -31
  449. package/scripts/gen-scripts-cli-exit.cjs +30 -3
  450. package/scripts/gen-test-timings.cjs +32 -7
  451. package/scripts/lib/cli-exit.cjs +12 -0
  452. package/scripts/lib/macos-conformance-tier.generated.cjs +34 -2
  453. package/scripts/lib/ndjson-reporter.cjs +31 -5
  454. package/scripts/lib/platform-conformance-tier.generated.cjs +45 -5
  455. package/scripts/lib/registration-ledger-preload.cjs +155 -0
  456. package/scripts/lib/vendor-bundle.cjs +59 -0
  457. package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
  458. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  459. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  460. package/scripts/lint-completion-predicate-drift.cjs +18 -19
  461. package/scripts/lint-descriptions.cjs +7 -3
  462. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +38 -1
  463. package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
  464. package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
  465. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
  466. package/scripts/lint-phase-arg-assignment.cjs +257 -0
  467. package/scripts/lint-phase-enumeration-drift.cjs +12 -8
  468. package/scripts/lint-phase-id-drift.cjs +319 -5
  469. package/scripts/lint-planning-document-positive-control.cjs +329 -0
  470. package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
  471. package/scripts/lint-response-language-coverage.cjs +3 -0
  472. package/scripts/lint-retired-runtime-name.cjs +619 -0
  473. package/scripts/lint-skill-deps.cjs +7 -3
  474. package/scripts/lint-state-write-path-drift.cjs +93 -0
  475. package/scripts/lint-test-file-count.allowlist.json +38 -9
  476. package/scripts/lint-test-file-count.cjs +34 -1
  477. package/scripts/lint-vendored-deps.cjs +41 -5
  478. package/scripts/lint-workflow-shellcheck-baseline.json +25 -10
  479. package/scripts/mutation-matrix.cjs +50 -5
  480. package/scripts/prompt-injection-scan.sh +4 -0
  481. package/scripts/release-tarball-smoke.cjs +194 -1
  482. package/scripts/require-issue-link-policy.cjs +6 -2
  483. package/scripts/sync-runtime-launcher.cjs +184 -2
  484. package/scripts/verify-npm-publish.cjs +76 -20
  485. package/skills/gsd-add-tests/SKILL.md +6 -1
  486. package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
  487. package/skills/gsd-audit-fix/SKILL.md +5 -0
  488. package/skills/gsd-audit-milestone/SKILL.md +6 -1
  489. package/skills/gsd-autonomous/SKILL.md +7 -2
  490. package/skills/gsd-capture/SKILL.md +9 -5
  491. package/skills/gsd-code-review/SKILL.md +7 -2
  492. package/skills/gsd-complete-milestone/SKILL.md +4 -0
  493. package/skills/gsd-config/SKILL.md +8 -4
  494. package/skills/gsd-debug/SKILL.md +11 -7
  495. package/skills/gsd-discuss-phase/SKILL.md +7 -3
  496. package/skills/gsd-docs-update/SKILL.md +12 -7
  497. package/skills/gsd-eval-review/SKILL.md +6 -1
  498. package/skills/gsd-execute-phase/SKILL.md +12 -7
  499. package/skills/gsd-extract-learnings/SKILL.md +5 -0
  500. package/skills/gsd-fast/SKILL.md +4 -0
  501. package/skills/gsd-forensics/SKILL.md +5 -1
  502. package/skills/gsd-graphify/SKILL.md +10 -6
  503. package/skills/gsd-health/SKILL.md +5 -0
  504. package/skills/gsd-help/SKILL.md +7 -2
  505. package/skills/gsd-import/SKILL.md +7 -3
  506. package/skills/gsd-inbox/SKILL.md +5 -0
  507. package/skills/gsd-ingest-docs/SKILL.md +5 -1
  508. package/skills/gsd-manager/SKILL.md +6 -1
  509. package/skills/gsd-map-codebase/SKILL.md +7 -3
  510. package/skills/gsd-mempalace-capture/SKILL.md +12 -4
  511. package/skills/gsd-mempalace-recall/SKILL.md +5 -1
  512. package/skills/gsd-milestone-summary/SKILL.md +5 -1
  513. package/skills/gsd-mvp-phase/SKILL.md +8 -3
  514. package/skills/gsd-new-milestone/SKILL.md +6 -1
  515. package/skills/gsd-new-project/SKILL.md +5 -0
  516. package/skills/gsd-next/SKILL.md +6 -1
  517. package/skills/gsd-ns-context/SKILL.md +4 -0
  518. package/skills/gsd-ns-ideate/SKILL.md +4 -0
  519. package/skills/gsd-ns-manage/SKILL.md +4 -0
  520. package/skills/gsd-ns-project/SKILL.md +4 -0
  521. package/skills/gsd-ns-review/SKILL.md +4 -0
  522. package/skills/gsd-ns-workflow/SKILL.md +4 -0
  523. package/skills/gsd-onboard/SKILL.md +6 -1
  524. package/skills/gsd-pause-work/SKILL.md +5 -1
  525. package/skills/gsd-phase/SKILL.md +8 -4
  526. package/skills/gsd-plan-phase/SKILL.md +6 -1
  527. package/skills/gsd-plan-review-convergence/SKILL.md +10 -6
  528. package/skills/gsd-pr-branch/SKILL.md +4 -0
  529. package/skills/gsd-profile-user/SKILL.md +5 -1
  530. package/skills/gsd-progress/SKILL.md +7 -2
  531. package/skills/gsd-quick/SKILL.md +16 -10
  532. package/skills/gsd-quick-batch/SKILL.md +21 -9
  533. package/skills/gsd-review/SKILL.md +7 -4
  534. package/skills/gsd-review-backlog/SKILL.md +3 -2
  535. package/skills/gsd-secure-phase/SKILL.md +6 -1
  536. package/skills/gsd-ship/SKILL.md +5 -0
  537. package/skills/gsd-sketch/SKILL.md +7 -2
  538. package/skills/gsd-spec-phase/SKILL.md +5 -1
  539. package/skills/gsd-spike/SKILL.md +8 -3
  540. package/skills/gsd-surface/SKILL.md +5 -1
  541. package/skills/gsd-thread/SKILL.md +4 -0
  542. package/skills/gsd-ui-phase/SKILL.md +6 -1
  543. package/skills/gsd-ui-review/SKILL.md +6 -1
  544. package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
  545. package/skills/gsd-undo/SKILL.md +5 -1
  546. package/skills/gsd-update/SKILL.md +6 -2
  547. package/skills/gsd-validate-phase/SKILL.md +6 -1
  548. package/skills/gsd-verify-work/SKILL.md +6 -1
  549. package/skills/gsd-workspace/SKILL.md +7 -3
  550. package/skills/gsd-workstreams/SKILL.md +6 -6
  551. package/vscode/package.json +1 -1
@@ -37,6 +37,22 @@
37
37
  * over markdown, not `.cts` source, so its sanction is an HTML comment on the
38
38
  * nearest preceding non-blank line: `<!-- phase-id-owner: <reason> -->`.
39
39
  *
40
+ * - phase-heading-scan literal drift (#4906 Phase 5 / #4984): `findPhaseHeadingScanLiteralDrift`
41
+ * detects a hand-rolled `#{2,4}\s*Phase\s+` heading-SCAN literal, which bypasses
42
+ * `buildPhaseHeadingScanRegex` / `phaseHeadingPrefixSrcFor` (both in
43
+ * `src/phase-id.cts`) and so silently fails to recognize bracket-convention
44
+ * headings. Sanctioned the same way as the token/bracket/name-validity rules
45
+ * (`// phase-id-owner:` on the nearest preceding non-blank line), with a
46
+ * line-level escape for a line that already names either owner function.
47
+ * Wired into `scanRepo` (ADR-4910 §8): every pre-existing site this phase
48
+ * could not migrate (src/phase.cts x11, src/roadmap-parser.cts x3,
49
+ * src/planning-snapshot.cts x1) is grandfathered with a dedicated
50
+ * `// phase-id-owner:` sanction comment rather than a separate allowlist —
51
+ * the guard is ACTIVE from this phase forward: a fresh unsanctioned copy
52
+ * fails CI immediately, and each grandfathered comment is deleted as its
53
+ * site migrates in a later phase (ADR-4910 §8's census/grandfather/delete
54
+ * sequence, never renewed).
55
+ *
40
56
  * - branch-slug fallback drift: a `.replace('{slug}', ... || 'phase')` call
41
57
  * silently substitutes the literal string `'phase'` when a phase's slug
42
58
  * can't be derived, producing a non-identifying branch name like
@@ -234,6 +250,67 @@ function findBranchSlugFallbackDrift(text) {
234
250
  return out;
235
251
  }
236
252
 
253
+ // #4906 Phase 5 (#4984): a hand-rolled heading-SCAN literal `#{2,4}\s*Phase\s+`
254
+ // (in either regex-literal `\s` or template `\\s` escaping, mirroring
255
+ // TOKEN_DRIFT_RE's tolerance) bypasses `buildPhaseHeadingScanRegex` /
256
+ // `phaseHeadingPrefixSrcFor` (both in `src/phase-id.cts`) entirely, so it
257
+ // silently fails to recognize bracket-convention headings (`[GSD.03] Phase
258
+ // 03:`) — the exact defect this phase fixed at five call sites in init.cts
259
+ // and milestone.cts. A line naming either owner function counts as "built
260
+ // from the owner" and is not flagged, mirroring the token rule's
261
+ // `line.includes(CANON_REF)` escape.
262
+ const PHASE_HEADING_SCAN_LITERAL_DRIFT_RE = /#\{2,4\}\\{1,2}s\*Phase\\{1,2}s\+/;
263
+ const PHASE_HEADING_SCAN_LITERAL_CANON_REFS = ['buildPhaseHeadingScanRegex', 'phaseHeadingPrefixSrcFor'];
264
+
265
+ /**
266
+ * Pure: find every unsanctioned hand-rolled `#{2,4}\s*Phase\s+` heading-scan
267
+ * literal in `text`. Sanctioned when the line already names either owner
268
+ * function (`buildPhaseHeadingScanRegex(` / `phaseHeadingPrefixSrcFor(`), or
269
+ * by a `// phase-id-owner:` comment on the nearest preceding non-blank line
270
+ * (same mechanism as every other rule in this file). Returns [{ line, found }].
271
+ */
272
+ function findPhaseHeadingScanLiteralDrift(text) {
273
+ const out = [];
274
+ const lines = text.split('\n');
275
+ for (let i = 0; i < lines.length; i++) {
276
+ const line = lines[i];
277
+ const m = PHASE_HEADING_SCAN_LITERAL_DRIFT_RE.exec(line);
278
+ if (!m) continue;
279
+ if (PHASE_HEADING_SCAN_LITERAL_CANON_REFS.some((ref) => line.includes(ref))) continue;
280
+ if (isSanctionedByPrecedingComment(lines, i, OWNER_RE)) continue;
281
+ out.push({ line: i + 1, found: m[0] });
282
+ }
283
+ return out;
284
+ }
285
+
286
+ /**
287
+ * Scan the authored source tree (`src/**\/*.cts`, the same `SCAN_DIRS` root
288
+ * and `phase-id.cts` owner exemption that `scanRepo` applies to this
289
+ * detector — the heading-scan literal is a `src/**\/*.cts` defect, not a
290
+ * markdown one, unlike its sibling wrappers below) for unsanctioned
291
+ * hand-rolled heading-scan literals. Returns [{ file, line, found }] with
292
+ * repo-relative paths.
293
+ */
294
+ function scanMarkdownPhaseHeadingScanLiteral(root) {
295
+ const violations = [];
296
+ for (const dir of SCAN_DIRS) {
297
+ for (const file of walk(path.join(root, dir), [])) {
298
+ const rel = path.relative(root, file);
299
+ if (EXEMPT.has(rel)) continue;
300
+ let text;
301
+ try {
302
+ text = fs.readFileSync(file, 'utf8');
303
+ } catch {
304
+ continue;
305
+ }
306
+ for (const d of findPhaseHeadingScanLiteralDrift(text)) {
307
+ violations.push({ file: rel, kind: 'phase-heading-scan-literal', ...d });
308
+ }
309
+ }
310
+ }
311
+ return violations;
312
+ }
313
+
237
314
  // #4634: ban base-10-forced shell arithmetic (`$((10#...))`) on a variable
238
315
  // that still carries a possibly-decimal/multi-segment phase id — this
239
316
  // construct is exactly the pattern that breaks on a value like `08.5`. The
@@ -246,11 +323,14 @@ function findBranchSlugFallbackDrift(text) {
246
323
  // 1. Prose mentioning the literal pattern in a full-line `#`-comment
247
324
  // (filtered by the caller, not this regex — see below).
248
325
  // 2. `$((10#$PHASE_INT))` / `$((10#$SPOT_PHASE_INT))` — arithmetic on the
249
- // NOW-safe variable the #4619 fix produces via `PHASE_INT=${PHASE_NUMBER%%.*}`;
250
- // a `%%.*`-stripped value can never contain a dot, so base-10 arithmetic
251
- // on it can never hit the #4619 syntax-error class. Any name ending in
252
- // `_INT` (case-insensitive) is that established "already reduced to a
253
- // safe integer" convention.
326
+ // NOW-safe variable the #4619 fix produces via a leading-digit-run split
327
+ // (`PHASE_INT=${PHASE_NUMBER%%[!0-9]*}` since #4748; `%%.*` before it);
328
+ // a digit-run value can never contain a dot OR a letter, so base-10
329
+ // arithmetic on it can never hit the #4619 / #4748 error classes. Any
330
+ // name ending in `_INT` (case-insensitive) is that established "already
331
+ // reduced to a safe integer" convention. That convention is a NAME, not
332
+ // a proof — `findDotOnlyIntegerSplitDrift` below polices that the split
333
+ // producing it actually stops at the first non-digit.
254
334
  // 3. `$((10#{plan_padded}))` / `$((10#${PLAN_ID}))` — plan ids are plain
255
335
  // integers and were never in scope; this rule only polices variables
256
336
  // that carry a *phase* id.
@@ -389,6 +469,204 @@ function scanMarkdownSingleSegmentPhaseRegex(root) {
389
469
  return violations;
390
470
  }
391
471
 
472
+ // #4660 (epic #4634): the six shell/markdown mirrors #4568 widened on the
473
+ // segment-count axis stayed digit-only on the LETTER axis — the canonical
474
+ // grammar (`src/phase-id.cts`) is `\d+[A-Z]?(?:\.\d+)*`, with an optional
475
+ // single uppercase letter after the leading digits (`12A`, `3A`, `23A.1.2`,
476
+ // documented in docs/CONFIGURATION.md and relied on by `renameIntegerPhases`).
477
+ // A digit-only mirror `[0-9]+(\.[0-9]+)*` hard-rejects (validating sites) or
478
+ // silently truncates (extracting sites) a letter-suffixed id. This rule is the
479
+ // ratchet for that axis, the twin of the single-segment rule above: it flags
480
+ // the unbounded-segment shape whose digit run is NOT followed by the letter
481
+ // class. `[A-Z]` is the canonical spelling; the case-flexible `[A-Za-z]`
482
+ // directory-scanning variant is a deliberately separate axis and is tolerated
483
+ // here so this rule cannot force it to narrow.
484
+ const LETTERLESS_PHASE_MIRROR_DRIFT_RE =
485
+ /(?:\\{1,2}d|\[0-9\])\+(?!\[A-Z(?:a-z)?\]\?)\(\\{1,2}\.(?:\\{1,2}d|\[0-9\])\+\)\*/;
486
+
487
+ /**
488
+ * Pure: find every unsanctioned digit-only (letter-less) unbounded-segment
489
+ * phase regex in `text`, restricted to lines that plausibly carry a
490
+ * phase-number variable — the same `PHASE_CARRYING_LINE_RE` filter and the
491
+ * same `<!-- phase-id-owner: ... -->` sanction as the single-segment rule.
492
+ * Returns [{ line, found }].
493
+ */
494
+ function findLetterlessPhaseMirrorDrift(text) {
495
+ const out = [];
496
+ const lines = text.split('\n');
497
+ for (let i = 0; i < lines.length; i++) {
498
+ const line = lines[i];
499
+ const m = LETTERLESS_PHASE_MIRROR_DRIFT_RE.exec(line);
500
+ if (!m) continue;
501
+ if (!PHASE_CARRYING_LINE_RE.test(line)) continue;
502
+ if (isSanctionedByPrecedingComment(lines, i, MD_OWNER_RE)) continue;
503
+ out.push({ line: i + 1, found: m[0] });
504
+ }
505
+ return out;
506
+ }
507
+
508
+ /**
509
+ * Scan the same three markdown roots as the single-segment rule for
510
+ * unsanctioned letter-less phase-regex mirrors. Returns [{ file, line, found }]
511
+ * with repo-relative paths.
512
+ */
513
+ function scanMarkdownLetterlessPhaseMirror(root) {
514
+ const violations = [];
515
+ for (const dir of SINGLE_SEGMENT_SCAN_DIRS) {
516
+ for (const file of walkMd(path.join(root, dir), [])) {
517
+ const rel = path.relative(root, file);
518
+ let text;
519
+ try {
520
+ text = fs.readFileSync(file, 'utf8');
521
+ } catch {
522
+ continue;
523
+ }
524
+ for (const d of findLetterlessPhaseMirrorDrift(text)) {
525
+ violations.push({ file: rel, kind: 'letterless-phase-mirror', ...d });
526
+ }
527
+ }
528
+ }
529
+ return violations;
530
+ }
531
+
532
+ // #4748 (epic #4634): three shell shapes OUTSIDE the grammar-mirror family the
533
+ // rules above police — consumers of a phase id rather than regexes for one —
534
+ // each of which the letter axis broke while every rule above reported clean:
535
+ //
536
+ // a. `PHASE_INT=${PHASE_NUMBER%%.*}` — the post-#4619 dot-only split. The
537
+ // `_INT` name it produces satisfies the shell-arithmetic rule's escape,
538
+ // but on `03A` the "integer" is `03A` and `$((10#03A))` aborts. The safe
539
+ // split stops at the first NON-digit: `${PHASE_NUMBER%%[!0-9]*}`.
540
+ // b. `[0-9]+\.?[0-9]*` (and `\d+\.?\d*`) — a digit-then-optional-dot
541
+ // extraction that is neither the bounded `(\.[0-9]+)?` shape the
542
+ // single-segment rule bans nor the unbounded `(\.[0-9]+)*` shape the
543
+ // letterless rule inspects, so both were blind to it. It captures `12`
544
+ // from `12A` and `23.1` from `23.1.2`, silently.
545
+ // c. `printf "%02d" "$PHASE_NUMBER"` — re-padding the whole id in shell.
546
+ // Rejects a letter id (prints `03`, exit 1) and misreads an already
547
+ // padded `08` as octal (prints `00`). Padding belongs to the canonical
548
+ // normalizer (`padded_phase` from init, or `normalizePhaseName`); the one
549
+ // legitimate shell pad is of an `_INT` value via `$((10#…))`.
550
+ //
551
+ // Same sanction as the other markdown rules: `<!-- phase-id-owner: … -->` on
552
+ // the nearest preceding non-blank line. Same documented limit: a per-line
553
+ // textual scan for the common accidental shape, not an obfuscated one.
554
+
555
+ // a. `<name>_INT=${<phase-carrying>%%.*}` — the `_INT` destination is the
556
+ // discriminator, deliberately: it is the name the shell-arithmetic rule
557
+ // trusts as "already a safe integer", so a dot-only split INTO it is the
558
+ // exact promise this rule exists to check. A dot-only split into any other
559
+ // name is a different, legitimate operation — `PARENT_PHASE="${PHASE_NUMBER%%.*}"`
560
+ // (gap-closure-artifacts.md) wants everything before the first dot, letter
561
+ // included, and is correct. Widening to any destination was tried and flagged
562
+ // that site. The optional quote after `=` is the one spelling that site uses.
563
+ const DOT_ONLY_INT_SPLIT_DRIFT_RE = /[A-Za-z0-9_]*_INT="?\$\{([A-Za-z0-9_]+)%%\\?\.\*\}/i;
564
+
565
+ /**
566
+ * Pure: find every unsanctioned dot-only integer split of a phase-carrying
567
+ * variable in `text`. Skips full-line `#` comments (prose). Returns [{ line, found }].
568
+ */
569
+ function findDotOnlyIntegerSplitDrift(text) {
570
+ const out = [];
571
+ const lines = text.split('\n');
572
+ for (let i = 0; i < lines.length; i++) {
573
+ const line = lines[i];
574
+ if (/^\s*#/.test(line)) continue;
575
+ const m = DOT_ONLY_INT_SPLIT_DRIFT_RE.exec(line);
576
+ if (!m) continue;
577
+ if (!/phase/i.test(m[1])) continue;
578
+ if (isSanctionedByPrecedingComment(lines, i, MD_OWNER_RE)) continue;
579
+ out.push({ line: i + 1, found: m[0] });
580
+ }
581
+ return out;
582
+ }
583
+
584
+ // b. The digit-then-optional-dot shape, in both `[0-9]` and `\d` spellings.
585
+ // Anchored on the trailing `*` of the second digit class so a bare `[0-9]+`
586
+ // probe or a `[0-9]+\.[0-9]+` (mandatory-dot) shape is not matched.
587
+ const LOOSE_DOTTED_PHASE_DRIFT_RE = /(?:\\{1,2}d|\[0-9\])\+\\{1,2}\.\?(?:\\{1,2}d|\[0-9\])\*/;
588
+
589
+ /**
590
+ * Pure: find every unsanctioned `[0-9]+\.?[0-9]*`-shaped phase extraction in
591
+ * `text`, restricted to phase-carrying lines like its two sibling regex rules.
592
+ * Returns [{ line, found }].
593
+ */
594
+ function findLooseDottedPhaseRegexDrift(text) {
595
+ const out = [];
596
+ const lines = text.split('\n');
597
+ for (let i = 0; i < lines.length; i++) {
598
+ const line = lines[i];
599
+ const m = LOOSE_DOTTED_PHASE_DRIFT_RE.exec(line);
600
+ if (!m) continue;
601
+ if (!PHASE_CARRYING_LINE_RE.test(line)) continue;
602
+ if (isSanctionedByPrecedingComment(lines, i, MD_OWNER_RE)) continue;
603
+ out.push({ line: i + 1, found: m[0] });
604
+ }
605
+ return out;
606
+ }
607
+
608
+ // c. `printf "%Nd" …` / `printf '%0Nd' …` — any integer conversion, either
609
+ // quote, with or without the zero flag — whose argument list names a
610
+ // phase-carrying variable that is NOT an `_INT` (the `$((10#$PHASE_INT))`
611
+ // pad is the sanctioned shape). `%d` cannot parse a letter id under any
612
+ // width, so the flag is not the discriminator. Captures the first such name
613
+ // so the report says what was padded.
614
+ const SHELL_PHASE_PRINTF_PAD_RE = /printf\s+(?:"%0?\d*d[^"]*"|'%0?\d*d[^']*')\s+(.*)$/;
615
+ const SHELL_VAR_NAME_RE = /\$\{?([A-Za-z_][A-Za-z0-9_]*)/g;
616
+
617
+ /**
618
+ * Pure: find every unsanctioned `printf "%02d"` re-pad of a phase-carrying,
619
+ * non-`_INT` shell variable in `text`. Skips full-line `#` comments.
620
+ * Returns [{ line, found }].
621
+ */
622
+ function findShellPhasePrintfPadDrift(text) {
623
+ const out = [];
624
+ const lines = text.split('\n');
625
+ for (let i = 0; i < lines.length; i++) {
626
+ const line = lines[i];
627
+ if (/^\s*#/.test(line)) continue;
628
+ const m = SHELL_PHASE_PRINTF_PAD_RE.exec(line);
629
+ if (!m) continue;
630
+ const offender = [...m[1].matchAll(SHELL_VAR_NAME_RE)]
631
+ .map((v) => v[1])
632
+ .find((name) => /phase/i.test(name) && !/_int$/i.test(name));
633
+ if (!offender) continue;
634
+ if (isSanctionedByPrecedingComment(lines, i, MD_OWNER_RE)) continue;
635
+ out.push({ line: i + 1, found: `printf "%0…d" …$${offender}` });
636
+ }
637
+ return out;
638
+ }
639
+
640
+ /**
641
+ * Scan the shell roots (`gsd-core/workflows/**\/*.md`, `gsd-core/references/**\/*.md`)
642
+ * for the two shell-idiom rules (a, c) and the three regex roots (those plus
643
+ * `agents/**\/*.md`) for the extraction-shape rule (b). Returns
644
+ * [{ file, kind, line, found }] with repo-relative paths.
645
+ */
646
+ function scanMarkdownLetterAxisConsumers(root) {
647
+ const violations = [];
648
+ const collect = (dirs, finder, kind) => {
649
+ for (const dir of dirs) {
650
+ for (const file of walkMd(path.join(root, dir), [])) {
651
+ const rel = path.relative(root, file);
652
+ let text;
653
+ try {
654
+ text = fs.readFileSync(file, 'utf8');
655
+ } catch {
656
+ continue;
657
+ }
658
+ for (const d of finder(text)) {
659
+ violations.push({ file: rel, kind, ...d });
660
+ }
661
+ }
662
+ }
663
+ };
664
+ collect(MD_SCAN_DIRS, findDotOnlyIntegerSplitDrift, 'dot-only-int-split');
665
+ collect(SINGLE_SEGMENT_SCAN_DIRS, findLooseDottedPhaseRegexDrift, 'loose-dotted-phase-regex');
666
+ collect(MD_SCAN_DIRS, findShellPhasePrintfPadDrift, 'shell-phase-printf-pad');
667
+ return violations;
668
+ }
669
+
392
670
  // Authored TypeScript source only (the generated bin/lib/*.cjs mirror it).
393
671
  const SCAN_DIRS = ['src'];
394
672
  const SCAN_EXT = new Set(['.cts', '.ts', '.mts']);
@@ -523,6 +801,16 @@ function scanRepo(root) {
523
801
  for (const d of findBranchSlugFallbackDrift(text)) {
524
802
  violations.push({ file: rel, kind: 'branch-slug-fallback', ...d });
525
803
  }
804
+ // #4906 Phase 5 (#4984): heading-scan literal drift, owner file exempt
805
+ // via the shared `EXEMPT` check above. Pre-existing sites this phase
806
+ // could not reach (src/phase.cts, src/roadmap-parser.cts,
807
+ // src/planning-snapshot.cts) are grandfathered with a `// phase-id-owner:`
808
+ // sanction each, per ADR-4910 §8's census/grandfather/delete Phase 6 plan
809
+ // — the allowlist is those sanction comments, not a separate list here,
810
+ // and it is deleted entry-by-entry as each site migrates.
811
+ for (const d of findPhaseHeadingScanLiteralDrift(text)) {
812
+ violations.push({ file: rel, kind: 'phase-heading-scan-literal', ...d });
813
+ }
526
814
  }
527
815
  }
528
816
  return violations;
@@ -541,6 +829,8 @@ function scanAll(root) {
541
829
  ...scanRepo(root),
542
830
  ...scanMarkdownShellArith(root),
543
831
  ...scanMarkdownSingleSegmentPhaseRegex(root),
832
+ ...scanMarkdownLetterlessPhaseMirror(root),
833
+ ...scanMarkdownLetterAxisConsumers(root),
544
834
  ];
545
835
  }
546
836
 
@@ -567,8 +857,19 @@ function main() {
567
857
  process.stderr.write('near-variant) is banned outright in gsd-core/workflows/**/*.md,\n');
568
858
  process.stderr.write('gsd-core/references/**/*.md, and agents/**/*.md — widen it to `*` (unbounded\n');
569
859
  process.stderr.write('segments) or sanction with `<!-- phase-id-owner: <reason> -->`.\n');
860
+ process.stderr.write('A digit-only unbounded-segment phase regex `[0-9]+(\\.[0-9]+)*` on the same roots\n');
861
+ process.stderr.write('is missing the canonical letter axis (#4660) — widen to `[0-9]+[A-Z]?(\\.[0-9]+)*`\n');
862
+ process.stderr.write('or sanction with `<!-- phase-id-owner: <reason> -->`.\n');
863
+ process.stderr.write('Three letter-hostile consumers of a phase id are banned on the same roots (#4748):\n');
864
+ process.stderr.write('a dot-only integer split `X_INT=${PHASE%%.*}` (split at the first non-digit,\n');
865
+ process.stderr.write('`${PHASE%%[!0-9]*}`); a `[0-9]+\\.?[0-9]*` extraction (use `[0-9]+[A-Z]?(\\.[0-9]+)*`);\n');
866
+ process.stderr.write('and a `printf "%02d"` re-pad of a phase variable (bind init\'s `padded_phase`, or pad\n');
867
+ process.stderr.write('only an `_INT` via `$((10#…))`) — or sanction with `<!-- phase-id-owner: <reason> -->`.\n');
570
868
  process.stderr.write('A `.replace(\'{slug}\', ... || \'phase\')` fallback is banned outright (#4126) —\n');
571
869
  process.stderr.write('use `renderPhaseBranchName(` or sanction with\n');
870
+ process.stderr.write('`// phase-id-owner: <reason>` on the line directly above.\n');
871
+ process.stderr.write('A hand-rolled `#{2,4}\\s*Phase\\s+` heading-scan literal is banned (#4906 Phase 5) —\n');
872
+ process.stderr.write('use `buildPhaseHeadingScanRegex(` / `phaseHeadingPrefixSrcFor(` or sanction with\n');
572
873
  process.stderr.write('`// phase-id-owner: <reason>` on the line directly above:\n');
573
874
  for (const d of violations) {
574
875
  process.stderr.write(` [${d.kind}] ${d.file}:${d.line} ${d.found}\n`);
@@ -583,10 +884,18 @@ module.exports = {
583
884
  findBracketGrammarDrift,
584
885
  findNameValidityDrift,
585
886
  findBranchSlugFallbackDrift,
887
+ findPhaseHeadingScanLiteralDrift,
888
+ scanMarkdownPhaseHeadingScanLiteral,
586
889
  findShellPhaseArithDrift,
587
890
  findSingleSegmentPhaseRegexDrift,
891
+ findLetterlessPhaseMirrorDrift,
892
+ findDotOnlyIntegerSplitDrift,
893
+ findLooseDottedPhaseRegexDrift,
894
+ findShellPhasePrintfPadDrift,
588
895
  scanMarkdownShellArith,
589
896
  scanMarkdownSingleSegmentPhaseRegex,
897
+ scanMarkdownLetterlessPhaseMirror,
898
+ scanMarkdownLetterAxisConsumers,
590
899
  scanRepo,
591
900
  scanAll,
592
901
  countSelectorBaselines,
@@ -595,6 +904,11 @@ module.exports = {
595
904
  BRACKET_CODE_DRIFT_RE,
596
905
  NAME_VALIDITY_DRIFT_RE,
597
906
  BRANCH_SLUG_FALLBACK_DRIFT_RE,
907
+ PHASE_HEADING_SCAN_LITERAL_DRIFT_RE,
598
908
  SHELL_PHASE_ARITH_DRIFT_RE,
599
909
  SINGLE_SEGMENT_PHASE_DRIFT_RE,
910
+ LETTERLESS_PHASE_MIRROR_DRIFT_RE,
911
+ DOT_ONLY_INT_SPLIT_DRIFT_RE,
912
+ LOOSE_DOTTED_PHASE_DRIFT_RE,
913
+ SHELL_PHASE_PRINTF_PAD_RE,
600
914
  };