@opengsd/gsd-core 1.10.0 → 1.12.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 (544) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/agents/gsd-code-fixer.md +1 -1
  4. package/agents/gsd-debug-session-manager.md +12 -1
  5. package/agents/gsd-debugger.md +1 -1
  6. package/agents/gsd-doc-synthesizer.md +2 -4
  7. package/agents/gsd-dom-verifier.md +169 -0
  8. package/agents/gsd-eval-auditor.md +1 -1
  9. package/agents/gsd-executor.md +22 -14
  10. package/agents/gsd-framework-selector.md +1 -3
  11. package/agents/gsd-intel-updater.md +1 -1
  12. package/agents/gsd-mempalace-curator.md +5 -3
  13. package/agents/gsd-pattern-mapper.md +11 -0
  14. package/agents/gsd-phase-researcher.md +23 -2
  15. package/agents/gsd-plan-checker.md +50 -53
  16. package/agents/gsd-planner.md +50 -50
  17. package/agents/gsd-project-researcher.md +1 -1
  18. package/agents/gsd-research-synthesizer.md +2 -2
  19. package/agents/gsd-roadmapper.md +15 -11
  20. package/agents/gsd-ui-checker.md +63 -4
  21. package/agents/gsd-ui-researcher.md +41 -3
  22. package/agents/gsd-user-profiler.md +3 -0
  23. package/agents/gsd-verifier.md +13 -4
  24. package/bin/install.js +1448 -1103
  25. package/commands/gsd/code-review.md +1 -1
  26. package/commands/gsd/discuss-phase.md +1 -1
  27. package/commands/gsd/execute-phase.md +1 -1
  28. package/commands/gsd/import.md +1 -1
  29. package/commands/gsd/map-codebase.md +1 -1
  30. package/commands/gsd/mempalace-capture.md +1 -1
  31. package/commands/gsd/mempalace-recall.md +1 -1
  32. package/commands/gsd/new-milestone.md +1 -1
  33. package/commands/gsd/quick.md +9 -5
  34. package/commands/gsd/review-backlog.md +2 -1
  35. package/commands/gsd/verify-work.md +1 -1
  36. package/gsd-core/bin/gsd-tools.cjs +1035 -138
  37. package/gsd-core/bin/lib/active-workstream-store.cjs +146 -22
  38. package/gsd-core/bin/lib/adr-parser.cjs +13 -7
  39. package/gsd-core/bin/lib/agent-install-check.cjs +392 -32
  40. package/gsd-core/bin/lib/api-coverage.cjs +33 -14
  41. package/gsd-core/bin/lib/artifacts.cjs +5 -0
  42. package/gsd-core/bin/lib/assumption-delta.cjs +32 -15
  43. package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
  44. package/gsd-core/bin/lib/audit.cjs +1026 -268
  45. package/gsd-core/bin/lib/broken-windows.cjs +306 -28
  46. package/gsd-core/bin/lib/capability-consent.cjs +149 -15
  47. package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
  48. package/gsd-core/bin/lib/capability-lock.cjs +10 -4
  49. package/gsd-core/bin/lib/capability-registry.cjs +845 -130
  50. package/gsd-core/bin/lib/capability-source.cjs +92 -0
  51. package/gsd-core/bin/lib/capability-state.cjs +18 -3
  52. package/gsd-core/bin/lib/capability-trust.cjs +444 -25
  53. package/gsd-core/bin/lib/capability-validator.cjs +700 -40
  54. package/gsd-core/bin/lib/capability-writer.cjs +3 -2
  55. package/gsd-core/bin/lib/check-command-router.cjs +216 -42
  56. package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
  57. package/gsd-core/bin/lib/cli-exit.cjs +496 -10
  58. package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
  59. package/gsd-core/bin/lib/codex-agent-toml.cjs +735 -0
  60. package/gsd-core/bin/lib/command-aliases.cjs +22 -0
  61. package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
  62. package/gsd-core/bin/lib/command-roster.cjs +44 -1
  63. package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
  64. package/gsd-core/bin/lib/commands.cjs +1172 -108
  65. package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
  66. package/gsd-core/bin/lib/complexity-trigger.cjs +1192 -0
  67. package/gsd-core/bin/lib/config-loader.cjs +187 -23
  68. package/gsd-core/bin/lib/config.cjs +102 -3
  69. package/gsd-core/bin/lib/configuration.cjs +129 -37
  70. package/gsd-core/bin/lib/core-utils.cjs +208 -33
  71. package/gsd-core/bin/lib/decisions.cjs +23 -0
  72. package/gsd-core/bin/lib/edge-probe.cjs +9 -1
  73. package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
  74. package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
  75. package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
  76. package/gsd-core/bin/lib/frontmatter.cjs +899 -229
  77. package/gsd-core/bin/lib/gap-checker.cjs +95 -10
  78. package/gsd-core/bin/lib/git-base-branch.cjs +276 -39
  79. package/gsd-core/bin/lib/gsd2-import.cjs +10 -1
  80. package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
  81. package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
  82. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +149 -0
  83. package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
  84. package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
  85. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
  86. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +268 -0
  87. package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
  88. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
  89. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +187 -0
  90. package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
  91. package/gsd-core/bin/lib/health-diagnostic.cjs +451 -0
  92. package/gsd-core/bin/lib/host-integration.cjs +39 -6
  93. package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
  94. package/gsd-core/bin/lib/init-command-router.cjs +118 -21
  95. package/gsd-core/bin/lib/init.cjs +439 -168
  96. package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
  97. package/gsd-core/bin/lib/install-engine.cjs +811 -259
  98. package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
  99. package/gsd-core/bin/lib/install-model-override-resolver.cjs +235 -0
  100. package/gsd-core/bin/lib/install-profiles.cjs +212 -61
  101. package/gsd-core/bin/lib/install-scope.cjs +270 -0
  102. package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
  103. package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
  104. package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
  105. package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
  106. package/gsd-core/bin/lib/installer-migrations.cjs +148 -38
  107. package/gsd-core/bin/lib/intel.cjs +101 -26
  108. package/gsd-core/bin/lib/io.cjs +170 -15
  109. package/gsd-core/bin/lib/learnings.cjs +85 -14
  110. package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
  111. package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
  112. package/gsd-core/bin/lib/markdown-table.cjs +183 -22
  113. package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
  114. package/gsd-core/bin/lib/milestone.cjs +842 -73
  115. package/gsd-core/bin/lib/model-catalog.cjs +232 -16
  116. package/gsd-core/bin/lib/model-resolver.cjs +193 -68
  117. package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
  118. package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
  119. package/gsd-core/bin/lib/pattern.cjs +122 -0
  120. package/gsd-core/bin/lib/phase-estimation.cjs +18 -9
  121. package/gsd-core/bin/lib/phase-id.cjs +514 -40
  122. package/gsd-core/bin/lib/phase-lifecycle.cjs +52 -19
  123. package/gsd-core/bin/lib/phase-locator.cjs +262 -34
  124. package/gsd-core/bin/lib/phase.cjs +1038 -214
  125. package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
  126. package/gsd-core/bin/lib/plan-document.cjs +263 -0
  127. package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
  128. package/gsd-core/bin/lib/plan-scan.cjs +98 -3
  129. package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
  130. package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
  131. package/gsd-core/bin/lib/planning-scope.cjs +31 -0
  132. package/gsd-core/bin/lib/planning-snapshot.cjs +894 -0
  133. package/gsd-core/bin/lib/planning-workspace.cjs +112 -6
  134. package/gsd-core/bin/lib/probe-core.cjs +5 -2
  135. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  136. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
  137. package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
  138. package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
  139. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +766 -0
  140. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
  141. package/gsd-core/bin/lib/review-lane-descriptor.cjs +22 -13
  142. package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
  143. package/gsd-core/bin/lib/review-lane-runner.cjs +421 -66
  144. package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
  145. package/gsd-core/bin/lib/roadmap-command-router.cjs +59 -11
  146. package/gsd-core/bin/lib/roadmap-parser.cjs +1006 -184
  147. package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
  148. package/gsd-core/bin/lib/roadmap.cjs +442 -96
  149. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +702 -52
  150. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
  151. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +459 -55
  152. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
  153. package/gsd-core/bin/lib/runtime-homes.cjs +69 -3
  154. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +402 -58
  155. package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
  156. package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
  157. package/gsd-core/bin/lib/runtime-slash.cjs +96 -8
  158. package/gsd-core/bin/lib/security.cjs +104 -5
  159. package/gsd-core/bin/lib/shell-command-projection.cjs +342 -7
  160. package/gsd-core/bin/lib/smart-entry.cjs +133 -23
  161. package/gsd-core/bin/lib/spec-section.cjs +12 -7
  162. package/gsd-core/bin/lib/state-command-router.cjs +52 -19
  163. package/gsd-core/bin/lib/state-contract.cjs +359 -0
  164. package/gsd-core/bin/lib/state-document.cjs +338 -8
  165. package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
  166. package/gsd-core/bin/lib/state-transition.cjs +846 -176
  167. package/gsd-core/bin/lib/state.cjs +2589 -369
  168. package/gsd-core/bin/lib/surface.cjs +33 -11
  169. package/gsd-core/bin/lib/task-command-router.cjs +111 -1
  170. package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
  171. package/gsd-core/bin/lib/teams-status.cjs +4 -1
  172. package/gsd-core/bin/lib/text-lines.cjs +80 -0
  173. package/gsd-core/bin/lib/token-scanner.cjs +76 -0
  174. package/gsd-core/bin/lib/uat-predicate.cjs +67 -23
  175. package/gsd-core/bin/lib/uat.cjs +1761 -167
  176. package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
  177. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
  178. package/gsd-core/bin/lib/ui-safety-gate.cjs +51 -12
  179. package/gsd-core/bin/lib/unusable-input.cjs +37 -0
  180. package/gsd-core/bin/lib/update-context.cjs +8 -2
  181. package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
  182. package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
  183. package/gsd-core/bin/lib/validate.cjs +20 -6
  184. package/gsd-core/bin/lib/vendor/README.md +75 -0
  185. package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
  186. package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
  187. package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
  188. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  189. package/gsd-core/bin/lib/verification.cjs +272 -9
  190. package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
  191. package/gsd-core/bin/lib/verify.cjs +453 -918
  192. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +53 -32
  193. package/gsd-core/bin/lib/workstream-inventory.cjs +63 -10
  194. package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
  195. package/gsd-core/bin/lib/workstream.cjs +2 -2
  196. package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
  197. package/gsd-core/bin/lib/worktree-safety.cjs +341 -18
  198. package/gsd-core/bin/shared/config-defaults.manifest.json +8 -1
  199. package/gsd-core/bin/shared/config-schema.manifest.json +12 -1
  200. package/gsd-core/bin/shared/exit-codes.json +8 -0
  201. package/gsd-core/bin/shared/exit-codes.sh +20 -0
  202. package/gsd-core/bin/shared/model-catalog.json +8 -1
  203. package/gsd-core/references/agent-contracts.md +44 -26
  204. package/gsd-core/references/api-coverage.md +24 -2
  205. package/gsd-core/references/autonomous-smart-discuss.md +3 -3
  206. package/gsd-core/references/checkpoints.md +39 -21
  207. package/gsd-core/references/context-budget.md +1 -1
  208. package/gsd-core/references/decimal-phase-calculation.md +5 -5
  209. package/gsd-core/references/dispatch-isolation-gate.md +138 -0
  210. package/gsd-core/references/doc-conflict-engine.md +1 -1
  211. package/gsd-core/references/edge-probe.md +8 -0
  212. package/gsd-core/references/execute-mvp-tdd.md +4 -6
  213. package/gsd-core/references/execute-phase-between-wave-reset.md +15 -14
  214. package/gsd-core/references/execute-phase-context-guard.md +1 -1
  215. package/gsd-core/references/execute-phase-response-language.md +1 -1
  216. package/gsd-core/references/execute-phase-wave-guard.md +17 -11
  217. package/gsd-core/references/failing-direction.md +78 -0
  218. package/gsd-core/references/gate-prompts.md +1 -1
  219. package/gsd-core/references/git-integration.md +5 -5
  220. package/gsd-core/references/git-planning-commit.md +5 -4
  221. package/gsd-core/references/gsd-run-resolver.md +1 -1
  222. package/gsd-core/references/loop-hook-dispatch.md +61 -2
  223. package/gsd-core/references/model-profiles.md +12 -4
  224. package/gsd-core/references/mvp-concepts.md +9 -9
  225. package/gsd-core/references/nyquist-compliance.md +74 -0
  226. package/gsd-core/references/offer-next.md +3 -5
  227. package/gsd-core/references/phase-argument-parsing.md +3 -3
  228. package/gsd-core/references/planner-failing-direction.md +53 -0
  229. package/gsd-core/references/planner-guidance.md +3 -9
  230. package/gsd-core/references/planner-human-verify-mode.md +15 -1
  231. package/gsd-core/references/planner-preconditions.md +1 -1
  232. package/gsd-core/references/planner-reviews.md +1 -1
  233. package/gsd-core/references/planner-revision.md +1 -1
  234. package/gsd-core/references/planner-verify-command-grounding.md +17 -0
  235. package/gsd-core/references/planning-config.md +44 -13
  236. package/gsd-core/references/reviewer-instances.md +31 -0
  237. package/gsd-core/references/revision-loop.md +1 -1
  238. package/gsd-core/references/runtime-aware-dispatch.md +1 -1
  239. package/gsd-core/references/specless-probe-fallback.md +1 -1
  240. package/gsd-core/references/tdd.md +1 -3
  241. package/gsd-core/references/ui-brand.md +65 -21
  242. package/gsd-core/references/ui-consideration-probe.md +1 -1
  243. package/gsd-core/references/universal-anti-patterns.md +5 -5
  244. package/gsd-core/references/verifier-phase-gates.md +192 -0
  245. package/gsd-core/references/verify-command-path-resolvability.md +42 -0
  246. package/gsd-core/references/verify-mvp-mode.md +2 -2
  247. package/gsd-core/references/workstream-flag.md +33 -17
  248. package/gsd-core/templates/README.md +1 -1
  249. package/gsd-core/templates/SECURITY.md +3 -3
  250. package/gsd-core/templates/UI-SPEC.md +25 -3
  251. package/gsd-core/templates/VALIDATION.md +3 -3
  252. package/gsd-core/templates/discussion-log.md +1 -1
  253. package/gsd-core/templates/phase-prompt.md +5 -4
  254. package/gsd-core/templates/state.md +11 -4
  255. package/gsd-core/templates/verification-report.md +9 -1
  256. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  257. package/gsd-core/workflows/add-backlog.md +1 -1
  258. package/gsd-core/workflows/add-phase.md +3 -3
  259. package/gsd-core/workflows/add-tests.md +3 -8
  260. package/gsd-core/workflows/add-todo.md +1 -1
  261. package/gsd-core/workflows/ai-integration-phase.md +13 -20
  262. package/gsd-core/workflows/audit-fix.md +12 -3
  263. package/gsd-core/workflows/audit-milestone.md +9 -9
  264. package/gsd-core/workflows/audit-uat.md +17 -2
  265. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
  266. package/gsd-core/workflows/autonomous.md +11 -27
  267. package/gsd-core/workflows/check-todos.md +1 -1
  268. package/gsd-core/workflows/cleanup.md +64 -5
  269. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +14 -4
  270. package/gsd-core/workflows/code-review-fix.md +38 -11
  271. package/gsd-core/workflows/code-review.md +159 -52
  272. package/gsd-core/workflows/complete-milestone.md +151 -23
  273. package/gsd-core/workflows/debug.md +12 -8
  274. package/gsd-core/workflows/diagnose-issues.md +47 -15
  275. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  276. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -8
  277. package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
  278. package/gsd-core/workflows/discuss-phase/modes/text.md +1 -1
  279. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
  280. package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
  281. package/gsd-core/workflows/discuss-phase.md +1 -1
  282. package/gsd-core/workflows/do.md +3 -6
  283. package/gsd-core/workflows/docs-update.md +5 -4
  284. package/gsd-core/workflows/edit-phase.md +27 -2
  285. package/gsd-core/workflows/eval-review.md +7 -14
  286. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
  287. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +142 -15
  288. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  289. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  290. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
  291. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +24 -4
  292. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
  293. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
  294. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -2
  295. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
  296. package/gsd-core/workflows/execute-phase.md +72 -100
  297. package/gsd-core/workflows/execute-plan.md +52 -15
  298. package/gsd-core/workflows/explore.md +131 -4
  299. package/gsd-core/workflows/extract-learnings.md +1 -1
  300. package/gsd-core/workflows/fast.md +10 -2
  301. package/gsd-core/workflows/forensics.md +1 -1
  302. package/gsd-core/workflows/graduation.md +5 -5
  303. package/gsd-core/workflows/health.md +76 -10
  304. package/gsd-core/workflows/import.md +18 -15
  305. package/gsd-core/workflows/inbox.md +4 -5
  306. package/gsd-core/workflows/ingest-docs.md +49 -16
  307. package/gsd-core/workflows/insert-phase.md +5 -5
  308. package/gsd-core/workflows/list-seeds.md +5 -3
  309. package/gsd-core/workflows/list-workspaces.md +1 -1
  310. package/gsd-core/workflows/manager.md +12 -23
  311. package/gsd-core/workflows/map-codebase.md +1 -1
  312. package/gsd-core/workflows/milestone-summary.md +1 -1
  313. package/gsd-core/workflows/mvp-phase.md +8 -5
  314. package/gsd-core/workflows/new-milestone.md +22 -29
  315. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  316. package/gsd-core/workflows/new-project.md +26 -40
  317. package/gsd-core/workflows/new-workspace.md +1 -1
  318. package/gsd-core/workflows/next.md +14 -2
  319. package/gsd-core/workflows/pause-work.md +1 -1
  320. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
  321. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
  322. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -4
  323. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +3 -3
  324. package/gsd-core/workflows/plan-phase.md +162 -59
  325. package/gsd-core/workflows/plan-review-convergence.md +96 -11
  326. package/gsd-core/workflows/plant-seed.md +2 -2
  327. package/gsd-core/workflows/pr-branch.md +187 -51
  328. package/gsd-core/workflows/profile-user.md +16 -14
  329. package/gsd-core/workflows/progress.md +61 -18
  330. package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
  331. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +5 -7
  332. package/gsd-core/workflows/quick/steps/quick-verification.md +28 -9
  333. package/gsd-core/workflows/quick/steps/research-phase.md +4 -6
  334. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
  335. package/gsd-core/workflows/quick.md +55 -44
  336. package/gsd-core/workflows/remove-phase.md +4 -4
  337. package/gsd-core/workflows/remove-workspace.md +2 -2
  338. package/gsd-core/workflows/resume-project.md +8 -12
  339. package/gsd-core/workflows/review.md +219 -20
  340. package/gsd-core/workflows/scan.md +1 -1
  341. package/gsd-core/workflows/secure-phase.md +3 -3
  342. package/gsd-core/workflows/session-report.md +2 -1
  343. package/gsd-core/workflows/settings-advanced.md +7 -9
  344. package/gsd-core/workflows/settings-integrations.md +64 -31
  345. package/gsd-core/workflows/settings.md +69 -7
  346. package/gsd-core/workflows/ship.md +116 -50
  347. package/gsd-core/workflows/sketch-wrap-up.md +11 -17
  348. package/gsd-core/workflows/sketch.md +12 -18
  349. package/gsd-core/workflows/smart-entry.md +3 -5
  350. package/gsd-core/workflows/spec-phase.md +53 -13
  351. package/gsd-core/workflows/spike-wrap-up.md +7 -11
  352. package/gsd-core/workflows/spike.md +20 -31
  353. package/gsd-core/workflows/stats.md +2 -2
  354. package/gsd-core/workflows/sync-skills.md +64 -9
  355. package/gsd-core/workflows/thread.md +11 -7
  356. package/gsd-core/workflows/transition.md +49 -14
  357. package/gsd-core/workflows/ui-phase.md +15 -21
  358. package/gsd-core/workflows/ui-review.md +8 -12
  359. package/gsd-core/workflows/ultraplan-phase.md +5 -13
  360. package/gsd-core/workflows/undo.md +8 -16
  361. package/gsd-core/workflows/update.md +7 -11
  362. package/gsd-core/workflows/validate-phase.md +3 -3
  363. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
  364. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  365. package/gsd-core/workflows/verify-work.md +66 -25
  366. package/hooks/dist/gsd-agent-isolation-guard.js +158 -30
  367. package/hooks/dist/gsd-check-update-worker.js +56 -13
  368. package/hooks/dist/gsd-check-update.js +19 -1
  369. package/hooks/dist/gsd-config-reload.js +18 -12
  370. package/hooks/dist/gsd-context-monitor.js +19 -10
  371. package/hooks/dist/gsd-cursor-post-tool.js +3 -1
  372. package/hooks/dist/gsd-cursor-pre-tool.js +2 -3
  373. package/hooks/dist/gsd-cursor-session-start.js +2 -1
  374. package/hooks/dist/gsd-cursor-stop.js +2 -1
  375. package/hooks/dist/gsd-cursor-subagent-start.js +83 -3
  376. package/hooks/dist/gsd-cursor-subagent-stop.js +6 -3
  377. package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
  378. package/hooks/dist/gsd-graphify-update.sh +22 -18
  379. package/hooks/dist/gsd-node-runner.sh +76 -0
  380. package/hooks/dist/gsd-phase-boundary.sh +1 -0
  381. package/hooks/dist/gsd-prompt-guard.js +37 -27
  382. package/hooks/dist/gsd-read-guard.js +16 -7
  383. package/hooks/dist/gsd-read-injection-scanner.js +55 -32
  384. package/hooks/dist/gsd-session-state.sh +1 -0
  385. package/hooks/dist/gsd-statusline.js +231 -24
  386. package/hooks/dist/gsd-update-banner.js +22 -1
  387. package/hooks/dist/gsd-validate-commit.sh +80 -6
  388. package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
  389. package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
  390. package/hooks/dist/gsd-workflow-guard.js +162 -46
  391. package/hooks/dist/gsd-worktree-path-guard.js +36 -21
  392. package/hooks/dist/gsd-write-guard.js +35 -25
  393. package/hooks/dist/lib/cli-exit.js +560 -0
  394. package/hooks/dist/lib/exit-code-registry.js +98 -0
  395. package/hooks/dist/lib/git-cmd.js +92 -59
  396. package/hooks/dist/lib/git-probe.js +84 -0
  397. package/hooks/dist/lib/hook-exit.js +81 -0
  398. package/hooks/dist/lib/injection-patterns.js +45 -0
  399. package/hooks/dist/lib/isolation-deny-reason.js +39 -0
  400. package/hooks/dist/lib/isolation-sentinel.js +9 -0
  401. package/hooks/dist/managed-hooks-registry.cjs +3 -0
  402. package/hooks/gsd-agent-isolation-guard.js +158 -30
  403. package/hooks/gsd-check-update-worker.js +56 -13
  404. package/hooks/gsd-check-update.js +19 -1
  405. package/hooks/gsd-config-reload.js +18 -12
  406. package/hooks/gsd-context-monitor.js +19 -10
  407. package/hooks/gsd-cursor-post-tool.js +3 -1
  408. package/hooks/gsd-cursor-pre-tool.js +2 -3
  409. package/hooks/gsd-cursor-session-start.js +2 -1
  410. package/hooks/gsd-cursor-stop.js +2 -1
  411. package/hooks/gsd-cursor-subagent-start.js +83 -3
  412. package/hooks/gsd-cursor-subagent-stop.js +6 -3
  413. package/hooks/gsd-ensure-canonical-path.js +2 -1
  414. package/hooks/gsd-graphify-update.sh +22 -18
  415. package/hooks/gsd-node-runner.sh +76 -0
  416. package/hooks/gsd-phase-boundary.sh +1 -0
  417. package/hooks/gsd-prompt-guard.js +37 -27
  418. package/hooks/gsd-read-guard.js +16 -7
  419. package/hooks/gsd-read-injection-scanner.js +55 -32
  420. package/hooks/gsd-session-state.sh +1 -0
  421. package/hooks/gsd-statusline.js +231 -24
  422. package/hooks/gsd-update-banner.js +22 -1
  423. package/hooks/gsd-validate-commit.sh +80 -6
  424. package/hooks/gsd-windsurf-pre-command.js +16 -11
  425. package/hooks/gsd-windsurf-pre-write.js +22 -13
  426. package/hooks/gsd-workflow-guard.js +162 -46
  427. package/hooks/gsd-worktree-path-guard.js +36 -21
  428. package/hooks/gsd-write-guard.js +35 -25
  429. package/hooks/lib/cli-exit.js +560 -0
  430. package/hooks/lib/exit-code-registry.js +98 -0
  431. package/hooks/lib/git-cmd.js +92 -59
  432. package/hooks/lib/git-probe.js +84 -0
  433. package/hooks/lib/hook-exit.js +81 -0
  434. package/hooks/lib/injection-patterns.js +45 -0
  435. package/hooks/lib/isolation-deny-reason.js +39 -0
  436. package/hooks/lib/isolation-sentinel.js +9 -0
  437. package/hooks/managed-hooks-registry.cjs +3 -0
  438. package/package.json +28 -11
  439. package/pi/gsd.cjs +19 -5
  440. package/scripts/base64-scan.sh +74 -12
  441. package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
  442. package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
  443. package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
  444. package/scripts/build-hooks.js +5 -0
  445. package/scripts/changeset/lint.cjs +60 -5
  446. package/scripts/check-alias-drift.cjs +7 -43
  447. package/scripts/check-contract-drift.cjs +297 -0
  448. package/scripts/check-glossary-refs.cjs +77 -15
  449. package/scripts/check-mutation-score-ratchet.cjs +156 -0
  450. package/scripts/ci-check-job-near-cap.cjs +49 -0
  451. package/scripts/ci-pr-mergeability.cjs +262 -0
  452. package/scripts/ci-test-scope.cjs +64 -14
  453. package/scripts/ci-timeout-report.cjs +230 -0
  454. package/scripts/command-contract-helpers.cjs +903 -1
  455. package/scripts/docs-guard-registry.cjs +396 -0
  456. package/scripts/gen-adr-index.cjs +728 -38
  457. package/scripts/gen-capability-registry.cjs +11 -21
  458. package/scripts/gen-context-index.cjs +2 -11
  459. package/scripts/gen-exit-code-docs.cjs +318 -0
  460. package/scripts/gen-exit-code-registry.cjs +891 -0
  461. package/scripts/gen-features.cjs +836 -0
  462. package/scripts/gen-health-docs.cjs +390 -0
  463. package/scripts/gen-hooks-cli-exit.cjs +239 -0
  464. package/scripts/gen-install-tree-fixtures.cjs +2 -2
  465. package/scripts/gen-inventory-manifest.cjs +50 -4
  466. package/scripts/gen-loop-host-contract.cjs +138 -25
  467. package/scripts/gen-registry.cjs +3 -14
  468. package/scripts/gen-scripts-cli-exit.cjs +185 -0
  469. package/scripts/gen-state-md-docs.cjs +727 -0
  470. package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
  471. package/scripts/lib/alias-drift-families.cjs +46 -0
  472. package/scripts/lib/ci-job-timing.cjs +72 -0
  473. package/scripts/lib/cli-exit.cjs +546 -44
  474. package/scripts/lib/drift-scan.cjs +308 -0
  475. package/scripts/lib/exit-code-registry.cjs +98 -0
  476. package/scripts/lib/ndjson-reporter.cjs +119 -0
  477. package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -26
  478. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
  479. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
  480. package/scripts/lint-canary-version-leak.cjs +73 -0
  481. package/scripts/lint-command-contract.cjs +96 -13
  482. package/scripts/lint-completion-predicate-drift.cjs +933 -0
  483. package/scripts/lint-completion-ratio-drift.cjs +214 -0
  484. package/scripts/lint-default-flip-documentation.cjs +193 -0
  485. package/scripts/lint-docs-guard-registration.cjs +495 -0
  486. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +193 -0
  487. package/scripts/lint-eslint-glob-coverage.allowlist.json +38 -0
  488. package/scripts/lint-eslint-glob-coverage.cjs +340 -0
  489. package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
  490. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
  491. package/scripts/lint-health-diagnostic-rule-table.cjs +461 -0
  492. package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
  493. package/scripts/lint-milestone-window-drift.cjs +468 -0
  494. package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
  495. package/scripts/lint-phase-enumeration-drift.cjs +492 -0
  496. package/scripts/lint-plan-count-drift.cjs +318 -0
  497. package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
  498. package/scripts/lint-planning-prompt-drift.cjs +471 -0
  499. package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
  500. package/scripts/lint-regression-test-names.cjs +15 -13
  501. package/scripts/lint-removed-but-needed.cjs +488 -0
  502. package/scripts/lint-seam-enforcement.cjs +182 -0
  503. package/scripts/lint-slug-derivation-drift.cjs +921 -0
  504. package/scripts/lint-source-test-name-collision.cjs +241 -0
  505. package/scripts/lint-state-field-drift.cjs +805 -0
  506. package/scripts/lint-state-write-path-drift.cjs +950 -0
  507. package/scripts/lint-test-file-count.allowlist.json +137 -8
  508. package/scripts/lint-test-file-count.cjs +25 -3
  509. package/scripts/lint-unreachable-guard-drift.cjs +830 -0
  510. package/scripts/lint-vendored-deps.cjs +297 -0
  511. package/scripts/mutation-matrix.cjs +599 -50
  512. package/scripts/pr-changed-files.cjs +63 -0
  513. package/scripts/pr-template-policy.cjs +14 -4
  514. package/scripts/prompt-injection-scan.sh +100 -14
  515. package/scripts/require-issue-link-policy.cjs +192 -0
  516. package/scripts/secret-scan.sh +75 -13
  517. package/scripts/select-docs-guards.cjs +56 -0
  518. package/scripts/sync-runtime-launcher.cjs +24 -7
  519. package/skills/gsd-autonomous/SKILL.md +0 -1
  520. package/skills/gsd-code-review/SKILL.md +1 -1
  521. package/skills/gsd-discuss-phase/SKILL.md +1 -1
  522. package/skills/gsd-execute-phase/SKILL.md +1 -2
  523. package/skills/gsd-import/SKILL.md +1 -1
  524. package/skills/gsd-map-codebase/SKILL.md +1 -1
  525. package/skills/gsd-mempalace-capture/SKILL.md +1 -1
  526. package/skills/gsd-mempalace-recall/SKILL.md +1 -1
  527. package/skills/gsd-new-milestone/SKILL.md +1 -1
  528. package/skills/gsd-next/SKILL.md +0 -1
  529. package/skills/gsd-plan-phase/SKILL.md +0 -1
  530. package/skills/gsd-progress/SKILL.md +0 -1
  531. package/skills/gsd-quick/SKILL.md +9 -5
  532. package/skills/gsd-review-backlog/SKILL.md +2 -1
  533. package/skills/gsd-stats/SKILL.md +0 -1
  534. package/skills/gsd-verify-work/SKILL.md +1 -1
  535. package/vscode/package.json +1 -1
  536. package/bin/lib/ui-safety-gate.cjs +0 -107
  537. package/gsd-core/workflows/discovery-phase.md +0 -298
  538. package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
  539. package/gsd-core/workflows/verify-phase.md +0 -574
  540. package/scripts/affected-tests-lib.cjs +0 -554
  541. package/scripts/lint-allow-test-rule-refs.cjs +0 -162
  542. package/scripts/lint-emitted-drift-ack.cjs +0 -344
  543. package/scripts/run-affected-tests.cjs +0 -7
  544. package/scripts/run-tests.cjs +0 -1051
