@opengsd/gsd-core 1.13.0 → 1.14.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 (257) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/agents/gsd-advisor-researcher.compact.md +85 -0
  4. package/agents/gsd-ai-researcher.compact.md +96 -0
  5. package/agents/gsd-assumptions-analyzer.compact.md +81 -0
  6. package/agents/gsd-code-fixer.compact.md +458 -0
  7. package/agents/gsd-code-fixer.md +5 -5
  8. package/agents/gsd-code-reviewer.compact.md +269 -0
  9. package/agents/gsd-code-reviewer.md +15 -3
  10. package/agents/gsd-codebase-mapper.compact.md +760 -0
  11. package/agents/gsd-debug-session-manager.compact.md +345 -0
  12. package/agents/gsd-doc-classifier.compact.md +192 -0
  13. package/agents/gsd-doc-synthesizer.compact.md +200 -0
  14. package/agents/gsd-doc-verifier.compact.md +143 -0
  15. package/agents/gsd-doc-writer.compact.md +440 -0
  16. package/agents/gsd-dom-verifier.compact.md +138 -0
  17. package/agents/gsd-domain-researcher.compact.md +141 -0
  18. package/agents/gsd-eval-auditor.compact.md +160 -0
  19. package/agents/gsd-eval-planner.compact.md +137 -0
  20. package/agents/gsd-framework-selector.compact.md +82 -0
  21. package/agents/gsd-integration-checker.compact.md +245 -0
  22. package/agents/gsd-intel-updater.compact.md +226 -0
  23. package/agents/gsd-mempalace-curator.compact.md +45 -0
  24. package/agents/gsd-nyquist-auditor.compact.md +179 -0
  25. package/agents/gsd-pattern-mapper.compact.md +275 -0
  26. package/agents/gsd-project-researcher.compact.md +587 -0
  27. package/agents/gsd-research-synthesizer.compact.md +212 -0
  28. package/agents/gsd-roadmapper.compact.md +454 -0
  29. package/agents/gsd-roadmapper.md +13 -0
  30. package/agents/gsd-security-auditor.compact.md +162 -0
  31. package/agents/gsd-ui-auditor.compact.md +404 -0
  32. package/agents/gsd-ui-checker.compact.md +277 -0
  33. package/agents/gsd-ui-researcher.compact.md +282 -0
  34. package/agents/gsd-user-profiler.compact.md +108 -0
  35. package/bin/install.js +206 -68
  36. package/commands/gsd/cleanup.md +1 -0
  37. package/commands/gsd/code-review.md +2 -1
  38. package/commands/gsd/complete-milestone.md +1 -0
  39. package/commands/gsd/config.md +1 -0
  40. package/commands/gsd/debug.md +1 -0
  41. package/commands/gsd/graphify.md +1 -0
  42. package/commands/gsd/health.md +1 -0
  43. package/commands/gsd/mempalace-capture.md +1 -0
  44. package/commands/gsd/mempalace-recall.md +1 -0
  45. package/commands/gsd/new-milestone.md +1 -0
  46. package/commands/gsd/new-project.md +1 -0
  47. package/commands/gsd/next.md +1 -0
  48. package/commands/gsd/pause-work.md +1 -0
  49. package/commands/gsd/phase.md +1 -0
  50. package/commands/gsd/pr-branch.md +1 -0
  51. package/commands/gsd/resume-work.md +1 -0
  52. package/commands/gsd/review-backlog.md +1 -0
  53. package/commands/gsd/settings.md +2 -1
  54. package/commands/gsd/stats.md +1 -0
  55. package/commands/gsd/thread.md +1 -0
  56. package/commands/gsd/workspace.md +1 -0
  57. package/commands/gsd/workstreams.md +1 -0
  58. package/gsd-core/bin/check-latest-version.cjs +8 -3
  59. package/gsd-core/bin/gsd-tools.cjs +338 -125
  60. package/gsd-core/bin/lib/adr-parser.cjs +1 -1
  61. package/gsd-core/bin/lib/artifacts.cjs +2 -1
  62. package/gsd-core/bin/lib/audit.cjs +39 -22
  63. package/gsd-core/bin/lib/broken-windows.cjs +168 -49
  64. package/gsd-core/bin/lib/capability-lifecycle.cjs +10 -6
  65. package/gsd-core/bin/lib/capability-loader.cjs +135 -1
  66. package/gsd-core/bin/lib/capability-registry.cjs +79 -67
  67. package/gsd-core/bin/lib/capability-source.cjs +19 -2
  68. package/gsd-core/bin/lib/capability-validator.cjs +14 -1
  69. package/gsd-core/bin/lib/check-command-router.cjs +113 -36
  70. package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
  71. package/gsd-core/bin/lib/commands.cjs +650 -72
  72. package/gsd-core/bin/lib/config-loader.cjs +1 -0
  73. package/gsd-core/bin/lib/config.cjs +153 -38
  74. package/gsd-core/bin/lib/coverage.cjs +1 -1
  75. package/gsd-core/bin/lib/decisions.cjs +137 -34
  76. package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
  77. package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
  78. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +12 -1
  79. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
  80. package/gsd-core/bin/lib/init.cjs +409 -47
  81. package/gsd-core/bin/lib/install-engine.cjs +16 -3
  82. package/gsd-core/bin/lib/install-profiles.cjs +14 -0
  83. package/gsd-core/bin/lib/installer-migrations.cjs +33 -4
  84. package/gsd-core/bin/lib/loop-resolver.cjs +50 -31
  85. package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
  86. package/gsd-core/bin/lib/milestone.cjs +19 -8
  87. package/gsd-core/bin/lib/model-resolver.cjs +101 -10
  88. package/gsd-core/bin/lib/phase-command-router.cjs +7 -1
  89. package/gsd-core/bin/lib/phase-id.cjs +161 -22
  90. package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
  91. package/gsd-core/bin/lib/phase.cjs +167 -63
  92. package/gsd-core/bin/lib/planning-inspect.cjs +34 -18
  93. package/gsd-core/bin/lib/planning-snapshot.cjs +61 -12
  94. package/gsd-core/bin/lib/planning-workspace.cjs +50 -1
  95. package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
  96. package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
  97. package/gsd-core/bin/lib/quick-batch.cjs +1 -1
  98. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +61 -2
  99. package/gsd-core/bin/lib/research-store.cjs +11 -12
  100. package/gsd-core/bin/lib/review-lane-invocation.cjs +23 -0
  101. package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
  102. package/gsd-core/bin/lib/roadmap-parser.cjs +56 -15
  103. package/gsd-core/bin/lib/roadmap.cjs +108 -14
  104. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +27 -10
  105. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +12 -3
  106. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +13 -5
  107. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +193 -4
  108. package/gsd-core/bin/lib/security.cjs +126 -7
  109. package/gsd-core/bin/lib/state-document.cjs +130 -28
  110. package/gsd-core/bin/lib/state-md-schema.cjs +21 -14
  111. package/gsd-core/bin/lib/state-transition.cjs +142 -28
  112. package/gsd-core/bin/lib/state.cjs +223 -27
  113. package/gsd-core/bin/lib/surface.cjs +60 -2
  114. package/gsd-core/bin/lib/task-command-router.cjs +12 -6
  115. package/gsd-core/bin/lib/uat.cjs +1 -1
  116. package/gsd-core/bin/lib/update-context.cjs +30 -24
  117. package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
  118. package/gsd-core/bin/lib/verification.cjs +47 -15
  119. package/gsd-core/bin/lib/verify-command-grounding.cjs +1 -1
  120. package/gsd-core/bin/lib/verify.cjs +188 -23
  121. package/gsd-core/bin/lib/workstream-inventory.cjs +1 -0
  122. package/gsd-core/bin/lib/worktree-safety.cjs +13 -7
  123. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  124. package/gsd-core/bin/shared/config-schema.manifest.json +5 -0
  125. package/gsd-core/bin/verify-reapply-patches.cjs +439 -80
  126. package/gsd-core/references/compact-content-gate.md +66 -0
  127. package/gsd-core/references/loop-hook-dispatch.md +18 -0
  128. package/gsd-core/references/model-profiles.md +12 -3
  129. package/gsd-core/references/planning-config.md +3 -0
  130. package/gsd-core/references/tdd.md +5 -2
  131. package/gsd-core/references/thinking-models-planning.md +18 -2
  132. package/gsd-core/references/verification-patterns.md +17 -4
  133. package/gsd-core/references/worktree-path-safety.md +112 -2
  134. package/gsd-core/templates/README.md +7 -1
  135. package/gsd-core/templates/state.md +6 -3
  136. package/gsd-core/templates/summary.compact.md +212 -0
  137. package/gsd-core/templates/user-setup.compact.md +199 -0
  138. package/gsd-core/templates/user-setup.md +0 -9
  139. package/gsd-core/workflows/add-todo.md +3 -2
  140. package/gsd-core/workflows/autonomous.md +13 -10
  141. package/gsd-core/workflows/check-todos.md +4 -2
  142. package/gsd-core/workflows/cleanup.md +3 -1
  143. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +7 -0
  144. package/gsd-core/workflows/code-review-fix.md +3 -3
  145. package/gsd-core/workflows/code-review.md +156 -30
  146. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
  147. package/gsd-core/workflows/complete-milestone.md +39 -262
  148. package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
  149. package/gsd-core/workflows/docs-update.md +14 -155
  150. package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
  151. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +18 -3
  152. package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
  153. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +7 -2
  154. package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
  155. package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
  156. package/gsd-core/workflows/execute-phase.md +53 -152
  157. package/gsd-core/workflows/execute-plan.md +20 -7
  158. package/gsd-core/workflows/help/modes/full.compact.md +398 -0
  159. package/gsd-core/workflows/help.md +1 -1
  160. package/gsd-core/workflows/map-codebase.md +50 -3
  161. package/gsd-core/workflows/new-milestone.md +54 -12
  162. package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
  163. package/gsd-core/workflows/new-project.md +32 -202
  164. package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
  165. package/gsd-core/workflows/plan-phase.md +22 -181
  166. package/gsd-core/workflows/pr-branch.md +19 -7
  167. package/gsd-core/workflows/quick.md +8 -1
  168. package/gsd-core/workflows/reapply-patches.md +77 -3
  169. package/gsd-core/workflows/settings.md +18 -5
  170. package/gsd-core/workflows/update.md +7 -5
  171. package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
  172. package/gsd-core/workflows/verify-work.md +20 -180
  173. package/hooks/dist/gsd-agent-isolation-guard.js +42 -16
  174. package/hooks/dist/gsd-context-monitor.js +88 -15
  175. package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
  176. package/hooks/dist/gsd-secret-read-guard.js +44 -18
  177. package/hooks/dist/gsd-statusline.js +11 -7
  178. package/hooks/dist/gsd-validate-commit.sh +34 -4
  179. package/hooks/dist/gsd-worktree-path-guard.js +25 -14
  180. package/hooks/dist/gsd-write-guard.js +46 -1
  181. package/hooks/dist/lib/dispatch-identity.js +187 -0
  182. package/hooks/dist/lib/filename-classification.js +64 -0
  183. package/hooks/dist/lib/isolation-deny-reason.js +53 -1
  184. package/hooks/dist/lib/isolation-sentinel.js +58 -19
  185. package/hooks/gsd-agent-isolation-guard.js +42 -16
  186. package/hooks/gsd-context-monitor.js +88 -15
  187. package/hooks/gsd-cursor-subagent-start.js +34 -14
  188. package/hooks/gsd-secret-read-guard.js +44 -18
  189. package/hooks/gsd-statusline.js +11 -7
  190. package/hooks/gsd-validate-commit.sh +34 -4
  191. package/hooks/gsd-worktree-path-guard.js +25 -14
  192. package/hooks/gsd-write-guard.js +46 -1
  193. package/hooks/lib/dispatch-identity.js +187 -0
  194. package/hooks/lib/filename-classification.js +64 -0
  195. package/hooks/lib/isolation-deny-reason.js +53 -1
  196. package/hooks/lib/isolation-sentinel.js +58 -19
  197. package/package.json +10 -6
  198. package/scripts/benchmark-compact-content-variants.cjs +298 -0
  199. package/scripts/benchmark-compact-content.cjs +368 -0
  200. package/scripts/check-contract-drift.cjs +4 -1
  201. package/scripts/check-env.cjs +36 -8
  202. package/scripts/check-glossary-refs.cjs +25 -21
  203. package/scripts/ci-next-health.cjs +271 -0
  204. package/scripts/ci-prepare-test-scope.cjs +7 -7
  205. package/scripts/ci-test-scope.cjs +126 -20
  206. package/scripts/ci-timeout-report.cjs +1 -1
  207. package/scripts/diff-touches-shipped-paths.cjs +1 -1
  208. package/scripts/docs-guard-registry.cjs +7 -2
  209. package/scripts/gen-adr-index.cjs +8 -2
  210. package/scripts/gen-inventory-manifest.cjs +12 -0
  211. package/scripts/gen-platform-conformance-tier.cjs +557 -0
  212. package/scripts/lib/drift-scan.cjs +1 -1
  213. package/scripts/lib/macos-conformance-tier.generated.cjs +210 -0
  214. package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
  215. package/scripts/lib/platform-conformance-tier.generated.cjs +276 -0
  216. package/scripts/lib/suite-detection.cjs +32 -0
  217. package/scripts/lint-allowed-tools-parity.cjs +221 -0
  218. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +19 -2
  219. package/scripts/lint-phase-id-drift.cjs +338 -13
  220. package/scripts/lint-response-language-coverage.cjs +9 -3
  221. package/scripts/lint-source-test-name-collision.cjs +1 -1
  222. package/scripts/lint-test-file-count.allowlist.json +1 -0
  223. package/scripts/lint-vendored-deps.cjs +128 -17
  224. package/scripts/lint-workflow-shellcheck-baseline.json +85 -0
  225. package/scripts/prompt-injection-scan.sh +14 -0
  226. package/scripts/workflow-size.cjs +139 -0
  227. package/skills/gsd-cleanup/SKILL.md +1 -0
  228. package/skills/gsd-code-review/SKILL.md +2 -1
  229. package/skills/gsd-complete-milestone/SKILL.md +1 -0
  230. package/skills/gsd-config/SKILL.md +1 -0
  231. package/skills/gsd-debug/SKILL.md +1 -0
  232. package/skills/gsd-graphify/SKILL.md +1 -0
  233. package/skills/gsd-health/SKILL.md +1 -0
  234. package/skills/gsd-mempalace-capture/SKILL.md +1 -0
  235. package/skills/gsd-mempalace-recall/SKILL.md +1 -0
  236. package/skills/gsd-new-milestone/SKILL.md +1 -0
  237. package/skills/gsd-new-project/SKILL.md +1 -0
  238. package/skills/gsd-next/SKILL.md +1 -0
  239. package/skills/gsd-pause-work/SKILL.md +1 -0
  240. package/skills/gsd-phase/SKILL.md +1 -0
  241. package/skills/gsd-pr-branch/SKILL.md +1 -0
  242. package/skills/gsd-resume-work/SKILL.md +1 -0
  243. package/skills/gsd-review-backlog/SKILL.md +1 -0
  244. package/skills/gsd-settings/SKILL.md +2 -1
  245. package/skills/gsd-stats/SKILL.md +1 -0
  246. package/skills/gsd-thread/SKILL.md +1 -0
  247. package/skills/gsd-workspace/SKILL.md +1 -0
  248. package/skills/gsd-workstreams/SKILL.md +1 -0
  249. package/vscode/package.json +1 -1
  250. package/gsd-core/templates/claude-md.md +0 -145
  251. package/gsd-core/templates/codebase/concerns.md +0 -310
  252. package/gsd-core/templates/codebase/conventions.md +0 -307
  253. package/gsd-core/templates/codebase/integrations.md +0 -280
  254. package/gsd-core/templates/codebase/structure.md +0 -285
  255. package/gsd-core/templates/codebase/testing.md +0 -480
  256. package/gsd-core/templates/debug-subagent-prompt.md +0 -91
  257. package/gsd-core/templates/discovery.md +0 -146
