@opengsd/gsd-core 1.9.0 → 1.10.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 (223) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -3
  3. package/.opencode/plugins/gsd-core.js +8 -1
  4. package/agents/gsd-code-fixer.md +131 -34
  5. package/agents/gsd-debugger.md +12 -246
  6. package/agents/gsd-executor.md +7 -5
  7. package/agents/gsd-integration-checker.md +3 -0
  8. package/agents/gsd-plan-checker.md +9 -0
  9. package/agents/gsd-planner.md +5 -8
  10. package/agents/gsd-roadmapper.md +21 -3
  11. package/agents/gsd-verifier.md +14 -70
  12. package/bin/install.js +503 -341
  13. package/commands/gsd/mempalace-capture.md +1 -1
  14. package/commands/gsd/new-milestone.md +1 -1
  15. package/commands/gsd/plan-phase.md +1 -1
  16. package/gsd-core/bin/gsd-tools.cjs +607 -63
  17. package/gsd-core/bin/lib/active-workstream-store.cjs +25 -0
  18. package/gsd-core/bin/lib/agent-install-check.cjs +38 -6
  19. package/gsd-core/bin/lib/api-coverage.cjs +120 -0
  20. package/gsd-core/bin/lib/audit.cjs +89 -1
  21. package/gsd-core/bin/lib/broken-windows.cjs +36 -6
  22. package/gsd-core/bin/lib/capability-registry.cjs +96 -110
  23. package/gsd-core/bin/lib/capability-validator.cjs +12 -2
  24. package/gsd-core/bin/lib/check-command-router.cjs +43 -1
  25. package/gsd-core/bin/lib/command-aliases.cjs +72 -0
  26. package/gsd-core/bin/lib/commands.cjs +26 -25
  27. package/gsd-core/bin/lib/commonjs-marker.cjs +136 -0
  28. package/gsd-core/bin/lib/config-loader.cjs +1 -0
  29. package/gsd-core/bin/lib/config.cjs +12 -1
  30. package/gsd-core/bin/lib/context-composer.cjs +278 -0
  31. package/gsd-core/bin/lib/context-predicates.cjs +506 -0
  32. package/gsd-core/bin/lib/core-utils.cjs +91 -12
  33. package/gsd-core/bin/lib/docs.cjs +3 -2
  34. package/gsd-core/bin/lib/external-job.cjs +19 -4
  35. package/gsd-core/bin/lib/frontmatter.cjs +84 -12
  36. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +57 -6
  37. package/gsd-core/bin/lib/git-base-branch.cjs +58 -15
  38. package/gsd-core/bin/lib/graphify.cjs +142 -27
  39. package/gsd-core/bin/lib/gsd2-import.cjs +27 -4
  40. package/gsd-core/bin/lib/host-integration.cjs +13 -1
  41. package/gsd-core/bin/lib/init-command-router.cjs +83 -8
  42. package/gsd-core/bin/lib/init.cjs +1021 -57
  43. package/gsd-core/bin/lib/install-engine.cjs +64 -10
  44. package/gsd-core/bin/lib/install-profiles.cjs +27 -1
  45. package/gsd-core/bin/lib/installer-migration-authoring.cjs +3 -1
  46. package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
  47. package/gsd-core/bin/lib/installer-migrations/007-retire-config-root-commonjs-marker.cjs +149 -0
  48. package/gsd-core/bin/lib/installer-migrations/008-cursor-retire-commands-surface.cjs +55 -0
  49. package/gsd-core/bin/lib/installer-migrations/009-pi-retire-reserved-hooks-dir.cjs +199 -0
  50. package/gsd-core/bin/lib/installer-migrations.cjs +87 -1
  51. package/gsd-core/bin/lib/io.cjs +28 -3
  52. package/gsd-core/bin/lib/markdown-sectionizer.cjs +6 -0
  53. package/gsd-core/bin/lib/mcp-catalog.cjs +518 -0
  54. package/gsd-core/bin/lib/mcp-server.cjs +135 -3
  55. package/gsd-core/bin/lib/milestone.cjs +106 -51
  56. package/gsd-core/bin/lib/phase-id.cjs +63 -0
  57. package/gsd-core/bin/lib/phase-locator.cjs +138 -45
  58. package/gsd-core/bin/lib/phase.cjs +260 -25
  59. package/gsd-core/bin/lib/plan-dependency-graph.cjs +232 -0
  60. package/gsd-core/bin/lib/planning-workspace.cjs +4 -0
  61. package/gsd-core/bin/lib/project-root.cjs +48 -0
  62. package/gsd-core/bin/lib/prompt-budget.cjs +128 -165
  63. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +80 -0
  64. package/gsd-core/bin/lib/review-lane-descriptor.cjs +99 -0
  65. package/gsd-core/bin/lib/review-lane-runner.cjs +30 -6
  66. package/gsd-core/bin/lib/roadmap-command-router.cjs +42 -9
  67. package/gsd-core/bin/lib/roadmap-parser.cjs +100 -18
  68. package/gsd-core/bin/lib/roadmap.cjs +37 -7
  69. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +195 -62
  70. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +15 -3
  71. package/gsd-core/bin/lib/runtime-homes.cjs +154 -41
  72. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +105 -41
  73. package/gsd-core/bin/lib/section-manifest.cjs +209 -0
  74. package/gsd-core/bin/lib/shell-command-projection.cjs +113 -27
  75. package/gsd-core/bin/lib/smart-entry.cjs +12 -0
  76. package/gsd-core/bin/lib/state-transition.cjs +73 -8
  77. package/gsd-core/bin/lib/state.cjs +151 -62
  78. package/gsd-core/bin/lib/surface.cjs +12 -1
  79. package/gsd-core/bin/lib/uat-predicate.cjs +11 -1
  80. package/gsd-core/bin/lib/uat.cjs +320 -21
  81. package/gsd-core/bin/lib/unusable-input.cjs +9 -0
  82. package/gsd-core/bin/lib/verification.cjs +29 -12
  83. package/gsd-core/bin/lib/verify.cjs +29 -5
  84. package/gsd-core/bin/lib/workflow-fragments.cjs +557 -0
  85. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +181 -18
  86. package/gsd-core/bin/lib/workstream-inventory.cjs +519 -27
  87. package/gsd-core/bin/lib/workstream.cjs +6 -0
  88. package/gsd-core/bin/lib/worktree-base-ref.cjs +50 -6
  89. package/gsd-core/bin/lib/worktree-safety.cjs +276 -118
  90. package/gsd-core/bin/shared/config-schema.manifest.json +2 -0
  91. package/gsd-core/references/artifact-types.md +10 -3
  92. package/gsd-core/references/autonomous-ui-design-contract.md +42 -0
  93. package/gsd-core/references/debugger-techniques.md +255 -0
  94. package/gsd-core/references/research-documentation-lookup.md +5 -3
  95. package/gsd-core/references/specless-probe-fallback.md +7 -6
  96. package/gsd-core/references/verifier-wiring-patterns.md +100 -0
  97. package/gsd-core/references/worktree-branch-check.md +2 -2
  98. package/gsd-core/templates/summary-complex.md +2 -0
  99. package/gsd-core/templates/summary-minimal.md +2 -0
  100. package/gsd-core/templates/summary-standard.md +2 -0
  101. package/gsd-core/templates/summary.md +2 -0
  102. package/gsd-core/workflows/audit-milestone.md +3 -0
  103. package/gsd-core/workflows/autonomous/steps/converge-banner.md +1 -0
  104. package/gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md +11 -0
  105. package/gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md +7 -0
  106. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +21 -0
  107. package/gsd-core/workflows/autonomous/steps/converge-loop.md +7 -0
  108. package/gsd-core/workflows/autonomous.md +32 -69
  109. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +39 -0
  110. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +83 -0
  111. package/gsd-core/workflows/code-review.md +42 -145
  112. package/gsd-core/workflows/complete-milestone/steps/git-tag.md +29 -0
  113. package/gsd-core/workflows/complete-milestone.md +23 -81
  114. package/gsd-core/workflows/debug.md +9 -12
  115. package/gsd-core/workflows/diagnose-issues.md +22 -0
  116. package/gsd-core/workflows/discovery-phase.md +4 -4
  117. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +15 -0
  118. package/gsd-core/workflows/discuss-phase-assumptions.md +5 -16
  119. package/gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md +51 -0
  120. package/gsd-core/workflows/docs-update.md +8 -51
  121. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +34 -2
  122. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +50 -0
  123. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +31 -0
  124. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +19 -0
  125. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +42 -0
  126. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +43 -37
  127. package/gsd-core/workflows/execute-phase.md +65 -137
  128. package/gsd-core/workflows/execute-plan.md +1 -1
  129. package/gsd-core/workflows/help/modes/full.md +6 -1
  130. package/gsd-core/workflows/ingest-docs.md +2 -1
  131. package/gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md +16 -0
  132. package/gsd-core/workflows/new-milestone/steps/reset-phase-safety.md +19 -0
  133. package/gsd-core/workflows/new-milestone.md +21 -38
  134. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +176 -0
  135. package/gsd-core/workflows/new-project/steps/auto-mode-detection.md +32 -0
  136. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +18 -0
  137. package/gsd-core/workflows/new-project.md +13 -226
  138. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +15 -0
  139. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +110 -0
  140. package/gsd-core/workflows/plan-phase/steps/prd-express-gate.md +8 -0
  141. package/gsd-core/workflows/plan-phase/steps/research-only-early-exit.md +17 -0
  142. package/gsd-core/workflows/plan-phase/steps/research-only-modifiers.md +16 -0
  143. package/gsd-core/workflows/plan-phase/steps/reviews-prerequisite.md +17 -0
  144. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +149 -0
  145. package/gsd-core/workflows/plan-phase.md +49 -193
  146. package/gsd-core/workflows/progress/steps/forensic-audit.md +125 -0
  147. package/gsd-core/workflows/progress/steps/mvp-display.md +18 -0
  148. package/gsd-core/workflows/progress.md +11 -153
  149. package/gsd-core/workflows/quick/steps/discussion-phase.md +124 -0
  150. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +111 -0
  151. package/gsd-core/workflows/quick/steps/quick-verification.md +46 -0
  152. package/gsd-core/workflows/quick/steps/research-phase.md +72 -0
  153. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +37 -0
  154. package/gsd-core/workflows/quick.md +20 -390
  155. package/gsd-core/workflows/resume-project.md +3 -0
  156. package/gsd-core/workflows/review/steps/reviewer-instances-note-1.md +4 -0
  157. package/gsd-core/workflows/review/steps/reviewer-instances-note-2.md +3 -0
  158. package/gsd-core/workflows/review.md +15 -8
  159. package/gsd-core/workflows/section-manifest.json +219 -0
  160. package/gsd-core/workflows/sketch.md +1 -1
  161. package/gsd-core/workflows/spec-phase.md +17 -14
  162. package/gsd-core/workflows/spike-wrap-up.md +20 -5
  163. package/gsd-core/workflows/spike.md +50 -16
  164. package/gsd-core/workflows/sync-skills.md +49 -11
  165. package/gsd-core/workflows/transition/steps/workstream-collision-check.md +17 -0
  166. package/gsd-core/workflows/transition.md +8 -21
  167. package/gsd-core/workflows/ui-phase.md +8 -7
  168. package/gsd-core/workflows/update/steps/channel-banner.md +7 -0
  169. package/gsd-core/workflows/update.md +18 -7
  170. package/gsd-core/workflows/verify-phase.md +4 -7
  171. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +36 -0
  172. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +21 -0
  173. package/gsd-core/workflows/verify-work.md +8 -58
  174. package/hooks/dist/gsd-agent-isolation-guard.js +428 -0
  175. package/hooks/dist/gsd-check-update-worker.js +14 -5
  176. package/hooks/dist/gsd-cursor-subagent-start.js +532 -26
  177. package/hooks/dist/gsd-read-injection-scanner.js +7 -0
  178. package/hooks/dist/gsd-statusline.js +72 -6
  179. package/hooks/dist/gsd-worktree-path-guard.js +2 -1
  180. package/hooks/dist/gsd-write-guard.js +359 -0
  181. package/hooks/dist/lib/isolation-sentinel.js +268 -0
  182. package/hooks/dist/managed-hooks-registry.cjs +2 -0
  183. package/hooks/gsd-agent-isolation-guard.js +428 -0
  184. package/hooks/gsd-check-update-worker.js +14 -5
  185. package/hooks/gsd-cursor-subagent-start.js +532 -26
  186. package/hooks/gsd-read-injection-scanner.js +7 -0
  187. package/hooks/gsd-statusline.js +72 -6
  188. package/hooks/gsd-worktree-path-guard.js +2 -1
  189. package/hooks/gsd-write-guard.js +359 -0
  190. package/hooks/hooks.json +12 -0
  191. package/hooks/lib/isolation-sentinel.js +268 -0
  192. package/hooks/managed-hooks-registry.cjs +2 -0
  193. package/package.json +14 -5
  194. package/pi/gsd.cjs +57 -12
  195. package/scripts/build-hooks.js +9 -0
  196. package/scripts/changeset/lint.cjs +9 -2
  197. package/scripts/changeset/serialize.cjs +5 -1
  198. package/scripts/gen-capability-matrix.cjs +1 -1
  199. package/scripts/gen-context-index.cjs +448 -0
  200. package/scripts/gen-inventory-manifest.cjs +101 -1
  201. package/scripts/gen-prompt-budget-parity-corpus.cjs +645 -0
  202. package/scripts/gen-registry.cjs +39 -15
  203. package/scripts/gen-section-manifest.cjs +638 -0
  204. package/scripts/generate-package-identity.cjs +4 -2
  205. package/scripts/lint-allow-test-rule-refs.allowlist.json +17 -31
  206. package/scripts/lint-compiled-artifact-sync.cjs +6 -1
  207. package/scripts/lint-docs-command-form.cjs +195 -0
  208. package/scripts/lint-docs-required.cjs +9 -1
  209. package/scripts/lint-emitted-drift-ack.cjs +215 -20
  210. package/scripts/lint-example-parser-parity.cjs +395 -0
  211. package/scripts/lint-test-file-count.allowlist.json +27 -1
  212. package/scripts/mutation-matrix.cjs +13 -0
  213. package/scripts/prompt-injection-scan.sh +27 -6
  214. package/scripts/registry-schema.cjs +323 -94
  215. package/scripts/run-tests.cjs +3 -2
  216. package/scripts/validate-registry.cjs +10 -6
  217. package/skills/gsd-autonomous/SKILL.md +1 -1
  218. package/skills/gsd-execute-phase/SKILL.md +1 -1
  219. package/skills/gsd-mempalace-capture/SKILL.md +1 -1
  220. package/skills/gsd-new-milestone/SKILL.md +1 -1
  221. package/skills/gsd-plan-phase/SKILL.md +2 -2
  222. package/vscode/package.json +1 -1
  223. package/scripts/gen-emitted-baseline.cjs +0 -145
