@opengsd/gsd-core 1.11.0 → 1.13.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 (498) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +12 -0
  4. package/agents/gsd-code-fixer.md +1 -1
  5. package/agents/gsd-debug-session-manager.md +1 -1
  6. package/agents/gsd-debugger.md +1 -1
  7. package/agents/gsd-dom-verifier.md +169 -0
  8. package/agents/gsd-eval-auditor.md +1 -1
  9. package/agents/gsd-executor.md +78 -42
  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 +0 -1
  13. package/agents/gsd-pattern-mapper.md +11 -0
  14. package/agents/gsd-phase-researcher.md +3 -1
  15. package/agents/gsd-plan-checker.md +91 -112
  16. package/agents/gsd-planner.md +20 -4
  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 +82 -7
  21. package/agents/gsd-ui-researcher.md +70 -3
  22. package/agents/gsd-verifier.md +24 -2
  23. package/bin/install.js +847 -200
  24. package/commands/gsd/discuss-phase.md +1 -1
  25. package/commands/gsd/execute-phase.md +1 -1
  26. package/commands/gsd/import.md +1 -1
  27. package/commands/gsd/ns-workflow.md +2 -1
  28. package/commands/gsd/phase.md +1 -1
  29. package/commands/gsd/quick-batch.md +105 -0
  30. package/commands/gsd/quick.md +8 -4
  31. package/commands/gsd/surface.md +18 -8
  32. package/gsd-core/bin/gsd-tools.cjs +761 -100
  33. package/gsd-core/bin/lib/active-workstream-store.cjs +8 -0
  34. package/gsd-core/bin/lib/adr-parser.cjs +13 -7
  35. package/gsd-core/bin/lib/agent-install-check.cjs +162 -0
  36. package/gsd-core/bin/lib/api-coverage.cjs +30 -9
  37. package/gsd-core/bin/lib/artifacts.cjs +2 -0
  38. package/gsd-core/bin/lib/assumption-delta.cjs +30 -11
  39. package/gsd-core/bin/lib/audit.cjs +163 -41
  40. package/gsd-core/bin/lib/broken-windows.cjs +306 -28
  41. package/gsd-core/bin/lib/capability-activation.cjs +27 -0
  42. package/gsd-core/bin/lib/capability-lock.cjs +10 -4
  43. package/gsd-core/bin/lib/capability-registry.cjs +785 -144
  44. package/gsd-core/bin/lib/capability-state.cjs +25 -4
  45. package/gsd-core/bin/lib/capability-validator.cjs +321 -18
  46. package/gsd-core/bin/lib/capability-writer.cjs +14 -4
  47. package/gsd-core/bin/lib/check-command-router.cjs +229 -6
  48. package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
  49. package/gsd-core/bin/lib/cli-exit.cjs +496 -10
  50. package/gsd-core/bin/lib/clusters.cjs +1 -0
  51. package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
  52. package/gsd-core/bin/lib/codex-agent-toml.cjs +410 -4
  53. package/gsd-core/bin/lib/command-aliases.cjs +16 -0
  54. package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
  55. package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
  56. package/gsd-core/bin/lib/commands.cjs +877 -54
  57. package/gsd-core/bin/lib/complexity-trigger.cjs +26 -6
  58. package/gsd-core/bin/lib/config-loader.cjs +121 -29
  59. package/gsd-core/bin/lib/config.cjs +92 -2
  60. package/gsd-core/bin/lib/configuration.cjs +129 -37
  61. package/gsd-core/bin/lib/core-utils.cjs +118 -14
  62. package/gsd-core/bin/lib/decisions.cjs +213 -1
  63. package/gsd-core/bin/lib/edge-probe.cjs +23 -2
  64. package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
  65. package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
  66. package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
  67. package/gsd-core/bin/lib/frontmatter.cjs +975 -326
  68. package/gsd-core/bin/lib/gap-checker.cjs +41 -8
  69. package/gsd-core/bin/lib/git-base-branch.cjs +182 -39
  70. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +7 -3
  71. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
  72. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +60 -14
  73. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +75 -22
  74. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +22 -8
  75. package/gsd-core/bin/lib/health-diagnostic.cjs +23 -3
  76. package/gsd-core/bin/lib/host-integration.cjs +96 -11
  77. package/gsd-core/bin/lib/init-command-router.cjs +132 -21
  78. package/gsd-core/bin/lib/init.cjs +252 -56
  79. package/gsd-core/bin/lib/install-engine.cjs +252 -15
  80. package/gsd-core/bin/lib/install-model-override-resolver.cjs +78 -1
  81. package/gsd-core/bin/lib/install-profiles.cjs +100 -18
  82. package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
  83. package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
  84. package/gsd-core/bin/lib/installer-migrations.cjs +10 -7
  85. package/gsd-core/bin/lib/intel.cjs +101 -26
  86. package/gsd-core/bin/lib/io.cjs +195 -15
  87. package/gsd-core/bin/lib/learnings.cjs +85 -14
  88. package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
  89. package/gsd-core/bin/lib/loop-resolver.cjs +14 -8
  90. package/gsd-core/bin/lib/markdown-table.cjs +175 -4
  91. package/gsd-core/bin/lib/milestone.cjs +112 -7
  92. package/gsd-core/bin/lib/model-catalog.cjs +177 -19
  93. package/gsd-core/bin/lib/model-resolver.cjs +10 -28
  94. package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
  95. package/gsd-core/bin/lib/phase-command-router.cjs +13 -6
  96. package/gsd-core/bin/lib/phase-estimation.cjs +17 -8
  97. package/gsd-core/bin/lib/phase-id.cjs +321 -13
  98. package/gsd-core/bin/lib/phase-lifecycle.cjs +24 -16
  99. package/gsd-core/bin/lib/phase-locator.cjs +138 -17
  100. package/gsd-core/bin/lib/phase.cjs +1175 -115
  101. package/gsd-core/bin/lib/plan-document.cjs +273 -0
  102. package/gsd-core/bin/lib/plan-scan.cjs +13 -2
  103. package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
  104. package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
  105. package/gsd-core/bin/lib/planning-snapshot.cjs +165 -34
  106. package/gsd-core/bin/lib/planning-workspace.cjs +159 -28
  107. package/gsd-core/bin/lib/probe-core.cjs +4 -1
  108. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
  109. package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
  110. package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
  111. package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
  112. package/gsd-core/bin/lib/quick-batch.cjs +840 -0
  113. package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
  114. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +71 -45
  115. package/gsd-core/bin/lib/review-lane-descriptor.cjs +62 -14
  116. package/gsd-core/bin/lib/review-lane-invocation.cjs +73 -1
  117. package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
  118. package/gsd-core/bin/lib/roadmap-command-router.cjs +45 -31
  119. package/gsd-core/bin/lib/roadmap-parser.cjs +577 -41
  120. package/gsd-core/bin/lib/roadmap.cjs +248 -64
  121. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +329 -41
  122. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +16 -17
  123. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +320 -109
  124. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +487 -83
  125. package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
  126. package/gsd-core/bin/lib/runtime-slash.cjs +72 -2
  127. package/gsd-core/bin/lib/shell-command-projection.cjs +75 -8
  128. package/gsd-core/bin/lib/smart-entry.cjs +19 -31
  129. package/gsd-core/bin/lib/spec-section.cjs +12 -7
  130. package/gsd-core/bin/lib/state-command-router.cjs +47 -18
  131. package/gsd-core/bin/lib/state-contract.cjs +359 -0
  132. package/gsd-core/bin/lib/state-document.cjs +216 -5
  133. package/gsd-core/bin/lib/state-md-schema.cjs +231 -0
  134. package/gsd-core/bin/lib/state-transition.cjs +850 -145
  135. package/gsd-core/bin/lib/state.cjs +1629 -287
  136. package/gsd-core/bin/lib/surface.cjs +33 -10
  137. package/gsd-core/bin/lib/task-command-router.cjs +111 -1
  138. package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
  139. package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
  140. package/gsd-core/bin/lib/teams-status.cjs +4 -1
  141. package/gsd-core/bin/lib/uat-predicate.cjs +58 -20
  142. package/gsd-core/bin/lib/uat.cjs +2542 -387
  143. package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
  144. package/gsd-core/bin/lib/ui-safety-gate.cjs +37 -7
  145. package/gsd-core/bin/lib/unusable-input.cjs +13 -0
  146. package/gsd-core/bin/lib/update-context.cjs +6 -2
  147. package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
  148. package/gsd-core/bin/lib/validate.cjs +230 -12
  149. package/gsd-core/bin/lib/vendor/README.md +43 -5
  150. package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
  151. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  152. package/gsd-core/bin/lib/verification.cjs +287 -13
  153. package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
  154. package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
  155. package/gsd-core/bin/lib/verify.cjs +441 -56
  156. package/gsd-core/bin/lib/workstream-inventory.cjs +20 -2
  157. package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
  158. package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
  159. package/gsd-core/bin/lib/worktree-safety.cjs +185 -21
  160. package/gsd-core/bin/shared/config-defaults.manifest.json +7 -1
  161. package/gsd-core/bin/shared/config-schema.manifest.json +13 -0
  162. package/gsd-core/bin/shared/exit-codes.json +8 -0
  163. package/gsd-core/bin/shared/exit-codes.sh +20 -0
  164. package/gsd-core/bin/shared/model-catalog.json +8 -1
  165. package/gsd-core/bin/verify-reapply-patches.cjs +70 -3
  166. package/gsd-core/references/agent-contracts.md +6 -5
  167. package/gsd-core/references/api-coverage.md +24 -2
  168. package/gsd-core/references/autonomous-smart-discuss.md +3 -3
  169. package/gsd-core/references/checkpoints.md +37 -19
  170. package/gsd-core/references/decimal-phase-calculation.md +5 -5
  171. package/gsd-core/references/edge-probe.md +17 -5
  172. package/gsd-core/references/execute-mvp-tdd.md +18 -18
  173. package/gsd-core/references/execute-phase-between-wave-reset.md +9 -12
  174. package/gsd-core/references/execute-phase-response-language.md +6 -0
  175. package/gsd-core/references/execute-phase-wave-guard.md +11 -9
  176. package/gsd-core/references/executor-examples.md +42 -0
  177. package/gsd-core/references/failing-direction.md +78 -0
  178. package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
  179. package/gsd-core/references/gate-prompts.md +1 -1
  180. package/gsd-core/references/git-integration.md +5 -5
  181. package/gsd-core/references/git-planning-commit.md +3 -3
  182. package/gsd-core/references/gsd-run-resolver.md +1 -1
  183. package/gsd-core/references/loop-hook-dispatch.md +22 -0
  184. package/gsd-core/references/model-profiles.md +1 -1
  185. package/gsd-core/references/mvp-concepts.md +2 -2
  186. package/gsd-core/references/nyquist-compliance.md +74 -0
  187. package/gsd-core/references/offer-next.md +3 -5
  188. package/gsd-core/references/phase-argument-parsing.md +3 -3
  189. package/gsd-core/references/plan-checker-examples.md +41 -0
  190. package/gsd-core/references/planner-antipatterns.md +25 -0
  191. package/gsd-core/references/planner-chunked.md +5 -1
  192. package/gsd-core/references/planner-coupling.md +42 -0
  193. package/gsd-core/references/planner-failing-direction.md +53 -0
  194. package/gsd-core/references/planner-human-verify-mode.md +15 -1
  195. package/gsd-core/references/planner-quick-batch.md +71 -0
  196. package/gsd-core/references/planner-reviews.md +47 -0
  197. package/gsd-core/references/planner-revision.md +76 -3
  198. package/gsd-core/references/planner-verify-command-grounding.md +17 -0
  199. package/gsd-core/references/planning-config.md +39 -9
  200. package/gsd-core/references/response-language-directive.md +9 -0
  201. package/gsd-core/references/reviewer-instances.md +31 -0
  202. package/gsd-core/references/revision-loop.md +118 -11
  203. package/gsd-core/references/runtime-aware-dispatch.md +1 -1
  204. package/gsd-core/references/tdd.md +15 -12
  205. package/gsd-core/references/ui-brand.md +65 -21
  206. package/gsd-core/references/ui-consideration-probe.md +1 -1
  207. package/gsd-core/references/universal-anti-patterns.md +2 -2
  208. package/gsd-core/references/verifier-evidence-gate.md +160 -0
  209. package/gsd-core/references/verify-command-path-resolvability.md +42 -0
  210. package/gsd-core/references/verify-mvp-mode.md +1 -1
  211. package/gsd-core/references/workstream-flag.md +11 -11
  212. package/gsd-core/templates/README.md +1 -1
  213. package/gsd-core/templates/SECURITY.md +3 -3
  214. package/gsd-core/templates/UI-SPEC.md +25 -3
  215. package/gsd-core/templates/VALIDATION.md +3 -3
  216. package/gsd-core/templates/phase-prompt.md +7 -0
  217. package/gsd-core/templates/state.md +7 -0
  218. package/gsd-core/templates/verification-report.md +5 -0
  219. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  220. package/gsd-core/workflows/add-backlog.md +3 -1
  221. package/gsd-core/workflows/add-phase.md +5 -3
  222. package/gsd-core/workflows/add-tests.md +4 -9
  223. package/gsd-core/workflows/add-todo.md +2 -2
  224. package/gsd-core/workflows/ai-integration-phase.md +5 -10
  225. package/gsd-core/workflows/analyze-dependencies.md +2 -0
  226. package/gsd-core/workflows/audit-fix.md +14 -3
  227. package/gsd-core/workflows/audit-milestone.md +11 -9
  228. package/gsd-core/workflows/audit-uat.md +19 -2
  229. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
  230. package/gsd-core/workflows/autonomous.md +12 -26
  231. package/gsd-core/workflows/check-todos.md +2 -2
  232. package/gsd-core/workflows/cleanup.md +3 -3
  233. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +16 -14
  234. package/gsd-core/workflows/code-review-fix.md +3 -1
  235. package/gsd-core/workflows/code-review.md +192 -69
  236. package/gsd-core/workflows/complete-milestone.md +28 -14
  237. package/gsd-core/workflows/debug.md +6 -4
  238. package/gsd-core/workflows/diagnose-issues.md +17 -7
  239. package/gsd-core/workflows/discuss-phase/modes/advisor.md +3 -1
  240. package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
  241. package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
  242. package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
  243. package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
  244. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -7
  245. package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
  246. package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
  247. package/gsd-core/workflows/discuss-phase/modes/text.md +3 -1
  248. package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
  249. package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
  250. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
  251. package/gsd-core/workflows/discuss-phase-assumptions.md +3 -3
  252. package/gsd-core/workflows/discuss-phase-power.md +2 -0
  253. package/gsd-core/workflows/discuss-phase.md +2 -2
  254. package/gsd-core/workflows/do.md +46 -19
  255. package/gsd-core/workflows/docs-update.md +6 -5
  256. package/gsd-core/workflows/edit-phase.md +3 -1
  257. package/gsd-core/workflows/eval-review.md +5 -10
  258. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +3 -1
  259. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +129 -11
  260. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
  261. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
  262. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
  263. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +29 -5
  264. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
  265. package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
  266. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +4 -2
  267. package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
  268. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
  269. package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
  270. package/gsd-core/workflows/execute-phase.md +68 -66
  271. package/gsd-core/workflows/execute-plan.md +25 -20
  272. package/gsd-core/workflows/explore.md +3 -1
  273. package/gsd-core/workflows/extract-learnings.md +3 -1
  274. package/gsd-core/workflows/fast.md +8 -2
  275. package/gsd-core/workflows/forensics.md +3 -1
  276. package/gsd-core/workflows/graduation.md +6 -6
  277. package/gsd-core/workflows/health.md +4 -7
  278. package/gsd-core/workflows/help/modes/brief.md +2 -0
  279. package/gsd-core/workflows/help/modes/default.md +2 -0
  280. package/gsd-core/workflows/help/modes/full.md +12 -0
  281. package/gsd-core/workflows/help/modes/topic.md +2 -0
  282. package/gsd-core/workflows/help.md +2 -0
  283. package/gsd-core/workflows/import.md +17 -14
  284. package/gsd-core/workflows/inbox.md +5 -6
  285. package/gsd-core/workflows/ingest-docs.md +45 -12
  286. package/gsd-core/workflows/insert-phase.md +7 -5
  287. package/gsd-core/workflows/list-phase-assumptions.md +2 -0
  288. package/gsd-core/workflows/list-seeds.md +7 -3
  289. package/gsd-core/workflows/list-workspaces.md +3 -1
  290. package/gsd-core/workflows/manager.md +15 -26
  291. package/gsd-core/workflows/map-codebase.md +3 -1
  292. package/gsd-core/workflows/milestone-summary.md +3 -1
  293. package/gsd-core/workflows/mvp-phase.md +3 -3
  294. package/gsd-core/workflows/new-milestone.md +10 -22
  295. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
  296. package/gsd-core/workflows/new-project.md +17 -29
  297. package/gsd-core/workflows/new-workspace.md +2 -2
  298. package/gsd-core/workflows/next.md +4 -2
  299. package/gsd-core/workflows/node-repair.md +2 -0
  300. package/gsd-core/workflows/note.md +2 -0
  301. package/gsd-core/workflows/onboard.md +1 -1
  302. package/gsd-core/workflows/pause-work.md +20 -5
  303. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
  304. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
  305. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +4 -4
  306. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +12 -3
  307. package/gsd-core/workflows/plan-phase.md +251 -54
  308. package/gsd-core/workflows/plan-review-convergence.md +148 -19
  309. package/gsd-core/workflows/plant-seed.md +3 -3
  310. package/gsd-core/workflows/pr-branch.md +195 -51
  311. package/gsd-core/workflows/profile-user.md +17 -15
  312. package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
  313. package/gsd-core/workflows/progress.md +52 -15
  314. package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
  315. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +38 -5
  316. package/gsd-core/workflows/quick/steps/quick-verification.md +2 -4
  317. package/gsd-core/workflows/quick/steps/research-phase.md +5 -7
  318. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
  319. package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
  320. package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
  321. package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
  322. package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
  323. package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
  324. package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
  325. package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
  326. package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
  327. package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
  328. package/gsd-core/workflows/quick-batch.md +203 -0
  329. package/gsd-core/workflows/quick.md +33 -32
  330. package/gsd-core/workflows/reapply-patches.md +2 -0
  331. package/gsd-core/workflows/remove-phase.md +6 -4
  332. package/gsd-core/workflows/remove-workspace.md +3 -3
  333. package/gsd-core/workflows/resume-project.md +14 -14
  334. package/gsd-core/workflows/review.md +404 -21
  335. package/gsd-core/workflows/scan.md +3 -1
  336. package/gsd-core/workflows/section-manifest.json +12 -0
  337. package/gsd-core/workflows/secure-phase.md +3 -3
  338. package/gsd-core/workflows/session-report.md +2 -0
  339. package/gsd-core/workflows/settings-advanced.md +9 -9
  340. package/gsd-core/workflows/settings-integrations.md +66 -32
  341. package/gsd-core/workflows/settings.md +4 -6
  342. package/gsd-core/workflows/ship.md +22 -16
  343. package/gsd-core/workflows/sketch-wrap-up.md +13 -17
  344. package/gsd-core/workflows/sketch.md +13 -19
  345. package/gsd-core/workflows/smart-entry.md +4 -6
  346. package/gsd-core/workflows/spec-phase.md +31 -4
  347. package/gsd-core/workflows/spike-wrap-up.md +9 -11
  348. package/gsd-core/workflows/spike.md +21 -32
  349. package/gsd-core/workflows/stats.md +4 -2
  350. package/gsd-core/workflows/sync-skills.md +13 -5
  351. package/gsd-core/workflows/thread.md +13 -7
  352. package/gsd-core/workflows/transition.md +7 -5
  353. package/gsd-core/workflows/ui-phase.md +36 -21
  354. package/gsd-core/workflows/ui-review.md +7 -11
  355. package/gsd-core/workflows/ultraplan-phase.md +7 -13
  356. package/gsd-core/workflows/undo.md +9 -17
  357. package/gsd-core/workflows/update.md +47 -48
  358. package/gsd-core/workflows/validate-phase.md +3 -3
  359. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
  360. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
  361. package/gsd-core/workflows/verify-work.md +106 -21
  362. package/hooks/dist/gsd-agent-isolation-guard.js +77 -38
  363. package/hooks/dist/gsd-check-update-worker.js +19 -2
  364. package/hooks/dist/gsd-config-reload.js +18 -12
  365. package/hooks/dist/gsd-context-monitor.js +302 -22
  366. package/hooks/dist/gsd-cursor-post-tool.js +3 -1
  367. package/hooks/dist/gsd-cursor-pre-tool.js +3 -1
  368. package/hooks/dist/gsd-cursor-session-start.js +2 -1
  369. package/hooks/dist/gsd-cursor-stop.js +2 -1
  370. package/hooks/dist/gsd-cursor-subagent-start.js +28 -23
  371. package/hooks/dist/gsd-cursor-subagent-stop.js +3 -1
  372. package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
  373. package/hooks/dist/gsd-graphify-update.sh +22 -18
  374. package/hooks/dist/gsd-node-runner.sh +77 -0
  375. package/hooks/dist/gsd-phase-boundary.sh +1 -0
  376. package/hooks/dist/gsd-prompt-guard.js +46 -12
  377. package/hooks/dist/gsd-read-guard.js +18 -7
  378. package/hooks/dist/gsd-read-injection-scanner.js +22 -13
  379. package/hooks/dist/gsd-secret-read-guard.js +1079 -0
  380. package/hooks/dist/gsd-session-state.sh +1 -0
  381. package/hooks/dist/gsd-statusline.js +222 -29
  382. package/hooks/dist/gsd-validate-commit.sh +523 -12
  383. package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
  384. package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
  385. package/hooks/dist/gsd-workflow-guard.js +36 -17
  386. package/hooks/dist/gsd-worktree-path-guard.js +36 -21
  387. package/hooks/dist/gsd-write-guard.js +35 -25
  388. package/hooks/dist/lib/cli-exit.js +560 -0
  389. package/hooks/dist/lib/exit-code-registry.js +98 -0
  390. package/hooks/dist/lib/git-cmd.js +210 -1
  391. package/hooks/dist/lib/git-probe.js +84 -0
  392. package/hooks/dist/lib/hook-exit.js +81 -0
  393. package/hooks/dist/lib/injection-patterns.js +36 -6
  394. package/hooks/dist/managed-hooks-registry.cjs +4 -0
  395. package/hooks/gsd-agent-isolation-guard.js +77 -38
  396. package/hooks/gsd-check-update-worker.js +19 -2
  397. package/hooks/gsd-config-reload.js +18 -12
  398. package/hooks/gsd-context-monitor.js +302 -22
  399. package/hooks/gsd-cursor-post-tool.js +3 -1
  400. package/hooks/gsd-cursor-pre-tool.js +3 -1
  401. package/hooks/gsd-cursor-session-start.js +2 -1
  402. package/hooks/gsd-cursor-stop.js +2 -1
  403. package/hooks/gsd-cursor-subagent-start.js +28 -23
  404. package/hooks/gsd-cursor-subagent-stop.js +3 -1
  405. package/hooks/gsd-ensure-canonical-path.js +2 -1
  406. package/hooks/gsd-graphify-update.sh +22 -18
  407. package/hooks/gsd-node-runner.sh +77 -0
  408. package/hooks/gsd-phase-boundary.sh +1 -0
  409. package/hooks/gsd-prompt-guard.js +46 -12
  410. package/hooks/gsd-read-guard.js +18 -7
  411. package/hooks/gsd-read-injection-scanner.js +22 -13
  412. package/hooks/gsd-secret-read-guard.js +1079 -0
  413. package/hooks/gsd-session-state.sh +1 -0
  414. package/hooks/gsd-statusline.js +222 -29
  415. package/hooks/gsd-validate-commit.sh +523 -12
  416. package/hooks/gsd-windsurf-pre-command.js +16 -11
  417. package/hooks/gsd-windsurf-pre-write.js +22 -13
  418. package/hooks/gsd-workflow-guard.js +36 -17
  419. package/hooks/gsd-worktree-path-guard.js +36 -21
  420. package/hooks/gsd-write-guard.js +35 -25
  421. package/hooks/hooks.json +6 -0
  422. package/hooks/lib/cli-exit.js +560 -0
  423. package/hooks/lib/exit-code-registry.js +98 -0
  424. package/hooks/lib/git-cmd.js +210 -1
  425. package/hooks/lib/git-probe.js +84 -0
  426. package/hooks/lib/hook-exit.js +81 -0
  427. package/hooks/lib/injection-patterns.js +36 -6
  428. package/hooks/managed-hooks-registry.cjs +4 -0
  429. package/package.json +14 -9
  430. package/scripts/base64-scan.sh +74 -12
  431. package/scripts/build-hooks.js +12 -0
  432. package/scripts/check-glossary-refs.cjs +77 -15
  433. package/scripts/check-mutation-score-ratchet.cjs +156 -0
  434. package/scripts/ci-check-job-near-cap.cjs +49 -0
  435. package/scripts/ci-pr-mergeability.cjs +262 -0
  436. package/scripts/ci-test-scope.cjs +52 -12
  437. package/scripts/ci-timeout-report.cjs +230 -0
  438. package/scripts/docs-guard-registry.cjs +406 -0
  439. package/scripts/gen-capability-registry.cjs +8 -6
  440. package/scripts/gen-exit-code-docs.cjs +318 -0
  441. package/scripts/gen-exit-code-registry.cjs +891 -0
  442. package/scripts/gen-features.cjs +836 -0
  443. package/scripts/gen-hooks-cli-exit.cjs +239 -0
  444. package/scripts/gen-install-tree-fixtures.cjs +2 -2
  445. package/scripts/gen-loop-host-contract.cjs +189 -4
  446. package/scripts/gen-scripts-cli-exit.cjs +185 -0
  447. package/scripts/gen-state-md-docs.cjs +727 -0
  448. package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
  449. package/scripts/lib/ci-job-timing.cjs +72 -0
  450. package/scripts/lib/cli-exit.cjs +546 -44
  451. package/scripts/lib/drift-scan.cjs +32 -2
  452. package/scripts/lib/exit-code-registry.cjs +98 -0
  453. package/scripts/lib/ndjson-reporter.cjs +119 -0
  454. package/scripts/lib/shellcheck-fetch.cjs +247 -0
  455. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
  456. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
  457. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
  458. package/scripts/lint-docs-guard-registration.cjs +495 -0
  459. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +198 -0
  460. package/scripts/lint-eslint-glob-coverage.allowlist.json +4 -0
  461. package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
  462. package/scripts/lint-health-diagnostic-rule-table.cjs +65 -8
  463. package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
  464. package/scripts/lint-phase-enumeration-drift.cjs +45 -14
  465. package/scripts/lint-phase-id-drift.cjs +133 -8
  466. package/scripts/lint-planning-prompt-drift.cjs +38 -1
  467. package/scripts/lint-portable-grep.cjs +176 -0
  468. package/scripts/lint-removed-but-needed.cjs +184 -16
  469. package/scripts/lint-response-language-coverage.cjs +524 -0
  470. package/scripts/lint-seam-enforcement.cjs +182 -0
  471. package/scripts/lint-slug-derivation-drift.cjs +921 -0
  472. package/scripts/lint-source-test-name-collision.cjs +241 -0
  473. package/scripts/lint-state-write-path-drift.cjs +337 -432
  474. package/scripts/lint-test-file-count.allowlist.json +124 -4
  475. package/scripts/lint-test-file-count.cjs +25 -3
  476. package/scripts/lint-unreachable-guard-drift.cjs +51 -64
  477. package/scripts/lint-vendored-deps.cjs +208 -35
  478. package/scripts/lint-workflow-shellcheck-baseline.json +1027 -0
  479. package/scripts/lint-workflow-shellcheck.cjs +614 -0
  480. package/scripts/mutation-matrix.cjs +599 -50
  481. package/scripts/npm-audit-baseline.cjs +376 -0
  482. package/scripts/prompt-injection-scan.sh +83 -14
  483. package/scripts/require-issue-link-policy.cjs +16 -1
  484. package/scripts/secret-scan.sh +75 -13
  485. package/scripts/select-docs-guards.cjs +56 -0
  486. package/scripts/sync-runtime-launcher.cjs +22 -3
  487. package/skills/gsd-discuss-phase/SKILL.md +1 -1
  488. package/skills/gsd-execute-phase/SKILL.md +1 -1
  489. package/skills/gsd-import/SKILL.md +1 -1
  490. package/skills/gsd-ns-workflow/SKILL.md +1 -0
  491. package/skills/gsd-phase/SKILL.md +1 -1
  492. package/skills/gsd-quick/SKILL.md +8 -4
  493. package/skills/gsd-quick-batch/SKILL.md +105 -0
  494. package/skills/gsd-surface/SKILL.md +18 -8
  495. package/vscode/package.json +1 -1
  496. package/bin/lib/ui-safety-gate.cjs +0 -109
  497. package/scripts/lint-emitted-drift-ack.cjs +0 -344
  498. package/scripts/state-write-path-drift-baseline.json +0 -19
