@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
@@ -11,6 +11,14 @@
11
11
  "path": "src/vendor/js-yaml.d.cts",
12
12
  "reason": "Vendored third-party type declaration (ADR-3473 §8.1, #3881): a .d.cts carries no executable code, so no ESLint rule is meaningful; the vendored js-yaml .cjs it describes is globally ignored as verbatim upstream output (gsd-core/bin/lib/vendor/**). Freshness is enforced by scripts/lint-vendored-deps.cjs, not by lint rules — same precedent as src/vendor/re2js.d.cts above."
13
13
  },
14
+ {
15
+ "path": "src/vendor/saxes.d.cts",
16
+ "reason": "Upstream type forwarding for the vendored saxes bundle (#4692): declaration-only export with no executable code. scripts/lint-vendored-deps.cjs enforces the exact forwarding declaration; TypeScript checks consumers against upstream types."
17
+ },
18
+ {
19
+ "path": "src/vendor/tap-parser.d.cts",
20
+ "reason": "Upstream type forwarding for the vendored tap-parser bundle (#4692): declaration-only export with no executable code. scripts/lint-vendored-deps.cjs enforces the exact forwarding declaration; TypeScript checks consumers against upstream types."
21
+ },
14
22
  {
15
23
  "path": "tests/fixtures/brand-typing/bad-calibrated-as-sample-basis.cts",
16
24
  "reason": "Deliberate MUST-NOT-COMPILE type-error fixture (#3059): type-aware linting would fail by design; it exists to prove the compiler rejects it."
@@ -34,5 +42,17 @@
34
42
  {
35
43
  "path": "tests/fixtures/brand-typing/ok-correct-composition.cts",
36
44
  "reason": "Positive-control counterpart to the bad-* must-not-compile fixtures (#3059); kept in the same exemption so the pair stays together."
45
+ },
46
+ {
47
+ "path": "tests/fixtures/gate-evidence-typing/bad-pass-from-unreadable.cts",
48
+ "reason": "Deliberate MUST-NOT-COMPILE type-error fixture (#5170): the unreadable-evidence branding makes a passing outcome from unreadable evidence a compile error, and tests/gate-evidence.test.cjs asserts tsc rejects it; type-aware linting would fail by design."
49
+ },
50
+ {
51
+ "path": "tests/fixtures/gate-evidence-typing/bad-unbranded-unreadable.cts",
52
+ "reason": "Deliberate MUST-NOT-COMPILE type-error fixture (#5170): the unreadable-evidence branding makes a passing outcome from unreadable evidence a compile error, and tests/gate-evidence.test.cjs asserts tsc rejects it; type-aware linting would fail by design."
53
+ },
54
+ {
55
+ "path": "tests/fixtures/gate-evidence-typing/ok-unreadable-arm.cts",
56
+ "reason": "Positive-control counterpart to the gate-evidence-typing bad-* must-not-compile fixtures (#5170): tsc compiles it clean; kept in the same exemption so the pair stays together."
37
57
  }
38
58
  ]