@@ -1,5 +1,5 @@
1
1
  [
2
- "tests/agent-classification-parity.test.cjs :: runtime-contract-is-the-product — docs/AGENTS.md section layout + docs/INVENTORY.md table ARE the classification surface being validated",
2
+ "tests/agent-classification-parity.test.cjs :: source-text-is-the-product",
3
3
  "tests/agent-frontmatter.test.cjs :: source-text-is-the-product",
4
4
  "tests/agent-required-reading-consistency.test.cjs :: source-text-is-the-product",
5
5
  "tests/agent-size-budget.test.cjs :: source-text-is-the-product",
@@ -15,23 +15,20 @@
15
15
  "tests/autonomous-interactive.test.cjs :: source-text-is-the-product",
16
16
  "tests/autonomous-to-flag.test.cjs :: source-text-is-the-product",
17
17
  "tests/chain-flag-plan-phase.test.cjs :: source-text-is-the-product",
18
- "tests/changeset-cli.test.cjs :: reads a product workflow .md file (not CJS source) to verify",
18
+ "tests/changeset-cli.test.cjs :: source-text-is-the-product",
19
19
  "tests/check-update-config-dir.test.cjs :: structural-regression-guard",
20
- "tests/ci-test-scope.test.cjs :: CLI usage banner presence is a user-facing contract.",
21
- "tests/ci-test-scope.test.cjs :: CLI usage failure text is user-facing contract for this parser guard.",
22
20
  "tests/claude-md.test.cjs :: source-text-is-the-product",
23
21
  "tests/claude-skills-migration.test.cjs :: source-text-is-the-product",
24
22
  "tests/cleanup-branch-pruning.test.cjs :: source-text-is-the-product",
25
23
  "tests/cline-install.test.cjs :: source-text-is-the-product",
26
24
  "tests/cline-support.test.cjs :: source-text-is-the-product",
27
- "tests/clock-seam.test.cjs :: line 159 reads the STATE.md temp file written by readModifyWriteStateMd — this is a runtime output file assertion, not a source-grep; the API returns void so a file read-back is the only way to verify the transform was applied",
28
25
  "tests/code-review-agent-skills.test.cjs :: source-text-is-the-product",
29
26
  "tests/code-review-command.test.cjs :: source-text-is-the-product",
30
27
  "tests/code-review-pipeline-regression.test.cjs :: source-text-is-the-product",
31
28
  "tests/code-review.test.cjs :: source-text-is-the-product",
32
29
  "tests/codebuddy-install.test.cjs :: source-text-is-the-product",
33
30
  "tests/codex-config.test.cjs :: source-text-is-the-product",
34
- "tests/command-contract.test.cjs :: source-text-is-the-product — commands/gsd/*.md files ARE the",
31
+ "tests/command-contract.test.cjs :: source-text-is-the-product",
35
32
  "tests/commands.test.cjs :: source-text-is-the-product",
36
33
  "tests/concurrency-safety.test.cjs :: source-text-is-the-product",
37
34
  "tests/config-field-docs.test.cjs :: docs-parity",
@@ -47,18 +44,15 @@
47
44
  "tests/discuss-phase-power.test.cjs :: source-text-is-the-product",
48
45
  "tests/docs-parity-live-registry.test.cjs :: source-text-is-the-product",
49
46
  "tests/drift-detection.test.cjs :: source-text-is-the-product",
50
- "tests/edge-probe-docs-fixtures.test.cjs :: runtime-contract-is-the-product — the rendered reference/SPEC/ADR vocab surfaces are the runtime contract; this pins their bijection to the code (docs-parity)",
51
- "tests/edge-probe-planner-contract.test.cjs :: runtime-contract-is-the-product — plan-phase.md's planner prompt is the deployed runtime contract under assertion",
52
- "tests/edge-probe-spec-phase-contract.test.cjs :: runtime-contract-is-the-product — spec-phase.md Step 5.5 is the deployed workflow runtime contract under assertion",
47
+ "tests/edge-probe-docs-fixtures.test.cjs :: source-text-is-the-product",
48
+ "tests/edge-probe-planner-contract.test.cjs :: source-text-is-the-product",
49
+ "tests/edge-probe-spec-phase-contract.test.cjs :: source-text-is-the-product",
53
50
  "tests/edit-phase.test.cjs :: source-text-is-the-product",
54
51
  "tests/eslint-rules.test.cjs :: <source-grep reason> must still error",
55
52
  "tests/eslint-rules.test.cjs :: pending migration",
56
53
  "tests/eslint-rules.test.cjs :: source-text-is-the-product",
57
54
  "tests/execute-phase-active-flags.test.cjs :: source-text-is-the-product",
58
55
  "tests/execute-phase-step-5-5-deviation-doc.test.cjs :: source-text-is-the-product",
59
- "tests/execute-phase-wave.test.cjs :: behavioral — calls gsd-tools and asserts structured output",
60
- "tests/execute-phase-wave.test.cjs :: behavioral — exercises config-set validation, not source text",
61
- "tests/execute-phase-wave.test.cjs :: behavioral — exercises gsd-tools wave-defaulting logic",
62
56
  "tests/execute-phase-wave.test.cjs :: source-text-is-the-product",
63
57
  "tests/execute-phase-worktree-artifacts.test.cjs :: source-text-is-the-product",
64
58
  "tests/explore-command.test.cjs :: source-text-is-the-product",
@@ -66,9 +60,8 @@
66
60
  "tests/forensics.test.cjs :: source-text-is-the-product",
67
61
  "tests/frontmatter-cli.test.cjs :: source-text-is-the-product",
68
62
  "tests/gates-taxonomy.test.cjs :: source-text-is-the-product",
69
- "tests/git-base-branch.test.cjs :: runtime-contract-is-the-product",
70
- "tests/git-base-branch.test.cjs :: runtime-contract-is-the-product — the workflow .md content IS",
71
- "tests/gsd-check-update-worker-platform-gate.test.cjs :: structural assertion on spawn-options shape; the behavior",
63
+ "tests/git-base-branch.test.cjs :: source-text-is-the-product",
64
+ "tests/gsd-check-update-worker-platform-gate.test.cjs :: structural-regression-guard",
72
65
  "tests/gsd-researcher-app-aware.test.cjs :: source-text-is-the-product",
73
66
  "tests/gsd-researcher-flow-diagram.test.cjs :: source-text-is-the-product",
74
67
  "tests/gsd-settings-advanced.test.cjs :: source-text-is-the-product",
@@ -80,21 +73,18 @@
80
73
  "tests/install-minimal-hooks.test.cjs :: source-text-is-the-product",
81
74
  "tests/install-nested-layout.test.cjs :: source-text-is-the-product",
82
75
  "tests/install-runtime-artifacts.test.cjs :: source-text-is-the-product",
83
- "tests/install.test.cjs :: runtime-contract-is-the-product",
84
76
  "tests/install.test.cjs :: source-text-is-the-product",
85
- "tests/intel.test.cjs :: source-text-is-the-product — agents/gsd-intel-updater.md IS the",
86
- "tests/intel.test.cjs :: source-text-is-the-product — readFileSync assertions target API-SURFACE.md, which is the generated product of intelApiSurface; asserting on its text content is the only way to verify correct generation.",
87
- "tests/inventory-headings-countfree.test.cjs :: runtime-contract-is-the-product — INVENTORY.md heading format is the shipped doc surface being locked",
77
+ "tests/intel.test.cjs :: source-text-is-the-product",
78
+ "tests/inventory-headings-countfree.test.cjs :: source-text-is-the-product",
88
79
  "tests/ios-scaffold-safety.test.cjs :: source-text-is-the-product",
89
80
  "tests/issue-2639-codex-toml-neutralization.test.cjs :: source-text-is-the-product",
90
81
  "tests/issue-429-comment-text-gate.test.cjs :: source-text-is-the-product",
91
- "tests/issue-498-update-backup-runtime-dir.test.cjs :: structural assertion on the deployed update.md backup bash;",
92
- "tests/issue-57-runtime-install-no-drift.test.cjs :: delegation-presence guard. Catches wholesale removal of the registry",
93
- "tests/issue-57-runtime-install-no-drift.test.cjs :: structural guard over bin/install.js source. Behavioral assertions",
82
+ "tests/issue-498-update-backup-runtime-dir.test.cjs :: source-text-is-the-product",
83
+ "tests/issue-57-runtime-install-no-drift.test.cjs :: structural-regression-guard",
94
84
  "tests/issue-607-installer-dry-run.install.test.cjs :: integration-test-input",
95
85
  "tests/issue-607-legacy-cleanup.test.cjs :: integration-test-input",
96
86
  "tests/issue-787-cline-hooks-agents.test.cjs :: source-text-is-the-product",
97
- "tests/issue-815-update-next-channel.test.cjs :: reads product workflow/command markdown to verify the --next RC channel contract — not a source-grep test",
87
+ "tests/issue-815-update-next-channel.test.cjs :: source-text-is-the-product",
98
88
  "tests/locking-bugs-1909-1916-1925-1927.test.cjs :: architectural-invariant",
99
89
  "tests/mcp-tool-inheritance.test.cjs :: source-text-is-the-product",
100
90
  "tests/milestone-summary.test.cjs :: source-text-is-the-product",
@@ -111,7 +101,6 @@
111
101
  "tests/path-replacement.test.cjs :: source-text-is-the-product",
112
102
  "tests/phase-dependency-levels.test.cjs :: source-text-is-the-product",
113
103
  "tests/phase.test.cjs :: source-text-is-the-product",
114
- "tests/phase.test.cjs :: state-md-is-the-runtime-contract — regression tests for",
115
104
  "tests/phase6-capability-docs.test.cjs :: source-text-is-the-product",
116
105
  "tests/phase6-capstone-conformance.test.cjs :: source-text-is-the-product",
117
106
  "tests/phase6-planning-capabilities.test.cjs :: source-text-is-the-product",
@@ -127,7 +116,6 @@
127
116
  "tests/product-name-purity.test.cjs :: source-text-is-the-product",
128
117
  "tests/profile-output.test.cjs :: source-text-is-the-product",
129
118
  "tests/progress-forensic.test.cjs :: source-text-is-the-product",
130
- "tests/prompt-budget-cli.test.cjs :: prompt-content-is-the-product",
131
119
  "tests/prompt-thinning.test.cjs :: source-text-is-the-product",
132
120
  "tests/quick-session-management.test.cjs :: source-text-is-the-product",
133
121
  "tests/qwen-skills-migration.test.cjs :: source-text-is-the-product",
@@ -137,12 +125,11 @@
137
125
  "tests/release-coverage-scope.test.cjs :: source-text-is-the-product",
138
126
  "tests/release-tarball-smoke-workflow.test.cjs :: source-text-is-the-product",
139
127
  "tests/release-tarball-smoke.install.test.cjs :: integration-test-input",
140
- "tests/research-agent-profiles.test.cjs :: <runtime-contract-is-the-product> research agent .md content is the governed surface",
128
+ "tests/research-agent-profiles.test.cjs :: source-text-is-the-product",
141
129
  "tests/review-default-reviewers-workflow.test.cjs :: source-text-is-the-product",
142
130
  "tests/roadmap.test.cjs :: source-text-is-the-product",
143
- "tests/run-tests-harness.test.cjs :: run-tests.cjs is a CLI test harness whose only IR is its",
144
- "tests/runtime-launcher-parity.test.cjs :: structural parity/drift guard — asserts literal presence/absence of the canonical gsd_run launcher and the retired $GSD_SDK / `/gsd-tools` tokens across workflow markdown; there is no typed IR for \"this source file does not contain substring X\".",
145
- "tests/runtime-name-policy.test.cjs :: runtime-contract-is-the-product — FALLBACK_ALIASES source text IS the",
131
+ "tests/runtime-launcher-parity.test.cjs :: structural-regression-guard",
132
+ "tests/runtime-name-policy.test.cjs :: source-text-is-the-product",
146
133
  "tests/scan-command.test.cjs :: source-text-is-the-product",
147
134
  "tests/secret-scan-lint.security.test.cjs :: source-text-is-the-product",
148
135
  "tests/secure-phase.test.cjs :: source-text-is-the-product",
@@ -153,7 +140,6 @@
153
140
  "tests/settings-jsonc.test.cjs :: structural-regression-guard",
154
141
  "tests/skill-frontmatter-contract.test.cjs :: source-text-is-the-product",
155
142
  "tests/spawn-liveness-banner.test.cjs :: source-text-is-the-product",
156
- "tests/state-acquirestatelock-non-eexist.test.cjs :: architectural-invariant",
157
143
  "tests/state.test.cjs :: source-text-is-the-product",
158
144
  "tests/subagent-timeout.test.cjs :: source-text-is-the-product",
159
145
  "tests/template.test.cjs :: source-text-is-the-product",
@@ -167,7 +153,7 @@
167
153
  "tests/workflow-compat.test.cjs :: source-text-is-the-product",
168
154
  "tests/workflow-guard-registration.test.cjs :: structural-regression-guard",
169
155
  "tests/workflow-maintainer-skip.test.cjs :: source-text-is-the-product",
170
- "tests/workflow-shell-pinning.test.cjs :: file-scope prefilter, not a test assertion — we need to",
156
+ "tests/workflow-shell-pinning.test.cjs :: source-text-is-the-product",
171
157
  "tests/workflow-size-budget.test.cjs :: source-text-is-the-product",
172
158
  "tests/workspace.test.cjs :: source-text-is-the-product",
173
159
  "tests/worktree-cleanup.test.cjs :: source-text-is-the-product",
@@ -43,7 +43,12 @@ const REASON = Object.freeze({
43
43
  });
44
44
 
45
45
  function git(args) {
46
- return execFileSync('git', args, { cwd: REPO_ROOT, encoding: 'utf8' });
46
+ // -c safe.directory=REPO_ROOT: containerized CI checkouts are frequently
47
+ // owned by a different uid than the one running the test process, and git
48
+ // refuses to operate at all on such a repo ("detected dubious ownership")
49
+ // unless explicitly trusted. Scoped per-invocation (not written to any
50
+ // config file) so this never widens trust beyond this one call.
51
+ return execFileSync('git', ['-c', `safe.directory=${REPO_ROOT}`, ...args], { cwd: REPO_ROOT, encoding: 'utf8' });
47
52
  }
48
53
 
49
54
  /**
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * lint-docs-command-form.cjs
4
+ *
5
+ * Enforces the human-facing command form in docs/ (#2903).
6
+ *
7
+ * `/gsd:<cmd>` (and bare `gsd:<cmd>`) is a SOURCE-AUTHORING token: install-time
8
+ * converters (`transformContentToHyphen`, `convertSlashCommandsTo<Runtime>SkillMentions`)
9
+ * rewrite it to `/gsd-<cmd>` per-runtime. It is correct in `commands/gsd/**`,
10
+ * `gsd-core/workflows/**`, and `agents/**` — but docs are never passed through a
11
+ * converter, so a doc telling a reader to type `/gsd:<cmd>` names a command no
12
+ * runtime registers. The real user-facing form is `/gsd-<cmd>`.
13
+ *
14
+ * This guard fails any `docs/**\/*.md` file that still contains `/gsd:<cmd>` or
15
+ * bare `gsd:<cmd>` where `<cmd>` is a real command name (drawn from the
16
+ * `commands/gsd/*.md` roster). It explicitly permits `/gsd-core:<cmd>` (the
17
+ * Claude Code plugin namespace) and any `gsd:<token>` whose `<token>` is not a
18
+ * real command (e.g. the `gsd:section` / `gsd:loop-host` workflow-fragment
19
+ * marker syntax documented in docs/reference/workflow-fragments.md, or
20
+ * `gsd:command-name` used as a placeholder while explaining the Gemini CLI
21
+ * colon-form convention).
22
+ *
23
+ * Exclusions (never checked):
24
+ * - docs/adr/** (historical record)
25
+ * - docs/RELEASE-NOTES-LEGACY.md (maintainer question still open)
26
+ * - commands/gsd/**, gsd-core/workflows/**, agents/** — never touched by this
27
+ * guard at all; the colon form is correct there.
28
+ *
29
+ * Exemption — `name:` frontmatter key citations: source command files
30
+ * (`commands/gsd/*.md`) carry the colon form in their `name:` YAML frontmatter
31
+ * key (e.g. `name: gsd:next`). A doc that quotes that key verbatim — e.g.
32
+ * `` `name: gsd:next` `` or `name: gsd:next` — is citing the real source file,
33
+ * not telling a reader what to type. Rewriting that citation to `gsd-next`
34
+ * would make the doc lie about the source it's quoting, so a `gsd:<cmd>` token
35
+ * immediately preceded by `name:` (optionally with a backtick/whitespace in
36
+ * between) is permitted. This is narrow: it does not exempt `gsd:<cmd>`
37
+ * anywhere else on the line or file, including the reader-facing `/gsd-<cmd>`
38
+ * form that may appear later in the same sentence.
39
+ *
40
+ * Detection is case-insensitive (`/GSD:next`, `Gsd:Next`, etc. are all
41
+ * flagged) since the install-time converters and runtimes treat command names
42
+ * case-insensitively in practice, and a doc typo in casing is still a lie
43
+ * about the real command form.
44
+ *
45
+ * Exit 0 if no violations; exit 1 if any are found (with stderr diagnostics).
46
+ */
47
+
48
+ 'use strict';
49
+
50
+ const { execFileSync } = require('child_process');
51
+ const fs = require('fs');
52
+ const path = require('path');
53
+ const { ExitError, runMain } = require('./lib/cli-exit.cjs');
54
+
55
+ const SELF_PATH = path.resolve(__filename);
56
+ // GSD_LINT_DOCS_COMMAND_FORM_REPO_ROOT is used by tests to redirect the guard to
57
+ // a temporary fixture git repo without touching the real working tree.
58
+ const REPO_ROOT = process.env.GSD_LINT_DOCS_COMMAND_FORM_REPO_ROOT
59
+ ? path.resolve(process.env.GSD_LINT_DOCS_COMMAND_FORM_REPO_ROOT)
60
+ : path.resolve(__dirname, '..');
61
+
62
+ const DOCS_PREFIX = 'docs/';
63
+ const ADR_PREFIX = 'docs/adr/';
64
+ const RELEASE_NOTES_LEGACY = 'docs/RELEASE-NOTES-LEGACY.md';
65
+ const COMMANDS_DIR = path.join(REPO_ROOT, 'commands/gsd');
66
+
67
+ // Matches `/gsd:<cmd>` and bare `gsd:<cmd>` (not part of `/gsd-core:<cmd>`,
68
+ // which does not contain the substring `gsd:` — the hyphen breaks it).
69
+ // Case-insensitive so `/GSD:next` / `Gsd:Next` are also caught.
70
+ const COMMAND_FORM_RE = /(^|[^A-Za-z0-9_-])(\/)?gsd:([A-Za-z0-9_-]+)/gi;
71
+
72
+ // A `gsd:<cmd>` token is exempt when it is a citation of a source file's
73
+ // YAML `name:` frontmatter key — i.e. the text immediately before the match
74
+ // (ending exactly where the match begins) is `name:` followed by optional
75
+ // whitespace and/or a backtick. Only applies to the bare (non-`/`) form,
76
+ // since the real frontmatter key never carries a leading slash.
77
+ const NAME_KEY_CITATION_RE = /name:\s*`?\s*$/i;
78
+
79
+ function loadRoster() {
80
+ let entries;
81
+ try {
82
+ entries = fs.readdirSync(COMMANDS_DIR);
83
+ } catch (err) {
84
+ throw new ExitError(1, 'ERROR lint-docs-command-form: could not read commands/gsd: ' + err.message);
85
+ }
86
+ return new Set(
87
+ entries.filter((f) => f.endsWith('.md')).map((f) => f.replace(/\.md$/, '')),
88
+ );
89
+ }
90
+
91
+ function isCheckedDocsFile(relPath) {
92
+ if (!relPath.startsWith(DOCS_PREFIX)) return false;
93
+ if (relPath.startsWith(ADR_PREFIX)) return false;
94
+ if (relPath === RELEASE_NOTES_LEGACY) return false;
95
+ return relPath.endsWith('.md');
96
+ }
97
+
98
+ /**
99
+ * Pure scan — no fs, no git. Returns violations for a single file's content.
100
+ *
101
+ * @param {string} relPath file path (used only in violation records)
102
+ * @param {string} content file contents
103
+ * @param {Set<string>} roster valid command names
104
+ * @returns {Array<{file:string, line:number, col:number, text:string}>}
105
+ */
106
+ function scanContent(relPath, content, roster) {
107
+ const violations = [];
108
+ const lines = content.split('\n');
109
+ for (let i = 0; i < lines.length; i++) {
110
+ const line = lines[i];
111
+ COMMAND_FORM_RE.lastIndex = 0;
112
+ let match;
113
+ while ((match = COMMAND_FORM_RE.exec(line)) !== null) {
114
+ const [, pre, slash, cmd] = match;
115
+ if (!roster.has(cmd.toLowerCase())) continue;
116
+ if (!slash) {
117
+ const preContext = line.slice(0, match.index + pre.length);
118
+ if (NAME_KEY_CITATION_RE.test(preContext)) continue;
119
+ }
120
+ const matchedToken = (slash || '') + 'gsd:' + cmd;
121
+ violations.push({
122
+ file: relPath,
123
+ line: i + 1,
124
+ col: match.index + pre.length + 1,
125
+ text: matchedToken,
126
+ });
127
+ }
128
+ }
129
+ return violations;
130
+ }
131
+
132
+ function main() {
133
+ const roster = loadRoster();
134
+
135
+ let trackedFiles;
136
+ try {
137
+ trackedFiles = execFileSync('git', ['ls-files'], { cwd: REPO_ROOT, encoding: 'utf8' })
138
+ .split('\n')
139
+ .map((f) => f.trim())
140
+ .filter(Boolean);
141
+ } catch (err) {
142
+ throw new ExitError(1, 'ERROR lint-docs-command-form: git ls-files failed: ' + err.message);
143
+ }
144
+
145
+ const docsFiles = trackedFiles.filter(isCheckedDocsFile);
146
+ const violations = [];
147
+
148
+ for (const relPath of docsFiles) {
149
+ const fullPath = path.join(REPO_ROOT, relPath);
150
+ if (path.resolve(fullPath) === SELF_PATH) continue;
151
+
152
+ let content;
153
+ try {
154
+ content = fs.readFileSync(fullPath, 'utf8');
155
+ } catch {
156
+ // Unreadable/deleted files — skip silently.
157
+ continue;
158
+ }
159
+
160
+ violations.push(...scanContent(relPath, content, roster));
161
+ }
162
+
163
+ if (violations.length === 0) {
164
+ process.stdout.write(
165
+ 'ok lint-docs-command-form: ' + docsFiles.length + ' file(s) checked, 0 violations\n',
166
+ );
167
+ return 0;
168
+ }
169
+
170
+ process.stderr.write('\nERROR lint-docs-command-form: ' + violations.length + ' violation(s) found\n\n');
171
+ for (const v of violations) {
172
+ process.stderr.write(' ' + v.file + ':' + v.line + ':' + v.col + ' — ' + JSON.stringify(v.text) + '\n');
173
+ }
174
+ process.stderr.write('\n');
175
+ process.stderr.write(
176
+ 'Fix: docs are never passed through the install-time slash-form converters, so the\n',
177
+ );
178
+ process.stderr.write(
179
+ ' colon form names a command no runtime registers. Rewrite to the hyphen form\n',
180
+ );
181
+ process.stderr.write(
182
+ ' (`/gsd-<cmd>`), or `/gsd-core:<cmd>` if this is genuinely the Claude Code\n',
183
+ );
184
+ process.stderr.write(' plugin namespace.\n\n');
185
+ return 1;
186
+ }
187
+
188
+ if (require.main === module) runMain(main);
189
+
190
+ module.exports = {
191
+ scanContent,
192
+ isCheckedDocsFile,
193
+ loadRoster,
194
+ COMMAND_FORM_RE,
195
+ };
@@ -16,6 +16,10 @@
16
16
  const { parseFragment, FRAGMENT_ERROR } = require('./changeset/parse.cjs');
17
17
  const { ExitError, runMain } = require('./lib/cli-exit.cjs');
18
18
 
19
+ // #2988: the repo's integration/default branch — the base every PR targets.
20
+ // Used as the local fallback when GITHUB_BASE_REF is unset (CI sets it).
21
+ const DEFAULT_BASE = 'next';
22
+
19
23
  const LINT_REASON = Object.freeze({
20
24
  OK_NO_TRIGGERING_FRAGMENTS: 'ok_no_triggering_fragments',
21
25
  OK_DOCS_UPDATED: 'ok_docs_updated',
@@ -149,7 +153,10 @@ function main() {
149
153
  } catch { /* fall through */ }
150
154
  }
151
155
 
152
- const base = process.env.GITHUB_BASE_REF || 'main';
156
+ // #2988: local fallback must match the repo's integration branch (`next`),
157
+ // not the release branch (`main`). CI sets GITHUB_BASE_REF explicitly; the
158
+ // fallback only fires locally, where `next` is the base every PR targets.
159
+ const base = process.env.GITHUB_BASE_REF || DEFAULT_BASE;
153
160
  let changedFiles = [];
154
161
  try {
155
162
  // execFileSync with argv — no shell, so a malicious GITHUB_BASE_REF
@@ -216,6 +223,7 @@ module.exports = {
216
223
  OPT_OUT_LABEL,
217
224
  TRIGGERING_TYPES,
218
225
  FRAGMENT_ERROR,
226
+ DEFAULT_BASE,
219
227
  isFragmentPath,
220
228
  isDocsFile,
221
229
  isExemptFragment,