@opengsd/gsd-core 1.13.0 → 1.15.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 (441) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.ja-JP.md +3 -3
  4. package/README.ko-KR.md +3 -3
  5. package/README.pt-BR.md +3 -3
  6. package/README.zh-CN.md +3 -3
  7. package/agents/gsd-advisor-researcher.compact.md +85 -0
  8. package/agents/gsd-ai-researcher.compact.md +96 -0
  9. package/agents/gsd-assumptions-analyzer.compact.md +81 -0
  10. package/agents/gsd-code-fixer.compact.md +459 -0
  11. package/agents/gsd-code-fixer.md +9 -8
  12. package/agents/gsd-code-reviewer.compact.md +269 -0
  13. package/agents/gsd-code-reviewer.md +15 -3
  14. package/agents/gsd-codebase-mapper.compact.md +760 -0
  15. package/agents/gsd-debug-session-manager.compact.md +360 -0
  16. package/agents/gsd-debug-session-manager.md +17 -2
  17. package/agents/gsd-debugger.md +2 -2
  18. package/agents/gsd-doc-classifier.compact.md +192 -0
  19. package/agents/gsd-doc-synthesizer.compact.md +200 -0
  20. package/agents/gsd-doc-verifier.compact.md +143 -0
  21. package/agents/gsd-doc-writer.compact.md +440 -0
  22. package/agents/gsd-dom-verifier.compact.md +138 -0
  23. package/agents/gsd-domain-researcher.compact.md +141 -0
  24. package/agents/gsd-eval-auditor.compact.md +160 -0
  25. package/agents/gsd-eval-auditor.md +1 -1
  26. package/agents/gsd-eval-planner.compact.md +137 -0
  27. package/agents/gsd-executor.md +13 -8
  28. package/agents/gsd-framework-selector.compact.md +82 -0
  29. package/agents/gsd-integration-checker.compact.md +245 -0
  30. package/agents/gsd-intel-updater.compact.md +226 -0
  31. package/agents/gsd-intel-updater.md +1 -1
  32. package/agents/gsd-mempalace-curator.compact.md +45 -0
  33. package/agents/gsd-nyquist-auditor.compact.md +179 -0
  34. package/agents/gsd-pattern-mapper.compact.md +275 -0
  35. package/agents/gsd-phase-researcher.md +19 -11
  36. package/agents/gsd-plan-checker.md +8 -7
  37. package/agents/gsd-planner.md +12 -8
  38. package/agents/gsd-project-researcher.compact.md +587 -0
  39. package/agents/gsd-project-researcher.md +1 -1
  40. package/agents/gsd-research-synthesizer.compact.md +212 -0
  41. package/agents/gsd-research-synthesizer.md +1 -1
  42. package/agents/gsd-roadmapper.compact.md +454 -0
  43. package/agents/gsd-roadmapper.md +13 -0
  44. package/agents/gsd-security-auditor.compact.md +162 -0
  45. package/agents/gsd-ui-auditor.compact.md +404 -0
  46. package/agents/gsd-ui-auditor.md +155 -17
  47. package/agents/gsd-ui-checker.compact.md +277 -0
  48. package/agents/gsd-ui-researcher.compact.md +282 -0
  49. package/agents/gsd-ui-researcher.md +1 -1
  50. package/agents/gsd-user-profiler.compact.md +108 -0
  51. package/agents/gsd-verifier.md +10 -9
  52. package/bin/install.js +848 -163
  53. package/commands/gsd/autonomous.md +2 -2
  54. package/commands/gsd/capture.md +1 -1
  55. package/commands/gsd/cleanup.md +1 -0
  56. package/commands/gsd/code-review.md +2 -1
  57. package/commands/gsd/complete-milestone.md +1 -0
  58. package/commands/gsd/config.md +1 -0
  59. package/commands/gsd/debug.md +1 -0
  60. package/commands/gsd/graphify.md +1 -0
  61. package/commands/gsd/health.md +1 -0
  62. package/commands/gsd/mempalace-capture.md +8 -3
  63. package/commands/gsd/mempalace-recall.md +1 -0
  64. package/commands/gsd/new-milestone.md +1 -0
  65. package/commands/gsd/new-project.md +1 -0
  66. package/commands/gsd/next.md +1 -0
  67. package/commands/gsd/pause-work.md +1 -0
  68. package/commands/gsd/phase.md +1 -0
  69. package/commands/gsd/plan-review-convergence.md +6 -6
  70. package/commands/gsd/pr-branch.md +1 -0
  71. package/commands/gsd/progress.md +1 -1
  72. package/commands/gsd/quick-batch.md +1 -1
  73. package/commands/gsd/resume-work.md +1 -0
  74. package/commands/gsd/review-backlog.md +1 -0
  75. package/commands/gsd/review.md +2 -3
  76. package/commands/gsd/settings.md +2 -1
  77. package/commands/gsd/stats.md +1 -0
  78. package/commands/gsd/thread.md +1 -0
  79. package/commands/gsd/workspace.md +1 -0
  80. package/commands/gsd/workstreams.md +1 -0
  81. package/gsd-core/bin/check-latest-version.cjs +8 -3
  82. package/gsd-core/bin/gsd-tools.cjs +672 -146
  83. package/gsd-core/bin/lib/adr-parser.cjs +4 -2
  84. package/gsd-core/bin/lib/artifacts.cjs +2 -1
  85. package/gsd-core/bin/lib/audit.cjs +119 -34
  86. package/gsd-core/bin/lib/broken-windows.cjs +168 -49
  87. package/gsd-core/bin/lib/capability-lifecycle.cjs +10 -6
  88. package/gsd-core/bin/lib/capability-loader.cjs +135 -1
  89. package/gsd-core/bin/lib/capability-registry.cjs +96 -189
  90. package/gsd-core/bin/lib/capability-source.cjs +19 -2
  91. package/gsd-core/bin/lib/capability-validator.cjs +14 -2
  92. package/gsd-core/bin/lib/check-command-router.cjs +213 -49
  93. package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
  94. package/gsd-core/bin/lib/codex-agent-toml.cjs +21 -25
  95. package/gsd-core/bin/lib/commands.cjs +823 -112
  96. package/gsd-core/bin/lib/config-loader.cjs +66 -4
  97. package/gsd-core/bin/lib/config.cjs +186 -45
  98. package/gsd-core/bin/lib/coverage.cjs +1 -1
  99. package/gsd-core/bin/lib/decisions.cjs +164 -45
  100. package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
  101. package/gsd-core/bin/lib/frontmatter.cjs +13 -0
  102. package/gsd-core/bin/lib/graphify.cjs +10 -2
  103. package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
  104. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +12 -1
  105. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
  106. package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
  107. package/gsd-core/bin/lib/init.cjs +614 -86
  108. package/gsd-core/bin/lib/install-engine.cjs +29 -3
  109. package/gsd-core/bin/lib/install-profiles.cjs +14 -0
  110. package/gsd-core/bin/lib/installer-migrations.cjs +41 -5
  111. package/gsd-core/bin/lib/loop-resolver.cjs +50 -31
  112. package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
  113. package/gsd-core/bin/lib/milestone.cjs +37 -13
  114. package/gsd-core/bin/lib/model-resolver.cjs +253 -53
  115. package/gsd-core/bin/lib/phase-command-router.cjs +16 -2
  116. package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
  117. package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
  118. package/gsd-core/bin/lib/phase-id.cjs +268 -27
  119. package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
  120. package/gsd-core/bin/lib/phase-locator.cjs +29 -10
  121. package/gsd-core/bin/lib/phase.cjs +393 -88
  122. package/gsd-core/bin/lib/plan-document.cjs +49 -1
  123. package/gsd-core/bin/lib/planning-document.cjs +459 -0
  124. package/gsd-core/bin/lib/planning-inspect.cjs +52 -19
  125. package/gsd-core/bin/lib/planning-snapshot.cjs +61 -12
  126. package/gsd-core/bin/lib/planning-workspace.cjs +57 -3
  127. package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
  128. package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
  129. package/gsd-core/bin/lib/probe-core.cjs +7 -1
  130. package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
  131. package/gsd-core/bin/lib/project-root.cjs +41 -2
  132. package/gsd-core/bin/lib/quick-batch.cjs +1 -1
  133. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +61 -2
  134. package/gsd-core/bin/lib/research-store.cjs +11 -12
  135. package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
  136. package/gsd-core/bin/lib/review-lane-invocation.cjs +23 -0
  137. package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
  138. package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
  139. package/gsd-core/bin/lib/roadmap-command-router.cjs +12 -4
  140. package/gsd-core/bin/lib/roadmap-parser.cjs +219 -18
  141. package/gsd-core/bin/lib/roadmap-upgrade.cjs +1539 -13
  142. package/gsd-core/bin/lib/roadmap.cjs +356 -42
  143. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +310 -41
  144. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +15 -4
  145. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +13 -5
  146. package/gsd-core/bin/lib/runtime-homes.cjs +4 -0
  147. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +408 -37
  148. package/gsd-core/bin/lib/runtime-name-policy.cjs +111 -1
  149. package/gsd-core/bin/lib/security.cjs +126 -7
  150. package/gsd-core/bin/lib/shell-command-projection.cjs +10 -6
  151. package/gsd-core/bin/lib/state-document.cjs +130 -28
  152. package/gsd-core/bin/lib/state-md-schema.cjs +21 -14
  153. package/gsd-core/bin/lib/state-transition.cjs +181 -30
  154. package/gsd-core/bin/lib/state.cjs +265 -27
  155. package/gsd-core/bin/lib/surface.cjs +77 -3
  156. package/gsd-core/bin/lib/task-command-router.cjs +12 -6
  157. package/gsd-core/bin/lib/tdd-red-evidence.cjs +78 -5
  158. package/gsd-core/bin/lib/uat-predicate.cjs +47 -4
  159. package/gsd-core/bin/lib/uat.cjs +9 -1
  160. package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
  161. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +100 -9
  162. package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
  163. package/gsd-core/bin/lib/update-context.cjs +30 -24
  164. package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
  165. package/gsd-core/bin/lib/verification.cjs +315 -30
  166. package/gsd-core/bin/lib/verify-command-grounding.cjs +47 -3
  167. package/gsd-core/bin/lib/verify.cjs +320 -48
  168. package/gsd-core/bin/lib/workstream-inventory.cjs +1 -0
  169. package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
  170. package/gsd-core/bin/lib/worktree-safety.cjs +797 -58
  171. package/gsd-core/bin/shared/config-defaults.manifest.json +4 -0
  172. package/gsd-core/bin/shared/config-schema.manifest.json +6 -0
  173. package/gsd-core/bin/verify-reapply-patches.cjs +439 -80
  174. package/gsd-core/references/checkpoints.md +5 -3
  175. package/gsd-core/references/compact-content-gate.md +66 -0
  176. package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
  177. package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
  178. package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
  179. package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
  180. package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
  181. package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
  182. package/gsd-core/references/edge-probe.md +195 -21
  183. package/gsd-core/references/execute-phase-between-wave-reset.md +7 -6
  184. package/gsd-core/references/execute-phase-wave-guard.md +22 -11
  185. package/gsd-core/references/gsd-run-resolver.md +1 -1
  186. package/gsd-core/references/loop-hook-dispatch.md +18 -0
  187. package/gsd-core/references/model-profiles.md +13 -4
  188. package/gsd-core/references/phase-argument-parsing.md +9 -7
  189. package/gsd-core/references/phase-id-convention.md +28 -0
  190. package/gsd-core/references/planner-gap-closure.md +2 -0
  191. package/gsd-core/references/planner-load-graph-context.md +24 -13
  192. package/gsd-core/references/planner-verify-command-grounding.md +14 -0
  193. package/gsd-core/references/planning-config.md +14 -2
  194. package/gsd-core/references/tdd.md +30 -4
  195. package/gsd-core/references/thinking-models-planning.md +18 -2
  196. package/gsd-core/references/ui-consideration-probe.md +10 -5
  197. package/gsd-core/references/verification-patterns.md +17 -4
  198. package/gsd-core/references/verify-command-path-resolvability.md +10 -2
  199. package/gsd-core/references/worktree-path-safety.md +433 -2
  200. package/gsd-core/templates/README.md +7 -1
  201. package/gsd-core/templates/state.md +6 -3
  202. package/gsd-core/templates/summary.compact.md +212 -0
  203. package/gsd-core/templates/user-setup.compact.md +199 -0
  204. package/gsd-core/templates/user-setup.md +0 -9
  205. package/gsd-core/templates/verification-report.md +1 -1
  206. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  207. package/gsd-core/workflows/add-backlog.md +1 -1
  208. package/gsd-core/workflows/add-phase.md +1 -1
  209. package/gsd-core/workflows/add-tests.md +2 -2
  210. package/gsd-core/workflows/add-todo.md +6 -5
  211. package/gsd-core/workflows/ai-integration-phase.md +11 -3
  212. package/gsd-core/workflows/audit-fix.md +1 -1
  213. package/gsd-core/workflows/audit-milestone.md +1 -1
  214. package/gsd-core/workflows/audit-uat.md +1 -1
  215. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
  216. package/gsd-core/workflows/autonomous.md +29 -16
  217. package/gsd-core/workflows/check-todos.md +6 -4
  218. package/gsd-core/workflows/cleanup.md +5 -3
  219. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
  220. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +8 -1
  221. package/gsd-core/workflows/code-review-fix.md +108 -22
  222. package/gsd-core/workflows/code-review.md +216 -73
  223. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
  224. package/gsd-core/workflows/complete-milestone.md +41 -264
  225. package/gsd-core/workflows/debug.md +3 -3
  226. package/gsd-core/workflows/diagnose-issues.md +1 -1
  227. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  228. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  229. package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
  230. package/gsd-core/workflows/discuss-phase.md +1 -1
  231. package/gsd-core/workflows/do.md +2 -2
  232. package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
  233. package/gsd-core/workflows/docs-update.md +17 -158
  234. package/gsd-core/workflows/edit-phase.md +1 -1
  235. package/gsd-core/workflows/eval-review.md +10 -3
  236. package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
  237. package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1017 -0
  238. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +19 -4
  239. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
  240. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +43 -4
  241. package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
  242. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  243. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  244. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  245. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
  246. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
  247. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
  248. package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
  249. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
  250. package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
  251. package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +24 -0
  252. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
  253. package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
  254. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +1 -1
  255. package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
  256. package/gsd-core/workflows/execute-phase.md +83 -172
  257. package/gsd-core/workflows/execute-plan.md +24 -10
  258. package/gsd-core/workflows/explore.md +3 -3
  259. package/gsd-core/workflows/extract-learnings.md +2 -1
  260. package/gsd-core/workflows/fast.md +1 -1
  261. package/gsd-core/workflows/forensics.md +1 -1
  262. package/gsd-core/workflows/graduation.md +1 -1
  263. package/gsd-core/workflows/health.md +2 -2
  264. package/gsd-core/workflows/help/modes/full.compact.md +398 -0
  265. package/gsd-core/workflows/help/modes/full.md +5 -5
  266. package/gsd-core/workflows/help/modes/topic.md +15 -5
  267. package/gsd-core/workflows/help.md +1 -1
  268. package/gsd-core/workflows/import.md +2 -2
  269. package/gsd-core/workflows/inbox.md +2 -2
  270. package/gsd-core/workflows/ingest-docs.md +3 -3
  271. package/gsd-core/workflows/insert-phase.md +1 -1
  272. package/gsd-core/workflows/list-seeds.md +1 -1
  273. package/gsd-core/workflows/list-workspaces.md +1 -1
  274. package/gsd-core/workflows/manager.md +2 -2
  275. package/gsd-core/workflows/map-codebase.md +52 -5
  276. package/gsd-core/workflows/milestone-summary.md +1 -1
  277. package/gsd-core/workflows/mvp-phase.md +1 -1
  278. package/gsd-core/workflows/new-milestone.md +56 -14
  279. package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
  280. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
  281. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
  282. package/gsd-core/workflows/new-project.md +39 -209
  283. package/gsd-core/workflows/new-workspace.md +2 -2
  284. package/gsd-core/workflows/next.md +1 -1
  285. package/gsd-core/workflows/note.md +1 -1
  286. package/gsd-core/workflows/onboard.md +1 -1
  287. package/gsd-core/workflows/pause-work.md +1 -1
  288. package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
  289. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
  290. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  291. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
  292. package/gsd-core/workflows/plan-phase.md +45 -187
  293. package/gsd-core/workflows/plan-review-convergence.md +21 -5
  294. package/gsd-core/workflows/plant-seed.md +62 -20
  295. package/gsd-core/workflows/pr-branch.md +132 -20
  296. package/gsd-core/workflows/profile-user.md +2 -2
  297. package/gsd-core/workflows/progress.md +1 -1
  298. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +25 -0
  299. package/gsd-core/workflows/quick/steps/quick-verification.md +1 -1
  300. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +1 -1
  301. package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
  302. package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
  303. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
  304. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
  305. package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
  306. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
  307. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +1 -1
  308. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
  309. package/gsd-core/workflows/quick-batch.md +1 -1
  310. package/gsd-core/workflows/quick.md +29 -10
  311. package/gsd-core/workflows/reapply-patches.md +86 -6
  312. package/gsd-core/workflows/remove-phase.md +1 -1
  313. package/gsd-core/workflows/remove-workspace.md +2 -2
  314. package/gsd-core/workflows/resume-project.md +1 -1
  315. package/gsd-core/workflows/review.md +31 -16
  316. package/gsd-core/workflows/scan.md +1 -1
  317. package/gsd-core/workflows/secure-phase.md +3 -2
  318. package/gsd-core/workflows/settings-advanced.md +30 -10
  319. package/gsd-core/workflows/settings-integrations.md +2 -3
  320. package/gsd-core/workflows/settings.md +22 -9
  321. package/gsd-core/workflows/ship.md +3 -2
  322. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  323. package/gsd-core/workflows/sketch.md +1 -1
  324. package/gsd-core/workflows/smart-entry.md +2 -2
  325. package/gsd-core/workflows/spec-phase.md +15 -5
  326. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  327. package/gsd-core/workflows/spike.md +1 -1
  328. package/gsd-core/workflows/stats.md +1 -1
  329. package/gsd-core/workflows/sync-skills.md +5 -5
  330. package/gsd-core/workflows/thread.md +1 -1
  331. package/gsd-core/workflows/transition.md +1 -1
  332. package/gsd-core/workflows/ui-phase.md +44 -8
  333. package/gsd-core/workflows/ui-review.md +18 -4
  334. package/gsd-core/workflows/ultraplan-phase.md +1 -1
  335. package/gsd-core/workflows/undo.md +339 -20
  336. package/gsd-core/workflows/update.md +14 -12
  337. package/gsd-core/workflows/validate-phase.md +3 -2
  338. package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
  339. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
  340. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  341. package/gsd-core/workflows/verify-work.md +101 -196
  342. package/hooks/dist/gsd-agent-isolation-guard.js +66 -16
  343. package/hooks/dist/gsd-context-monitor.js +88 -15
  344. package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
  345. package/hooks/dist/gsd-secret-read-guard.js +71 -19
  346. package/hooks/dist/gsd-statusline.js +81 -20
  347. package/hooks/dist/gsd-validate-commit.sh +97 -8
  348. package/hooks/dist/gsd-worktree-path-guard.js +25 -14
  349. package/hooks/dist/gsd-write-guard.js +46 -1
  350. package/hooks/dist/lib/dispatch-identity.js +187 -0
  351. package/hooks/dist/lib/filename-classification.js +64 -0
  352. package/hooks/dist/lib/isolation-deny-reason.js +53 -1
  353. package/hooks/dist/lib/isolation-sentinel.js +58 -19
  354. package/hooks/gsd-agent-isolation-guard.js +66 -16
  355. package/hooks/gsd-context-monitor.js +88 -15
  356. package/hooks/gsd-cursor-subagent-start.js +34 -14
  357. package/hooks/gsd-secret-read-guard.js +71 -19
  358. package/hooks/gsd-statusline.js +81 -20
  359. package/hooks/gsd-validate-commit.sh +97 -8
  360. package/hooks/gsd-worktree-path-guard.js +25 -14
  361. package/hooks/gsd-write-guard.js +46 -1
  362. package/hooks/lib/dispatch-identity.js +187 -0
  363. package/hooks/lib/filename-classification.js +64 -0
  364. package/hooks/lib/isolation-deny-reason.js +53 -1
  365. package/hooks/lib/isolation-sentinel.js +58 -19
  366. package/package.json +11 -6
  367. package/scripts/benchmark-compact-content-variants.cjs +298 -0
  368. package/scripts/benchmark-compact-content.cjs +368 -0
  369. package/scripts/build-hooks.js +15 -6
  370. package/scripts/check-contract-drift.cjs +131 -12
  371. package/scripts/check-env.cjs +36 -8
  372. package/scripts/check-glossary-refs.cjs +25 -21
  373. package/scripts/ci-next-health.cjs +271 -0
  374. package/scripts/ci-prepare-test-scope.cjs +7 -7
  375. package/scripts/ci-test-scope.cjs +126 -20
  376. package/scripts/ci-timeout-report.cjs +1 -1
  377. package/scripts/command-contract-helpers.cjs +3 -0
  378. package/scripts/diff-touches-shipped-paths.cjs +1 -1
  379. package/scripts/docs-guard-registry.cjs +35 -2
  380. package/scripts/gen-adr-index.cjs +8 -2
  381. package/scripts/gen-inventory-manifest.cjs +12 -0
  382. package/scripts/gen-loop-host-contract.cjs +69 -0
  383. package/scripts/gen-platform-conformance-tier.cjs +557 -0
  384. package/scripts/lib/drift-scan.cjs +1 -1
  385. package/scripts/lib/macos-conformance-tier.generated.cjs +224 -0
  386. package/scripts/lib/ndjson-reporter.cjs +3 -2
  387. package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
  388. package/scripts/lib/platform-conformance-tier.generated.cjs +287 -0
  389. package/scripts/lib/suite-detection.cjs +32 -0
  390. package/scripts/lint-allowed-tools-parity.cjs +221 -0
  391. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +47 -3
  392. package/scripts/lint-phase-arg-assignment.cjs +257 -0
  393. package/scripts/lint-phase-id-drift.cjs +623 -13
  394. package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
  395. package/scripts/lint-response-language-coverage.cjs +9 -3
  396. package/scripts/lint-retired-runtime-name.cjs +619 -0
  397. package/scripts/lint-source-test-name-collision.cjs +1 -1
  398. package/scripts/lint-state-write-path-drift.cjs +93 -0
  399. package/scripts/lint-test-file-count.allowlist.json +29 -9
  400. package/scripts/lint-vendored-deps.cjs +128 -17
  401. package/scripts/lint-workflow-shellcheck-baseline.json +100 -0
  402. package/scripts/prompt-injection-scan.sh +18 -0
  403. package/scripts/release-tarball-smoke.cjs +194 -1
  404. package/scripts/workflow-size.cjs +139 -0
  405. package/skills/gsd-autonomous/SKILL.md +2 -2
  406. package/skills/gsd-capture/SKILL.md +1 -1
  407. package/skills/gsd-cleanup/SKILL.md +1 -0
  408. package/skills/gsd-code-review/SKILL.md +2 -1
  409. package/skills/gsd-complete-milestone/SKILL.md +1 -0
  410. package/skills/gsd-config/SKILL.md +1 -0
  411. package/skills/gsd-debug/SKILL.md +1 -0
  412. package/skills/gsd-graphify/SKILL.md +1 -0
  413. package/skills/gsd-health/SKILL.md +1 -0
  414. package/skills/gsd-mempalace-capture/SKILL.md +8 -3
  415. package/skills/gsd-mempalace-recall/SKILL.md +1 -0
  416. package/skills/gsd-new-milestone/SKILL.md +1 -0
  417. package/skills/gsd-new-project/SKILL.md +1 -0
  418. package/skills/gsd-next/SKILL.md +1 -0
  419. package/skills/gsd-pause-work/SKILL.md +1 -0
  420. package/skills/gsd-phase/SKILL.md +1 -0
  421. package/skills/gsd-plan-review-convergence/SKILL.md +5 -5
  422. package/skills/gsd-pr-branch/SKILL.md +1 -0
  423. package/skills/gsd-progress/SKILL.md +1 -1
  424. package/skills/gsd-quick-batch/SKILL.md +1 -1
  425. package/skills/gsd-resume-work/SKILL.md +1 -0
  426. package/skills/gsd-review/SKILL.md +2 -3
  427. package/skills/gsd-review-backlog/SKILL.md +1 -0
  428. package/skills/gsd-settings/SKILL.md +2 -1
  429. package/skills/gsd-stats/SKILL.md +1 -0
  430. package/skills/gsd-thread/SKILL.md +1 -0
  431. package/skills/gsd-workspace/SKILL.md +1 -0
  432. package/skills/gsd-workstreams/SKILL.md +1 -0
  433. package/vscode/package.json +1 -1
  434. package/gsd-core/templates/claude-md.md +0 -145
  435. package/gsd-core/templates/codebase/concerns.md +0 -310
  436. package/gsd-core/templates/codebase/conventions.md +0 -307
  437. package/gsd-core/templates/codebase/integrations.md +0 -280
  438. package/gsd-core/templates/codebase/structure.md +0 -285
  439. package/gsd-core/templates/codebase/testing.md +0 -480
  440. package/gsd-core/templates/debug-subagent-prompt.md +0 -91
  441. package/gsd-core/templates/discovery.md +0 -146