@@ -0,0 +1,313 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Anti-divergence drift guard for the FRONTMATTER FENCE seam (found while
6
+ * implementing #5105; ADR-5057 one-owner rule).
7
+ *
8
+ * `src/frontmatter-fence.cts`'s `locateFrontmatterFence` is the SINGLE owner of
9
+ * "where does a document's frontmatter block start and stop" — the BOM, the
10
+ * byte-0 opening fence, the whole-line closing fence, an adjacent empty block,
11
+ * the lenient `----` closer. Before it existed that answer was re-derived in
12
+ * some thirty places across `src/` (regexes like `/^---\r?\n([\s\S]*?)\r?\n---/`,
13
+ * `indexOf('\n---', 4)`, `lines[0].trim() === '---'`), and the copies disagreed
14
+ * on a BOM, CRLF, an adjacent empty block, `----`, `--- x`, a `---` inside a
15
+ * value and leading whitespace. This guard keeps a new copy from appearing.
16
+ *
17
+ * Mechanism: the shared `scripts/lib/drift-scan.cjs` tree walk and regex-literal
18
+ * tokenizer (ADR-3180 Decision 4), scanning the WHOLE `src/` and `hooks/` trees
19
+ * (the hooks load the built `bin/lib` behind `ensureRuntimeBuild`), the dev-time
20
+ * `scripts/` and `eslint-rules/` trees (every one of them that runs after
21
+ * `build:lib` requires the owner from `gsd-core/bin/lib/frontmatter-fence.cjs`),
22
+ * the two hand-written entry points that load `bin/lib` (`bin/install.js`,
23
+ * `gsd-core/bin/gsd-tools.cjs`), and the two native plugin adapters
24
+ * (`.opencode/plugins/gsd-core.js`, `.kilo/plugins/gsd-core.js`), with
25
+ * FUNCTION-SCOPED exemptions carrying a written reason — never a bare file
26
+ * allowlist — exactly as `lint-milestone-window-drift.cjs` does.
27
+ *
28
+ * KEPT COPIES (found while implementing #5105). A file that must run where the
29
+ * built owner may not exist keeps a self-contained copy of `locateFrontmatterFence`,
30
+ * and only that one function is allowlisted: `scripts/changeset/parse.cjs` (the
31
+ * `changeset-lint` CI job runs it with no `npm ci` and no build) and the two plugin
32
+ * adapters (a package/git-spec tree may carry no built `bin/lib`). Each copy is
33
+ * pinned to the owner by tests/frontmatter-fence.test.cjs ("kept frontmatter fence
34
+ * copies agree with the owner") over a fixture corpus and a property test.
35
+ *
36
+ * DETECTORS. Three files carry a regex that recognizes a fence idiom in OTHER
37
+ * text — this guard itself, `lint-frontmatter-scalar-broad-grep.cjs` (workflow
38
+ * shell snippets) and the `no-crlf-fragile-split` ESLint rule (regex literals in
39
+ * source). None of them locates a frontmatter block; each is exempt only for its
40
+ * exact fragment (`DETECTOR_EXEMPTIONS`), so any other fence code in the same
41
+ * file is still flagged.
42
+ *
43
+ * A line (comment text stripped) is a fence re-derivation when it carries:
44
+ * (a) a regex literal whose text contains `---` (`/^---/`, `/\n---/`,
45
+ * `/(\r?\n)---$/`), or
46
+ * (b) `new RegExp(` together with a string/template literal containing `---`, or
47
+ * (c) a fence-shaped string literal — `'---'`, `'\n---'`, `'---\n'`,
48
+ * `'---\r\n'`, `'\r\n---'` — that is the direct argument of
49
+ * `.startsWith(`/`.endsWith(`/`.indexOf(`/`.lastIndexOf(`/`.split(`, or an
50
+ * operand of `===`/`!==`/`==`/`!=`, or (only when it carries a line
51
+ * ending) the argument of `.includes(`.
52
+ * A template literal that BUILDS a block (`` `---\n${yaml}\n---` ``) or an array
53
+ * of fence lines to join is a writer emitting a fence, not a reader locating
54
+ * one, and is not flagged.
55
+ *
56
+ * KNOWN, ACCEPTED limits of a per-line textual scan (the sibling guards'
57
+ * tradeoff): a derivation split across lines, or routed through a variable
58
+ * holding the `---` literal, is left to code review and to the consumer-parity
59
+ * tests in `tests/frontmatter-fence.test.cjs`.
60
+ */
61
+
62
+ const fs = require('node:fs');
63
+ const path = require('node:path');
64
+ const driftScan = require('./lib/drift-scan.cjs');
65
+ const { readRegexLiteralAt, MAX_REGEX_LITERAL_LEN, sanitizeForReport, scanTree } = driftScan;
66
+
67
+ // Authored TypeScript source (the generated bin/lib/*.cjs mirror it) and the runtime hooks
68
+ // (`hooks/dist`, their build output, is skipped by the shared walker), plus the two hand-written
69
+ // entry points that load bin/lib and so can — and must — read the owner too.
70
+ const SCAN_TREES = [
71
+ { dirs: ['src'], ext: new Set(['.cts', '.ts', '.mts']) },
72
+ { dirs: ['hooks'], ext: new Set(['.js', '.cjs']) },
73
+ { dirs: ['scripts', 'eslint-rules'], ext: new Set(['.js', '.cjs', '.mjs']) },
74
+ ];
75
+ const SCAN_FILES = [
76
+ path.join('bin', 'install.js'),
77
+ path.join('gsd-core', 'bin', 'gsd-tools.cjs'),
78
+ path.join('.opencode', 'plugins', 'gsd-core.js'),
79
+ path.join('.kilo', 'plugins', 'gsd-core.js'),
80
+ ];
81
+
82
+ const OWNER_FILE = path.join('src', 'frontmatter-fence.cts');
83
+
84
+ // Code outside any top-level function (a module-scope constant) is keyed as this.
85
+ const TOP_LEVEL = '<top-level>';
86
+
87
+ // FUNCTION-SCOPED exemptions, each with its reason:
88
+ // - frontmatter-fence.cts `locateFrontmatterFence`: this IS the owner. Its
89
+ // module-scope fence constants (`CLOSING_FENCE_LINE`, `LENIENT_CLOSING_FENCE_LINE`)
90
+ // sit OUTSIDE this function, at TOP_LEVEL, and are exempted by exact fragment
91
+ // in DETECTOR_EXEMPTIONS below instead — a blanket TOP_LEVEL pass here would
92
+ // let any new top-level helper in this file go unscanned (#5105 fix).
93
+ // - phase.cts `phaseEntryInsertOffset`: its `lastIndexOf('\n---')` finds the
94
+ // ROADMAP's trailing section SEPARATOR (a thematic break closing the phase
95
+ // list) so a new phase entry is appended before it — it never asks where a
96
+ // frontmatter block is.
97
+ // - shell-command-projection.cts `_normalizeMd`: `prevTrimmed !== '---'` is
98
+ // the Markdown normalizer's "no blank line after a thematic break" rule,
99
+ // applied line by line to BODY text; that normalizer's frontmatter skip
100
+ // (`leadingFrontmatterLineCount`) reads the owner.
101
+ // - scripts/changeset/parse.cjs `locateFrontmatterFence`: a kept copy of the
102
+ // owner (#5105) — the `changeset-lint` job in changeset-required.yml runs it
103
+ // with no `npm ci` and no `build:lib`. Pinned to the owner by the parity test
104
+ // tests/frontmatter-fence.test.cjs "kept frontmatter fence copies agree with the owner".
105
+ // - .opencode/plugins/gsd-core.js and .kilo/plugins/gsd-core.js
106
+ // `locateFrontmatterFence`: kept copies of the owner (#5105) — the plugin loads
107
+ // from a package/git-spec tree that may carry no built bin/lib. Pinned to the
108
+ // owner by the same parity test.
109
+ const FUNCTION_SCOPED_EXEMPTIONS = new Map([
110
+ [OWNER_FILE, new Set(['locateFrontmatterFence'])],
111
+ [path.join('src', 'phase.cts'), new Set(['phaseEntryInsertOffset'])],
112
+ [path.join('src', 'shell-command-projection.cts'), new Set(['_normalizeMd'])],
113
+ [path.join('scripts', 'changeset', 'parse.cjs'), new Set(['locateFrontmatterFence'])],
114
+ [path.join('.opencode', 'plugins', 'gsd-core.js'), new Set(['locateFrontmatterFence'])],
115
+ [path.join('.kilo', 'plugins', 'gsd-core.js'), new Set(['locateFrontmatterFence'])],
116
+ ]);
117
+
118
+ // FRAGMENT-SCOPED exemptions for DETECTORS (#5105), each pinned to the exact
119
+ // reported fragment (the literal's source text) — a regex that recognizes a fence
120
+ // idiom in other text, never one that locates a frontmatter block:
121
+ // - this guard's own fence-literal matcher (`FENCE_LITERAL_CONTENT_RE`);
122
+ // - lint-frontmatter-scalar-broad-grep.cjs `FRONTMATTER_SCOPE_RE`, which finds a
123
+ // `^---`-scoped extraction in a workflow's shell snippet;
124
+ // - the no-crlf-fragile-split ESLint rule's `^---` probe, which classifies a
125
+ // regex literal in linted source as frontmatter-shaped.
126
+ const DETECTOR_EXEMPTIONS = new Map([
127
+ [path.join('scripts', 'lint-frontmatter-fence-drift.cjs'), new Set(['/^(?:\\\\r)?(?:\\\\n)?---(?:\\\\r)?(?:\\\\n)?$/'])],
128
+ [path.join('scripts', 'lint-frontmatter-scalar-broad-grep.cjs'), new Set(['/\\^---[\\s\\S]{0,300}?---/'])],
129
+ [path.join('eslint-rules', 'no-crlf-fragile-split.cjs'), new Set(['/\\^---/'])],
130
+ // The owner's own module-scope fence-literal constants (#5105 fix): these ARE
131
+ // the canonical closing-fence patterns, not a re-derivation — exempted by their
132
+ // exact fragment rather than by a blanket TOP_LEVEL pass, so a NEW top-level
133
+ // helper in this file (one that merely happens to sit outside a function) is
134
+ // still caught.
135
+ [OWNER_FILE, new Set(['/^---[ \\t]*$/', '/^-{4,}[ \\t]*$/'])],
136
+ ]);
137
+
138
+ // Only a column-0 top-level `function` declaration updates the current-function
139
+ // tracker (mirrors lint-milestone-window-drift.cjs); ANY OTHER non-blank,
140
+ // non-`}` column-0 line — a `const`, a `module.exports =`, an `export const`
141
+ // arrow, anything — resets it to TOP_LEVEL. (#5105 fix: the previous version
142
+ // only reset on a fixed keyword list, so a top-level statement it didn't
143
+ // recognize — e.g. `module.exports = { ... }` — silently inherited the LAST
144
+ // exempted function's name and went unscanned.)
145
+ const TOP_LEVEL_FUNCTION_RE = /^(?:export\s+)?(?:async\s+)?function\s+([A-Za-z0-9_$]+)\s*\(/;
146
+ const COLUMN_ZERO_RESET_RE = /^[^\s}]/;
147
+
148
+ const NEW_REGEXP_RE = /new\s+RegExp\s*\(/;
149
+
150
+ // A fence-shaped string literal's CONTENT (source text between the quotes):
151
+ // `---`, optionally preceded by `\n`/`\r\n` and optionally followed by `\n`/`\r\n`.
152
+ const FENCE_LITERAL_CONTENT_RE = /^(?:\\r)?(?:\\n)?---(?:\\r)?(?:\\n)?$/;
153
+
154
+ const SEARCH_CALL_BEFORE_RE = /\.(startsWith|endsWith|indexOf|lastIndexOf|split|includes)\(\s*$/;
155
+ const COMPARE_BEFORE_RE = /[!=]==?\s*$/;
156
+ const COMPARE_AFTER_RE = /^\s*[!=]==?/;
157
+
158
+ /**
159
+ * Read the quoted or backtick-delimited string literal starting at `line[start]`.
160
+ * Returns `{ text, end }` (delimiters included) or null. Same single-pass,
161
+ * escape-aware, bounded style as the shared `readRegexLiteralAt`.
162
+ */
163
+ function readStringLiteralAt(line, start) {
164
+ const quote = line[start];
165
+ if (quote !== "'" && quote !== '"' && quote !== '`') return null;
166
+ const limit = Math.min(line.length, start + MAX_REGEX_LITERAL_LEN);
167
+ for (let i = start + 1; i < limit; i++) {
168
+ const ch = line[i];
169
+ if (ch === '\\') {
170
+ i++;
171
+ continue;
172
+ }
173
+ if (ch === '\r' || ch === '\n') return null;
174
+ if (ch === quote) return { text: line.slice(start, i + 1), end: i + 1 };
175
+ }
176
+ return null;
177
+ }
178
+
179
+ /**
180
+ * Strip comment text from a line (whole-line `*`, `/*`, `//`, and a trailing
181
+ * `//`), as the sibling guards do — prose about a fence is not a fence.
182
+ */
183
+ function stripComments(line) {
184
+ const trimmed = line.trim();
185
+ if (trimmed.startsWith('*') || trimmed.startsWith('/*') || trimmed.startsWith('//')) return '';
186
+ const idx = line.indexOf('//');
187
+ return idx === -1 ? line : line.slice(0, idx);
188
+ }
189
+
190
+ /** Every regex and string literal on `code`, in order, with its kind and span. */
191
+ function literalsOf(code) {
192
+ const out = [];
193
+ for (let i = 0; i < code.length; i++) {
194
+ const ch = code[i];
195
+ let literal = null;
196
+ let kind = null;
197
+ if (ch === '/' && code[i + 1] !== '/' && code[i + 1] !== '*') {
198
+ literal = readRegexLiteralAt(code, i);
199
+ kind = 'regex';
200
+ } else if (ch === "'" || ch === '"' || ch === '`') {
201
+ literal = readStringLiteralAt(code, i);
202
+ kind = 'string';
203
+ }
204
+ if (!literal) continue;
205
+ out.push({ kind, text: literal.text, start: i, end: literal.end });
206
+ i = literal.end - 1;
207
+ }
208
+ return out;
209
+ }
210
+
211
+ /** The fence re-derivation fragment on a comment-stripped line, or null. */
212
+ function fenceFragment(code) {
213
+ const literals = literalsOf(code);
214
+ const hasNewRegExp = NEW_REGEXP_RE.test(code);
215
+ for (const lit of literals) {
216
+ if (lit.kind === 'regex') {
217
+ if (lit.text.includes('---')) return lit.text;
218
+ continue;
219
+ }
220
+ const content = lit.text.slice(1, -1);
221
+ if (hasNewRegExp && content.includes('---')) return lit.text;
222
+ if (!FENCE_LITERAL_CONTENT_RE.test(content)) continue;
223
+ const before = code.slice(0, lit.start);
224
+ const after = code.slice(lit.end);
225
+ const call = SEARCH_CALL_BEFORE_RE.exec(before);
226
+ if (call && (call[1] !== 'includes' || content.includes('\\n'))) return lit.text;
227
+ if (COMPARE_BEFORE_RE.test(before) || COMPARE_AFTER_RE.test(after)) return lit.text;
228
+ }
229
+ return null;
230
+ }
231
+
232
+ /**
233
+ * Pure: every unsanctioned frontmatter-fence re-derivation in `text`.
234
+ * `relPath` is the repo-relative path, for reporting and the exemptions.
235
+ * Returns [{ line, fn, found }].
236
+ */
237
+ function findFrontmatterFenceDrift(text, relPath) {
238
+ const out = [];
239
+ const lines = text.split('\n');
240
+ const exemptFunctions = FUNCTION_SCOPED_EXEMPTIONS.get(relPath) || null;
241
+ const exemptFragments = DETECTOR_EXEMPTIONS.get(relPath) || null;
242
+ let currentFunction = TOP_LEVEL;
243
+ for (let i = 0; i < lines.length; i++) {
244
+ const line = lines[i];
245
+ const fnMatch = TOP_LEVEL_FUNCTION_RE.exec(line);
246
+ if (fnMatch) currentFunction = fnMatch[1];
247
+ else if (COLUMN_ZERO_RESET_RE.test(line)) currentFunction = TOP_LEVEL;
248
+
249
+ const code = stripComments(line);
250
+ if (!code.includes('---')) continue;
251
+ const found = fenceFragment(code);
252
+ if (found === null) continue;
253
+ if (exemptFunctions && exemptFunctions.has(currentFunction)) continue;
254
+ if (exemptFragments && exemptFragments.has(found)) continue;
255
+ out.push({ line: i + 1, fn: currentFunction, found });
256
+ }
257
+ return out;
258
+ }
259
+
260
+ /** Scan the authored source tree and entry points; every violation carries its repo-relative file. */
261
+ function scanRepo(root) {
262
+ const violations = [];
263
+ for (const { dirs, ext } of SCAN_TREES) {
264
+ violations.push(...scanTree({
265
+ root,
266
+ scanDirs: dirs,
267
+ scanExt: ext,
268
+ onFile(rel, text) {
269
+ return findFrontmatterFenceDrift(text, rel).map((d) => ({ file: rel, ...d }));
270
+ },
271
+ }));
272
+ }
273
+ for (const rel of SCAN_FILES) {
274
+ let text;
275
+ try {
276
+ text = fs.readFileSync(path.join(root, rel), 'utf8');
277
+ } catch {
278
+ continue; // absent in a fixture tree
279
+ }
280
+ violations.push(...findFrontmatterFenceDrift(text, rel).map((d) => ({ file: rel, ...d })));
281
+ }
282
+ return violations;
283
+ }
284
+
285
+ function main() {
286
+ const root = path.join(__dirname, '..');
287
+ const violations = scanRepo(root);
288
+ if (violations.length === 0) {
289
+ process.stdout.write('ok frontmatter-fence-drift: no frontmatter fence re-derivations outside frontmatter-fence.cts\n');
290
+ return;
291
+ }
292
+ process.stderr.write('frontmatter-fence-drift: independent re-derivation(s) of the frontmatter fence found.\n');
293
+ process.stderr.write('Use `locateFrontmatterFence` (src/frontmatter-fence.cts) for offsets, or `frontmatterBlock` /\n');
294
+ process.stderr.write('`frontmatterRegion` / `extractFrontmatter` / `stripFrontmatter` (src/frontmatter.cts) for content:\n');
295
+ for (const d of violations) {
296
+ process.stderr.write(` ${sanitizeForReport(d.file)}:${d.line} (${sanitizeForReport(d.fn)}) ${sanitizeForReport(d.found)}\n`);
297
+ }
298
+ process.exitCode = 1;
299
+ }
300
+
301
+ if (require.main === module) main();
302
+
303
+ module.exports = {
304
+ findFrontmatterFenceDrift,
305
+ scanRepo,
306
+ fenceFragment,
307
+ stripComments,
308
+ readStringLiteralAt,
309
+ OWNER_FILE,
310
+ TOP_LEVEL,
311
+ FUNCTION_SCOPED_EXEMPTIONS,
312
+ DETECTOR_EXEMPTIONS,
313
+ };
@@ -17,10 +17,22 @@
17
17
  * `passed+gaps_found+human_needed` instead of `passed` and blocking a
18
18
  * passed phase).
19
19
  *
20
- * The fix-forward is to scope the grep to the leading frontmatter block and
21
- * take only the first match:
20
+ * The fix-forward for a scalar with no owning query is to scope the grep to
21
+ * the leading frontmatter block and take only the first match:
22
22
  * sed -n '/^---$/,/^---$/p' "$f" | grep -m1 "^<key>:" | cut -d: -f2 | tr -d ' '
23
23
  *
24
+ * ## Rule `verification-status-raw-read` (#5118, ADR-5057 Phase 4)
25
+ *
26
+ * A VERIFICATION report's `status` HAS an owning query — its closed enum,
27
+ * staleness check and routing live in src/verification.cts. Reading that
28
+ * scalar with awk / sed / grep `^status:` (scoped to the frontmatter or not)
29
+ * bypasses all three (transition.md's awk read was W15 in the #5118 census),
30
+ * so it is red even when frontmatter-scoped. The fix-forward is the owner:
31
+ * gsd_run query verification.status "$PHASE_DIR" --pick status
32
+ * `findRawVerificationStatusReadsInBlock` flags a logical line (backslash
33
+ * continuations joined) that names a `*VERIFICATION*` path or variable and
34
+ * reads `^status` with awk, sed or grep.
35
+ *
24
36
  * ## What this scans
25
37
  *
26
38
  * Every fenced ```bash / ```sh code block in `gsd-core/workflows/*.md`,
@@ -68,6 +80,17 @@ const FRONTMATTER_SCOPE_RE = /\^---[\s\S]{0,300}?---/;
68
80
 
69
81
  const ALLOW_RE = /#\s*lint-allow:\s*frontmatter-scalar-broad-grep/;
70
82
 
83
+ const RULE_BROAD_GREP = 'frontmatter-scalar-broad-grep';
84
+ const RULE_VERIFICATION_RAW_READ = 'verification-status-raw-read';
85
+
86
+ // #5118: a VERIFICATION report path or variable (`*-VERIFICATION.md`,
87
+ // `$VERIFICATION_FILE`, `${VERIFICATION_PATH}`), a raw `^status` pattern, and
88
+ // the text tool doing the read. Case-INsensitive (#5118 review): a lower-case
89
+ // `$verification_file` / `*-verification.md` read is the same bypass.
90
+ const VERIFICATION_PATH_RE = /verification/i;
91
+ const RAW_STATUS_PATTERN_RE = /\^status\b/;
92
+ const RAW_READ_TOOL_RE = /(^|[\s|;&(`$])(awk|gawk|sed|grep|egrep)\s/;
93
+
71
94
  // `| head -1` / `| head -n 1` immediately after the grep is functionally
72
95
  // equivalent to `-m1` for this check: frontmatter always precedes the body
73
96
  // in these generated reports, so the first grep match is always the
@@ -163,12 +186,63 @@ function findBroadGrepsInBlock(lines) {
163
186
  }
164
187
 
165
188
  if (pipedToTokenTool || comparedLater) {
166
- findings.push({ lineIndex: i, key, snippet: line.trim() });
189
+ findings.push({ lineIndex: i, key, snippet: line.trim(), rule: RULE_BROAD_GREP });
167
190
  }
168
191
  }
169
192
  return findings;
170
193
  }
171
194
 
195
+ /**
196
+ * Join backslash-continued physical lines into logical lines, remembering the
197
+ * index of each logical line's FIRST physical line.
198
+ * @param {string[]} lines
199
+ * @returns {{ lineIndex: number, text: string }[]}
200
+ */
201
+ function logicalLines(lines) {
202
+ const out = [];
203
+ let current = null;
204
+ for (let i = 0; i < lines.length; i += 1) {
205
+ const line = lines[i];
206
+ const continued = /\\\s*$/.test(line);
207
+ const piece = continued ? line.replace(/\\\s*$/, ' ') : line;
208
+ if (current === null) current = { lineIndex: i, text: piece };
209
+ else current.text += piece;
210
+ if (!continued) {
211
+ out.push(current);
212
+ current = null;
213
+ }
214
+ }
215
+ if (current !== null) out.push(current);
216
+ return out;
217
+ }
218
+
219
+ /**
220
+ * Pure (#5118): find every raw read of a VERIFICATION report's `status` in a
221
+ * single fenced bash/sh block — awk / sed / grep over a `*VERIFICATION*`
222
+ * path with a `^status` pattern, whether or not it is frontmatter-scoped.
223
+ * The owner query (`gsd_run query verification.status …`) carries no
224
+ * `^status` pattern and is never flagged. Returns
225
+ * `{ lineIndex, key, snippet, rule }[]` (lineIndex = the logical line's first
226
+ * physical line).
227
+ * @param {string[]} lines
228
+ * @returns {{ lineIndex: number, key: string, snippet: string, rule: string }[]}
229
+ */
230
+ function findRawVerificationStatusReadsInBlock(lines) {
231
+ const findings = [];
232
+ for (const { lineIndex, text } of logicalLines(lines)) {
233
+ if (!VERIFICATION_PATH_RE.test(text)) continue;
234
+ if (!RAW_STATUS_PATTERN_RE.test(text)) continue;
235
+ if (!RAW_READ_TOOL_RE.test(text)) continue;
236
+ findings.push({
237
+ lineIndex,
238
+ key: 'status',
239
+ snippet: text.replace(/\s+/g, ' ').trim(),
240
+ rule: RULE_VERIFICATION_RAW_READ,
241
+ });
242
+ }
243
+ return findings;
244
+ }
245
+
172
246
  function walkMarkdown(dir) {
173
247
  const out = [];
174
248
  let entries;
@@ -198,12 +272,18 @@ function scan(roots = DEFAULT_ROOTS) {
198
272
  for (const file of walkMarkdown(abs)) {
199
273
  const blocks = extractBashBlocks(fs.readFileSync(file, 'utf8'));
200
274
  for (const block of blocks) {
201
- for (const finding of findBroadGrepsInBlock(block.lines)) {
275
+ const rawReads = findRawVerificationStatusReadsInBlock(block.lines);
276
+ const rawReadLines = new Set(rawReads.map((f) => f.lineIndex));
277
+ // A raw VERIFICATION `status` read is reported once, under its own
278
+ // rule, not a second time as a broad grep.
279
+ const broad = findBroadGrepsInBlock(block.lines).filter((f) => !rawReadLines.has(f.lineIndex));
280
+ for (const finding of [...rawReads, ...broad]) {
202
281
  offenders.push({
203
282
  file: path.relative(ROOT, file),
204
283
  line: block.startLine + finding.lineIndex,
205
284
  key: finding.key,
206
285
  snippet: finding.snippet,
286
+ rule: finding.rule,
207
287
  });
208
288
  }
209
289
  }
@@ -217,21 +297,47 @@ function main() {
217
297
  const roots = rootsEnv ? rootsEnv.split(path.delimiter).filter(Boolean) : DEFAULT_ROOTS;
218
298
  const offenders = scan(roots);
219
299
  if (offenders.length > 0) {
220
- const detail = offenders.map((o) => ` ${o.file}:${o.line} ${o.snippet}`).join('\n');
221
- throw new ExitError(
222
- 1,
223
- 'lint-frontmatter-scalar-broad-grep: `grep "^key:"` over the whole file, compared to an\n'
224
- + 'exact token, with no frontmatter scoping and no -m1 (DEFECT.FRONTMATTER-SCALAR-BROAD-GREP).\n'
225
- + 'A body line beginning `key:` is enough to break this. Scope to the frontmatter block:\n'
226
- + ' sed -n \'/^---$/,/^---$/p\' "$f" | grep -m1 "^<key>:" | cut -d: -f2 | tr -d \' \'\n'
227
- + 'or add `# lint-allow: frontmatter-scalar-broad-grep — <reason>` if this is a genuine\n'
228
- + 'whole-body scan:\n'
229
- + detail,
230
- );
300
+ const detailFor = (rule) => offenders
301
+ .filter((o) => o.rule === rule)
302
+ .map((o) => ` ${o.file}:${o.line} ${o.snippet}`)
303
+ .join('\n');
304
+ const sections = [];
305
+ const rawReads = detailFor(RULE_VERIFICATION_RAW_READ);
306
+ if (rawReads) {
307
+ sections.push(
308
+ `[${RULE_VERIFICATION_RAW_READ}] a VERIFICATION report's \`status\` read with awk/sed/grep\n`
309
+ + '(DEFECT.FRONTMATTER-SCALAR-BROAD-GREP, #5118). It bypasses the closed VerificationStatus\n'
310
+ + 'enum, the staleness check and the routing table. Read it through its owner:\n'
311
+ + ' gsd_run query verification.status "$PHASE_DIR" --pick status\n'
312
+ + rawReads,
313
+ );
314
+ }
315
+ const broad = detailFor(RULE_BROAD_GREP);
316
+ if (broad) {
317
+ sections.push(
318
+ `[${RULE_BROAD_GREP}] \`grep "^key:"\` over the whole file, compared to an exact token,\n`
319
+ + 'with no frontmatter scoping and no -m1 (DEFECT.FRONTMATTER-SCALAR-BROAD-GREP).\n'
320
+ + 'A body line beginning `key:` is enough to break this. Scope a scalar that has no owning\n'
321
+ + 'query to the frontmatter block (a VERIFICATION `status` always goes through its owner):\n'
322
+ + ' sed -n \'/^---$/,/^---$/p\' "$f" | grep -m1 "^<key>:" | cut -d: -f2 | tr -d \' \'\n'
323
+ + 'or add `# lint-allow: frontmatter-scalar-broad-grep — <reason>` if this is a genuine\n'
324
+ + 'whole-body scan:\n'
325
+ + broad,
326
+ );
327
+ }
328
+ throw new ExitError(1, `lint-frontmatter-scalar-broad-grep:\n${sections.join('\n')}`);
231
329
  }
232
330
  console.log(`ok lint-frontmatter-scalar-broad-grep: no un-scoped frontmatter-scalar greps in ${roots.length} root(s)`);
233
331
  }
234
332
 
235
- module.exports = { findBroadGrepsInBlock, extractBashBlocks, scan, DEFAULT_ROOTS };
333
+ module.exports = {
334
+ findBroadGrepsInBlock,
335
+ findRawVerificationStatusReadsInBlock,
336
+ extractBashBlocks,
337
+ scan,
338
+ DEFAULT_ROOTS,
339
+ RULE_BROAD_GREP,
340
+ RULE_VERIFICATION_RAW_READ,
341
+ };
236
342
 
237
343
  if (require.main === module) runMain(main);