@@ -63,7 +63,19 @@ function countRoadmapPhases(roadmapPath, fallbackCount, cwd, ws, versionOverride
63
63
  return fallbackCount;
64
64
  if (!cwd)
65
65
  return fallbackCount;
66
- const filter = getMilestonePhaseFilter(cwd, versionOverride ?? null, null, ws ?? null);
66
+ // #2761 B1 (trek-e review): `undefined`, NOT `null`. The third argument
67
+ // discriminates "not resolved yet — resolve it from this workstream's
68
+ // config" (`undefined`) from "resolved, and it is not bracket" (`null`).
69
+ // This site meant the former and spelled the latter, so a workstream that
70
+ // opted into `phase_id_convention: "bracket"` had its ROADMAP scanned with
71
+ // the LEGACY grammar: the heading set came back empty, `phaseCount` was 0,
72
+ // and the count silently fell back to the on-disk directory count — the
73
+ // very degrade the #3185 rewrite of this function existed to remove.
74
+ // Measured on a bracket workstream whose milestone declares 3 phases:
75
+ // `null` -> 0 (fallback), `undefined` -> 3. A non-bracket workstream
76
+ // resolves to a value that compiles the same base grammar `null` did, so
77
+ // its count is unchanged (verified against a legacy control).
78
+ const filter = getMilestonePhaseFilter(cwd, versionOverride ?? null, undefined, ws ?? null);
67
79
  // A pass-all degrade (phaseCount 0) means the window declared no phases —
68
80
  // fall back rather than reporting a confident zero.
69
81
  return filter.phaseCount > 0 ? filter.phaseCount : fallbackCount;
@@ -437,7 +449,13 @@ function inspectWorkstream(cwd, name, options = {}) {
437
449
  // filtering. Consulted only when it is genuinely scoped to a single milestone
438
450
  // (`versionScoped`); the unversioned whole-roadmap shape spans the project's
439
451
  // lifetime and would re-admit prior-milestone phases — the very defect here.
440
- const headingFilter = getMilestonePhaseFilter(cwd, currentVersion, null, name);
452
+ //
453
+ // #2761 B1 (trek-e review): `undefined`, not `null` — same discriminator fix
454
+ // as `countRoadmapPhases` above. This site iterates workstreams by NAME, so
455
+ // it is exactly the caller that cannot set `GSD_WORKSTREAM`; spelling `null`
456
+ // pinned every workstream to the legacy grammar and made `headingScoped`
457
+ // unreachable (`phaseCount > 0` never held) on a bracket workstream.
458
+ const headingFilter = getMilestonePhaseFilter(cwd, currentVersion, undefined, name);
441
459
  const headingScoped = headingFilter.versionScoped && headingFilter.phaseCount > 0;
442
460
  // Phase keys the ROADMAP attributes to some OTHER milestone. A row carrying an
443
461
  // explicit version that is not the current one is a positive claim by a prior
@@ -6,6 +6,24 @@
6
6
  * byte-for-behaviour from the prior hand-written .cjs; only types are added.
7
7
  *
8
8
  * Used by active-workstream-store.cjs, planning-workspace.cjs, workstream.cjs.
9
+ *
10
+ * #3883 (ADR-3473 §8.3): toWorkstreamSlug delegates to core-utils.cjs's
11
+ * generateSlugInternal (the canonical slug formula), passing `maxLen: null`
12
+ * to preserve this site's pre-migration untruncated contract — the 60-char
13
+ * default collided distinct >60-char workstream names onto the same slug
14
+ * (verified: `"a".repeat(60)+"alpha"` and `"a".repeat(60)+"beta"` truncated
15
+ * identically). core-utils.cjs already
16
+ * requires (transitively, at module-init time) THIS module:
17
+ * core-utils.cjs -> planning-workspace.cjs -> active-workstream-store.cjs ->
18
+ * workstream-name-policy.cjs. A top-level require of core-utils.cjs here
19
+ * would therefore close that cycle and — per this codebase's compiled-.cjs
20
+ * convention of a single `module.exports = {...}` reassignment at the bottom
21
+ * of core-utils.cjs — capture a stale, still-empty exports object forever
22
+ * (verified live: "generateSlugInternal is not a function" whichever module
23
+ * loads first). The require is deferred (lazy, inside toWorkstreamSlug's
24
+ * body) instead, mirroring the same cycle-break already used by
25
+ * core-utils.cts's own getPhaseFileStats/plan-scan.cjs seam and by
26
+ * phase-id.cts's toDir/getPhaseDirFromPhaseId.
9
27
  */
10
28
  Object.defineProperty(exports, "__esModule", { value: true });
11
29
  exports.INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE = void 0;
@@ -68,10 +86,13 @@ function validateWorkstreamName(name) {
68
86
  * Lowercases, collapses non-alphanumeric runs to hyphens, strips leading/trailing hyphens.
69
87
  */
70
88
  function toWorkstreamSlug(name) {
71
- return String(name ?? '')
72
- .toLowerCase()
73
- .replace(/[^a-z0-9]+/g, '-')
74
- .replace(/^-+|-+$/g, '');
89
+ // #3883 (ADR-3473 §8.3): delegate to the canonical slug formula
90
+ // (generateSlugInternal, core-utils.cts) rather than re-implementing it —
91
+ // this call site previously diverged from it (no transliteration, no
92
+ // 60-char truncation). Lazy require to break the core-utils.cjs cycle
93
+ // (see the module dependency doc comment above).
94
+ // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
95
+ return require('./core-utils.cjs').generateSlugInternal(String(name ?? ''), null) ?? '';
75
96
  }
76
97
  /**
77
98
  * Returns true when `name` is a valid active workstream name:
@@ -94,10 +94,13 @@ function parseJsonc(text) {
94
94
  }
95
95
  // ─── Message constants (verbatim — downstream docs/tests depend on these) ─────
96
96
  function buildMsgDiverged(headSha, forkRef, forkSha) {
97
- return `⚠ Worktree base mismatch: HEAD (${shortSha(headSha)}) differs from ${forkRef} (${shortSha(forkSha)}). Running this phase sequentially on the main working tree. To keep parallel worktrees, set worktree.baseRef:"head" in .claude/settings.local.json (or run: gsd-tools worktree set-baseref). See #683.`;
97
+ return `⚠ Worktree base mismatch: HEAD (${shortSha(headSha)}) differs from ${forkRef} (${shortSha(forkSha)}). Running this phase sequentially on the main working tree. Parallel worktrees return once HEAD is merged/pushed so ${forkRef} matches it. (worktree.baseRef:"head" applies only where GSD itself creates the worktree — the runtime harness does not read it; #48, #3659.)`;
98
98
  }
99
- const MSG_UNKNOWN = `⚠ Cannot determine the worktree fork base (origin/HEAD unresolved). Running this phase sequentially on the main working tree to avoid a base mismatch. To keep parallel worktrees, set worktree.baseRef:"head" in .claude/settings.local.json (or run: gsd-tools worktree set-baseref). See #683.`;
100
- const MSG_HEAD_UNRESOLVABLE = `⚠ Cannot determine the worktree base (git rev-parse HEAD did not return a definitive answer). Running this phase sequentially on the main working tree to avoid an unverified base mismatch. Note: worktree.baseRef:"head" would silence this check without verifying the base — it skips the comparison rather than resolving it. Retry; if it persists, check for a stalled filesystem mount or a stale git index lock (.git/index.lock). See #683, #3050.`;
99
+ const MSG_UNKNOWN = `⚠ Cannot determine the worktree fork base (origin/HEAD unresolved). Running this phase sequentially on the main working tree to avoid a base mismatch. Parallel worktrees return once origin/HEAD resolves and matches HEAD. See #683, #3659.`;
100
+ function buildMsgBaserefHeadIgnored(headSha, forkRef, forkSha) {
101
+ return `⚠ Worktree base mismatch: worktree.baseRef:"head" is set, but the runtime harness does not honor it for isolated dispatch — the fork base stays ${forkRef} (${shortSha(forkSha)}) while HEAD is ${shortSha(headSha)} (#48; upstream claude-code#44965). Running this phase sequentially on the main working tree. Parallel worktrees return once HEAD is merged/pushed so ${forkRef} matches it, or on runtimes where GSD itself manages worktree creation. See #3659.`;
102
+ }
103
+ const MSG_HEAD_UNRESOLVABLE = `⚠ Cannot determine the worktree base (git rev-parse HEAD did not return a definitive answer). Running this phase sequentially on the main working tree to avoid an unverified base mismatch. Note: worktree.baseRef:"head" silences this check only where GSD itself creates the worktree (orchestrator-managed runtimes) — in harness mode it never applied (#48, #3659). Retry; if it persists, check for a stalled filesystem mount or a stale git index lock (.git/index.lock). See #683, #3050.`;
101
104
  /**
102
105
  * Returns true when an execGit result indicates the subprocess was killed by
103
106
  * a timeout. A timeout means the command genuinely could not complete — it
@@ -228,7 +231,20 @@ function resolveEffectiveBaseRef(claudeDir, deps, userClaudeDir) {
228
231
  * deps.userClaudeDir overrides the user/global config directory resolution
229
232
  * (default: getGlobalConfigDir('claude'), which honours CLAUDE_CONFIG_DIR).
230
233
  */
231
- function cmdWorktreeBaseCheck(cwd, _args, deps) {
234
+ function cmdWorktreeBaseCheck(cwd, args, deps) {
235
+ // --mode threads the dispatch isolation mode through to the evaluation
236
+ // (#3659): 'harness-worktree' (default) or 'orchestrator-worktree'. Invalid
237
+ // or missing values after --mode fail closed — a silently defaulted typo
238
+ // would re-open the hole the flag exists to close.
239
+ let isolationMode = 'harness-worktree';
240
+ const modeIdx = args.indexOf('--mode');
241
+ if (modeIdx !== -1) {
242
+ const value = args[modeIdx + 1];
243
+ if (value !== 'harness-worktree' && value !== 'orchestrator-worktree') {
244
+ throw new Error(`worktree base-check: --mode must be harness-worktree or orchestrator-worktree, got ${JSON.stringify(value ?? null)}`);
245
+ }
246
+ isolationMode = value;
247
+ }
232
248
  const claudeDir = node_path_1.default.join(cwd, '.claude');
233
249
  const userClaudeDir = Object.prototype.hasOwnProperty.call(deps ?? {}, 'userClaudeDir')
234
250
  ? deps.userClaudeDir
@@ -238,8 +254,22 @@ function cmdWorktreeBaseCheck(cwd, _args, deps) {
238
254
  cwd,
239
255
  effectiveBaseRef,
240
256
  execGit: deps?.execGit,
257
+ isolationMode,
258
+ });
259
+ // Default emit goes through fs.writeSync(1, …), NOT process.stdout.write:
260
+ // the CLI's --pick capture intercepts writeSync, and command substitution
261
+ // is a pipe — via process.stdout.write a `$(gsd-tools … --pick x)` capture
262
+ // received the full JSON instead of the picked field, so the workflow
263
+ // auto-degrade guards never matched (#3659 review). Short-count loop per
264
+ // io.cjs writeAllSync's rationale (a non-blocking pipe can accept partial
265
+ // writes).
266
+ const write = deps?.write ?? ((s) => {
267
+ const buf = Buffer.from(s, 'utf8');
268
+ let offset = 0;
269
+ while (offset < buf.length) {
270
+ offset += node_fs_1.default.writeSync(1, buf, offset, buf.length - offset);
271
+ }
241
272
  });
242
- const write = deps?.write ?? ((s) => process.stdout.write(s));
243
273
  write(JSON.stringify(result, null, 2) + '\n');
244
274
  return result;
245
275
  }
@@ -295,7 +325,20 @@ function cmdWorktreeSetBaseRef(cwd, _args, deps) {
295
325
  baseRef: 'head',
296
326
  file,
297
327
  };
298
- const write = deps?.write ?? ((s) => process.stdout.write(s));
328
+ // Default emit goes through fs.writeSync(1, …), NOT process.stdout.write:
329
+ // the CLI's --pick capture intercepts writeSync, and command substitution
330
+ // is a pipe — via process.stdout.write a `$(gsd-tools … --pick x)` capture
331
+ // received the full JSON instead of the picked field, so the workflow
332
+ // auto-degrade guards never matched (#3659 review). Short-count loop per
333
+ // io.cjs writeAllSync's rationale (a non-blocking pipe can accept partial
334
+ // writes).
335
+ const write = deps?.write ?? ((s) => {
336
+ const buf = Buffer.from(s, 'utf8');
337
+ let offset = 0;
338
+ while (offset < buf.length) {
339
+ offset += node_fs_1.default.writeSync(1, buf, offset, buf.length - offset);
340
+ }
341
+ });
299
342
  write(JSON.stringify(output, null, 2) + '\n');
300
343
  return output;
301
344
  }
@@ -311,12 +354,19 @@ function evaluateWorktreeBaseDegrade(deps) {
311
354
  const execGit = deps?.execGit ?? shell_command_projection_cjs_1.execGit;
312
355
  const cwd = deps?.cwd;
313
356
  const cwdOpts = cwd ? { cwd } : {};
314
- // a. If baseRef is explicitly 'head' the harness forks from HEAD — no mismatch possible.
315
- // Claude Code's worktree.baseRef accepts only "fresh" (= origin/HEAD, the default) or "head".
316
- // Therefore special-casing "head" here and otherwise comparing HEAD against origin/HEAD is
317
- // complete: any non-"head" value (including "fresh" and absent/null) has fresh/origin-HEAD
318
- // semantics and must be evaluated against origin/HEAD. (Reference: Claude Code worktrees docs, #683.)
319
- if (deps?.effectiveBaseRef === 'head') {
357
+ // a. baseRef 'head' suppresses ONLY where GSD controls the fork start-point
358
+ // (#3659). The former unconditional suppress trusted the harness to honor the
359
+ // setting; #48 verified 5/5 that the Agent-isolation dispatch path never
360
+ // routes through project settings (upstream claude-code#44965), so in
361
+ // harness mode the fork base is always origin/HEAD and 'head' must fall
362
+ // through to the same comparison the fresh path runs. In
363
+ // orchestrator-worktree mode GSD itself runs `git worktree add <path>
364
+ // <start-point>` with the orchestrator HEAD — 'head' is honored by
365
+ // construction there and the suppress is correct. Any non-"head" value
366
+ // (including "fresh" and absent/null) has fresh/origin-HEAD semantics and is
367
+ // evaluated against origin/HEAD as before. (Reference: #683, #48, #3659.)
368
+ const headIgnoredByHarness = deps?.effectiveBaseRef === 'head';
369
+ if (headIgnoredByHarness && (deps?.isolationMode ?? 'harness-worktree') === 'orchestrator-worktree') {
320
370
  return { shouldDegrade: false, reason: 'baseref-head', message: null, headSha: null, forkRef: null, forkSha: null, headAbsenceVerified: null };
321
371
  }
322
372
  // b. Resolve HEAD sha.
@@ -389,6 +439,10 @@ function evaluateWorktreeBaseDegrade(deps) {
389
439
  if (forkSha === headSha) {
390
440
  return { shouldDegrade: false, reason: 'head-matches-fork', message: null, headSha, forkRef, forkSha, headAbsenceVerified: null };
391
441
  }
442
+ if (headIgnoredByHarness) {
443
+ const message = buildMsgBaserefHeadIgnored(headSha, forkRef, forkSha);
444
+ return { shouldDegrade: true, reason: 'baseref-head-ignored-by-harness', message, headSha, forkRef, forkSha, headAbsenceVerified: null };
445
+ }
392
446
  const message = buildMsgDiverged(headSha, forkRef, forkSha);
393
447
  return { shouldDegrade: true, reason: 'head-diverged-from-fork', message, headSha, forkRef, forkSha, headAbsenceVerified: null };
394
448
  }
@@ -374,6 +374,12 @@ function normalizeCleanupManifestEntry(entry) {
374
374
  // would make an unrecorded plan look 100% out of scope.
375
375
  const filesModified = (Array.isArray(e.files_modified) ? e.files_modified : [])
376
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);
377
383
  const normalized = {
378
384
  agent_id: typeof e.agent_id === 'string' ? e.agent_id : null,
379
385
  worktree_path: worktreePath,
@@ -383,6 +389,8 @@ function normalizeCleanupManifestEntry(entry) {
383
389
  };
384
390
  if (filesModified.length > 0)
385
391
  normalized.files_modified = filesModified;
392
+ if (declaredDeletions.length > 0)
393
+ normalized.declared_deletions = declaredDeletions;
386
394
  return normalized;
387
395
  }
388
396
  function normalizeCleanupManifest(manifest) {
@@ -480,16 +488,84 @@ function repoRootStillMidMerge(execGit, repoRoot) {
480
488
  // advisory fire on essentially every wave.
481
489
  const SUMMARY_ARTIFACT_DIR = '.planning';
482
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
+ * Exported (#4081) so the codebase-drift gate's `--name-status` parser can
514
+ * decode the identical C-quoted form before classifying paths — the gate's
515
+ * `execGit` call sets no `core.quotepath` config, so it receives the same
516
+ * quoting and must decode it with the same single owner of this seam.
517
+ */
518
+ function decodeGitQuotedPath(raw) {
519
+ if (raw.length < 2 || !raw.startsWith('"') || !raw.endsWith('"'))
520
+ return raw;
521
+ const body = raw.slice(1, -1);
522
+ const bytes = [];
523
+ for (let i = 0; i < body.length; i++) {
524
+ const ch = body[i];
525
+ if (ch !== '\\' || i === body.length - 1) {
526
+ // UTF-8 bytes, not the code unit: a DECLARED path may be quoted while
527
+ // still holding a literal `é`, and pushing 0xE9 alone is invalid UTF-8.
528
+ // codePointAt keeps a surrogate pair together.
529
+ const codePoint = body.codePointAt(i);
530
+ const char = codePoint === undefined ? ch : String.fromCodePoint(codePoint);
531
+ bytes.push(...Buffer.from(char, 'utf8'));
532
+ i += char.length - 1;
533
+ continue;
534
+ }
535
+ const rest = body.slice(i + 1);
536
+ const octalMatch = /^([0-3][0-7][0-7])/.exec(rest);
537
+ if (octalMatch) {
538
+ bytes.push(parseInt(octalMatch[1], 8));
539
+ i += 3;
540
+ continue;
541
+ }
542
+ const next = body[i + 1];
543
+ const CONTROL_ESCAPES = {
544
+ a: 0x07, b: 0x08, f: 0x0c, n: 0x0a, r: 0x0d, t: 0x09, v: 0x0b,
545
+ '\\': 0x5c, '"': 0x22,
546
+ };
547
+ if (Object.prototype.hasOwnProperty.call(CONTROL_ESCAPES, next)) {
548
+ bytes.push(CONTROL_ESCAPES[next]);
549
+ }
550
+ else {
551
+ bytes.push(next.charCodeAt(0));
552
+ }
553
+ i += 1;
554
+ }
555
+ return Buffer.from(bytes).toString('utf8');
556
+ }
483
557
  /**
484
558
  * Normalize one path for scope comparison. Applied to BOTH sides so a declared
485
- * path and a git-reported path meet in the same shape: backslashes become
486
- * slashes unconditionally (a backslash path is not a Windows-only input),
487
- * a leading `./` and any trailing `/` are stripped. This is the single
488
- * normalizer shared by the SUMMARY-artifact predicate and the scope advisory,
489
- * so the two can never disagree about what `./a\b/` means.
559
+ * path and a git-reported path meet in the same shape: any git C-quoting is
560
+ * decoded first (order matters — the backslash-to-slash conversion below
561
+ * would destroy the escape sequences if it ran first), then backslashes
562
+ * become slashes unconditionally (a backslash path is not a Windows-only
563
+ * input), and a leading `./` and any trailing `/` are stripped. This is the
564
+ * single normalizer shared by the SUMMARY-artifact predicate and the scope
565
+ * advisory, so the two can never disagree about what `./a\b/` means.
490
566
  */
491
567
  function normalizeScopePath(raw) {
492
- return String(raw || '')
568
+ return decodeGitQuotedPath(String(raw || '').trim())
493
569
  .replace(/\\/g, '/')
494
570
  .trim()
495
571
  .replace(/^\.\//, '')
@@ -703,6 +779,42 @@ function planWaveScopeConformance(changedPaths, declaredFiles, branch) {
703
779
  }
704
780
  return warnings;
705
781
  }
782
+ /**
783
+ * #3003: split git's reported deletions into declared and undeclared.
784
+ *
785
+ * EXACT match after `normalizeScopePath` — the same normalizer both other path
786
+ * comparisons in this file use, so a declared path and a git-reported path meet in the
787
+ * same shape (`a\b` and `./a/b/` both become `a/b`).
788
+ *
789
+ * Deliberately NOT `declaredScopePrefix`. That helper returns `null` for a glob-leading
790
+ * pattern meaning "matches everything", which is right for the ADVISORY it serves — a
791
+ * false alarm there costs more than a miss — and exactly wrong for a GATE, where it would
792
+ * let `["*.ts"]` disarm the guard. A glob here is simply a literal path that matches
793
+ * nothing. Prefix matching is likewise refused: `["tests"]` must not authorize deleting
794
+ * everything under tests/.
795
+ *
796
+ * Pure — no git, no IO. Returns the undeclared residue in the order git reported it.
797
+ */
798
+ function partitionDeclaredDeletions(deletedPaths, declared) {
799
+ const allowed = new Set((Array.isArray(declared) ? declared : [])
800
+ .filter((p) => typeof p === 'string')
801
+ .map((p) => normalizeScopePath(p))
802
+ .filter((p) => p.length > 0));
803
+ const undeclared = [];
804
+ const seen = new Set();
805
+ for (const raw of Array.isArray(deletedPaths) ? deletedPaths : []) {
806
+ if (typeof raw !== 'string')
807
+ continue;
808
+ const normalized = normalizeScopePath(raw);
809
+ if (!normalized || seen.has(normalized))
810
+ continue;
811
+ seen.add(normalized);
812
+ if (allowed.has(normalized))
813
+ continue;
814
+ undeclared.push(normalized);
815
+ }
816
+ return undeclared;
817
+ }
706
818
  function executeWorktreeWaveCleanupPlan(plan, deps = {}) {
707
819
  const execGit = deps.execGit || execGitDefault;
708
820
  const entries = Array.isArray(plan?.entries) ? plan.entries : [];
@@ -762,13 +874,17 @@ function executeWorktreeWaveCleanupPlan(plan, deps = {}) {
762
874
  continue; // #2852: isolate
763
875
  }
764
876
  if (deletions.stdout) {
765
- // Unconditional: any deletion in this entry's branch blocks THIS entry. Whether
766
- // that guard should have an opt-in for intentional deletions is a deferred
767
- // product decision (issue #2852's own triage scoped it out — tracked in #3003);
768
- // this fix only isolates the block to this one entry (#2852) instead of aborting
769
- // the rest of the wave, same as every other block reason below.
770
- blockEntry(result, 'branch_contains_deletions', deletions.stdout);
771
- continue; // #2852: isolate
877
+ // #3003: a deletion the PLAN declared is authorized; anything else still blocks.
878
+ // Only a SUCCESSFUL check reaches here — a failed one blocked above on its own
879
+ // reason, so a broken check can never be filtered into a pass.
880
+ //
881
+ // The block detail carries ONLY the undeclared residue. Listing declared paths
882
+ // there would misdirect the operator toward paths that were fine.
883
+ const undeclaredDeletions = partitionDeclaredDeletions(deletions.stdout.split('\n'), entry.declared_deletions);
884
+ if (undeclaredDeletions.length > 0) {
885
+ blockEntry(result, 'branch_contains_deletions', undeclaredDeletions.join('\n'));
886
+ continue; // #2852: isolate
887
+ }
772
888
  }
773
889
  // #2596: advisory scope conformance — does the branch's ACTUAL committed
774
890
  // diff stay inside the scope the plan declared? Gated on a declared scope
@@ -779,13 +895,34 @@ function executeWorktreeWaveCleanupPlan(plan, deps = {}) {
779
895
  // ADVISORY ONLY. Unlike the deletions check above, a finding here does NOT
780
896
  // call blockEntry and does NOT touch `ok` — the merge proceeds. Promotion
781
897
  // to a hard gate is a separate, disclosed change.
782
- if (Array.isArray(entry.files_modified) && entry.files_modified.length > 0) {
898
+ // #3003: a declared deletion is in scope by construction — `git diff --name-only`
899
+ // includes deleted paths, so without accounting for the declaration, authorizing a
900
+ // deletion would immediately warn that the same path is out of declared scope.
901
+ //
902
+ // It is SUBTRACTED from the findings rather than UNIONED into the declared scope,
903
+ // and the difference is not cosmetic. `planWaveScopeConformance` reads its scope
904
+ // list with prefix-and-glob semantics, so unioning would silently hand
905
+ // `declared_deletions` a second, WIDER matching rule than the gate gives it:
906
+ // `["*.md"]` (inert at the gate) would yield a null prefix meaning "matches
907
+ // everything" and mute the advisory entirely, and `["src"]` would mute all of
908
+ // `src/`. One field with two matching rules is a trap. Subtracting keeps the
909
+ // field exact-match-only on every surface it touches.
910
+ //
911
+ // Gating stays on `files_modified` alone for the same reason: a plan that declares
912
+ // only deletions has still declared no modification scope, so the advisory stays
913
+ // exactly as silent as it was before this change instead of warning on every
914
+ // modified path.
915
+ const declaredFiles = Array.isArray(entry.files_modified) ? entry.files_modified : [];
916
+ if (declaredFiles.length > 0) {
783
917
  const scopeDiff = execGit(['diff', '--name-only', `HEAD...${entry.branch}`], { cwd: plan.repoRoot });
784
918
  const scopeWarnings = !gitResultOk(scopeDiff)
785
919
  // A broken advisory must never become a gate: record that conformance
786
920
  // is unknown rather than blocking (or, worse, silently passing).
787
921
  ? [{ code: WAVE_CLEANUP_WARNING.SCOPE_CHECK_UNAVAILABLE, branch: entry.branch, path: null }]
788
- : planWaveScopeConformance((scopeDiff.stdout || '').split('\n'), entry.files_modified, entry.branch);
922
+ : planWaveScopeConformance((scopeDiff.stdout || '').split('\n'), declaredFiles, entry.branch)
923
+ // A path-less warning (SCOPE_CHECK_UNAVAILABLE) is never subtracted.
924
+ .filter((w) => w.path === null
925
+ || partitionDeclaredDeletions([w.path], entry.declared_deletions).length > 0);
789
926
  result.warnings.push(...scopeWarnings);
790
927
  allWarnings.push(...scopeWarnings);
791
928
  }
@@ -973,12 +1110,16 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
973
1110
  // 2. Shared validation: run the candidate through the reader's normalizer.
974
1111
  // If it returns null the reader would drop this entry on read — reject now.
975
1112
  const declaredScope = parseDeclaredScopeFlag(fields.files);
1113
+ // #3003: reuse parseDeclaredScopeFlag — a blank/absent --deletions leaves the
1114
+ // entry shape untouched, mirroring the --files rule directly above.
1115
+ const declaredDeletions = parseDeclaredScopeFlag(fields.deletions);
976
1116
  const candidate = {
977
1117
  agent_id: agentId,
978
1118
  worktree_path: worktreePath,
979
1119
  branch,
980
1120
  expected_base: base,
981
1121
  ...(declaredScope.length > 0 ? { files_modified: declaredScope } : {}),
1122
+ ...(declaredDeletions.length > 0 ? { declared_deletions: declaredDeletions } : {}),
982
1123
  };
983
1124
  const entry = normalizeCleanupManifestEntry(candidate);
984
1125
  if (!entry) {
@@ -1072,6 +1213,11 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
1072
1213
  if (entry.files_modified && entry.files_modified.length > 0) {
1073
1214
  recorded.files_modified = entry.files_modified;
1074
1215
  }
1216
+ // #3003: same conservative rule as --files above — a blank --deletions
1217
+ // leaves the entry shape untouched.
1218
+ if (entry.declared_deletions && entry.declared_deletions.length > 0) {
1219
+ recorded.declared_deletions = entry.declared_deletions;
1220
+ }
1075
1221
  worktrees.push(recorded);
1076
1222
  return {
1077
1223
  ok: true,
@@ -1083,7 +1229,7 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
1083
1229
  /**
1084
1230
  * CLI command: append a validated per-agent entry to a wave cleanup manifest.
1085
1231
  *
1086
- * Usage: worktree record-agent --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> [--files "<space-separated paths>"]
1232
+ * Usage: worktree record-agent --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> [--files "<space-separated paths>"] [--deletions "<space-separated paths>"]
1087
1233
  *
1088
1234
  * Fails loudly (non-zero exit + recovery hint on stderr) when a field is
1089
1235
  * missing/garbled or the manifest is absent/malformed, rather than appending an
@@ -1092,13 +1238,15 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
1092
1238
  function cmdWorktreeRecordAgent(cwd, args = [], deps = {}) {
1093
1239
  const flag = (name) => {
1094
1240
  const i = args.indexOf(name);
1095
- return i >= 0 && i + 1 < args.length ? args[i + 1] : '';
1241
+ if (i < 0 || i + 1 >= args.length)
1242
+ return '';
1243
+ return args[i + 1];
1096
1244
  };
1097
1245
  const write = deps.write || ((s) => process.stdout.write(s));
1098
1246
  const writeErr = deps.writeErr || ((s) => process.stderr.write(s));
1099
1247
  const manifestPath = flag('--manifest');
1100
1248
  if (!manifestPath) {
1101
- writeErr('Usage: worktree record-agent --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> [--files "<space-separated paths>"]\n');
1249
+ 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');
1102
1250
  process.exitCode = 2;
1103
1251
  return { ok: false, reason: 'usage', entry: null };
1104
1252
  }
@@ -1121,6 +1269,7 @@ function cmdWorktreeRecordAgent(cwd, args = [], deps = {}) {
1121
1269
  branch: flag('--branch'),
1122
1270
  base: flag('--base'),
1123
1271
  files: flag('--files'),
1272
+ deletions: flag('--deletions'),
1124
1273
  });
1125
1274
  if (!plan.ok || plan.manifest === null) {
1126
1275
  writeErr(`[gsd] worktree.record-agent: ${plan.reason} — ${plan.hint || ''}\n`);
@@ -1165,12 +1314,16 @@ function planWorktreeCreate(fields) {
1165
1314
  };
1166
1315
  }
1167
1316
  const declaredScope = parseDeclaredScopeFlag(fields.files);
1317
+ // #3003: reuse parseDeclaredScopeFlag — a blank/absent --deletions leaves the
1318
+ // entry shape untouched, mirroring the --files rule directly above.
1319
+ const declaredDeletions = parseDeclaredScopeFlag(fields.deletions);
1168
1320
  const candidate = {
1169
1321
  agent_id: agentId,
1170
1322
  worktree_path: worktreePath,
1171
1323
  branch,
1172
1324
  expected_base: base,
1173
1325
  ...(declaredScope.length > 0 ? { files_modified: declaredScope } : {}),
1326
+ ...(declaredDeletions.length > 0 ? { declared_deletions: declaredDeletions } : {}),
1174
1327
  };
1175
1328
  const entry = normalizeCleanupManifestEntry(candidate);
1176
1329
  if (!entry) {
@@ -1298,7 +1451,7 @@ function executeWorktreeCreatePlan(plan, repoRoot, deps = {}) {
1298
1451
  * validated manifest entry so the worktree is immediately manageable by
1299
1452
  * `worktree cleanup-wave` / `worktree reap-orphans`.
1300
1453
  *
1301
- * Usage: worktree create --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> --root <dir> [--files "<space-separated paths>"]
1454
+ * Usage: worktree create --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> --root <dir> [--files "<space-separated paths>"] [--deletions "<space-separated paths>"]
1302
1455
  *
1303
1456
  * #2584 FIX 1 — ORDERING CONTRACT: every manifest read/parse/shape-validate/
1304
1457
  * plan step runs BEFORE the git side effect (step 5). The ONLY manifest
@@ -1312,13 +1465,15 @@ function executeWorktreeCreatePlan(plan, repoRoot, deps = {}) {
1312
1465
  function cmdWorktreeCreate(cwd, args = [], deps = {}) {
1313
1466
  const flag = (name) => {
1314
1467
  const i = args.indexOf(name);
1315
- return i >= 0 && i + 1 < args.length ? args[i + 1] : '';
1468
+ if (i < 0 || i + 1 >= args.length)
1469
+ return '';
1470
+ return args[i + 1];
1316
1471
  };
1317
1472
  const write = deps.write || ((s) => process.stdout.write(s));
1318
1473
  const writeErr = deps.writeErr || ((s) => process.stderr.write(s));
1319
1474
  const manifestPath = flag('--manifest');
1320
1475
  if (!manifestPath) {
1321
- writeErr('Usage: worktree create --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> --root <dir> [--files "<space-separated paths>"]\n');
1476
+ 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');
1322
1477
  process.exitCode = 2;
1323
1478
  return { ok: false, reason: 'usage' };
1324
1479
  }
@@ -1384,6 +1539,7 @@ function cmdWorktreeCreate(cwd, args = [], deps = {}) {
1384
1539
  branch: flag('--branch'),
1385
1540
  base: flag('--base'),
1386
1541
  files: flag('--files'),
1542
+ deletions: flag('--deletions'),
1387
1543
  });
1388
1544
  if (!plan.ok || !plan.entry) {
1389
1545
  writeErr(`[gsd] worktree.create: ${plan.reason} — ${plan.hint || ''}\n`);
@@ -1455,6 +1611,11 @@ function cmdWorktreeCreate(cwd, args = [], deps = {}) {
1455
1611
  if (Array.isArray(plan.entry.files_modified) && plan.entry.files_modified.length > 0) {
1456
1612
  recorded.files_modified = plan.entry.files_modified;
1457
1613
  }
1614
+ // #3003: same conservative rule as --files above — a blank --deletions
1615
+ // leaves the entry shape untouched.
1616
+ if (Array.isArray(plan.entry.declared_deletions) && plan.entry.declared_deletions.length > 0) {
1617
+ recorded.declared_deletions = plan.entry.declared_deletions;
1618
+ }
1458
1619
  const dedupeKey = `${recorded.worktree_path}\0${recorded.branch}`;
1459
1620
  const alreadyPresent = worktrees.some((existing) => {
1460
1621
  const normalized = normalizeCleanupManifestEntry(existing);
@@ -1830,6 +1991,9 @@ function pruneOrphanedWorktrees(repoRoot, deps = {}) {
1830
1991
  return [];
1831
1992
  }
1832
1993
  module.exports = {
1994
+ // Re-exported for the codebase-drift gate's --name-status parser (#4081):
1995
+ // single owner of git C-quoted-path decoding.
1996
+ decodeGitQuotedPath,
1833
1997
  resolveWorktreeContext,
1834
1998
  resolveWorktreeLinkage,
1835
1999
  parseWorktreePorcelain,
@@ -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,
@@ -46,11 +46,13 @@
46
46
  "context_coverage_gate": true,
47
47
  "code_review": true,
48
48
  "code_review_depth": "standard",
49
+ "code_review_depth_overrides": [],
49
50
  "code_review_command": null,
50
51
  "pattern_mapper": true,
51
52
  "plan_bounce": false,
52
53
  "plan_bounce_script": null,
53
54
  "plan_bounce_passes": 2,
55
+ "inline_plan_threshold": 2,
54
56
  "auto_prune_state": false,
55
57
  "post_planning_gaps": true,
56
58
  "security_enforcement": true,
@@ -60,6 +62,7 @@
60
62
  },
61
63
  "planning": {
62
64
  "commit_docs": true,
65
+ "pr_strict": false,
63
66
  "search_gitignored": false,
64
67
  "sub_repos": [],
65
68
  "granularity": "standard"
@@ -97,6 +100,9 @@
97
100
  "source_grounding": true,
98
101
  "source_grounding_authority": "grep"
99
102
  },
103
+ "review": {
104
+ "max_prompt_tokens": null
105
+ },
100
106
  "capabilities": {
101
107
  "strict_known_registries": null,
102
108
  "auto_update": false