@@ -0,0 +1,43 @@
1
+ Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
2
+
3
+ # Executor Progress Policy (#4218)
4
+
5
+ Read this before treating any executor as stalled.
6
+
7
+ ## A working executor is never steered
8
+
9
+ The stall threshold measures a period **without meaningful progress**. It is not a maximum
10
+ total runtime, and it is not a budget the executor has to finish inside. A plan with a long
11
+ verification or closeout tail legitimately spends many minutes between its last commit and
12
+ its SUMMARY.
13
+
14
+ Reconcile activity as well as artifacts:
15
+
16
+ - **Commits exist and SUMMARY.md is missing, with recent meaningful activity → KEEP
17
+ WAITING.** Do not steer it, do not interrupt it, do not re-dispatch it. Recent
18
+ RED/GREEN/REFACTOR commits, passing verification, or ongoing reasoning/tool telemetry
19
+ from the child are all meaningful activity.
20
+ - **Only after `${EXECUTOR_STALL_THRESHOLD_MINUTES}` of no meaningful progress** — measured
21
+ from the LAST sign of progress, not from dispatch — may the pause in step 3 fire, and it
22
+ asks the user; it does not act on its own.
23
+
24
+ ## Never inject urgency or finalization instructions into a live executor
25
+
26
+ Messages of the "Finalize immediately", "wrap up now", "you are taking too long" family are
27
+ forbidden: they arrive mid-verification and turn a correct run into a truncated one. If an
28
+ executor must be stopped, the pause in step 3 is the only route, and `kill and retry` is a
29
+ clean restart — not a nudge.
30
+
31
+ ## The absence of a local OS test/build process is NOT idleness
32
+
33
+ The orchestrator cannot see the child's work that way. A native subagent runs in the
34
+ runtime's own session, not as a visible local process, and an executor between two tool
35
+ calls — reasoning, reading a file, waiting on a runtime round-trip — shows no process at
36
+ all. Judge progress ONLY by the signals this workflow names: commits on the expected
37
+ branch, the SUMMARY, and the child's own activity. A process listing is not one of them.
38
+
39
+ ## If a stalled executor ran in an isolated worktree
40
+
41
+ `kill and switch to inline execution` edits the primary checkout — see worktree recovery
42
+ policy (`execute-phase/steps/worktree-recovery-policy.md`). Prefer `kill and retry` in a
43
+ fresh worktree; inline execution requires explicit confirmation, never the default.
@@ -0,0 +1,35 @@
1
+ # Sequential root pin (#4254)
2
+
3
+ Apply response_language to all user-facing prose — narration between tool calls, status
4
+ updates, progress notes, and findings included; preserve code, paths, and identifiers.
5
+
6
+ Read and execute this fragment from `execute-phase.md`'s **Sequential mode** branch before
7
+ composing any sequential dispatch prompt. It owns the sequential root-pin build-time embed,
8
+ the `<required_reading>` root substitution, and the wave serialization rules.
9
+
10
+ ## Root pin — ORCHESTRATOR build-time embed (#4254; NOT a sub-agent runtime step)
11
+
12
+ Before this dispatch, read `gsd-core/references/worktree-path-safety.md` step 0p
13
+ ("Supplied-root pin") and copy its guard template into this prompt inside a
14
+ `<project_root_pin>` block, substituting `{PINNED_ROOT}` with the literal value of
15
+ `$ORCHESTRATOR_WT` resolved at execute_waves entry, shell-single-quoted per that section's
16
+ composition contract — the dispatched prompt must carry the bound, runnable guard verbatim;
17
+ do not pass this instruction through in its place.
18
+
19
+ In this dispatch's `<required_reading>`, also replace the self-derivation line
20
+ `PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)` with
21
+ `PROJECT_ROOT='<the same literal $ORCHESTRATOR_WT>'` — a sequential executor must never
22
+ re-derive its root from its own (possibly drifted) cwd. This substitution is sequential-mode
23
+ ONLY: worktree-mode dispatches keep the self-derived line — an isolated executor's own
24
+ toplevel IS its correct (and intentionally different) worktree, and substituting the
25
+ orchestrator's root there would break every worktree-mode dispatch.
26
+
27
+ ## Wave serialization (moved verbatim from the host step — ADR-857 Phase 6 ceiling, #1168)
28
+
29
+ When worktrees are disabled for a plan (per-plan or project-level), that plan's executor runs
30
+ on the main working tree. If **any** plan in the current wave dropped to sequential mode,
31
+ execute the affected plan(s) **one at a time** to avoid concurrent writes to the main working
32
+ tree — plans in the same wave that retained worktree isolation can still run in parallel
33
+ alongside the sequential ones, but two non-worktree plans in the same wave must serialize.
34
+ When the project-level `USE_WORKTREES=false`, all plans in the wave serialize regardless of
35
+ the `PARALLELIZATION` setting.
@@ -25,6 +25,9 @@ Orchestrator coordinates, not executes. Each subagent loads the full execute-pla
25
25
  instead of spawning parallel agents. Only attempt parallel spawning if the user