@@ -366,13 +366,32 @@ function normalizeCleanupManifestEntry(entry) {
366
366
  return null;
367
367
  const rawAllowedBases = Array.isArray(e.allowed_bases) ? e.allowed_bases : [];
368
368
  const allowedBases = Array.from(new Set([expectedBase, ...rawAllowedBases.filter((base) => typeof base === 'string' && base.length > 0)]));
369
- return {
369
+ // #2596: liberal in what we accept — non-array, or non-string / empty
370
+ // elements, are dropped rather than coerced. An EMPTY result omits the field
371
+ // entirely, so "declared nothing" is indistinguishable from "not recorded":
372
+ // that ambiguity is already resolved as *unknown* by the per-plan submodule
373
+ // gate's own `[ -z "$PLAN_FILES" ]` rule, and inventing a second rule here
374
+ // would make an unrecorded plan look 100% out of scope.
375
+ const filesModified = (Array.isArray(e.files_modified) ? e.files_modified : [])
376
+ .filter((f) => typeof f === 'string' && f.trim().length > 0);
377
+ // #3003: same liberal-in-what-we-accept rule as `files_modified` above — non-array,
378
+ // or non-string / empty elements, are dropped rather than coerced, and an EMPTY
379
+ // result omits the field entirely so "declares nothing" stays indistinguishable
380
+ // from "not recorded" (the guard's own absence-check already treats both as unknown).
381
+ const declaredDeletions = (Array.isArray(e.declared_deletions) ? e.declared_deletions : [])
382
+ .filter((f) => typeof f === 'string' && f.trim().length > 0);
383
+ const normalized = {
370
384
  agent_id: typeof e.agent_id === 'string' ? e.agent_id : null,
371
385
  worktree_path: worktreePath,
372
386
  branch,
373
387
  expected_base: expectedBase,
374
388
  allowed_bases: allowedBases,
375
389
  };
390
+ if (filesModified.length > 0)
391
+ normalized.files_modified = filesModified;
392
+ if (declaredDeletions.length > 0)
393
+ normalized.declared_deletions = declaredDeletions;
394
+ return normalized;
376
395
  }
377
396
  function normalizeCleanupManifest(manifest) {
378
397
  let parsed = manifest;
@@ -461,6 +480,102 @@ function repoRootStillMidMerge(execGit, repoRoot) {
461
480
  return false; // ref not found — repoRoot is not mid-merge
462
481
  return true; // any other exit code (e.g. a fatal git error) — fail closed
463
482
  }
483
+ // #2596: the single definition of "this file is an executor-written SUMMARY
484
+ // artifact". Shared by `defaultFindSummaryFiles` (which walks for them to
485
+ // rescue) and the scope advisory below (which must never flag them) — a plan's
486
+ // declared `files_modified` never lists a SUMMARY, because the executor writes
487
+ // it by orchestration contract, so a second copy of this rule would make the
488
+ // advisory fire on essentially every wave.
489
+ const SUMMARY_ARTIFACT_DIR = '.planning';
490
+ const SUMMARY_ARTIFACT_SUFFIX = 'SUMMARY.md';
491
+ /**
492
+ * Decode a git-quoted path. With `core.quotepath` left at its default (`true`)
493
+ * git wraps any path containing non-ASCII or special bytes in double quotes
494
+ * and C-escapes it — e.g. `tests/é.ts` is emitted as the literal
495
+ * `"tests/\303\251.ts"`. Both sides of the deletion/scope comparison
496
+ * (a declared path and a git-reported path) must agree on the same decoded
497
+ * shape, and decoding it here — rather than passing `-c core.quotepath=false`
498
+ * on the `execGit` call — keeps the git argv, and therefore every existing
499
+ * test fixture that asserts on exact argv, unchanged. It also works
500
+ * regardless of the user's own `core.quotepath` config.
501
+ *
502
+ * A value that is not wrapped in a leading and trailing `"` is returned
503
+ * completely untouched — this is the overwhelmingly common (plain ASCII)
504
+ * case and must not be altered in any way.
505
+ *
506
+ * Escapes decode to BYTES, collected into a Buffer and decoded as UTF-8 only
507
+ * at the end: `\303\251` is two bytes that together form one character (é),
508
+ * so decoding them one at a time would produce mojibake. Malformed input
509
+ * (a trailing lone backslash, or an octal escape with fewer than three
510
+ * digits) never throws — it degrades to treating the character literally, so
511
+ * a single bad path can never take down the whole cleanup wave.
512
+ */
513
+ function decodeGitQuotedPath(raw) {
514
+ if (raw.length < 2 || !raw.startsWith('"') || !raw.endsWith('"'))
515
+ return raw;
516
+ const body = raw.slice(1, -1);
517
+ const bytes = [];
518
+ for (let i = 0; i < body.length; i++) {
519
+ const ch = body[i];
520
+ if (ch !== '\\' || i === body.length - 1) {
521
+ // UTF-8 bytes, not the code unit: a DECLARED path may be quoted while
522
+ // still holding a literal `é`, and pushing 0xE9 alone is invalid UTF-8.
523
+ // codePointAt keeps a surrogate pair together.
524
+ const codePoint = body.codePointAt(i);
525
+ const char = codePoint === undefined ? ch : String.fromCodePoint(codePoint);
526
+ bytes.push(...Buffer.from(char, 'utf8'));
527
+ i += char.length - 1;
528
+ continue;
529
+ }
530
+ const rest = body.slice(i + 1);
531
+ const octalMatch = /^([0-3][0-7][0-7])/.exec(rest);
532
+ if (octalMatch) {
533
+ bytes.push(parseInt(octalMatch[1], 8));
534
+ i += 3;
535
+ continue;
536
+ }
537
+ const next = body[i + 1];
538
+ const CONTROL_ESCAPES = {
539
+ a: 0x07, b: 0x08, f: 0x0c, n: 0x0a, r: 0x0d, t: 0x09, v: 0x0b,
540
+ '\\': 0x5c, '"': 0x22,
541
+ };
542
+ if (Object.prototype.hasOwnProperty.call(CONTROL_ESCAPES, next)) {
543
+ bytes.push(CONTROL_ESCAPES[next]);
544
+ }
545
+ else {
546
+ bytes.push(next.charCodeAt(0));
547
+ }
548
+ i += 1;
549
+ }
550
+ return Buffer.from(bytes).toString('utf8');
551
+ }
552
+ /**
553
+ * Normalize one path for scope comparison. Applied to BOTH sides so a declared
554
+ * path and a git-reported path meet in the same shape: any git C-quoting is
555
+ * decoded first (order matters — the backslash-to-slash conversion below
556
+ * would destroy the escape sequences if it ran first), then backslashes
557
+ * become slashes unconditionally (a backslash path is not a Windows-only
558
+ * input), and a leading `./` and any trailing `/` are stripped. This is the
559
+ * single normalizer shared by the SUMMARY-artifact predicate and the scope
560
+ * advisory, so the two can never disagree about what `./a\b/` means.
561
+ */
562
+ function normalizeScopePath(raw) {
563
+ return decodeGitQuotedPath(String(raw || '').trim())
564
+ .replace(/\\/g, '/')
565
+ .trim()
566
+ .replace(/^\.\//, '')
567
+ .replace(/\/+$/, '');
568
+ }
569
+ /**
570
+ * True when a worktree-relative path is a SUMMARY artifact. Input may use
571
+ * either separator; normalization to POSIX is unconditional (backslash paths
572
+ * reach Linux too).
573
+ */
574
+ function isSummaryArtifactRelPath(relPath) {
575
+ const normalized = normalizeScopePath(relPath);
576
+ return normalized.startsWith(`${SUMMARY_ARTIFACT_DIR}/`)
577
+ && normalized.endsWith(SUMMARY_ARTIFACT_SUFFIX);
578
+ }
464
579
  /**
465
580
  * Walk <worktreePath>/.planning/ recursively and collect absolute paths of
466
581
  * all files whose names match *SUMMARY.md. Returns [] when the directory
@@ -470,7 +585,7 @@ function repoRootStillMidMerge(execGit, repoRoot) {
470
585
  * find "$WT/.planning" -name "*SUMMARY.md"
471
586
  */
472
587
  function defaultFindSummaryFiles(worktreePath) {
473
- const planningDir = node_path_1.default.join(worktreePath, '.planning');
588
+ const planningDir = node_path_1.default.join(worktreePath, SUMMARY_ARTIFACT_DIR);
474
589
  const results = [];
475
590
  function walk(dir) {
476
591
  let entries;
@@ -485,7 +600,7 @@ function defaultFindSummaryFiles(worktreePath) {
485
600
  if (entry.isDirectory()) {
486
601
  walk(full);
487
602
  }
488
- else if (entry.isFile() && entry.name.endsWith('SUMMARY.md')) {
603
+ else if (entry.isFile() && entry.name.endsWith(SUMMARY_ARTIFACT_SUFFIX)) {
489
604
  results.push(full);
490
605
  }
491
606
  }
@@ -588,6 +703,113 @@ function rescueSummaryArtifacts(worktreePath, repoRoot, deps) {
588
703
  }
589
704
  return { rescuedRelPaths, failures };
590
705
  }
706
+ /**
707
+ * #2596: advisory codes emitted by the wave-cleanup gauntlet. Frozen and
708
+ * exported so tests assert on a code rather than on rendered prose (this repo
709
+ * forbids raw-text matching on test output).
710
+ */
711
+ const WAVE_CLEANUP_WARNING = Object.freeze({
712
+ /** A committed path fell outside the plan's declared `files_modified`. */
713
+ SCOPE_OUT_OF_DECLARED: 'scope_out_of_declared',
714
+ /** The scope diff could not be computed, so conformance is unknown. */
715
+ SCOPE_CHECK_UNAVAILABLE: 'scope_check_unavailable',
716
+ });
717
+ /**
718
+ * The literal directory prefix a declared path covers, or `null` when the
719
+ * pattern begins with a glob metacharacter and therefore has no usable prefix.
720
+ *
721
+ * Deliberately literal-prefix only — NOT a glob engine. A hand-rolled
722
+ * `**`/`*`/`?` matcher inside a worktree-lifecycle module is an informal,
723
+ * undocumented pattern language living where no language belongs, and this
724
+ * repo forbids external deps in core. The submodule-intersection gate
725
+ * (`workflows/execute-phase/steps/per-plan-worktree-gate.md`) already ships
726
+ * exactly this glob-prefix rule; reusing it beats inventing a second one.
727
+ *
728
+ * `null` (no literal prefix, e.g. `*.md`) means "matches everything": for an
729
+ * ADVISORY, a false alarm costs more than a miss, so the ambiguous case
730
+ * suppresses rather than shouts.
731
+ */
732
+ function declaredScopePrefix(declared) {
733
+ const globAt = declared.search(/[*?[]/);
734
+ if (globAt < 0)
735
+ return declared;
736
+ const literal = declared.slice(0, globAt).replace(/\/+$/, '');
737
+ return literal.length > 0 ? literal : null;
738
+ }
739
+ /**
740
+ * #2596: compare a branch's actual committed paths against the plan's declared
741
+ * scope. Pure — no git, no IO. Returns one warning per out-of-scope path, in
742
+ * the order the paths were given. Returns [] when nothing usable was declared:
743
+ * absence of data is not evidence of over-reach.
744
+ */
745
+ function planWaveScopeConformance(changedPaths, declaredFiles, branch) {
746
+ if (!Array.isArray(declaredFiles))
747
+ return [];
748
+ const prefixes = [];
749
+ for (const declared of declaredFiles) {
750
+ if (typeof declared !== 'string')
751
+ continue;
752
+ const normalized = normalizeScopePath(declared);
753
+ if (!normalized)
754
+ continue;
755
+ prefixes.push(declaredScopePrefix(normalized));
756
+ }
757
+ if (prefixes.length === 0)
758
+ return [];
759
+ const warnings = [];
760
+ const seen = new Set();
761
+ for (const raw of Array.isArray(changedPaths) ? changedPaths : []) {
762
+ if (typeof raw !== 'string')
763
+ continue;
764
+ const changed = normalizeScopePath(raw);
765
+ if (!changed || seen.has(changed))
766
+ continue;
767
+ seen.add(changed);
768
+ if (isSummaryArtifactRelPath(changed))
769
+ continue;
770
+ const covered = prefixes.some((prefix) => (prefix === null || changed === prefix || changed.startsWith(`${prefix}/`)));
771
+ if (covered)
772
+ continue;
773
+ warnings.push({ code: WAVE_CLEANUP_WARNING.SCOPE_OUT_OF_DECLARED, branch, path: changed });
774
+ }
775
+ return warnings;
776
+ }
777
+ /**
778
+ * #3003: split git's reported deletions into declared and undeclared.
779
+ *
780
+ * EXACT match after `normalizeScopePath` — the same normalizer both other path
781
+ * comparisons in this file use, so a declared path and a git-reported path meet in the
782
+ * same shape (`a\b` and `./a/b/` both become `a/b`).
783
+ *
784
+ * Deliberately NOT `declaredScopePrefix`. That helper returns `null` for a glob-leading
785
+ * pattern meaning "matches everything", which is right for the ADVISORY it serves — a
786
+ * false alarm there costs more than a miss — and exactly wrong for a GATE, where it would
787
+ * let `["*.ts"]` disarm the guard. A glob here is simply a literal path that matches
788
+ * nothing. Prefix matching is likewise refused: `["tests"]` must not authorize deleting
789
+ * everything under tests/.
790
+ *
791
+ * Pure — no git, no IO. Returns the undeclared residue in the order git reported it.
792
+ */
793
+ function partitionDeclaredDeletions(deletedPaths, declared) {
794
+ const allowed = new Set((Array.isArray(declared) ? declared : [])
795
+ .filter((p) => typeof p === 'string')
796
+ .map((p) => normalizeScopePath(p))
797
+ .filter((p) => p.length > 0));
798
+ const undeclared = [];
799
+ const seen = new Set();
800
+ for (const raw of Array.isArray(deletedPaths) ? deletedPaths : []) {
801
+ if (typeof raw !== 'string')
802
+ continue;
803
+ const normalized = normalizeScopePath(raw);
804
+ if (!normalized || seen.has(normalized))
805
+ continue;
806
+ seen.add(normalized);
807
+ if (allowed.has(normalized))
808
+ continue;
809
+ undeclared.push(normalized);
810
+ }
811
+ return undeclared;
812
+ }
591
813
  function executeWorktreeWaveCleanupPlan(plan, deps = {}) {
592
814
  const execGit = deps.execGit || execGitDefault;
593
815
  const entries = Array.isArray(plan?.entries) ? plan.entries : [];
@@ -598,10 +820,12 @@ function executeWorktreeWaveCleanupPlan(plan, deps = {}) {
598
820
  reason: plan ? (plan.reason || 'missing_entries') : 'missing_plan',
599
821
  entries: [],
600
822
  pending: entries,
823
+ warnings: [],
601
824
  };
602
825
  }
603
826
  const results = [];
604
827
  const pending = [];
828
+ const allWarnings = [];
605
829
  let ok = true;
606
830
  // #2852: every per-entry failure site marks the SAME shape — status='blocked',
607
831
  // a reason code, the captured stderr, push to results, flip the overall `ok`
@@ -622,6 +846,7 @@ function executeWorktreeWaveCleanupPlan(plan, deps = {}) {
622
846
  status: 'pending',
623
847
  reason: null,
624
848
  stderr: '',
849
+ warnings: [],
625
850
  };
626
851
  const branchCheck = execGit(['-C', entry.worktree_path, 'rev-parse', '--abbrev-ref', 'HEAD'], { cwd: plan.repoRoot });
627
852
  if (!gitResultOk(branchCheck) || branchCheck.stdout.trim() !== entry.branch) {
@@ -644,13 +869,57 @@ function executeWorktreeWaveCleanupPlan(plan, deps = {}) {
644
869
  continue; // #2852: isolate
645
870
  }
646
871
  if (deletions.stdout) {
647
- // Unconditional: any deletion in this entry's branch blocks THIS entry. Whether
648
- // that guard should have an opt-in for intentional deletions is a deferred
649
- // product decision (issue #2852's own triage scoped it out — tracked in #3003);
650
- // this fix only isolates the block to this one entry (#2852) instead of aborting
651
- // the rest of the wave, same as every other block reason below.
652
- blockEntry(result, 'branch_contains_deletions', deletions.stdout);
653
- continue; // #2852: isolate
872
+ // #3003: a deletion the PLAN declared is authorized; anything else still blocks.
873
+ // Only a SUCCESSFUL check reaches here — a failed one blocked above on its own
874
+ // reason, so a broken check can never be filtered into a pass.
875
+ //
876
+ // The block detail carries ONLY the undeclared residue. Listing declared paths
877
+ // there would misdirect the operator toward paths that were fine.
878
+ const undeclaredDeletions = partitionDeclaredDeletions(deletions.stdout.split('\n'), entry.declared_deletions);
879
+ if (undeclaredDeletions.length > 0) {
880
+ blockEntry(result, 'branch_contains_deletions', undeclaredDeletions.join('\n'));
881
+ continue; // #2852: isolate
882
+ }
883
+ }
884
+ // #2596: advisory scope conformance — does the branch's ACTUAL committed
885
+ // diff stay inside the scope the plan declared? Gated on a declared scope
886
+ // being present: with nothing declared there is nothing to compare, so no
887
+ // git subprocess is spent at all (and every pre-#2596 fixture, none of
888
+ // which declares one, issues exactly the git calls it always did).
889
+ //
890
+ // ADVISORY ONLY. Unlike the deletions check above, a finding here does NOT
891
+ // call blockEntry and does NOT touch `ok` — the merge proceeds. Promotion
892
+ // to a hard gate is a separate, disclosed change.
893
+ // #3003: a declared deletion is in scope by construction — `git diff --name-only`
894
+ // includes deleted paths, so without accounting for the declaration, authorizing a
895
+ // deletion would immediately warn that the same path is out of declared scope.
896
+ //
897
+ // It is SUBTRACTED from the findings rather than UNIONED into the declared scope,
898
+ // and the difference is not cosmetic. `planWaveScopeConformance` reads its scope
899
+ // list with prefix-and-glob semantics, so unioning would silently hand
900
+ // `declared_deletions` a second, WIDER matching rule than the gate gives it:
901
+ // `["*.md"]` (inert at the gate) would yield a null prefix meaning "matches
902
+ // everything" and mute the advisory entirely, and `["src"]` would mute all of
903
+ // `src/`. One field with two matching rules is a trap. Subtracting keeps the
904
+ // field exact-match-only on every surface it touches.
905
+ //
906
+ // Gating stays on `files_modified` alone for the same reason: a plan that declares
907
+ // only deletions has still declared no modification scope, so the advisory stays
908
+ // exactly as silent as it was before this change instead of warning on every
909
+ // modified path.
910
+ const declaredFiles = Array.isArray(entry.files_modified) ? entry.files_modified : [];
911
+ if (declaredFiles.length > 0) {
912
+ const scopeDiff = execGit(['diff', '--name-only', `HEAD...${entry.branch}`], { cwd: plan.repoRoot });
913
+ const scopeWarnings = !gitResultOk(scopeDiff)
914
+ // A broken advisory must never become a gate: record that conformance
915
+ // is unknown rather than blocking (or, worse, silently passing).
916
+ ? [{ code: WAVE_CLEANUP_WARNING.SCOPE_CHECK_UNAVAILABLE, branch: entry.branch, path: null }]
917
+ : planWaveScopeConformance((scopeDiff.stdout || '').split('\n'), declaredFiles, entry.branch)
918
+ // A path-less warning (SCOPE_CHECK_UNAVAILABLE) is never subtracted.
919
+ .filter((w) => w.path === null
920
+ || partitionDeclaredDeletions([w.path], entry.declared_deletions).length > 0);
921
+ result.warnings.push(...scopeWarnings);
922
+ allWarnings.push(...scopeWarnings);
654
923
  }
655
924
  // Safety net: rescue uncommitted SUMMARY.md artifacts before the dirty check.
656
925
  // The executor leaves <quick_id>-SUMMARY.md uncommitted by contract — the
@@ -737,6 +1006,7 @@ function executeWorktreeWaveCleanupPlan(plan, deps = {}) {
737
1006
  reason: ok ? 'ok' : 'cleanup_blocked',
738
1007
  entries: results,
739
1008
  pending,
1009
+ warnings: allWarnings,
740
1010
  };
741
1011
  }
742
1012
  function cmdWorktreeCleanupWave(cwd, args = []) {
@@ -777,6 +1047,15 @@ function cmdWorktreeCleanupWave(cwd, args = []) {
777
1047
  process.exitCode = 1;
778
1048
  }
779
1049
  }
1050
+ /**
1051
+ * #2596: split a `--files` value into declared paths. Whitespace-separated,
1052
+ * matching the `PLAN_FILES` shape the per-plan worktree gate already builds
1053
+ * with `jq -r '.files_modified // [] | join(" ")'`. Values are DATA compared
1054
+ * against a diff — never opened, never passed to a shell.
1055
+ */
1056
+ function parseDeclaredScopeFlag(raw) {
1057
+ return String(raw || '').split(/\s+/).filter((token) => token.length > 0);
1058
+ }
780
1059
  /**
781
1060
  * Pure planner for the per-agent wave-manifest append.
782
1061
  *
@@ -793,8 +1072,9 @@ function cmdWorktreeCleanupWave(cwd, args = []) {
793
1072
  * rejected loudly — the reader dedups on that key, so a re-record would be
794
1073
  * silently dropped (the failure mode this verb exists to eliminate). The
795
1074
  * on-disk shape stays the existing 4-field entry (`agent_id`, `worktree_path`,
796
- * `branch`, `expected_base`) — no schema change; the reader re-derives
797
- * `allowed_bases`.
1075
+ * `branch`, `expected_base`) unless `--files` declares a scope, in which case
1076
+ * an optional `files_modified` is appended (#2596); the reader still
1077
+ * re-derives `allowed_bases`.
798
1078
  */
799
1079
  function planWorktreeRecordAgent(manifestRaw, fields) {
800
1080
  // 1. Write-strict required-field check (loud, with which flag is missing).
@@ -824,11 +1104,17 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
824
1104
  }
825
1105
  // 2. Shared validation: run the candidate through the reader's normalizer.
826
1106
  // If it returns null the reader would drop this entry on read — reject now.
1107
+ const declaredScope = parseDeclaredScopeFlag(fields.files);
1108
+ // #3003: reuse parseDeclaredScopeFlag — a blank/absent --deletions leaves the
1109
+ // entry shape untouched, mirroring the --files rule directly above.
1110
+ const declaredDeletions = parseDeclaredScopeFlag(fields.deletions);
827
1111
  const candidate = {
828
1112
  agent_id: agentId,
829
1113
  worktree_path: worktreePath,
830
1114
  branch,
831
1115
  expected_base: base,
1116
+ ...(declaredScope.length > 0 ? { files_modified: declaredScope } : {}),
1117
+ ...(declaredDeletions.length > 0 ? { declared_deletions: declaredDeletions } : {}),
832
1118
  };
833
1119
  const entry = normalizeCleanupManifestEntry(candidate);
834
1120
  if (!entry) {
@@ -917,6 +1203,16 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
917
1203
  branch: entry.branch,
918
1204
  expected_base: entry.expected_base,
919
1205
  };
1206
+ // #2596: only written when a scope was actually declared — conservative in
1207
+ // what we send, so a blank --files leaves the 4-field shape untouched.
1208
+ if (entry.files_modified && entry.files_modified.length > 0) {
1209
+ recorded.files_modified = entry.files_modified;
1210
+ }
1211
+ // #3003: same conservative rule as --files above — a blank --deletions
1212
+ // leaves the entry shape untouched.
1213
+ if (entry.declared_deletions && entry.declared_deletions.length > 0) {
1214
+ recorded.declared_deletions = entry.declared_deletions;
1215
+ }
920
1216
  worktrees.push(recorded);
921
1217
  return {
922
1218
  ok: true,
@@ -928,7 +1224,7 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
928
1224
  /**
929
1225
  * CLI command: append a validated per-agent entry to a wave cleanup manifest.
930
1226
  *
931
- * Usage: worktree record-agent --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha>
1227
+ * Usage: worktree record-agent --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> [--files "<space-separated paths>"] [--deletions "<space-separated paths>"]
932
1228
  *
933
1229
  * Fails loudly (non-zero exit + recovery hint on stderr) when a field is
934
1230
  * missing/garbled or the manifest is absent/malformed, rather than appending an
@@ -937,13 +1233,15 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
937
1233
  function cmdWorktreeRecordAgent(cwd, args = [], deps = {}) {
938
1234
  const flag = (name) => {
939
1235
  const i = args.indexOf(name);
940
- return i >= 0 && i + 1 < args.length ? args[i + 1] : '';
1236
+ if (i < 0 || i + 1 >= args.length)
1237
+ return '';
1238
+ return args[i + 1];
941
1239
  };
942
1240
  const write = deps.write || ((s) => process.stdout.write(s));
943
1241
  const writeErr = deps.writeErr || ((s) => process.stderr.write(s));
944
1242
  const manifestPath = flag('--manifest');
945
1243
  if (!manifestPath) {
946
- writeErr('Usage: worktree record-agent --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha>\n');
1244
+ writeErr('Usage: worktree record-agent --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> [--files "<space-separated paths>"] [--deletions "<space-separated paths>"]\n');
947
1245
  process.exitCode = 2;
948
1246
  return { ok: false, reason: 'usage', entry: null };
949
1247
  }
@@ -965,6 +1263,8 @@ function cmdWorktreeRecordAgent(cwd, args = [], deps = {}) {
965
1263
  worktreePath: flag('--path'),
966
1264
  branch: flag('--branch'),
967
1265
  base: flag('--base'),
1266
+ files: flag('--files'),
1267
+ deletions: flag('--deletions'),
968
1268
  });
969
1269
  if (!plan.ok || plan.manifest === null) {
970
1270
  writeErr(`[gsd] worktree.record-agent: ${plan.reason} — ${plan.hint || ''}\n`);
@@ -1008,11 +1308,17 @@ function planWorktreeCreate(fields) {
1008
1308
  entry: null,
1009
1309
  };
1010
1310
  }
1311
+ const declaredScope = parseDeclaredScopeFlag(fields.files);
1312
+ // #3003: reuse parseDeclaredScopeFlag — a blank/absent --deletions leaves the
1313
+ // entry shape untouched, mirroring the --files rule directly above.
1314
+ const declaredDeletions = parseDeclaredScopeFlag(fields.deletions);
1011
1315
  const candidate = {
1012
1316
  agent_id: agentId,
1013
1317
  worktree_path: worktreePath,
1014
1318
  branch,
1015
1319
  expected_base: base,
1320
+ ...(declaredScope.length > 0 ? { files_modified: declaredScope } : {}),
1321
+ ...(declaredDeletions.length > 0 ? { declared_deletions: declaredDeletions } : {}),
1016
1322
  };
1017
1323
  const entry = normalizeCleanupManifestEntry(candidate);
1018
1324
  if (!entry) {
@@ -1140,7 +1446,7 @@ function executeWorktreeCreatePlan(plan, repoRoot, deps = {}) {
1140
1446
  * validated manifest entry so the worktree is immediately manageable by
1141
1447
  * `worktree cleanup-wave` / `worktree reap-orphans`.
1142
1448
  *
1143
- * Usage: worktree create --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> --root <dir>
1449
+ * Usage: worktree create --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> --root <dir> [--files "<space-separated paths>"] [--deletions "<space-separated paths>"]
1144
1450
  *
1145
1451
  * #2584 FIX 1 — ORDERING CONTRACT: every manifest read/parse/shape-validate/
1146
1452
  * plan step runs BEFORE the git side effect (step 5). The ONLY manifest
@@ -1154,13 +1460,15 @@ function executeWorktreeCreatePlan(plan, repoRoot, deps = {}) {
1154
1460
  function cmdWorktreeCreate(cwd, args = [], deps = {}) {
1155
1461
  const flag = (name) => {
1156
1462
  const i = args.indexOf(name);
1157
- return i >= 0 && i + 1 < args.length ? args[i + 1] : '';
1463
+ if (i < 0 || i + 1 >= args.length)
1464
+ return '';
1465
+ return args[i + 1];
1158
1466
  };
1159
1467
  const write = deps.write || ((s) => process.stdout.write(s));
1160
1468
  const writeErr = deps.writeErr || ((s) => process.stderr.write(s));
1161
1469
  const manifestPath = flag('--manifest');
1162
1470
  if (!manifestPath) {
1163
- writeErr('Usage: worktree create --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> --root <dir>\n');
1471
+ writeErr('Usage: worktree create --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> --root <dir> [--files "<space-separated paths>"] [--deletions "<space-separated paths>"]\n');
1164
1472
  process.exitCode = 2;
1165
1473
  return { ok: false, reason: 'usage' };
1166
1474
  }
@@ -1225,6 +1533,8 @@ function cmdWorktreeCreate(cwd, args = [], deps = {}) {
1225
1533
  worktreePath: flag('--path'),
1226
1534
  branch: flag('--branch'),
1227
1535
  base: flag('--base'),
1536
+ files: flag('--files'),
1537
+ deletions: flag('--deletions'),
1228
1538
  });
1229
1539
  if (!plan.ok || !plan.entry) {
1230
1540
  writeErr(`[gsd] worktree.create: ${plan.reason} — ${plan.hint || ''}\n`);
@@ -1291,6 +1601,16 @@ function cmdWorktreeCreate(cwd, args = [], deps = {}) {
1291
1601
  branch: plan.entry.branch,
1292
1602
  expected_base: plan.entry.expected_base,
1293
1603
  };
1604
+ // #2596: only written when a scope was actually declared — conservative in
1605
+ // what we send, so a blank --files leaves the 4-field shape untouched.
1606
+ if (Array.isArray(plan.entry.files_modified) && plan.entry.files_modified.length > 0) {
1607
+ recorded.files_modified = plan.entry.files_modified;
1608
+ }
1609
+ // #3003: same conservative rule as --files above — a blank --deletions
1610
+ // leaves the entry shape untouched.
1611
+ if (Array.isArray(plan.entry.declared_deletions) && plan.entry.declared_deletions.length > 0) {
1612
+ recorded.declared_deletions = plan.entry.declared_deletions;
1613
+ }
1294
1614
  const dedupeKey = `${recorded.worktree_path}\0${recorded.branch}`;
1295
1615
  const alreadyPresent = worktrees.some((existing) => {
1296
1616
  const normalized = normalizeCleanupManifestEntry(existing);
@@ -1677,6 +1997,9 @@ module.exports = {
1677
1997
  normalizeCleanupManifest,
1678
1998
  planWorktreeWaveCleanup,
1679
1999
  executeWorktreeWaveCleanupPlan,
2000
+ WAVE_CLEANUP_WARNING,
2001
+ planWaveScopeConformance,
2002
+ isSummaryArtifactRelPath,
1680
2003
  cmdWorktreeCleanupWave,
1681
2004
  planWorktreeRecordAgent,
1682
2005
  cmdWorktreeRecordAgent,
@@ -1,5 +1,5 @@
1
1
  {
2
- "_comment": "Canonical CONFIG_DEFAULTS for the Configuration Module. Nested shape is canonical. CJS flat projection (branching_strategy, sub_repos, etc.) is handled by consumers at the boundary. Security keys (security_enforcement, security_asvs_level, security_block_on) and post_planning_gaps live in workflow.* as their canonical location. resolve_model_ids, context_window, phase_naming are CJS-originated top-level keys included here. brave_search, firecrawl, exa_search default to false in the manifest; at runtime buildNewProjectConfig detects API keys. The plan_checker (CJS flat) → workflow.plan_check (canonical nested) divergence is resolved: canonical name is workflow.plan_check. _auto_chain_active is a runtime-state field included for completeness.",
2
+ "_comment": "Canonical CONFIG_DEFAULTS for the Configuration Module. Nested shape is canonical. CJS flat projection (branching_strategy, sub_repos, etc.) is handled by consumers at the boundary. Security keys (security_enforcement, security_asvs_level, security_block_on) and post_planning_gaps live in workflow.* as their canonical location. resolve_model_ids, context_window, phase_naming are CJS-originated top-level keys included here. brave_search, firecrawl, exa_search default to false in the manifest; at runtime buildNewProjectConfig detects API keys. The plan_checker (CJS flat) \u2192 workflow.plan_check (canonical nested) divergence is resolved: canonical name is workflow.plan_check. _auto_chain_active is a runtime-state field included for completeness.",
3
3
  "model_profile": "balanced",
4
4
  "commit_docs": true,
5
5
  "parallelization": true,
@@ -28,6 +28,7 @@
28
28
  "verifier": true,
29
29
  "nyquist_validation": true,
30
30
  "ai_integration_phase": true,
31
+ "agent_hint_routing": true,
31
32
  "human_verify_mode": "end-of-phase",
32
33
  "auto_advance": false,
33
34
  "_auto_chain_active": false,
@@ -45,11 +46,13 @@
45
46
  "context_coverage_gate": true,
46
47
  "code_review": true,
47
48
  "code_review_depth": "standard",
49
+ "code_review_depth_overrides": [],
48
50
  "code_review_command": null,
49
51
  "pattern_mapper": true,
50
52
  "plan_bounce": false,
51
53
  "plan_bounce_script": null,
52
54
  "plan_bounce_passes": 2,
55
+ "inline_plan_threshold": 2,
53
56
  "auto_prune_state": false,
54
57
  "post_planning_gaps": true,
55
58
  "security_enforcement": true,
@@ -59,6 +62,7 @@
59
62
  },
60
63
  "planning": {
61
64
  "commit_docs": true,
65
+ "pr_strict": false,
62
66
  "search_gitignored": false,
63
67
  "sub_repos": [],
64
68
  "granularity": "standard"
@@ -96,6 +100,9 @@
96
100
  "source_grounding": true,
97
101
  "source_grounding_authority": "grep"
98
102
  },
103
+ "review": {
104
+ "max_prompt_tokens": null
105
+ },
99
106
  "capabilities": {
100
107
  "strict_known_registries": null,
101
108
  "auto_update": false
@@ -29,12 +29,14 @@
29
29
  "workflow.use_worktrees",
30
30
  "workflow.worktree_skip_hooks",
31
31
  "workflow.code_review_command",
32
+ "workflow.code_review_depth_overrides",
32
33
  "workflow.plan_bounce",
33
34
  "workflow.plan_bounce_script",
34
35
  "workflow.plan_bounce_passes",
35
36
  "workflow.plan_chunked",
36
37
  "workflow.specless_probe_fallback",
37
38
  "workflow.plan_review_convergence",
39
+ "workflow.agent_hint_routing",
38
40
  "code_quality.fallow.enabled",
39
41
  "code_quality.fallow.scope",
40
42
  "code_quality.fallow.profile",
@@ -42,16 +44,19 @@
42
44
  "ship.pr_body_sections",
43
45
  "git.branching_strategy",
44
46
  "git.base_branch",
47
+ "git.protected_branches",
45
48
  "git.create_tag",
46
49
  "git.phase_branch_template",
47
50
  "git.milestone_branch_template",
48
51
  "git.quick_branch_template",
49
52
  "planning.commit_docs",
53
+ "planning.pr_strict",
50
54
  "planning.search_gitignored",
51
55
  "planning.sub_repos",
52
56
  "review.default_reviewers",
53
57
  "review.max_prompt_tokens",
54
58
  "review.max_prompt_tokens_per_reviewer",
59
+ "review.parallel_lanes",
55
60
  "workflow.cross_ai_execution",
56
61
  "workflow.cross_ai_command",
57
62
  "workflow.cross_ai_timeout",
@@ -74,6 +79,7 @@
74
79
  "statusline.show_context_tokens",
75
80
  "statusline.state_format",
76
81
  "statusline.show_git",
82
+ "statusline.show_state_freshness",
77
83
  "workflow.max_discuss_passes",
78
84
  "features.thinking_partner",
79
85
  "context",
@@ -180,7 +186,12 @@
180
186
  {
181
187
  "topLevel": "model_policy",
182
188
  "source": "^model_policy\\.runtime_tiers\\.[a-zA-Z0-9_-]+\\.(opus|sonnet|haiku)$",
183
- "description": "model_policy.runtime_tiers.<runtime>.<opus|sonnet|haiku>"
189
+ "description": "model_policy.runtime_tiers.<runtime>.<opus|sonnet|haiku> (#3587)"
190
+ },
191
+ {
192
+ "topLevel": "phase_commit_docs",
193
+ "source": "^phase_commit_docs\\.\\d+[A-Z]?(?:\\.\\d+)*$",
194
+ "description": "phase_commit_docs.<phase-id> — per-phase commit_docs override (#3587). The <phase-id> segment is a hand-copy of the canonical PHASE_NUMBER_TOKEN_SOURCE grammar owned by src/phase-id.cts (#2128); this manifest is hand-maintained JSON so it cannot import that constant. Pinned against drift by the behavioral parity test in tests/commit-docs-bypass.test.cjs (folded 'phase-commit-docs' block, describe block 'E', #3587) — do not hand-edit this pattern without updating that test."
184
195
  }
185
196
  ]
186
197
  }
@@ -0,0 +1,8 @@
1
+ [
2
+ { "code": 2, "name": "HOOK_DENY", "meaning": "Hook protocol deny — the harness blocks the tool call", "owner": "hook-adapter", "authorizedBy": "ADR-3889" },
3
+ { "code": 64, "name": "USAGE", "meaning": "Caller error — bad argv, unknown subcommand, missing argument", "owner": "generic", "authorizedBy": "ADR-3889" },
4
+ { "code": 66, "name": "NO_INPUT", "meaning": "Ran; zero units were in scope, and that emptiness is known to be genuine", "owner": "generic", "authorizedBy": "ADR-3889" },
5
+ { "code": 69, "name": "UNAVAILABLE", "meaning": "Could not run — prerequisite absent, input unreadable, scope unestablished", "owner": "generic", "authorizedBy": "ADR-3889" },
6
+ { "code": 70, "name": "INTERNAL", "meaning": "Self-failure — crash, timeout, killed subprocess", "owner": "generic", "authorizedBy": "ADR-3889" },
7
+ { "code": 80, "name": "DEGRADED", "meaning": "Ran to completion and is reporting a condition through its result payload rather than as a process failure", "owner": "gsd-tools", "authorizedBy": "ADR-3889 + ADR-2980" }
8
+ ]