@@ -4,9 +4,9 @@
4
4
  // Shell-agnostic: invoked as `node scripts/ci-prepare-test-scope.cjs` from any shell.
5
5
  //
6
6
  // Required environment variables (set by the workflow step's `env:` block):
7
- // TEST_SCOPE — "windows" | "targeted"
7
+ // TEST_SCOPE — "targeted" (the `windows` scope was retired by #4641:
8
+ // test-conformance is now the sole Windows selector)
8
9
  // TARGETED_TESTS — space-separated test file list (from ci-test-scope.cjs output)
9
- // WINDOWS_TESTS — space-separated test file list for the windows lane
10
10
  //
11
11
  // Writes: .ci-selected-tests.txt (one file per line, no blanks)
12
12
  // Exit 0 = success; exit 1 = unknown scope.
@@ -46,13 +46,14 @@ function isResolvable(entry, root) {
46
46
 
47
47
  // Resolve the scoped test selection for the lane. Pure (no I/O beyond the
48
48
  // existence probe under `root`) so it can be unit-tested directly.
49
- function resolveSelection({ scope, targeted, windows, root }) {
49
+ function resolveSelection({ scope, targeted, root }) {
50
50
  let selected;
51
- if (scope === 'windows') {
52
- selected = windows;
53
- } else if (scope === 'targeted') {
51
+ if (scope === 'targeted') {
54
52
  selected = targeted;
55
53
  } else {
54
+ // #4641: the `windows` scope was retired (test-conformance is now the
55
+ // sole Windows selector) — an unknown/retired scope must fail loudly
56
+ // rather than silently selecting nothing.
56
57
  throw new ExitError(1, `::error::Unknown test scope: ${scope}`);
57
58
  }
58
59
 
@@ -75,7 +76,6 @@ function main() {
75
76
  const lines = resolveSelection({
76
77
  scope: process.env.TEST_SCOPE || '',
77
78
  targeted: process.env.TARGETED_TESTS || '',
78
- windows: process.env.WINDOWS_TESTS || '',
79
79
  root,
80
80
  });
81
81
 
@@ -3,9 +3,10 @@
3
3
 
4
4
  const path = require('path');
5
5
  const { execFileSync } = require('child_process');
6
- const { existsSync, readdirSync, appendFileSync } = require('fs');
6
+ const { existsSync, readdirSync, appendFileSync, readFileSync } = require('fs');
7
7
 
8
8
  const { ExitError, runMain } = require('./lib/cli-exit.cjs');
9
+ const { classifyContent, NOISY_FOR_SOURCE_REACHABILITY } = require('./gen-platform-conformance-tier.cjs');
9
10
 
10
11
  // Workflow files that are purely administrative / policy bots. Changes to these
11
12
  // files do NOT require the cross-platform test matrix — only a lightweight
@@ -484,12 +485,68 @@ function addAll(set, values) {
484
485
  // fullMatrix=true, so the full Windows lane already runs when those paths
485
486
  // change. The old six-hint list pulled 102 of ~633 test files into the scoped
486
487
  // windows lane, turning it into a ~10-minute job on every PR.
488
+ // #4641: the scoped windows lane itself is gone. These hints now drive
489
+ // full_matrix instead — a matched RULE whose tests[] includes a
490
+ // windows-hint filename AND that hinted file is itself in the conformance
491
+ // tier (per reachesConformanceTierOrSeam) escalates straight to full_matrix
492
+ // (routed to test-conformance, the sole Windows selector) rather than
493
+ // feeding a side lane. Tier-backed on purpose: full_matrix only ever runs
494
+ // CONFORMANCE_TIER_FILES, so a hint on a non-tier file would cost 4 CI jobs
495
+ // with zero Windows coverage of that file. See
496
+ // docs/adr/4641-windows-selector-consolidation.md.
487
497
  const WINDOWS_HINTS = ['windows', 'win32', 'shell', 'path'];
488
498
  const isWindowsHint = s => WINDOWS_HINTS.some(k => s.toLowerCase().includes(k));
489
499
 
490
- function classify(files) {
500
+ // A change to the classification mechanism itself cannot be presumed safe by
501
+ // the very mechanism being changed (#4592).
502
+ const CLASSIFIER_DEFINITION_FILES = new Set([
503
+ 'scripts/gen-platform-conformance-tier.cjs',
504
+ 'scripts/lib/platform-conformance-tier.generated.cjs',
505
+ 'scripts/lib/suite-detection.cjs',
506
+ ]);
507
+
508
+ /**
509
+ * Does `file`'s blast radius reach (a) Phase 2's conformance-tier test-file
510
+ * list or (b) a live platform-conditional signal in src/? Fail-safe: any
511
+ * thrown error (a require failure, a readFileSync failure, a malformed
512
+ * generated module, etc.) is treated as uncertainty and returns true — per
513
+ * #4592's explicit "fail-safe to full_matrix=true on any reachability-
514
+ * computation error or uncertainty" requirement.
515
+ * `loadConformanceTier` is injectable (defaults to the real generated module)
516
+ * solely so tests can simulate a load failure without touching the real,
517
+ * committed generated file.
518
+ * @param {string} file
519
+ * @param {{loadConformanceTier?: () => {CONFORMANCE_TIER_FILES: string[]}}} [deps]
520
+ * @returns {boolean}
521
+ */
522
+ function reachesConformanceTierOrSeam(file, deps = {}) {
523
+ const loadConformanceTier =
524
+ deps.loadConformanceTier || (() => require('./lib/platform-conformance-tier.generated.cjs'));
525
+ try {
526
+ if (file.startsWith('tests/') && file.endsWith('.test.cjs')) {
527
+ const { CONFORMANCE_TIER_FILES } = loadConformanceTier();
528
+ return CONFORMANCE_TIER_FILES.includes(file);
529
+ }
530
+
531
+ if (file.startsWith('src/')) {
532
+ const content = readFileSync(file, 'utf8');
533
+ const { signals } = classifyContent(content);
534
+ const narrowSignals = signals.filter(signal => !NOISY_FOR_SOURCE_REACHABILITY.has(signal));
535
+ return narrowSignals.length > 0;
536
+ }
537
+
538
+ return false;
539
+ } catch {
540
+ return true;
541
+ }
542
+ }
543
+
544
+ // `reachabilityDeps` is injectable (defaults to {}, which makes
545
+ // reachesConformanceTierOrSeam use the real generated module) solely so
546
+ // tests can simulate a reachability-computation failure without touching
547
+ // the real, committed generated file.
548
+ function classify(files, reachabilityDeps = {}) {
491
549
  const targeted = new Set();
492
- const windows = new Set();
493
550
  const reasons = [];
494
551
  let productOrPipelineChanged = false; // product/pipeline code (excludes docs)
495
552
  let inertCiChanged = false; // inert workflow files
@@ -526,15 +583,35 @@ function classify(files) {
526
583
 
527
584
  if (file.startsWith('tests/') && file.endsWith('.test.cjs')) {
528
585
  targeted.add(file);
529
- // #494 invariant, narrowed: a changed test must still be exercised on
530
- // the divergent OS before merge, but at per-file cost — it ALWAYS joins
531
- // the scoped windows lane instead of triggering the three full parity
532
- // lanes. (full_matrix fired on 15/15 sampled PRs because test-driven
533
- // PRs always touch tests/, costing ~25 runner-minutes each.) Changed
534
- // tests already run on the two ubuntu-24 lanes via targeted_tests; the
535
- // residual macOS / windows cross-product is covered by the full
536
- // matrix on every push to next.
537
- windows.add(file);
586
+ // #494 originally narrowed this to skip full_matrix for changed test
587
+ // files, on the theory that ubuntu targeted_tests + the scoped windows
588
+ // lane already covered them. Rescinded per #4421: PR #4384 landed a
589
+ // macOS-only regression on 2026-09-06 that stayed invisible pre-merge
590
+ // precisely because this carve-out suppressed the only macOS signal.
591
+ // #4592: the blanket rule is replaced with a reachability check — only
592
+ // a changed test file that actually reaches Phase 2's conformance-tier
593
+ // list (or is the classification mechanism itself) forces full_matrix.
594
+ if (reachesConformanceTierOrSeam(file, reachabilityDeps)) {
595
+ fullMatrix = true;
596
+ reasons.push(`${file}: conformance-tier reachability`);
597
+ }
598
+ }
599
+
600
+ // #4592: a src/-only diff (no test file touched) must still be able to
601
+ // set full_matrix=true when it carries a live platform-conditional
602
+ // signal — this is independent of the tests/ branch above.
603
+ if (file.startsWith('src/') && reachesConformanceTierOrSeam(file, reachabilityDeps)) {
604
+ fullMatrix = true;
605
+ reasons.push(`${file}: platform seam reachability`);
606
+ }
607
+
608
+ // #4592: a changed file that IS the classification mechanism itself
609
+ // (neither under tests/ nor src/, so neither branch above reaches it)
610
+ // must also force full_matrix — a change to the mechanism cannot be
611
+ // presumed safe by the very mechanism being changed.
612
+ if (CLASSIFIER_DEFINITION_FILES.has(file)) {
613
+ fullMatrix = true;
614
+ reasons.push(`${file}: reachability classifier definition changed`);
538
615
  }
539
616
 
540
617
  for (const rule of RULES) {
@@ -542,6 +619,32 @@ function classify(files) {
542
619
  addAll(targeted, rule.tests);
543
620
  reasons.push(`${file}: ${rule.name}`);
544
621
  if (rule.fullMatrix) fullMatrix = true;
622
+ // #4641: a rule that pulls in a test file matching a Windows-sensitive
623
+ // filename hint is the one non-redundant residue of the deleted
624
+ // scoped windows lane — escalate to full_matrix (test-conformance)
625
+ // instead of feeding a side lane. TIER-BACKED (measured): full_matrix
626
+ // routes to test-conformance, which runs ONLY CONFORMANCE_TIER_FILES —
627
+ // escalating on the filename hint alone can fire on a hinted test that
628
+ // isn't in that tier, costing 4 CI jobs while never actually running it
629
+ // on Windows. The predicate below requires BOTH the hint AND tier
630
+ // membership (via reachesConformanceTierOrSeam, the same fail-safe
631
+ // reachability helper used elsewhere in this file, so error/uncertainty
632
+ // behavior stays identical). Measured: over the 16 RULES entries this
633
+ // narrowed form fires on the same rules as the un-narrowed form today
634
+ // (no behavior change now, correct-by-construction going forward). The
635
+ // broader alternative — escalate on ANY tier member a rule pulls in,
636
+ // ignoring the filename hint — was measured and rejected: it fires on
637
+ // 14 of 16 rules, newly escalating most ordinary product-code PRs
638
+ // (src/, agents/, commands/, hooks/, skills/, config paths). Only one
639
+ // rule's escalation is live today: 'portability lint rules (ADR-1703)'.
640
+ // Four others already had fullMatrix: true (no-op here), and 'inert
641
+ // CI''s escalation is overridden downstream by the inert-CI reset.
642
+ // Distinct, greppable reason so the conformance-lane coverage for it
643
+ // is traceable per rule.
644
+ if (rule.tests.some(t => isWindowsHint(t) && reachesConformanceTierOrSeam(t, reachabilityDeps))) {
645
+ fullMatrix = true;
646
+ reasons.push(`${file}: ${rule.name} (windows-hint rule test, #4641)`);
647
+ }
545
648
  }
546
649
  }
547
650
  }
@@ -555,7 +658,7 @@ function classify(files) {
555
658
  // covered by .github/workflows/install-smoke.yml
556
659
  'tests/release-tarball-smoke.install.test.cjs',
557
660
  ]);
558
- for (const f of SCOPED_LANE_EXCLUDE) { targeted.delete(f); windows.delete(f); }
661
+ for (const f of SCOPED_LANE_EXCLUDE) { targeted.delete(f); }
559
662
 
560
663
  // code_changed: true when product/pipeline OR inert CI changed.
561
664
  // Docs-only PRs (neither flag set) get code_changed=false → full matrix skip.
@@ -569,8 +672,6 @@ function classify(files) {
569
672
  targetedTests.push('unit');
570
673
  }
571
674
 
572
- const windowsTests = existingTests([...new Set([...windows, ...targetedTests.filter(isWindowsHint)])].sort());
573
-
574
675
  // Inert-CI-only: full_matrix must be false (override any RULES that fired).
575
676
  if (inertCiChanged && !productOrPipelineChanged) {
576
677
  fullMatrix = false;
@@ -579,12 +680,11 @@ function classify(files) {
579
680
  // Normalize: when code_changed is false, the output must be self-consistent.
580
681
  // A docs file can coincidentally match a coarse content RULE (e.g. docs/installer-migrations.md
581
682
  // matches the installer rule via path.includes('install')), leaving full_matrix=true and
582
- // non-empty targeted_tests/windows_tests. The workflow skips correctly (gated on code_changed)
683
+ // non-empty targeted_tests. The workflow skips correctly (gated on code_changed)
583
684
  // but the output object would be self-contradictory. Force a clean "nothing to run" result.
584
685
  if (!codeChanged) {
585
686
  fullMatrix = false;
586
687
  targetedTests.length = 0;
587
- windowsTests.length = 0;
588
688
  }
589
689
 
590
690
  return {
@@ -592,7 +692,6 @@ function classify(files) {
592
692
  product_changed: productOrPipelineChanged,
593
693
  full_matrix: fullMatrix,
594
694
  targeted_tests: targetedTests,
595
- windows_tests: windowsTests,
596
695
  reasons: [...new Set(reasons)].sort(),
597
696
  };
598
697
  }
@@ -604,7 +703,6 @@ function writeOutputs(result) {
604
703
  `product_changed=${result.product_changed}`,
605
704
  `full_matrix=${result.full_matrix}`,
606
705
  `targeted_tests=${result.targeted_tests.join(' ')}`,
607
- `windows_tests=${result.windows_tests.join(' ')}`,
608
706
  ];
609
707
  appendFileSync(process.env.GITHUB_OUTPUT, `${lines.join('\n')}\n`);
610
708
  }
@@ -630,4 +728,12 @@ if (require.main === module) {
630
728
  runMain(main);
631
729
  }
632
730
 
633
- module.exports = { RULES, missingRuleTestFiles, PROTECTED_WORKFLOWS, INERT_WORKFLOWS, missingProtectedWorkflows };
731
+ module.exports = {
732
+ RULES,
733
+ missingRuleTestFiles,
734
+ PROTECTED_WORKFLOWS,
735
+ INERT_WORKFLOWS,
736
+ missingProtectedWorkflows,
737
+ classify,
738
+ reachesConformanceTierOrSeam,
739
+ };
@@ -33,8 +33,8 @@ const WORKFLOWS_DIR = path.join(__dirname, '..', '.github', 'workflows');
33
33
  const JOB_RULES = [
34
34
  { workflowFile: 'test.yml', jobKey: 'test-inert', test: (name) => name === 'test (inert CI)' },
35
35
  { workflowFile: 'test.yml', jobKey: 'test', test: (name) => name.startsWith('test (') && name !== 'test (inert CI)' },
36
- { workflowFile: 'test.yml', jobKey: 'test-full', test: (name) => name.startsWith('full test (') },
37
36
  { workflowFile: 'test.yml', jobKey: 'coverage-gate', test: (name) => name === 'Coverage gate (merged shards)' },
37
+ { workflowFile: 'test.yml', jobKey: 'test-conformance', test: (name) => name.startsWith('conformance test (') },
38
38
  { workflowFile: 'install-smoke.yml', jobKey: 'smoke', test: (name) => name.startsWith('smoke (') },
39
39
  ];
40
40
 
@@ -890,6 +890,7 @@ const VIOLATION_KINDS = Object.freeze({
890
890
  LEGACY_READ_TAG: 'legacy_read_tag',
891
891
  READ_TAG_GATE_MISSING: 'read_tag_gate_missing',
892
892
  UNMATCHED_CONSUMER_TOKEN: 'unmatched_consumer_token',
893
+ UNRESOLVED_REFERENCE_INCLUDE: 'unresolved_reference_include',
893
894
  });
894
895
 
895
896
  /**
@@ -925,6 +926,8 @@ const REMEDIES = Object.freeze({
925
926
  "add the <required_reading> MUST-Read gate clause to this agent's instructions (see docs/AGENTS.md)",
926
927
  unmatched_consumer_token:
927
928
  'declare the producing agent and marker in the registry, or remove the dispatch — nothing emits this token',
929
+ unresolved_reference_include:
930
+ 'fix the gsd-core/references/ pointer so it names an existing reference file whole and ends at the name (whitespace, end of line, or closing punctuation)',
928
931
  });
929
932
 
930
933
  /**
@@ -72,7 +72,7 @@ function isShipped(diffPath, shipPrefixes) {
72
72
  // forward slashes, but a developer running this locally on a different
73
73
  // tool's output shouldn't get a false negative).
74
74
  const p = diffPath.replace(/\\/g, '/');
75
- return shipPrefixes.some((s) => p === s || p.startsWith(s + '/'));
75
+ return shipPrefixes.some((s) => p === s || p.startsWith(s + '/')); // allow-handrolled-containment: shipped-path filtering for a CI check, not a safety decision
76
76
  }
77
77
 
78
78
  // #2980: commits that touch `.github/workflows/*` cannot be cherry-picked
@@ -9,8 +9,12 @@
9
9
  *
10
10
  * A prior version of this PR added a `docs guards` RULE to `RULES` in
11
11
  * scripts/ci-test-scope.cjs, on the theory that classify()'s `!codeChanged`
12
- * normalization (which zeroes fullMatrix/targeted_tests/windows_tests for
13
- * docs-only diffs) made the RULE inert to classify()'s scope decision.
12
+ * normalization (which at the time zeroed fullMatrix/targeted_tests/
13
+ * windows_tests for docs-only diffs) made the RULE inert to classify()'s
14
+ * scope decision. (#4641 later removed `windows_tests` from classify()'s
15
+ * output entirely; the normalization today only zeroes fullMatrix and
16
+ * targeted_tests. This paragraph is historical narration of a rejected
17
+ * design, not a description of current behaviour.)
14
18
  *
15
19
  * That is true for docs-ONLY diffs and FALSE for MIXED docs+code diffs:
16
20
  * `codeChanged` is true whenever ANY changed file is product/pipeline code,
@@ -170,6 +174,7 @@ const DOCS_GUARD_TESTS = {
170
174
  // entry).
171
175
  'tests/learnings.test.cjs': ['docs/FEATURES.md'],
172
176
  'tests/analyze-dependencies.test.cjs': ['docs/COMMANDS.md'],
177
+ 'tests/auto-select-attribute.test.cjs': ['docs/reference/plan-md.md'],
173
178
  'tests/autonomous-converge.test.cjs': [
174
179
  'docs/COMMANDS.md',
175
180
  'docs/how-to/run-phases-autonomously.md',
@@ -193,6 +198,7 @@ const DOCS_GUARD_TESTS = {
193
198
  // (commit-files-pathspec.test.cjs:1618) — cannot be resolved to specific
194
199
  // files without re-deriving the scan's own file-discovery logic.
195
200
  'tests/commit-files-pathspec.test.cjs': ['*'],
201
+ 'tests/compact-content-4139.test.cjs': ['docs/CONFIGURATION.md'],
196
202
  'tests/config-field-docs.test.cjs': ['docs/CONFIGURATION.md'],
197
203
  'tests/config.test.cjs': ['docs/CONFIGURATION.md'],
198
204
  'tests/context-index-sync.test.cjs': ['docs/CONTEXT-INDEX.json'],
@@ -267,6 +273,32 @@ const DOCS_GUARD_TESTS = {
267
273
  // seeding, so a content edit to any of them (e.g. renaming a landmark
268
274
  // heading/string a hostile-input test targets) can change this test's
269
275
  // fixture assumptions.
276
+ // #4728: pins the retirement of Gemini CLI prose from every localized
277
+ // how-to/ARCHITECTURE/USER-GUIDE/CONFIGURATION/context-monitor mirror, plus
278
+ // the PRESERVE (Antigravity) and MODEL-AXIS (Gemini 2.5 Pro) negative-space
279
+ // checks in the same locales.
280
+ 'tests/gemini-runtime-removed.test.cjs': [
281
+ 'docs/ja-JP/how-to/install-on-your-runtime.md',
282
+ 'docs/ko-KR/how-to/install-on-your-runtime.md',
283
+ 'docs/pt-BR/how-to/install-on-your-runtime.md',
284
+ 'docs/zh-CN/how-to/install-on-your-runtime.md',
285
+ 'docs/ja-JP/ARCHITECTURE.md',
286
+ 'docs/ko-KR/ARCHITECTURE.md',
287
+ 'docs/pt-BR/ARCHITECTURE.md',
288
+ 'docs/zh-CN/ARCHITECTURE.md',
289
+ 'docs/ja-JP/USER-GUIDE.md',
290
+ 'docs/ko-KR/USER-GUIDE.md',
291
+ 'docs/pt-BR/USER-GUIDE.md',
292
+ 'docs/zh-CN/USER-GUIDE.md',
293
+ 'docs/ja-JP/CONFIGURATION.md',
294
+ 'docs/ko-KR/CONFIGURATION.md',
295
+ 'docs/pt-BR/CONFIGURATION.md',
296
+ 'docs/zh-CN/CONFIGURATION.md',
297
+ 'docs/ja-JP/context-monitor.md',
298
+ 'docs/ko-KR/context-monitor.md',
299
+ 'docs/pt-BR/context-monitor.md',
300
+ 'docs/zh-CN/context-monitor.md',
301
+ ],
270
302
  'tests/gen-state-md-docs.test.cjs': [
271
303
  'docs/reference/state-md.md',
272
304
  'docs/ja-JP/reference/state-md.md',
@@ -371,6 +403,7 @@ const DOCS_GUARD_TESTS = {
371
403
  'docs/how-to/plan-a-phase.md',
372
404
  'docs/AGENTS.md',
373
405
  ],
406
+ 'tests/ui-interaction-capture.test.cjs': ['docs/CONFIGURATION.md'],
374
407
  'tests/ui-spec-inventory-provenance.test.cjs': [
375
408
  'docs/FEATURES.md',
376
409
  'docs/how-to/design-a-ui-phase.md',
@@ -31,6 +31,7 @@ const path = require('node:path');
31
31
 
32
32
  const { ExitError, runMain } = require('./lib/cli-exit.cjs');
33
33
  const { escapeRegex: escapeRegExp } = require('../gsd-core/bin/lib/pattern.cjs');
34
+ const { isContainedIn } = require('../gsd-core/bin/lib/security.cjs');
34
35
 
35
36
  const ROOT = path.resolve(__dirname, '..');
36
37
  const ADR_DIR = path.join(ROOT, 'docs', 'adr');
@@ -176,10 +177,15 @@ const ADR_FILENAME_RE = /^[0-9]+-[a-z0-9-]+\.md$/;
176
177
  * segment merely BEGINS with two dots (`..hidden.md`), and a false "escapes
177
178
  * the repository" on a valid path is a worse failure than a miss — hence the
178
179
  * whole-segment `rel === '..' || rel.startsWith('..' + sep)` form.
180
+ *
181
+ * Delegates to the shared `isContainedIn` (ADR-4650): every call site here
182
+ * already resolved both operands itself (either lexically, before any
183
+ * filesystem call, or via realpathSync after a symlink) and needs only this
184
+ * comparison step — the exact already-resolved-caller case `isContainedIn`
185
+ * documents.
179
186
  */
180
187
  function escapesRoot(abs, root) {
181
- const rel = path.relative(root, abs);
182
- return rel === '..' || rel.startsWith(`..${path.sep}`) || path.isAbsolute(rel);
188
+ return !isContainedIn(abs, root);
183
189
  }
184
190
 
185
191
  /**
@@ -91,6 +91,18 @@ const NESTED_FAMILIES = [
91
91
  subdir: 'steps',
92
92
  filter: (f) => f.endsWith('.md'),
93
93
  },
94
+ {
95
+ name: 'workflow_detail',
96
+ root: path.join(ROOT, 'gsd-core', 'workflows'),
97
+ subdir: 'detail',
98
+ filter: (f) => f.endsWith('.md'),
99
+ },
100
+ {
101
+ name: 'workflow_templates',
102
+ root: path.join(ROOT, 'gsd-core', 'workflows'),
103
+ subdir: 'templates',
104
+ filter: (f) => f.endsWith('.md'),
105
+ },
94
106
  ];
95
107
 
96
108
  /**
@@ -78,6 +78,23 @@ const ROLE_TO_AGENT = {
78
78
  verifier: 'gsd-verifier',
79
79
  };
80
80
 
81
+ // #4740 — Role → family mapping. Three families: orchestration, planning,
82
+ // execution. This constrains what a workflow may DECLARE in agent-roles for
83
+ // a given step (admissibility), a separate concern from ROLE_TO_AGENT's
84
+ // agent-file presence check above.
85
+ const ROLE_FAMILY = {
86
+ orchestrator: 'orchestration',
87
+ researcher: 'planning', planner: 'planning', checker: 'planning',
88
+ executor: 'execution', verifier: 'execution',
89
+ };
90
+ const EXPECTED_FAMILY_BY_STEP = {
91
+ discuss: 'orchestration',
92
+ plan: 'planning',
93
+ execute: 'execution',
94
+ verify: 'orchestration',
95
+ ship: 'orchestration',
96
+ };
97
+
81
98
  // ─── Parser ───────────────────────────────────────────────────────────────────
82
99
 
83
100
  /**
@@ -228,6 +245,52 @@ function crossCheckRoles(content, agentRoles, fileName) {
228
245
  return errors;
229
246
  }
230
247
 
248
+ // ─── Cross-check: declared roles vs. their permitted family (#4740) ──────────
249
+
250
+ /**
251
+ * For a step, verify every role declared in agentRoles belongs to that step's
252
+ * expected family (orchestration / planning / execution).
253
+ *
254
+ * Unlike `assertPointsCoverage`'s `if (!expected) continue // caught
255
+ * elsewhere` guard, an unknown step here fails CLOSED: for points
256
+ * there is a second net (the canonical-set and duplicate checks), but nothing
257
+ * else in the repo validates role families, so failing open on an unknown
258
+ * step would make it the one input that silently bypasses this gate — the
259
+ * "unknown resolving to a safe known" failure mode this check exists to close.
260
+ *
261
+ * Pure: never sorts, de-dupes, or otherwise mutates `agentRoles` — the same
262
+ * array `buildContract` puts into the generated contract.
263
+ *
264
+ * @param {string} step The step named in the marker block.
265
+ * @param {string[]} agentRoles Roles declared in the block.
266
+ * @param {string} fileName For error messages.
267
+ * @returns {string[]} Array of error strings; empty = OK.
268
+ */
269
+ function crossCheckRoleFamilies(step, agentRoles, fileName) {
270
+ const expectedFamily = EXPECTED_FAMILY_BY_STEP[step];
271
+ if (!expectedFamily) {
272
+ return [fileName + ': step "' + step + '" has no entry in EXPECTED_FAMILY_BY_STEP'];
273
+ }
274
+
275
+ const errors = [];
276
+ for (const role of agentRoles) {
277
+ const family = ROLE_FAMILY[role];
278
+ if (!family) {
279
+ errors.push(
280
+ fileName + ': declared agent-role "' + role + '" has no entry in ROLE_FAMILY mapping',
281
+ );
282
+ continue;
283
+ }
284
+ if (family !== expectedFamily) {
285
+ errors.push(
286
+ fileName + ': declared agent-role "' + role + '" (family "' + family +
287
+ '") is not permitted at step "' + step + '" (expected family "' + expectedFamily + '")',
288
+ );
289
+ }
290
+ }
291
+ return errors;
292
+ }
293
+
231
294
  // ─── 12-points coverage assertion ────────────────────────────────────────────
232
295
 
233
296
  /**
@@ -331,6 +394,10 @@ function buildContract(workflowsDir) {
331
394
  const roleErrors = crossCheckRoles(content, entry.agentRoles, file);
332
395
  allErrors.push(...roleErrors);
333
396
 
397
+ // Cross-check role families (#4740)
398
+ const roleFamilyErrors = crossCheckRoleFamilies(entry.step, entry.agentRoles, file);
399
+ allErrors.push(...roleFamilyErrors);
400
+
334
401
  for (const auxiliary of auxiliaryHosts) {
335
402
  let auxiliaryContent;
336
403
  try {
@@ -667,6 +734,7 @@ function getWiredLoopPoints(repoRoot) {
667
734
  module.exports = {
668
735
  parseLoopHostBlock,
669
736
  crossCheckRoles,
737
+ crossCheckRoleFamilies,
670
738
  assertPointsCoverage,
671
739
  buildContract,
672
740
  serializeContract,
@@ -676,6 +744,7 @@ module.exports = {
676
744
  CANONICAL_POINTS,
677
745
  EXPECTED_POINTS_BY_STEP,
678
746
  ROLE_TO_AGENT,
747
+ ROLE_FAMILY,
679
748
  scanWiredPoints,
680
749
  getWiredLoopPoints,
681
750
  coveredKindsInRegion,