26
26
  explicitly requests it — and in that case, rely on the spot-check fallback in step 3
27
27
  to detect completion.
28
+ - **Codex:** native subagent sessions can end abnormally (`turn_aborted`) after the plan
29
+ work is already committed. Completion is decided by the step-4 artifact reconciliation
30
+ (SUMMARY + matching recent commits), not by the session's terminal state (#4217).
28
31
  - **Other runtimes:** If `Agent`/`agent` tool is genuinely unavailable (e.g. a backgrounded
29
32
  Claude Code agent per #853, or a non-Claude runtime), use sequential inline execution as
30
33
  the fallback for executor parallelization only. If `Agent` IS available (top-level Claude
@@ -64,6 +67,8 @@ Always use the exact name from this list — do not fall back to 'general-purpos
64
67
 
65
68
  <process>
66
69
 
70
+ **Compact Content Gate.** Read and follow `gsd-core/references/compact-content-gate.md` now — it states the `workflow.compact_content` check and the resolution rule this spine defers to. When it directs a Read, read `gsd-core/workflows/execute-phase/detail/elaboration.md` in full before continuing past this point; its content elaborates on two steps below (check_interactive_mode, cross_ai_delegation).
71
+
67
72
  <step name="parse_args" priority="first">
68
73
  Parse `$ARGUMENTS` before loading any context:
69
74
 
@@ -185,7 +190,12 @@ from the active incomplete plan in `INIT`, then search recent history:
185
190
  SUMMARY_PATH="{phase_dir}/{plan_padded}-SUMMARY.md"
186
191
  # #4003: no padding rule in the commit protocol, so zero-strip both components and
187
192
  # match ANCHORED at the commit scope; bound to the latest reachable tag (milestone marker).
188
- PHASE_N=$((10#{phase_number}))
193
+ PHASE_NUMBER="{phase_number}"
194
+ # #4619: {phase_number} may be decimal (01.1) or N-segment (23.1.2) — $((10#...))
195
+ # is a hard shell syntax error on a non-integer, so zero-strip only the LEADING
196
+ # integer segment and keep the rest as an escaped-dot string for the ERE below.
197
+ PHASE_INT=${PHASE_NUMBER%%.*}; PHASE_FRAC=${PHASE_NUMBER#"$PHASE_INT"}
198
+ PHASE_N="$((10#$PHASE_INT))${PHASE_FRAC//./\\.}"
189
199
  PLAN_N=$((10#{plan_padded}))
190
200
  PLAN_SCOPE_RE="^[a-z]+\((0*${PHASE_N})-(0*${PLAN_N})\):"
191
201
  MILESTONE_BASE=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
@@ -206,9 +216,12 @@ if [ "$TDD_MODE" = "true" ]; then
206
216
  if [ "$IS_BEHAVIOR_ADDING" = "true" ]; then
207
217
  # #4003: same anchored scope and milestone bound as safe_resume_gate — a padded
208
218
  # literal grep hard-halts on a correct unpadded RED commit.
209
- PHASE_N=$((10#${PHASE_NUMBER}))
219
+ # #4619: PHASE_NUMBER may be decimal/N-segment; zero-strip only the leading
220
+ # integer segment, escape the rest for the ERE below.
221
+ PHASE_INT=${PHASE_NUMBER%%.*}; PHASE_FRAC=${PHASE_NUMBER#"$PHASE_INT"}
222
+ PHASE_N="$((10#$PHASE_INT))${PHASE_FRAC//./\\.}"
210
223
  PLAN_N=$((10#${PLAN_ID}))
211
- PLAN_SCOPE_RE="^[a-z]+\((0*${PHASE_N})-(0*${PLAN_N})\):"
224
+ PLAN_SCOPE_RE="^[a-z]+\((0*${PHASE_N})-(0*${PLAN_N})\):" # TDD gate's own scope check
212
225
  TDD_MILESTONE_BASE=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
213
226
  RED_COMMIT=$(git log --oneline -E ${TDD_MILESTONE_BASE:+"$TDD_MILESTONE_BASE..HEAD"} --grep="${PLAN_SCOPE_RE}" -- "**/*.test.*" "**/*.spec.*" "tests/" | head -1)
214
227
  if [ -z "$RED_COMMIT" ]; then
@@ -247,43 +260,7 @@ Write these answers inline before continuing. If a blocking anti-pattern cannot
247
260
  </step>
248
261
 
249
262
  <step name="check_interactive_mode">
250
- **Parse `--interactive` flag from $ARGUMENTS.**
251
-
252
- **If `--interactive` flag present:** Switch to interactive execution mode.
253
-
254
- Interactive mode executes plans sequentially **inline** (no subagent spawning) with user
255
- checkpoints between tasks. The user can review, modify, or redirect work at any point.
256
-
257
- **Interactive execution flow:**
258
-
259
- 1. Load plan inventory as normal (discover_and_group_plans)
260
- 2. For each plan (sequentially, ignoring wave grouping):
261
-
262
- a. **Present the plan to the user:**
263
- ```
264
- ## Plan {plan_id}: {plan_name}
265
-
266
- Objective: {from plan file}
267
- Tasks: {task_count}
268
-
269
- Options:
270
- - Execute (proceed with all tasks)
271
- - Review first (show task breakdown before starting)
272
- - Skip (move to next plan)
273
- - Stop (end execution, save progress)
274
- ```
275
-
276
- b. **If "Review first":** Read and display the full plan file. Ask again: Execute, Modify, Skip.
277
-
278
- c. **If "Execute":** Read and follow `~/.claude/gsd-core/workflows/execute-plan.md` **inline**
279
- (do NOT spawn a subagent). Execute tasks one at a time.
280
-
281
- d. **After each task:** Pause briefly. If the user intervenes (types anything), stop and address
282
- their feedback before continuing. Otherwise proceed to next task.
283
-
284
- e. **After plan complete:** Show results, commit, create SUMMARY.md, then present next plan.
285
-
286
- 3. After all plans: proceed to verification (same as normal mode).
263
+ **Parse `--interactive` flag from $ARGUMENTS.** If present, switch to interactive execution mode: plans run sequentially **inline** (no subagent spawning, ignoring wave grouping), reading `execute-plan.md` directly rather than dispatching `gsd-executor`. **Once per plan** (not per task), present a 4-option menu (execute / review-first / skip / stop) before starting that plan's tasks. Once executing, tasks run one at a time with only a brief pause after each — the agent stops mid-plan only if the user actually types something, it does not re-show the menu. After all plans, proceed to verification as normal. Full flow (the exact presentation format, the review-first sub-branch): `gsd-core/workflows/execute-phase/detail/elaboration.md` § 1.
287
264
 
288
265
  **Skip to handle_branching step** (interactive plans execute inline after grouping).
289
266
  </step>
@@ -419,74 +396,11 @@ Report:
419
396
  </step>
420
397
 
421
398
  <step name="cross_ai_delegation">
422
- **Optional step 2.5 — Delegate plans to an external AI runtime.**
423
-
424
- This step runs after plan discovery and before normal wave execution. It identifies plans
425
- that should be delegated to an external AI command and executes them via stdin-based prompt
426
- delivery. Plans handled here are removed from the execute_waves plan list so the normal
427
- executor skips them.
428
-
429
- **Activation logic:**
430
-
431
- 1. If `CROSS_AI_DISABLED` is true (`--no-cross-ai` flag): skip this step entirely.
432
- 2. If `CROSS_AI_FORCE` is true (`--cross-ai` flag): mark ALL incomplete plans for cross-AI execution.
433
- 3. Otherwise: check each plan's frontmatter for `cross_ai: true` AND verify config
434
- `workflow.cross_ai_execution` is `true`. Plans matching both conditions are marked for cross-AI.
435
-
436
- ```bash
437
- CROSS_AI_ENABLED=$(gsd_run query config-get workflow.cross_ai_execution --raw 2>/dev/null || echo "false")
438
- CROSS_AI_CMD=$(gsd_run query config-get workflow.cross_ai_command --raw 2>/dev/null || echo "")
439
- CROSS_AI_TIMEOUT=$(gsd_run query config-get workflow.cross_ai_timeout --raw 2>/dev/null || echo "300")
440
- ```
441
-
442
- **If no plans are marked for cross-AI:** Skip to execute_waves.
443
-
444
- **If plans are marked but `cross_ai_command` is empty:** Error — tell user to set
445
- `workflow.cross_ai_command` via `gsd_run query config-set workflow.cross_ai_command "<command>"`.
446
-
447
- **For each cross-AI plan (sequentially):**
448
-
449
- 1. **Construct the task prompt** from the plan file:
450
- - Extract `<objective>` and `<tasks>` sections from the PLAN.md
451
- - Append PROJECT.md context (project name, description, tech stack)
452
- - Format as a self-contained execution prompt
399
+ **Optional step 2.5 — Delegate plans to an external AI runtime.** Runs after plan discovery, before wave execution. Activates when `--cross-ai` forces all incomplete plans, `--no-cross-ai` disables it entirely, or (default) a plan's `cross_ai: true` frontmatter agrees with the `workflow.cross_ai_execution` config. If no plan is marked, skip to execute_waves; if marked but `workflow.cross_ai_command` is unset, error and tell the user to set it.
453
400
 
454
- 2. **Check for dirty working tree before execution:**
455
- ```bash
456
- if ! git diff --quiet HEAD 2>/dev/null; then
457
- echo "WARNING: dirty working tree detected — the external AI command may produce uncommitted changes that conflict with existing modifications"
458
- fi
459
- ```
460
-
461
- 3. **Run the external command** from the project root, writing the prompt to stdin.
462
- Never shell-interpolate the prompt — always pipe via stdin to prevent injection:
463
- ```bash
464
- echo "$TASK_PROMPT" | gsd_run run-with-timeout "${CROSS_AI_TIMEOUT}" -- ${CROSS_AI_CMD} > "$CANDIDATE_SUMMARY" 2>"$ERROR_LOG"
465
- EXIT_CODE=$?
466
- ```
401
+ For each marked plan: build a self-contained prompt from the plan's `<objective>`/`<tasks>` plus PROJECT.md context, warn on a dirty working tree, then run the configured command **wrapped in `gsd_run run-with-timeout "${CROSS_AI_TIMEOUT}"` (config `workflow.cross_ai_timeout`, default 300s) — never run it unbounded** — with the prompt piped to **stdin, never shell-interpolated, to prevent injection**. On success (exit 0): validate the captured SUMMARY output is non-empty and structurally valid before writing it as the plan's SUMMARY.md, update STATE/ROADMAP, mark handled. On failure (non-zero exit, or the summary fails that validation): show the error, warn about possible partial edits, and offer **retry** / **skip** (falls back to the normal executor) / **abort**. Successfully handled plans are removed from execute_waves' list; skipped-to-fallback plans remain in it.
467
402
 
468
- 4. **Evaluate the result:**
469
-
470
- **Success (exit 0 + valid summary):**
471
- - Read `$CANDIDATE_SUMMARY` and validate it contains meaningful content
472
- (not empty, has at least a heading and description — a valid SUMMARY.md structure)
473
- - Write it as the plan's SUMMARY.md file
474
- - Update STATE.md plan status to complete
475
- - Update ROADMAP.md progress
476
- - Mark plan as handled — skip it in execute_waves
477
-
478
- **Failure (non-zero exit or invalid summary):**
479
- - Display the error output and exit code
480
- - Warn: "The external command may have left uncommitted changes or partial edits
481
- in the working tree. Review `git status` and `git diff` before proceeding."
482
- - Offer three choices:
483
- - **retry** — run the same plan through cross-AI again
484
- - **skip** — fall back to normal executor for this plan (re-add to execute_waves list)
485
- - **abort** — stop execution entirely, preserve state for resume
486
-
487
- 5. **After all cross-AI plans processed:** Remove successfully handled plans from the
488
- incomplete plan list so execute_waves skips them. Any skipped-to-fallback plans remain
489
- in the list for normal executor processing.
403
+ Exact bash and per-branch wording: `gsd-core/workflows/execute-phase/detail/elaboration.md` § 2.
490
404
  </step>
491
405
 
492
406
  <step name="execute_waves">
@@ -677,6 +591,8 @@ increases monotonically across waves. `{status}` is `complete` (success),
677
591
 
678
592
  Pass paths only — executors read files themselves.
679
593
 
594
+ **Substitute `{plan_id}` in the prompt below with this plan's `id` field** from the `phase-plan-index` JSON loaded in step 1 (the same field referred to elsewhere in this workflow as `plan.id`) — unmodified and un-truncated, never a paraphrase. The guard hooks compare this value verbatim against the sentinel the per-plan gate wrote (`per-plan-worktree-gate.md`'s `plan_id`); a paraphrase or an omission costs the dispatch its recorded isolation decision.
595
+
680
596
  **Executor routing (#1689/#3370).** Per plan, run `gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md` to set `EXECUTOR_TYPE` for `subagent_type="{EXECUTOR_TYPE}"` below.
681
597
 
682
598
  **TDD-applicability resolution (#4266/#4272).** Run `gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md`.
@@ -727,6 +643,7 @@ increases monotonically across waves. `{status}` is `complete` (success),
727
643
  prompt="
728
644
  <objective>
729
645
  Execute plan {plan_number} of phase {phase_number}-{phase_name}.
646
+ [gsd:dispatch phase="{phase_number}" plan="{plan_id}"]
730
647
  Commit each task atomically. Create SUMMARY.md.
731
648
  Do NOT update STATE.md or ROADMAP.md — the orchestrator owns those writes after all worktree agents in the wave complete.
732
649
  </objective>
@@ -806,20 +723,29 @@ increases monotonically across waves. `{status}` is `complete` (success),
806
723
 
807
724
  > **Worktree recovery policy (#48 + #1292):** See `execute-phase/steps/worktree-recovery-policy.md` — FAIL-CLOSED rule for base/HEAD-namespace mismatches AND isolated-run fail-safe recovery.
808
725
 
809
- > **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above to spawn executor agent(s), stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available.
726
+ > **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above to spawn executor agent(s), stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available. While waiting, run the step-4 completion surveillance; if the child's session ends abnormally — including `turn_aborted` — reconcile artifacts per `execute-phase/steps/completion-reconciliation.md` before classifying the plan (#4217).
810
727
 
811
728
  **Orchestrator-managed worktree dispatch** (`ISOLATION=orchestrator-worktree`): read and execute `execute-phase/steps/executor-isolation-dispatch.md`. GSD creates each worktree (`worktree create`) and spawns the executor into it; the orchestrator performs every git operation. Merge-back and cleanup are the existing manifest-scoped gauntlet, unchanged.
812
729
 
813
730
  **Sequential mode** (`USE_WORKTREES_FOR_PLAN` is `false` — either project-level `USE_WORKTREES=false`, or per-plan submodule intersection forced it false in step 2.5):
814
731
 
815
- Omit `isolation="worktree"` from the Agent call. Replace the `<parallel_execution>` block with:
732
+ Omit `isolation="worktree"` from the Agent call. Before composing the prompt, read and execute
733
+ `execute-phase/steps/sequential-root-pin.md` (#4254) — it owns the sequential root-pin build-time
734
+ embed and the wave serialization rules.
735
+
736
+ Replace the `<parallel_execution>` block with:
816
737
 
817
738
  ```
818
739
  <sequential_execution>
819
740
  You are running as a SEQUENTIAL executor agent on the main working tree.
820
741
  Use normal git commits (with hooks). Do NOT use --no-verify.
742
+ Run the `<project_root_pin>` guard before your first Edit/Write and before every commit (#4254).
821
743
  REQUIRED ORDER: Write SUMMARY.md → commit → only then any narration. No text between Write and commit (truncation risk; #2070 rescue is not primary defense).
822
744
  </sequential_execution>
745
+
746
+ <project_root_pin>
747
+ {ORCHESTRATOR build-time embed: bound step-0p guard per sequential-root-pin.md — never this note}
748
+ </project_root_pin>
823
749
  ```
824
750
 
825
751
  The sequential mode Agent prompt uses the same structure as worktree mode but with these differences in success_criteria — since there is only one agent writing at a time, there are no shared-file conflicts:
@@ -834,8 +760,6 @@ increases monotonically across waves. `{status}` is `complete` (success),
834
760
  </success_criteria>
835
761
  ```
836
762
 
837
- When worktrees are disabled for a plan (per-plan or project-level), that plan's executor runs on the main working tree. If **any** plan in the current wave dropped to sequential mode, execute the affected plan(s) **one at a time** to avoid concurrent writes to the main working tree — plans in the same wave that retained worktree isolation can still run in parallel alongside the sequential ones, but two non-worktree plans in the same wave must serialize. When the project-level `USE_WORKTREES=false`, all plans in the wave serialize regardless of the `PARALLELIZATION` setting.
838
-
839
763
  4. **Wait for all agents in wave to complete.**
840
764
 
841
765
  **Plan-complete heartbeat (#2410):** as each executor returns (or is verified
@@ -848,28 +772,9 @@ increases monotonically across waves. `{status}` is `complete` (success),
848
772
  [checkpoint] phase {PHASE_NUMBER} wave {N}/{M} plan {plan_id} checkpoint ({P}/{Q} plans done)
849
773
  ```
850
774
 
851
- **Completion signal fallback (Copilot and runtimes where Agent() may not return):**
775
+ **Completion reconciliation (EVERY runtime — any spawn whose terminal response may not arrive):**
852
776
 
853
- If a spawned agent does not return a completion signal but appears to have finished
854
- its work, do NOT block indefinitely. Instead, verify completion via spot-checks:
855
-
856
- ```bash
857
- # For each plan in this wave, check if the executor finished:
858
- SUMMARY_EXISTS=$(test -f "{phase_dir}/{plan_number}-{plan_padded}-SUMMARY.md" && echo "true" || echo "false")
859
- # #4003: anchored, zero-pad-tolerant scope (see safe_resume_gate); --since stays.
860
- SPOT_PHASE_N=$((10#{phase_number}))
861
- SPOT_PLAN_N=$((10#{plan_padded}))
862
- COMMITS_FOUND=$(git log --oneline --all -E --grep="^[a-z]+\((0*${SPOT_PHASE_N})-(0*${SPOT_PLAN_N})\):" --since="1 hour ago" | head -1)
863
- COMMITS_SINCE_DISPATCH=$(git log "${EXPECTED_BRANCH}" --since="${DISPATCH_TS}" --oneline | head -1)
864
- ```
865
-
866
- **If SUMMARY.md exists AND commits are found:** The agent completed successfully —
867
- treat as done and proceed to step 5. Log: `"✓ {Plan ID} completed (verified via spot-check — completion signal not received)"`
868
-
869
- **If SUMMARY.md does NOT exist after a reasonable wait:** The agent may still be
870
- running or may have failed silently. Check `git log --oneline -5` for recent
871
- activity. If commits are still appearing, wait longer. If no activity, report
872
- the plan as failed and route to the failure handler in step 6.
777
+ If a spawned agent does not return a normal terminal completion response — or its session ends abnormally (interrupted, aborted, closed, killed, timed out, `turn_aborted`, including ends the orchestrator itself initiated) — do NOT block indefinitely and do NOT classify the plan as failed yet. Read and execute `gsd-core/workflows/execute-phase/steps/completion-reconciliation.md` — reconcile the plan artifacts FIRST, classify SECOND: SUMMARY present AND matching recent commits → complete (proceed to step 5, do NOT re-dispatch); no completion evidence → the failure handler. Verify, never wait.
873
778
 
874
779
  **Configurable stall surveillance (#3212):** Every `${EXECUTOR_STALL_INTERVAL_MINUTES}`
875
780
  minutes while waiting, inspect `git log "${EXPECTED_BRANCH}" --since="${DISPATCH_TS}"`
@@ -878,10 +783,9 @@ increases monotonically across waves. `{status}` is `complete` (success),
878
783
  ask for one recovery path: `continue waiting`, `kill and retry`, or
879
784
  `kill and switch to inline execution`.
880
785
 
881
- If the stalled executor ran in an isolated worktree, `kill and switch to inline execution` edits the primary checkout — see worktree recovery policy (`execute-phase/steps/worktree-recovery-policy.md`). Prefer `kill and retry` in a fresh worktree; inline execution requires explicit confirmation, never the default.
882
-
883
- **This fallback applies to all runtimes.** Claude Code's Agent() backgrounds by
884
- default: the completion signal may never arrive. Verify, never wait.
786
+ **A working executor is never steered (#4218).** The threshold measures time WITHOUT
787
+ PROGRESS, not total runtime. Before treating an executor as stalled — and before sending it
788
+ any message — read and execute `execute-phase/steps/executor-progress-policy.md`.
885
789
 
886
790
  5. **Post-wave hook validation (parallel mode only):** Hooks run on every executor commit by default (#2924); this post-wave run only fires when `workflow.worktree_skip_hooks=true` opted out of per-commit hooks:
887
791
  ```bash
@@ -1115,6 +1019,7 @@ increases monotonically across waves. `{status}` is `complete` (success),
1115
1019
  if [ -n "$RETRY_AFTER" ]; then RETRY_HINT=" Provider hinted retry-after: ${RETRY_AFTER}s"; else RETRY_HINT=""; fi
1116
1020
  ```
1117
1021
  One classifier branch handles sentinels across Claude/Copilot/Codex/Gemini. Reference: `docs/research/provider-rate-limit-signals.md`.
1022
+ **Abnormal ends reconcile first (#4217):** an abnormal session end (`turn_aborted`-class) routes through the step-4 artifact reconciliation BEFORE classifying the failure — artifacts decide.
1118
1023
  **Step 7.1 — `class == "quota-exceeded"`:** follow the quota-recovery fragment below.
1119
1024
  **Step 7.2 — `class == "classify-handoff-bug"`:**
1120
1025
  If error contains `classifyHandoffIfNeeded is not defined`, treat as Claude runtime bug. Run the same step-5 spot-checks; PASS => treat as success, FAIL => fall through.
@@ -1141,6 +1046,7 @@ When executor returns a checkpoint AND `AUTO_MODE` is `true`:
1141
1046
  - **decision** → Auto-spawn continuation agent with `{user_response}` = first option from checkpoint details. Log `⚡ Auto-selected: [option]`. **Except `blocking-human`.**
1142
1047
  - **human-action** → Present to user (existing behavior below). Auth gates cannot be automated.
1143
1048
 
1049
+ <!-- gsd:protected -->
1144
1050
  **Carve-out — overrides all branches above.** If the returned `Gate:` is `blocking-human` (precondition-unmet, #3210), or its `<what-built>` mentions `Package verification required before install` or `Package install failed — human verification required`, never auto-approve or auto-select. Present to user (standard flow). Log `⛔ blocking-human gate — auto-mode suspended`.
1145
1051
 
1146
1052
  **Standard flow (not auto-mode, human-action, or blocking-human):**
@@ -1318,7 +1224,7 @@ ${VERIFIER_SKILLS}",
1318
1224
  )
1319
1225
  ```
1320
1226
 
1321
- > **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above, stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available.
1227
+ > **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above, stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available. If the session ends abnormally (`turn_aborted`), reconcile via the `verification.status` query below — the session's terminal state is not evidence of failure (#4217).
1322
1228
 
1323
1229
  Read status via the canonical query (scoped to frontmatter, covers missing/unknown cases):
1324
1230
  ```bash
@@ -1486,42 +1392,37 @@ Copy failure must NOT block phase completion.
1486
1392
  </step>
1487
1393
 
1488
1394
  <step name="close_phase_todos">
1489
- **Auto-close pending todos tagged for this phase (#2433).**
1490
-
1491
- After `update_roadmap`, moves todos whose `resolves_phase` matches to `completed/`.
1395
+ **Auto-close todos whose `resolves_phase` matches this phase (#2433)**, after `update_roadmap`.
1492
1396
 
1493
1397
  ```bash
1494
1398
  shopt -s nullglob 2>/dev/null; setopt NULL_GLOB 2>/dev/null
1495
- PHASE_NUM="${PHASE_NUMBER}"
1496
1399
  PENDING_DIR=".planning/todos/pending"
1497
1400
  COMPLETED_DIR=".planning/todos/completed"
1498
1401
  mkdir -p "$COMPLETED_DIR"
1499
-
1402
+ PHASE_NUM="${PHASE_NUMBER}"
1500
1403
  #2576
1501
1404
  normalize_phase_num() {
1502
- local p="${1//\"/}"; printf '%s' "$p" | sed 's/^0*\([0-9]\)/\1/'
1405
+ printf '%s' "${1//\"/}" | sed 's/^0*\([0-9]\)/\1/'
1503
1406
  }
1504
1407
  PHASE_NUM_NORM=$(normalize_phase_num "$PHASE_NUM")
1505
-
1506
1408
  CLOSED=()
1507
1409
  for TODO_FILE in "$PENDING_DIR"/*.md; do
1508
1410
  [ -f "$TODO_FILE" ] || continue
1509
1411
  RP=$(awk '/^---/{c++;next} c==1 && /^resolves_phase:/{print $2;exit} c==2{exit}' "$TODO_FILE" 2>/dev/null || true)
1510
1412
  RP_NORM=$(normalize_phase_num "$RP")
1511
- if [ -n "$RP_NORM" ] && [ "$RP_NORM" = "$PHASE_NUM_NORM" ]; then
1512
- mv "$TODO_FILE" "$COMPLETED_DIR/"
1513
- CLOSED+=("$(basename "$TODO_FILE")")
1514
- fi
1413
+ [ -n "$RP_NORM" ] && [ "$RP_NORM" = "$PHASE_NUM_NORM" ] || continue
1414
+ mv "$TODO_FILE" "$COMPLETED_DIR/"
1415
+ CLOSED+=("$(basename "$TODO_FILE")")
1515
1416
  done
1516
-
1517
1417
  if [ ${#CLOSED[@]} -gt 0 ]; then
1518
- gsd_run query commit "docs(phase-${PHASE_NUMBER}): close ${#CLOSED[@]} resolved todo(s)" --files .planning/todos/completed/ .planning/todos/pending/ .planning/STATE.md|| true
1519
- echo "◆ Closed ${#CLOSED[@]} todo(s) resolved by Phase ${PHASE_NUMBER}:"
1520
- for f in "${CLOSED[@]}"; do echo " ✓ $f"; done
1418
+ ADDED=(); REMOVED=()
1419
+ for f in "${CLOSED[@]}"; do ADDED+=("$COMPLETED_DIR/$f"); REMOVED+=("$PENDING_DIR/$f"); done
1420
+ gsd_run query commit "docs(phase-${PHASE_NUMBER}): close ${#CLOSED[@]} resolved todo(s)" --files "${ADDED[@]}" .planning/STATE.md --files-removed "${REMOVED[@]}" || true
1421
+ echo "◆ Closed ${#CLOSED[@]} todo(s) for Phase ${PHASE_NUMBER}:"; printf ' ✓ %s\n' "${CLOSED[@]}"
1521
1422
  fi
1522
1423
  ```
1523
1424
 
1524
- **No matches:** skip silently (always additive, non-blocking).
1425
+ No matches: skip silently, never blocks.
1525
1426
  </step>
1526
1427
 
1527
1428
  <step name="delegate_post_completion_to_transition">
@@ -67,7 +67,7 @@ Find first PLAN without matching SUMMARY. Decimal phases supported (`01.1-hotfix
67
67
  **Exclude `external_job_waiting` plans from selection.** When choosing the first PLAN that lacks a matching SUMMARY, skip any plan whose `plan_id` matches an async-job manifest in `.planning/async-jobs/` (any status) — that plan is `external_job_waiting` or awaiting reconciliation, never work to (re-)dispatch (re-dispatching would duplicate the external job). Reconcile via the manifest / safe_resume_gate instead.
68
68
 
69
69
  ```bash
70
- PHASE=$(echo "$PLAN_PATH" | grep -oE '[0-9]+(\.[0-9]+)?-[0-9]+')
70
+ PHASE=$(echo "$PLAN_PATH" | grep -oE '[0-9]+(\.[0-9]+)*-[0-9]+')
71
71
  # config settings can be fetched via gsd_run query config-get if needed
72
72
  ```
73
73
 
@@ -400,7 +400,7 @@ fi
400
400
  grep -A 50 "^user_setup:" .planning/phases/XX-name/{phase}-{plan}-PLAN.md | head -50
401
401
  ```
402
402
 
403
- If user_setup exists: create `{phase}-USER-SETUP.md` using template `~/.claude/gsd-core/templates/user-setup.md`. Per service: env vars table, account setup checklist, dashboard config, local dev notes, verification commands. Status "Incomplete". Set `USER_SETUP_CREATED=true`. If empty/missing: skip.
403
+ If user_setup exists: create `{phase}-USER-SETUP.md` using the template at `~/.claude/gsd-core/templates/user-setup.md` (or its `~/.claude/gsd-core/templates/user-setup.compact.md` variant — resolve per `~/.claude/gsd-core/references/compact-content-gate.md` §"Streams 1b and 4"). Per service: env vars table, account setup checklist, dashboard config, local dev notes, verification commands. Status "Incomplete". Set `USER_SETUP_CREATED=true`. If empty/missing: skip.
404
404
  </step>
405
405
 
406
406
  <step name="create_summary">
@@ -409,7 +409,7 @@ emit narrative output between the Write tool call and the commit tool call.
409
409
  Truncation at this boundary is a known failure mode (see #2070 rescue logic in
410
410
  execute-phase.md step 5.5).
411
411
 
412
- Create `{phase}-{plan}-SUMMARY.md` at `.planning/phases/XX-name/`. Use `~/.claude/gsd-core/templates/summary.md`.
412
+ Create `{phase}-{plan}-SUMMARY.md` at `.planning/phases/XX-name/`. Use the template at `~/.claude/gsd-core/templates/summary.md` (or `summary.compact.md` — same `compact-content-gate.md` resolution as the USER-SETUP template above).
413
413
 
414
414
  **Frontmatter:** phase, plan, subsystem, tags | requires/provides/affects | tech-stack.added/patterns | key-files.created/modified | key-decisions | requirements-completed (**MUST** copy `requirements` array from PLAN.md frontmatter verbatim) | duration ($DURATION), completed ($PLAN_END_TIME date).
415
415
 
@@ -547,8 +547,21 @@ fi
547
547
  If .planning/codebase/ doesn't exist: skip.
548
548
 
549
549
  ```bash
550
- FIRST_TASK=$(git log --oneline --grep="feat({phase}-{plan}):" --grep="fix({phase}-{plan}):" --grep="test({phase}-{plan}):" --reverse | head -1 | cut -d' ' -f1)
551
- git diff --name-only ${FIRST_TASK}^..HEAD 2>/dev/null || true
550
+ # #4459: a phase number is unique within a MILESTONE, not a repository. The
551
+ # former commit-subject grep had no milestone bound, and its `--reverse |
552
+ # head -1` deliberately selected the OLDEST matching subject — on a
553
+ # milestone that reuses this phase number, that drags in the PREVIOUS
554
+ # milestone's same-numbered phase's commits too. The phase's own directory
555
+ # is the unique identity: base = the parent of the first commit that added
556
+ # anything under the phase directory — the same anchor code-review.md's
557
+ # structural-pre-pass step already uses for the identical problem (#3995).
558
+ PHASE_START=$(git log --format="%H" --diff-filter=A -- ".planning/phases/XX-name" 2>/dev/null | tail -1)
559
+ if [ -n "$PHASE_START" ] && git rev-parse "${PHASE_START}^" >/dev/null 2>&1; then
560
+ DIFF_BASE="${PHASE_START}^"
561
+ else
562
+ DIFF_BASE="${PHASE_START:-HEAD}"
563
+ fi
564
+ git diff --name-only ${DIFF_BASE}..HEAD 2>/dev/null || true
552
565
  ```
553
566
 
554
567
  Update only structural changes: new src/ dir → STRUCTURE.md | deps → STACK.md | file pattern → CONVENTIONS.md | API client → INTEGRATIONS.md | config → STACK.md | renamed → update paths. Skip code-only/bugfix/content changes.
@@ -589,7 +602,7 @@ All routes: `/clear` first for fresh context.
589
602
  - USER-SETUP.md generated if user_setup in frontmatter
590
603
  - SUMMARY.md created with substantive content
591
604
  - STATE.md updated (position, decisions, issues, session) — unless parallel mode (orchestrator handles)
592
- - ROADMAP.md updated — unless parallel mode (orchestrator handles)
605
+ - ROADMAP.md updated — same exception
593
606
  - If codebase map exists: map updated with execution changes (or skipped if no significant changes)
594
- - If USER-SETUP.md created: prominently surfaced in completion output
607
+ - If USER-SETUP.md created: surfaced in completion output
595
608
  </success_criteria>