@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
@@ -0,0 +1,285 @@
1
+ "use strict";
2
+ /**
3
+ * `check verify-codebase-drift` as a gate module (#5219, epic #5056, ADR-5057 §4 closing arm C): it
4
+ * returns a `GateResult`; the command router formats it. Imports no io module and performs no direct
5
+ * console/stdout/stderr write (ESLint-enforced).
6
+ *
7
+ * The `drift` capability's gate at `execute:wave:post`. It diffs the repository's HEAD against the
8
+ * commit `.planning/codebase/STRUCTURE.md` was last mapped at (`last_mapped_commit`, stamped by
9
+ * `stamp-codebase-map`) and reports structural change the map does not describe (`detectDrift`,
10
+ * `drift.cjs`). Non-blocking unless the drift crosses the configured threshold (`block` = the drift
11
+ * library's `actionRequired`).
12
+ *
13
+ * Dispatched gate, payload exit mode (see `gate-schema-drift.cts`): a blocking verdict is exit 0 and
14
+ * "could not look" is exit 69 (#5170).
15
+ *
16
+ * Non-blocking contract: a throw anywhere yields a non-blocking `unreadable` verdict, never a crash.
17
+ *
18
+ * Argv after the verb: none.
19
+ */
20
+ var __importDefault = (this && this.__importDefault) || function (mod) {
21
+ return (mod && mod.__esModule) ? mod : { "default": mod };
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.evaluateCodebaseDriftGate = evaluateCodebaseDriftGate;
25
+ const node_fs_1 = __importDefault(require("node:fs"));
26
+ const node_path_1 = __importDefault(require("node:path"));
27
+ const gate_verdict_cjs_1 = require("./gate-verdict.cjs");
28
+ const gate_config_cjs_1 = require("./gate-config.cjs");
29
+ const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
30
+ const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
31
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- planning-workspace.cjs is an export= CommonJS module
32
+ const planningWorkspace = require("./planning-workspace.cjs");
33
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- worktree-safety.cjs is an export= CommonJS module
34
+ const worktreeSafetyMod = require("./worktree-safety.cjs");
35
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- onboard-projection.cjs is an export= CommonJS module
36
+ const onboardProjectionMod = require("./onboard-projection.cjs");
37
+ // drift.cjs is a pure library that imports no gate or verify module, so it is loaded at the top.
38
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- drift.cjs is an export= CommonJS module
39
+ const driftModule = require("./drift.cjs");
40
+ const drift = driftModule;
41
+ /**
42
+ * A mapped-commit stamp must be a hex object id (abbreviated to at least 7, or a full SHA-1 / SHA-256
43
+ * id) before git sees it. A ref name (`HEAD`), a shorter abbreviation and an option-shaped value
44
+ * (`--batch`) are not baselines: each is routed to `unresolvable-mapped-commit`, so no stamp can reach
45
+ * `git cat-file` / `git diff` as anything but an object id.
46
+ */
47
+ const HEX_OBJECT_ID_RE = /^[0-9a-f]{7,64}$/i;
48
+ const { planningDir, planningRoot } = planningWorkspace;
49
+ // Single owner of git C-quoted-path decoding (see #4081 note at the --name-status parse loop).
50
+ const { decodeGitQuotedPath } = worktreeSafetyMod;
51
+ const { REQUIRED_CODEBASE_MAP_FILES } = onboardProjectionMod;
52
+ /**
53
+ * A generated document is read only when it is a regular file (symlinks followed) no larger than
54
+ * this: a FIFO would block the gate forever and a huge file would exhaust memory.
55
+ */
56
+ const MAX_DOCUMENT_BYTES = 1048576;
57
+ function readDocument(file) {
58
+ const st = node_fs_1.default.statSync(file);
59
+ if (!st.isFile())
60
+ throw new Error('not a regular file');
61
+ if (st.size > MAX_DOCUMENT_BYTES)
62
+ throw new Error(`larger than ${MAX_DOCUMENT_BYTES} bytes`);
63
+ return node_fs_1.default.readFileSync(file, 'utf-8');
64
+ }
65
+ /**
66
+ * The drift gates' fixed non-answer payload; `skip` is a documented "nothing to compare", `unreadable`
67
+ * is "could not look" (#5170) and exits UNAVAILABLE. Both keep the non-blocking payload.
68
+ */
69
+ function nonAnswer(reason, extra = {}) {
70
+ return {
71
+ // Uniform gate contract: block = action_required (false when skipped).
72
+ block: false,
73
+ skipped: true,
74
+ reason,
75
+ action_required: false,
76
+ directive: 'none',
77
+ elements: [],
78
+ ...extra,
79
+ };
80
+ }
81
+ function skipped(reason, extra = {}) {
82
+ return (0, gate_verdict_cjs_1.gateVerdict)('skip', false, nonAnswer(reason, extra));
83
+ }
84
+ function unreadable(reason, extra = {}) {
85
+ return (0, gate_verdict_cjs_1.gateUnreadable)(false, nonAnswer(reason, extra));
86
+ }
87
+ function runCodebaseDriftGate(cwd) {
88
+ const codebaseDir = node_path_1.default.join(planningDir(cwd), 'codebase');
89
+ const structurePath = node_path_1.default.join(codebaseDir, 'STRUCTURE.md');
90
+ let structureMd;
91
+ try {
92
+ structureMd = readDocument(structurePath);
93
+ }
94
+ catch (err) {
95
+ if (err?.code === 'ENOENT') {
96
+ return skipped('no-structure-md');
97
+ }
98
+ return unreadable('cannot-read-structure-md: ' + (err instanceof Error ? err.message : String(err)));
99
+ }
100
+ const lastMapped = drift['readMappedCommit'](structurePath);
101
+ const revProbe = (0, shell_command_projection_cjs_1.execGit)(['rev-parse', 'HEAD'], { cwd });
102
+ if (revProbe.exitCode !== 0) {
103
+ return skipped('not-a-git-repo');
104
+ }
105
+ // #3418: an absent or unresolvable baseline means NO COMPARISON IS POSSIBLE.
106
+ // It is neither zero drift nor total drift, and reporting it as either is a
107
+ // lie the consumer cannot detect. The former fallback diffed HEAD against
108
+ // the empty tree, so every tracked file read as newly added and the gate
109
+ // reported maximum drift identically on every run -- which made a genuinely
110
+ // stale map indistinguishable from a fresh one, and let `spawn_mapper` fire
111
+ // a whole-repo remap while presenting itself as an incremental one.
112
+ if (!lastMapped) {
113
+ return skipped('no-mapped-commit', { last_mapped_commit: null });
114
+ }
115
+ // A stamp that is not a hex object id is not a baseline (a ref name such as `HEAD` would "resolve" to
116
+ // a commit and diff against the wrong object; an option-shaped value must never reach git): same arm
117
+ // as a stamp git cannot resolve, and no git call is made with it.
118
+ if (!HEX_OBJECT_ID_RE.test(lastMapped)) {
119
+ return unreadable('unresolvable-mapped-commit', { last_mapped_commit: lastMapped });
120
+ }
121
+ const baseProbe = (0, shell_command_projection_cjs_1.execGit)(['cat-file', '-t', lastMapped], { cwd });
122
+ if (baseProbe.exitCode !== 0 || baseProbe.stdout.trim() !== 'commit') {
123
+ // A stamp git cannot resolve: history rewrite, GC, or a shallow clone.
124
+ // Distinct reason from 'no-mapped-commit' -- the map claims a baseline,
125
+ // this repository just cannot see it, which is an operator-actionable
126
+ // difference (re-map vs. unshallow). A resolvable non-commit (a tree or
127
+ // blob sha) is the same class of bad baseline: git would happily diff
128
+ // against it and report drift against the wrong object.
129
+ // The repository cannot resolve the baseline the map claims: it could not look (#5170).
130
+ return unreadable('unresolvable-mapped-commit', { last_mapped_commit: lastMapped });
131
+ }
132
+ const base = lastMapped;
133
+ const diff = (0, shell_command_projection_cjs_1.execGit)(['diff', '--name-status', base, 'HEAD'], { cwd });
134
+ if (diff.exitCode !== 0) {
135
+ return unreadable('git-diff-failed');
136
+ }
137
+ // #3418: GSD's own planning artifacts are not codebase structure. A
138
+ // map-codebase run commits `.planning/codebase/*.md`, so a correctly
139
+ // stamped baseline would be re-poisoned by the very commit that carries
140
+ // the stamp -- the next gate invocation would report the map's own seven
141
+ // documents as seven new directories, back over the default threshold of
142
+ // three. Derived from planningRoot() rather than a hardcoded literal so a
143
+ // repoint of the planning root cannot leave this filter behind.
144
+ //
145
+ // `git diff --name-status` always prints repo-root-relative paths, so a cwd
146
+ // below the root needs the `sub/` prefix or the filter matches nothing.
147
+ // That prefix comes from git (`--show-prefix`: root-relative, forward
148
+ // slashes, trailing slash, empty at the root). The rejected alternative was
149
+ // path.relative(`--show-toplevel`, cwd), which mixes two path producers: on
150
+ // Windows os.tmpdir() hands back the 8.3 short form while git resolves the
151
+ // long one, so relative() between them yields a `../..` chain that matches
152
+ // nothing. The `.planning` half below is safe to compute with relative()
153
+ // because both of its sides are the same cwd string.
154
+ const prefixProbe = (0, shell_command_projection_cjs_1.execGit)(['rev-parse', '--show-prefix'], { cwd });
155
+ const repoPrefix = prefixProbe.exitCode === 0 ? prefixProbe.stdout.trim() : '';
156
+ const planningPrefix = repoPrefix + node_path_1.default.relative(cwd, planningRoot(cwd)).split(node_path_1.default.sep).join('/') + '/';
157
+ const isPlanningArtifact = (file) => file.split('\\').join('/').startsWith(planningPrefix);
158
+ const added = [];
159
+ const modified = [];
160
+ const deleted = [];
161
+ for (const line of diff.stdout.split(/\r?\n/)) {
162
+ if (!line.trim())
163
+ continue;
164
+ const m = line.match(/^([A-Z])\d*\t(.+?)(?:\t(.+))?$/);
165
+ if (!m)
166
+ continue;
167
+ const status = m[1];
168
+ // execGit sets no core.quotepath config, so git's default `true` applies:
169
+ // any path containing non-ASCII bytes (or `"`, `\`, control bytes) is
170
+ // C-quoted — `"docs/\350\256\276…/overview.md"`. Capturing that verbatim
171
+ // garbles affected_paths/elements and makes isPathMapped compare the
172
+ // quoted prefix (`"docs`) against STRUCTURE.md, misclassifying DOCUMENTED
173
+ // directories as new_dir (#4081). Decode with the single owner of the
174
+ // git C-quote seam (worktree-safety.cjs); a non-quoted value — the plain
175
+ // ASCII common case — passes through untouched. Both capture groups are
176
+ // decoded: R/C lines carry old AND new paths, either may be quoted.
177
+ // A rename is a deletion of the old path plus an addition of the new
178
+ // one; a copy leaves its source in place and adds only the new path.
179
+ const oldPath = decodeGitQuotedPath(m[2]);
180
+ const newPath = m[3] ? decodeGitQuotedPath(m[3]) : oldPath;
181
+ const put = (file, into) => {
182
+ if (!isPlanningArtifact(file))
183
+ into.push(file);
184
+ };
185
+ if (status === 'R') {
186
+ put(oldPath, deleted);
187
+ put(newPath, added);
188
+ }
189
+ else if (status === 'C')
190
+ put(newPath, added);
191
+ else if (status === 'A')
192
+ put(newPath, added);
193
+ else if (status === 'M' || status === 'T')
194
+ put(newPath, modified);
195
+ else if (status === 'D')
196
+ put(newPath, deleted);
197
+ }
198
+ // Every generated document is territory the map describes, so all seven are
199
+ // read (the one owner of the names is REQUIRED_CODEBASE_MAP_FILES).
200
+ // STRUCTURE.md was read above; an unreadable other document is omitted and
201
+ // named rather than sinking the whole check, and an absent one is simply
202
+ // not part of this map (a `--fast` map writes four of the seven).
203
+ const documents = {};
204
+ const documentsRead = [];
205
+ const documentsUnreadable = [];
206
+ for (const name of REQUIRED_CODEBASE_MAP_FILES) {
207
+ if (name === 'STRUCTURE.md') {
208
+ documents[name] = structureMd;
209
+ documentsRead.push(name);
210
+ continue;
211
+ }
212
+ try {
213
+ documents[name] = readDocument(node_path_1.default.join(codebaseDir, name));
214
+ documentsRead.push(name);
215
+ }
216
+ catch (err) {
217
+ if (err?.code !== 'ENOENT')
218
+ documentsUnreadable.push(name);
219
+ }
220
+ }
221
+ // loadConfig() returns a flattened object — there is no nested `workflow`
222
+ // key. Read the workflow-scoped keys through the quiet gate-config reader (the dot-path
223
+ // resolver `config-get workflow.*` shares: workstream config first, then the project
224
+ // root's; a missing or malformed config is "key absent", nothing is printed).
225
+ const configuredThreshold = (0, gate_config_cjs_1.readWorkflowConfigValue)(cwd, 'workflow.drift_threshold').value;
226
+ const threshold = Number.isInteger(configuredThreshold) && configuredThreshold >= 1
227
+ ? configuredThreshold
228
+ : 3;
229
+ const action = (0, gate_config_cjs_1.readWorkflowConfigValue)(cwd, 'workflow.drift_action').value === 'auto-remap' ? 'auto-remap' : 'warn';
230
+ const driftResult = drift['detectDrift']({
231
+ addedFiles: added,
232
+ modifiedFiles: modified,
233
+ deletedFiles: deleted,
234
+ documents,
235
+ threshold,
236
+ action,
237
+ runtime: (0, runtime_slash_cjs_1.resolveRuntime)(cwd),
238
+ });
239
+ const actionRequired = !!driftResult['actionRequired'];
240
+ // Paths are attacker-controlled (they come from git); the raw values stay
241
+ // in the library result, the CLI JSON carries display-safe renderings and
242
+ // a bounded withheld list with its true size alongside.
243
+ const display = drift['displaySafePath'];
244
+ const WITHHELD_LIST_CAP = 50;
245
+ const withheldAll = driftResult['withheldPaths'] || [];
246
+ const elementsRaw = driftResult['elements'] || [];
247
+ const isSkipped = !!driftResult['skipped'];
248
+ const payload = {
249
+ // Uniform gate contract: block = action_required.
250
+ block: actionRequired,
251
+ skipped: isSkipped,
252
+ reason: driftResult['reason'] || null,
253
+ action_required: actionRequired,
254
+ directive: driftResult['directive'],
255
+ spawn_mapper: !!driftResult['spawnMapper'],
256
+ affected_paths: driftResult['affectedPaths'] || [],
257
+ withheld_paths: withheldAll.slice(0, WITHHELD_LIST_CAP).map((p) => display(p)),
258
+ withheld_count: withheldAll.length,
259
+ documents_read: documentsRead,
260
+ documents_unreadable: documentsUnreadable,
261
+ elements: elementsRaw.map((e) => ({ category: e.category, path: display(e.path) })),
262
+ threshold,
263
+ action,
264
+ last_mapped_commit: lastMapped,
265
+ message: driftResult['message'] || '',
266
+ };
267
+ // #5170: the drift was detected over fewer documents than the map has. A BLOCKING verdict stands
268
+ // (more documents could only add territory the map describes); anything else was computed from
269
+ // evidence the gate never saw and is `unreadable` (exit UNAVAILABLE), never a clean pass or skip.
270
+ return actionRequired
271
+ ? (0, gate_verdict_cjs_1.gateVerdict)('block', true, payload)
272
+ : documentsUnreadable.length > 0
273
+ ? (0, gate_verdict_cjs_1.gateUnreadable)(false, payload)
274
+ : (0, gate_verdict_cjs_1.gateVerdict)(isSkipped ? 'skip' : 'pass', false, payload);
275
+ }
276
+ function evaluateCodebaseDriftGate(input) {
277
+ // Non-blocking contract: a throw anywhere yields the non-blocking payload; the exit status says
278
+ // "could not look" (#5170) rather than a clean exit 0.
279
+ try {
280
+ return runCodebaseDriftGate(input.projectDir);
281
+ }
282
+ catch (err) {
283
+ return unreadable('exception: ' + (err && err instanceof Error ? err.message : String(err)));
284
+ }
285
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ /**
3
+ * Gate config — the one place a gate reads a `workflow.*` switch (#5139, epic #5056, ADR-5057
4
+ * Phase 6, design D5; fixes #4978).
5
+ *
6
+ * A gate module may not import `./io.cjs` and may not hand-parse `config.json`. It reads its switch
7
+ * through the shared dot-path resolver `config-get workflow.*` is defined by
8
+ * (`capability-activation.cts` `resolveConfigKey`): own-property traversal (a prototype-chain key
9
+ * is never a value), the active workstream's config first, then the project root's, and a missing,
10
+ * unreadable or non-object config is simply "the key is absent".
11
+ *
12
+ * The lookup is NESTED-ONLY. A top-level `context_coverage_gate` / `auto_advance` /
13
+ * `_auto_chain_active` is never read — `config-get workflow.<key>` does not answer it either, so a
14
+ * gate and `config-get` can no longer disagree about the same config file (#4978).
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.readWorkflowConfigValue = readWorkflowConfigValue;
18
+ exports.isDecisionCoverageGateEnabled = isDecisionCoverageGateEnabled;
19
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
20
+ const capabilityActivationMod = require("./capability-activation.cjs");
21
+ const { resolveConfigKey } = capabilityActivationMod;
22
+ /**
23
+ * The resolved raw value of a dotted config key, or `{ found: false }` when absent/unreadable.
24
+ * QUIET: a malformed config.json is "key absent" with nothing written to stderr (the pre-#5139
25
+ * gate readers printed nothing either); `config-get` keeps its one-time parse warning.
26
+ */
27
+ function readWorkflowConfigValue(projectDir, dotKey) {
28
+ return resolveConfigKey(dotKey, { config: {}, cwd: projectDir, registry: {}, quiet: true });
29
+ }
30
+ /**
31
+ * `workflow.context_coverage_gate`: the decision-coverage gates' on/off switch.
32
+ * A boolean is taken as written; the strings `'true'`/`'false'` (any case) are coerced; anything
33
+ * else — including an absent key or an unreadable config — leaves the gate ENABLED.
34
+ */
35
+ function isDecisionCoverageGateEnabled(projectDir) {
36
+ const resolved = readWorkflowConfigValue(projectDir, 'workflow.context_coverage_gate');
37
+ const value = resolved.found ? resolved.value : undefined;
38
+ if (typeof value === 'boolean')
39
+ return value;
40
+ if (typeof value === 'string') {
41
+ const lower = value.toLowerCase();
42
+ if (lower === 'false' || lower === 'true')
43
+ return lower !== 'false';
44
+ }
45
+ return true;
46
+ }
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ /**
3
+ * `check verify-context-drift` as a gate module (#5219, epic #5056, ADR-5057 §4 closing arm C): it
4
+ * returns a `GateResult`; the command router formats it. Imports no io module and performs no direct
5
+ * console/stdout/stderr write (ESLint-enforced).
6
+ *
7
+ * The `drift` capability's gate at `plan:pre` (#3348). It reports the phase's upstream artifacts
8
+ * (RESEARCH, PATTERNS, VALIDATION, SPEC) whose effective last-changed time is STRICTLY BEFORE the
9
+ * phase CONTEXT.md's own: the decisions moved after the artifact was written. Non-blocking unless
10
+ * `workflow.context_drift_action` is `block`.
11
+ *
12
+ * Dispatched gate, payload exit mode (see `gate-schema-drift.cts`): a blocking verdict is exit 0 and
13
+ * "could not look" is exit 69 (#5170).
14
+ *
15
+ * Non-blocking contract: a throw anywhere (an invalid GSD_WORKSTREAM, an unreadable file) yields a
16
+ * non-blocking `unreadable` verdict, never a crash.
17
+ *
18
+ * Argv after the verb: `<phase>`.
19
+ */
20
+ var __importDefault = (this && this.__importDefault) || function (mod) {
21
+ return (mod && mod.__esModule) ? mod : { "default": mod };
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.computeContextDrift = computeContextDrift;
25
+ exports.evaluateContextDriftGate = evaluateContextDriftGate;
26
+ const node_fs_1 = __importDefault(require("node:fs"));
27
+ const node_path_1 = __importDefault(require("node:path"));
28
+ const gate_verdict_cjs_1 = require("./gate-verdict.cjs");
29
+ const gate_evidence_cjs_1 = require("./gate-evidence.cjs");
30
+ const gate_config_cjs_1 = require("./gate-config.cjs");
31
+ const gate_phase_context_cjs_1 = require("./gate-phase-context.cjs");
32
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- planning-workspace.cjs is an export= CommonJS module
33
+ const planningWorkspace = require("./planning-workspace.cjs");
34
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- verification.cjs is an export= CommonJS module
35
+ const verificationMod = require("./verification.cjs");
36
+ const { planningDir } = planningWorkspace;
37
+ const { defaultPhaseCleanCommitTimesMs } = verificationMod;
38
+ /**
39
+ * Pure comparator: which of `entries` have an effective last-changed time
40
+ * STRICTLY BEFORE `contextEffectiveMs` (CONTEXT.md's own effective time)? Strict
41
+ * `<` is "stale" (matches findStaleVerificationSummary's own strict `>` convention
42
+ * for "newer than" elsewhere in this codebase — an artifact committed in the SAME
43
+ * commit/second as CONTEXT.md is in sync, not stale).
44
+ */
45
+ function computeContextDrift(contextEffectiveMs, entries) {
46
+ return entries.filter((e) => e.effectiveMs < contextEffectiveMs).map((e) => e.file);
47
+ }
48
+ function buildContextDriftMessage(staleArtifacts, phaseArg) {
49
+ const parts = [`CONTEXT.md decisions are newer than: ${staleArtifacts.join(', ')}.`];
50
+ if (staleArtifacts.some((f) => f.endsWith('-RESEARCH.md'))) {
51
+ parts.push(`Regenerate research: /gsd:plan-phase ${phaseArg} --research.`);
52
+ }
53
+ if (staleArtifacts.some((f) => f.endsWith('-PATTERNS.md'))) {
54
+ parts.push('Regenerate patterns: delete the PATTERNS.md file, then re-run /gsd:plan-phase.');
55
+ }
56
+ if (staleArtifacts.some((f) => f.endsWith('-VALIDATION.md') || (f.endsWith('-SPEC.md') && !f.endsWith('-AI-SPEC.md') && !f.endsWith('-UI-SPEC.md')))) {
57
+ parts.push('Regenerate or manually reconcile VALIDATION.md / SPEC.md against the current decisions.');
58
+ }
59
+ parts.push('Do not hand-inject the newer decisions into a prompt as a substitute for regenerating — that carries the staleness forward.');
60
+ return parts.join(' ');
61
+ }
62
+ /** The non-blocking context-drift payload for an arm that did not compare artifacts: `skip` or `unreadable`. */
63
+ function contextDriftPayload(build, reason, message = '') {
64
+ return build(false, { block: false, skipped: true, reason, stale_artifacts: [], message });
65
+ }
66
+ function runContextDriftGate(cwd, phaseArg) {
67
+ const pDir = planningDir(cwd);
68
+ const phasesDir = node_path_1.default.join(pDir, 'phases');
69
+ // `none`: a documented "nothing to compare" (no CONTEXT.md, no upstream artifact).
70
+ const skip = (reason, message = '') => contextDriftPayload((block, payload) => (0, gate_verdict_cjs_1.gateVerdict)('skip', block, payload), reason, message);
71
+ // An unresolvable phase is "could not look" (#5170): there is no phase directory to compare.
72
+ const unresolvable = () => contextDriftPayload(gate_verdict_cjs_1.gateUnreadable, 'phase-not-found', `Phase directory not found: ${phaseArg}`);
73
+ // The same policy as `verify schema-drift`: an ABSENT phases tree is `none` (the documented
74
+ // "nothing to compare" skip); one that exists but cannot be examined is `unreadable`.
75
+ const phasesRoot = (0, gate_evidence_cjs_1.statEvidence)(phasesDir);
76
+ if (phasesRoot.kind === 'unreadable') {
77
+ return contextDriftPayload(gate_verdict_cjs_1.gateUnreadable, 'phases-dir-unreadable', `Could not examine ${phasesDir} (${phasesRoot.reason})`);
78
+ }
79
+ if (phasesRoot.kind === 'none') {
80
+ return skip('no-phases-directory', 'No phases directory');
81
+ }
82
+ // Same phase-directory resolution rule the schema-drift gate uses (#1571, #2528):
83
+ // matchPhaseDirs, never a naive substring test.
84
+ const phaseDir = (0, gate_phase_context_cjs_1.resolvePhaseDirByToken)(phasesDir, phaseArg);
85
+ if (!phaseDir) {
86
+ return unresolvable();
87
+ }
88
+ const phaseEntries = (0, gate_evidence_cjs_1.readDirEvidence)(phaseDir);
89
+ if (phaseEntries.kind !== 'found') {
90
+ return unresolvable();
91
+ }
92
+ const phaseFiles = phaseEntries.value.slice().sort();
93
+ const contextFile = phaseFiles.find((f) => f.endsWith('-CONTEXT.md'));
94
+ if (!contextFile) {
95
+ return skip('no-context-md');
96
+ }
97
+ const researchFile = phaseFiles.find((f) => f.endsWith('-RESEARCH.md'));
98
+ const patternsFile = phaseFiles.find((f) => f.endsWith('-PATTERNS.md'));
99
+ const validationFile = phaseFiles.find((f) => f.endsWith('-VALIDATION.md'));
100
+ const specFile = phaseFiles.find((f) => f.endsWith('-SPEC.md') && !f.endsWith('-AI-SPEC.md') && !f.endsWith('-UI-SPEC.md'));
101
+ const upstreamFiles = [researchFile, patternsFile, validationFile, specFile].filter((f) => !!f);
102
+ if (upstreamFiles.length === 0) {
103
+ return skip('no-upstream-artifacts');
104
+ }
105
+ const allFiles = [contextFile, ...upstreamFiles];
106
+ const cleanCommitMs = defaultPhaseCleanCommitTimesMs(phaseDir, allFiles);
107
+ const effectiveTimeMs = (file) => cleanCommitMs.has(file)
108
+ ? cleanCommitMs.get(file)
109
+ : node_fs_1.default.statSync(node_path_1.default.join(phaseDir, file)).mtimeMs;
110
+ const contextMs = effectiveTimeMs(contextFile);
111
+ const driftEntries = upstreamFiles.map((f) => ({ file: f, effectiveMs: effectiveTimeMs(f) }));
112
+ const staleArtifacts = computeContextDrift(contextMs, driftEntries);
113
+ // Through the quiet gate-config reader (workstream config first, then the project root's; a
114
+ // missing or malformed config is "key absent", nothing is printed).
115
+ const action = (0, gate_config_cjs_1.readWorkflowConfigValue)(cwd, 'workflow.context_drift_action').value === 'block' ? 'block' : 'warn';
116
+ const block = staleArtifacts.length > 0 && action === 'block';
117
+ const message = staleArtifacts.length > 0 ? buildContextDriftMessage(staleArtifacts, phaseArg) : '';
118
+ return (0, gate_verdict_cjs_1.gateVerdict)(block ? 'block' : (staleArtifacts.length > 0 ? 'advisory' : 'pass'), block, {
119
+ block,
120
+ skipped: false,
121
+ stale_artifacts: staleArtifacts,
122
+ action,
123
+ message,
124
+ });
125
+ }
126
+ function evaluateContextDriftGate(input) {
127
+ const phaseArg = input.args[0] || '';
128
+ if (!phaseArg) {
129
+ // UNKNOWN: the pre-move `error('Usage…')` named no reason, and the reason is observable (#5219).
130
+ return (0, gate_verdict_cjs_1.gateUsageFailure)(gate_verdict_cjs_1.GATE_FAILURE_CODE.UNKNOWN, 'Usage: verify context-drift <phase>');
131
+ }
132
+ // Non-blocking contract: a throw anywhere (an invalid GSD_WORKSTREAM, an unreadable file)
133
+ // yields the non-blocking payload; the exit status says "could not look" (#5170) rather than
134
+ // a clean exit 0.
135
+ try {
136
+ return runContextDriftGate(input.projectDir, phaseArg);
137
+ }
138
+ catch (err) {
139
+ return contextDriftPayload(gate_verdict_cjs_1.gateUnreadable, 'exception: ' + (err instanceof Error ? err.message : String(err)));
140
+ }
141
+ }
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ /**
3
+ * `check decision-coverage-plan` — blocking plan-phase decision-coverage gate
4
+ * (#2492, #1365 fail-loud, #2770 empty-arg fail-closed), as a gate module (#5139, epic #5056,
5
+ * ADR-5057 §4 first bullet): it returns a `GateResult`; the command router formats it.
6
+ * Imports no io module and performs no direct console/stdout/stderr write (ESLint-enforced).
7
+ *
8
+ * Invocation (the context path may be supplied EITHER way; #4130 follow-up), argv after the verb:
9
+ * <phase-dir> <context-path> (positional, the workflow caller's form)
10
+ * --context <path> [<phase-dir>]
11
+ *
12
+ * `--context <path>` follows the sibling flag convention (`check predicate`,
13
+ * #2008): `--flag value` pairs parsed by the shared partitionPredicateArgs
14
+ * pass, the flag WINNING over a same-purpose positional when both appear,
15
+ * and a valueless `--context` counting as no context at all (it falls
16
+ * through to the #2770 caller-error branch, not to the "CONTEXT.md missing"
17
+ * green skip). The positional form keeps working unchanged — no sibling
18
+ * check verb deprecates positionals and the plan-phase workflow passes them.
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.evaluateDecisionCoveragePlan = evaluateDecisionCoveragePlan;
22
+ const gate_verdict_cjs_1 = require("./gate-verdict.cjs");
23
+ const gate_evidence_cjs_1 = require("./gate-evidence.cjs");
24
+ const gate_args_cjs_1 = require("./gate-args.cjs");
25
+ const gate_phase_context_cjs_1 = require("./gate-phase-context.cjs");
26
+ const gate_config_cjs_1 = require("./gate-config.cjs");
27
+ const decision_coverage_support_cjs_1 = require("./decision-coverage-support.cjs");
28
+ /**
29
+ * The verdict when CONTEXT.md or a plan could not be read. The blocking policy is unchanged
30
+ * (`block: true`, fail-closed like the neighbouring arms); the outcome is `unreadable`, so the exit
31
+ * status is UNAVAILABLE and nothing is certified from content the gate never saw (#5170).
32
+ */
33
+ function unreadableDecisionGate(readError) {
34
+ return (0, gate_verdict_cjs_1.gateUnreadable)(true, {
35
+ passed: false,
36
+ skipped: false,
37
+ reason: 'unreadable evidence',
38
+ total: null,
39
+ covered: null,
40
+ readError,
41
+ message: `Decision coverage gate could not read its evidence (${readError}). Fix the file permissions or encoding, then re-run the gate.`,
42
+ });
43
+ }
44
+ /** The verdict when there is no CONTEXT.md: the legitimate green skip (authoritatively `none`, never `unreadable`). */
45
+ function contextMissingSkip() {
46
+ return (0, gate_verdict_cjs_1.gateVerdict)('skip', false, { passed: true, skipped: true, reason: 'CONTEXT.md missing', total: 0, covered: 0, uncovered: [], message: 'No CONTEXT.md - nothing to check.' });
47
+ }
48
+ function evaluateDecisionCoveragePlan(input) {
49
+ const { projectDir, args } = input;
50
+ // Partition the argv AFTER the verb so flag tokens and their values never land in a
51
+ // positional slot.
52
+ const { flags, positionals } = (0, gate_args_cjs_1.partitionPredicateArgs)(args);
53
+ let phaseDir = '';
54
+ if (positionals[0]) {
55
+ const resolved = (0, gate_phase_context_cjs_1.resolveContainedPath)(positionals[0], projectDir);
56
+ if ((0, gate_verdict_cjs_1.isGateUsageFailure)(resolved))
57
+ return resolved;
58
+ phaseDir = resolved;
59
+ }
60
+ // A VALUELESS `--context` stays a bare token in the positionals (sibling
61
+ // parser semantics); it must not then be read as the context PATH — a
62
+ // `--`-prefixed "path" is a caller mistake, and #2770's law says a missing
63
+ // context argument fails CLOSED, never a silent "CONTEXT.md missing" green
64
+ // skip. So only a non-flag positional may serve as the context.
65
+ const positionalContext = positionals[1] && !positionals[1].startsWith('--') ? positionals[1] : '';
66
+ const contextArg = flags['context'] ?? positionalContext ?? '';
67
+ let contextPath = '';
68
+ if (contextArg) {
69
+ const resolved = (0, gate_phase_context_cjs_1.resolveContainedPath)(contextArg, projectDir);
70
+ if ((0, gate_verdict_cjs_1.isGateUsageFailure)(resolved))
71
+ return resolved;
72
+ contextPath = resolved;
73
+ }
74
+ if (!(0, gate_config_cjs_1.isDecisionCoverageGateEnabled)(projectDir)) {
75
+ return (0, gate_verdict_cjs_1.gateVerdict)('skip', false, { passed: true, skipped: true, reason: 'workflow.context_coverage_gate is false', total: 0, covered: 0, uncovered: [], message: 'Decision coverage gate disabled by config.' });
76
+ }
77
+ // #2770: an EMPTY/MISSING contextPath argument is a CALLER ERROR (the workflow
78
+ // forgot to pass the path — e.g. a shell variable lost between Bash blocks), not
79
+ // evidence the phase has no CONTEXT.md. Fail closed (mirrors #1365 fail-loud) so a
80
+ // blocking gate cannot silently certify success on a caller mistake.
81
+ if (!contextArg || contextArg === '') {
82
+ return (0, gate_verdict_cjs_1.gateVerdict)('block', true, { passed: false, skipped: false, reason: 'missing context path argument', total: 0, covered: 0, uncovered: [], message: 'Decision coverage gate called without a context path argument — the caller (e.g. the plan-phase workflow) must pass the CONTEXT.md path. An empty argument is a caller error, not evidence there is nothing to check (#2770).' });
83
+ }
84
+ // One stat answers both questions (#5170): `none` (ENOENT/ENOTDIR) is a REAL path whose file
85
+ // genuinely does not exist — the LEGITIMATE green skip. `fs.existsSync` answered `false` for an
86
+ // EACCES on a parent too, certifying "nothing to check" over a CONTEXT.md the gate never saw.
87
+ const contextStat = (0, gate_evidence_cjs_1.statEvidence)(contextPath);
88
+ if (contextStat.kind === 'none') {
89
+ return contextMissingSkip();
90
+ }
91
+ // #4794: a NON-FILE path (a directory — the adjacent same-looking positional
92
+ // swapped, the issue's repro 2) is a caller error like #2770's empty argument:
93
+ // the read yields nothing, and the gate used to certify passed:true on a phase
94
+ // full of decisions. Fail closed, naming it. A stat failure other than "absent"
95
+ // answers the SAME fail-closed JSON (outcome `unreadable`), never a throw.
96
+ const contextIsFile = contextStat.kind === 'found' && contextStat.value.isFile();
97
+ if (!contextIsFile) {
98
+ const contextKind = contextStat.kind === 'found'
99
+ ? (contextStat.value.isDirectory() ? 'directory' : 'non-file entry')
100
+ : 'unreadable path';
101
+ const notAFile = { passed: false, skipped: false, reason: 'context path is not a file', total: null, covered: null, message: `Decision coverage gate: the context path "${contextArg}" is not a readable file (${contextKind}). Swap the adjacent positionals or pass --context <path-to-CONTEXT.md>.` };
102
+ // Fail-closed policy is unchanged (`block: true`); a path that could not even be examined is
103
+ // "could not look" (#5170), so its outcome is `unreadable` and the exit status follows it.
104
+ return contextStat.kind === 'unreadable' ? (0, gate_verdict_cjs_1.gateUnreadable)(true, notAFile) : (0, gate_verdict_cjs_1.gateVerdict)('block', true, notAFile);
105
+ }
106
+ const extracted = (0, decision_coverage_support_cjs_1.loadDecisionExtraction)(contextPath);
107
+ if (extracted.kind === 'unreadable')
108
+ return unreadableDecisionGate(`${extracted.span ?? contextPath}: ${extracted.reason}`);
109
+ if (extracted.kind === 'none') {
110
+ return contextMissingSkip();
111
+ }
112
+ const { trackable: decisions, outcome, unreadableIds } = extracted.value;
113
+ // #1365 fail-loud gate: any could-not-parse outcome must NOT silently pass —
114
+ // even when some decisions were extracted (e.g. D-01 valid but D-02 malformed).
115
+ // A parse-miss on ANY bullet means the gate cannot certify full coverage.
116
+ // Fire independent of decisions.length so a partial-parse still blocks.
117
+ if (outcome === 'could-not-parse') {
118
+ // #4794: nothing was measured — the answer must not carry the fields of a
119
+ // gate that did. total/covered are null (a type change is the point:
120
+ // 0 reads as data, null does not), `uncovered` is OMITTED (the list was
121
+ // never built), and the ids that failed to parse are carried so a caller
122
+ // capturing stdout knows which decision to fix.
123
+ const partialParse = decisions.length > 0;
124
+ return (0, gate_verdict_cjs_1.gateVerdict)('block', true, {
125
+ passed: false,
126
+ skipped: false,
127
+ reason: 'could-not-parse',
128
+ total: null,
129
+ covered: null,
130
+ unreadable: unreadableIds,
131
+ message: (partialParse
132
+ ? 'Decision coverage gate: decisions could not be fully parsed — one or more ' +
133
+ '`- **D-NN ...**` bullets appear malformed (missing `:` or ` — ` separator, or a phase ' +
134
+ 'prefix that is not a digit run, e.g. `D4x-01`). Fix the bullet format so all decisions ' +
135
+ 'can be read before re-running the gate.'
136
+ : 'Decision coverage gate: could not parse decisions — possible format mismatch. ' +
137
+ 'The CONTEXT.md appears to be decision-shaped (has a <decisions> block, a decisions heading, ' +
138
+ 'or D- tokens) but no decision bullets could be extracted. Check the formatting of the decisions ' +
139
+ 'block and ensure bullets follow the `- **D-NN:** text`, `- **D4-NN:** text` (phase-prefixed), ' +
140
+ 'or `- **D-NN — title** body` form. An ID grammar the parser does not support (e.g. `DEC-01`) ' +
141
+ 'also lands here.')
142
+ + (unreadableIds.length > 0 ? ' Unreadable ids: ' + unreadableIds.join(', ') + '.' : ''),
143
+ });
144
+ }
145
+ if (decisions.length === 0) {
146
+ return (0, gate_verdict_cjs_1.gateVerdict)('skip', false, { passed: true, skipped: true, reason: 'no trackable decisions', total: 0, covered: 0, uncovered: [], message: 'No trackable decisions in CONTEXT.md.' });
147
+ }
148
+ const planContents = (0, decision_coverage_support_cjs_1.loadPlanContents)(phaseDir);
149
+ if (planContents.kind === 'unreadable')
150
+ return unreadableDecisionGate(`${planContents.span ?? phaseDir}: ${planContents.reason}`);
151
+ const sections = planContents.value.map(decision_coverage_support_cjs_1.extractPlanDesignatedSections);
152
+ const uncovered = [];
153
+ let covered = 0;
154
+ for (const decision of decisions) {
155
+ if (sections.some((section) => (0, decision_coverage_support_cjs_1.decisionMentioned)(section, decision)))
156
+ covered++;
157
+ else
158
+ uncovered.push({ id: decision.id, text: decision.text, category: decision.category });
159
+ }
160
+ const passed = uncovered.length === 0;
161
+ return (0, gate_verdict_cjs_1.gateVerdict)(passed ? 'pass' : 'block', !passed, {
162
+ passed,
163
+ skipped: false,
164
+ total: decisions.length,
165
+ covered,
166
+ uncovered,
167
+ message: (0, decision_coverage_support_cjs_1.buildPlanMessage)(uncovered),
168
+ });
169
+ }