@pareto4/pp-core 1.11.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (256) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +31 -0
  3. package/agents/pp-code-fixer.md +1 -1
  4. package/agents/pp-debug-session-manager.md +1 -1
  5. package/agents/pp-debugger.md +1 -1
  6. package/agents/pp-executor.md +20 -10
  7. package/agents/pp-intel-updater.md +1 -1
  8. package/agents/pp-phase-researcher.md +1 -1
  9. package/agents/pp-plan-checker.md +5 -5
  10. package/agents/pp-planner.md +10 -24
  11. package/agents/pp-project-researcher.md +1 -1
  12. package/agents/pp-research-synthesizer.md +1 -1
  13. package/agents/pp-ui-researcher.md +1 -1
  14. package/agents/pp-verifier.md +8 -4
  15. package/bin/install.js +429 -82
  16. package/commands/pp-autonomous.md +8 -6
  17. package/commands/pp-discovery-to-build.md +1 -1
  18. package/commands/pp-discovery.md +3 -2
  19. package/commands/pp-discuss-phase.md +2 -2
  20. package/commands/pp-execute-phase.md +3 -1
  21. package/commands/pp-graphify.md +5 -5
  22. package/commands/pp-import.md +1 -1
  23. package/commands/pp-map-codebase.md +1 -1
  24. package/commands/pp-ns-project.md +2 -3
  25. package/commands/pp-ns-workflow.md +1 -1
  26. package/commands/pp-plan-phase.md +2 -1
  27. package/commands/pp-verify-work.md +2 -1
  28. package/gemini-extension.json +1 -1
  29. package/hooks/dist/pp-cursor-session-start.js +2 -2
  30. package/hooks/dist/pp-session-state.sh +1 -1
  31. package/hooks/dist/pp-statusline.js +21 -2
  32. package/hooks/pp-cursor-session-start.js +2 -2
  33. package/hooks/pp-session-state.sh +1 -1
  34. package/hooks/pp-statusline.js +21 -2
  35. package/package.json +18 -5
  36. package/pareto-skills/pp-project-setup/SKILL.md +5 -63
  37. package/pp-core/bin/detect-build-commands.sh +182 -0
  38. package/pp-core/bin/lib/capability-registry.cjs +65 -7
  39. package/pp-core/bin/lib/check-command-router.cjs +79 -38
  40. package/pp-core/bin/lib/clusters.cjs +2 -3
  41. package/pp-core/bin/lib/command-aliases.cjs +36 -0
  42. package/pp-core/bin/lib/command-arg-projection.cjs +99 -1
  43. package/pp-core/bin/lib/commands.cjs +21 -6
  44. package/pp-core/bin/lib/compose-bindings.cjs +128 -15
  45. package/pp-core/bin/lib/config-schema.cjs +16 -0
  46. package/pp-core/bin/lib/config.cjs +142 -27
  47. package/pp-core/bin/lib/core-utils.cjs +43 -7
  48. package/pp-core/bin/lib/discovery-input-check.cjs +218 -0
  49. package/pp-core/bin/lib/discovery-rebaseline.cjs +1372 -0
  50. package/pp-core/bin/lib/discovery-research-track.cjs +979 -0
  51. package/pp-core/bin/lib/discovery-rollup.cjs +476 -0
  52. package/pp-core/bin/lib/discovery-screens.cjs +1995 -0
  53. package/pp-core/bin/lib/discovery-sweep.cjs +390 -0
  54. package/pp-core/bin/lib/discovery-table.cjs +98 -0
  55. package/pp-core/bin/lib/dispatch-plan.cjs +472 -0
  56. package/pp-core/bin/lib/frontmatter.cjs +17 -2
  57. package/pp-core/bin/lib/init-command-router.cjs +8 -5
  58. package/pp-core/bin/lib/init-contract.cjs +213 -33
  59. package/pp-core/bin/lib/init-interactive.cjs +20 -1
  60. package/pp-core/bin/lib/init.cjs +124 -134
  61. package/pp-core/bin/lib/install-profiles.cjs +5 -0
  62. package/pp-core/bin/lib/install-run.cjs +536 -0
  63. package/pp-core/bin/lib/io.cjs +15 -0
  64. package/pp-core/bin/lib/loop-resolver.cjs +24 -0
  65. package/pp-core/bin/lib/milestone.cjs +345 -48
  66. package/pp-core/bin/lib/phase-command-router.cjs +23 -1
  67. package/pp-core/bin/lib/phase-locator.cjs +15 -6
  68. package/pp-core/bin/lib/phase-scope.cjs +91 -0
  69. package/pp-core/bin/lib/phase-tier.cjs +467 -0
  70. package/pp-core/bin/lib/phase.cjs +247 -21
  71. package/pp-core/bin/lib/phases-command-router.cjs +2 -0
  72. package/pp-core/bin/lib/plan-graph.cjs +368 -0
  73. package/pp-core/bin/lib/planning-workspace.cjs +53 -0
  74. package/pp-core/bin/lib/platform-bindings.cjs +32 -2
  75. package/pp-core/bin/lib/profile-output.cjs +11 -3
  76. package/pp-core/bin/lib/prohibition-enforcement.cjs +112 -0
  77. package/pp-core/bin/lib/roadmap-parser.cjs +366 -99
  78. package/pp-core/bin/lib/roadmap.cjs +141 -39
  79. package/pp-core/bin/lib/runtime-hooks-surface.cjs +1 -1
  80. package/pp-core/bin/lib/shell-command-projection.cjs +24 -0
  81. package/pp-core/bin/lib/state-command-router.cjs +82 -13
  82. package/pp-core/bin/lib/state-document.cjs +124 -7
  83. package/pp-core/bin/lib/state.cjs +784 -257
  84. package/pp-core/bin/lib/template.cjs +22 -6
  85. package/pp-core/bin/lib/vault-command-router.cjs +57 -6
  86. package/pp-core/bin/lib/vault-practices.cjs +6 -36
  87. package/pp-core/bin/lib/vault-write-back.cjs +20 -4
  88. package/pp-core/bin/lib/vault.cjs +555 -23
  89. package/pp-core/bin/lib/verify.cjs +53 -31
  90. package/pp-core/bin/lib/workstream.cjs +1 -1
  91. package/pp-core/bin/lib/worktree-safety.cjs +26 -15
  92. package/pp-core/bin/portable-timeout.sh +89 -0
  93. package/pp-core/bin/pp-tools.cjs +158 -8
  94. package/pp-core/bin/shared/config-defaults.manifest.json +7 -0
  95. package/pp-core/bin/shared/config-schema.manifest.json +3 -0
  96. package/pp-core/references/autonomous-best-effort.md +461 -0
  97. package/pp-core/references/autonomous-lifecycle.md +146 -0
  98. package/pp-core/references/autonomous-smart-discuss.md +16 -12
  99. package/pp-core/references/checkpoints.md +1 -1
  100. package/pp-core/references/discovery-id-conventions.md +202 -0
  101. package/pp-core/references/discovery-rebaseline.md +254 -0
  102. package/pp-core/references/discovery-research-track.md +283 -0
  103. package/pp-core/references/discovery-traceability.md +400 -0
  104. package/pp-core/references/loop-hook-dispatch.md +7 -0
  105. package/pp-core/references/mandatory-initial-read.md +1 -1
  106. package/pp-core/references/planner-gap-closure.md +1 -0
  107. package/pp-core/references/planner-human-verify-mode.md +1 -1
  108. package/pp-core/references/planner-load-graph-context.md +1 -1
  109. package/pp-core/references/planner-plan-graph.md +66 -0
  110. package/pp-core/references/planner-tdd.md +1 -0
  111. package/pp-core/references/planning-config.md +8 -0
  112. package/pp-core/references/sketch-tooling.md +4 -0
  113. package/pp-core/references/tdd.md +1 -0
  114. package/pp-core/templates/claude-md.md +1 -1
  115. package/pp-core/templates/phase-prompt.md +6 -2
  116. package/pp-core/templates/prototype-review/review.js +303 -0
  117. package/pp-core/templates/state.md +6 -0
  118. package/pp-core/workflows/_runtime-launcher.snippet.sh +1 -1
  119. package/pp-core/workflows/add-backlog.md +1 -1
  120. package/pp-core/workflows/add-phase.md +1 -1
  121. package/pp-core/workflows/add-tests.md +1 -1
  122. package/pp-core/workflows/add-todo.md +1 -1
  123. package/pp-core/workflows/ai-integration-phase.md +2 -2
  124. package/pp-core/workflows/audit-fix.md +12 -16
  125. package/pp-core/workflows/audit-milestone.md +1 -1
  126. package/pp-core/workflows/audit-uat.md +1 -1
  127. package/pp-core/workflows/autonomous.md +68 -306
  128. package/pp-core/workflows/check-todos.md +1 -1
  129. package/pp-core/workflows/cleanup.md +1 -1
  130. package/pp-core/workflows/code-review-fix.md +1 -1
  131. package/pp-core/workflows/code-review.md +19 -7
  132. package/pp-core/workflows/complete-milestone.md +41 -60
  133. package/pp-core/workflows/debug.md +1 -1
  134. package/pp-core/workflows/diagnose-issues.md +1 -1
  135. package/pp-core/workflows/discovery-sprint/gap-analysis.md +140 -0
  136. package/pp-core/workflows/discovery-sprint/input-package.md +140 -0
  137. package/pp-core/workflows/discovery-sprint/prefill.md +92 -0
  138. package/pp-core/workflows/discovery-sprint/prototype.md +257 -0
  139. package/pp-core/workflows/discovery-sprint/rebaseline.md +276 -0
  140. package/pp-core/workflows/discovery-sprint/session-13-gates.md +24 -0
  141. package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +92 -0
  142. package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +98 -0
  143. package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +215 -0
  144. package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +146 -0
  145. package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +98 -0
  146. package/pp-core/workflows/discovery-sprint/sessions/06-security.md +107 -0
  147. package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +98 -0
  148. package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +85 -0
  149. package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +109 -0
  150. package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +119 -0
  151. package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +92 -0
  152. package/pp-core/workflows/discovery-sprint/sessions/12-delivery-model.md +98 -0
  153. package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +205 -0
  154. package/pp-core/workflows/discovery-sprint/templates/context-template.md +266 -0
  155. package/pp-core/workflows/discovery-sprint.md +79 -1714
  156. package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +5 -5
  157. package/pp-core/workflows/discovery-to-build/steps/screen-inventory-gate.md +70 -0
  158. package/pp-core/workflows/discovery-to-build/templates/discovery-references.md +54 -0
  159. package/pp-core/workflows/discovery-to-build/templates/pp-handoff.md +184 -0
  160. package/pp-core/workflows/discovery-to-build.md +21 -238
  161. package/pp-core/workflows/discuss-phase/modes/advisor.md +1 -1
  162. package/pp-core/workflows/discuss-phase/modes/auto.md +1 -1
  163. package/pp-core/workflows/discuss-phase/modes/chain.md +1 -1
  164. package/pp-core/workflows/discuss-phase-assumptions.md +1 -1
  165. package/pp-core/workflows/discuss-phase.md +9 -2
  166. package/pp-core/workflows/do.md +4 -4
  167. package/pp-core/workflows/docs-update.md +1 -1
  168. package/pp-core/workflows/edit-phase.md +1 -1
  169. package/pp-core/workflows/eval-review.md +1 -1
  170. package/pp-core/workflows/execute-phase/steps/checkpoint-handling.md +45 -0
  171. package/pp-core/workflows/execute-phase/steps/client-context-gate.md +1 -1
  172. package/pp-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
  173. package/pp-core/workflows/execute-phase/steps/cross-ai-delegation.md +90 -0
  174. package/pp-core/workflows/execute-phase/steps/install-run.md +29 -0
  175. package/pp-core/workflows/execute-phase/steps/phase-close-rebaseline.md +23 -0
  176. package/pp-core/workflows/execute-phase/steps/post-merge-gate.md +76 -77
  177. package/pp-core/workflows/execute-phase/steps/serial-group-dispatch.md +72 -0
  178. package/pp-core/workflows/execute-phase/steps/vault-fetch.md +5 -5
  179. package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +19 -112
  180. package/pp-core/workflows/execute-phase.md +102 -216
  181. package/pp-core/workflows/execute-plan.md +6 -2
  182. package/pp-core/workflows/explore.md +1 -1
  183. package/pp-core/workflows/extract-learnings.md +1 -1
  184. package/pp-core/workflows/forensics.md +4 -4
  185. package/pp-core/workflows/graduation.md +1 -1
  186. package/pp-core/workflows/health.md +1 -1
  187. package/pp-core/workflows/help/modes/brief.md +1 -0
  188. package/pp-core/workflows/help/modes/default.md +2 -1
  189. package/pp-core/workflows/help/modes/full.md +12 -5
  190. package/pp-core/workflows/import.md +1 -1
  191. package/pp-core/workflows/ingest-docs.md +1 -1
  192. package/pp-core/workflows/init.md +18 -2
  193. package/pp-core/workflows/insert-phase.md +1 -1
  194. package/pp-core/workflows/list-workspaces.md +1 -1
  195. package/pp-core/workflows/manager.md +3 -3
  196. package/pp-core/workflows/map-codebase.md +2 -2
  197. package/pp-core/workflows/milestone-summary.md +4 -4
  198. package/pp-core/workflows/mvp-phase.md +1 -1
  199. package/pp-core/workflows/new-milestone.md +7 -8
  200. package/pp-core/workflows/new-project.md +6 -1
  201. package/pp-core/workflows/new-workspace.md +1 -1
  202. package/pp-core/workflows/next.md +2 -2
  203. package/pp-core/workflows/note.md +2 -2
  204. package/pp-core/workflows/pause-work.md +1 -1
  205. package/pp-core/workflows/plan-milestone-gaps.md +1 -1
  206. package/pp-core/workflows/plan-phase/steps/chunked-planning.md +111 -0
  207. package/pp-core/workflows/plan-phase/steps/phase-tier.md +34 -0
  208. package/pp-core/workflows/plan-phase.md +43 -167
  209. package/pp-core/workflows/plan-review-convergence.md +2 -2
  210. package/pp-core/workflows/plant-seed.md +1 -1
  211. package/pp-core/workflows/pr-branch.md +1 -1
  212. package/pp-core/workflows/profile-user.md +1 -1
  213. package/pp-core/workflows/progress.md +3 -3
  214. package/pp-core/workflows/quick.md +3 -1
  215. package/pp-core/workflows/remove-phase.md +1 -1
  216. package/pp-core/workflows/remove-workspace.md +1 -1
  217. package/pp-core/workflows/resume-project.md +6 -12
  218. package/pp-core/workflows/review.md +1 -1
  219. package/pp-core/workflows/scan.md +1 -1
  220. package/pp-core/workflows/secure-phase.md +1 -1
  221. package/pp-core/workflows/settings-advanced.md +1 -1
  222. package/pp-core/workflows/settings-integrations.md +1 -1
  223. package/pp-core/workflows/settings.md +1 -1
  224. package/pp-core/workflows/ship.md +25 -8
  225. package/pp-core/workflows/sketch-wrap-up.md +1 -1
  226. package/pp-core/workflows/sketch.md +2 -1
  227. package/pp-core/workflows/spec-phase.md +1 -1
  228. package/pp-core/workflows/spike-wrap-up.md +1 -1
  229. package/pp-core/workflows/spike.md +1 -1
  230. package/pp-core/workflows/stats.md +2 -2
  231. package/pp-core/workflows/thread.md +1 -1
  232. package/pp-core/workflows/transition.md +5 -9
  233. package/pp-core/workflows/ui-phase.md +23 -2
  234. package/pp-core/workflows/ui-review.md +1 -1
  235. package/pp-core/workflows/ultraplan-phase.md +2 -2
  236. package/pp-core/workflows/validate-phase.md +1 -1
  237. package/pp-core/workflows/vault-write-back.md +1 -1
  238. package/pp-core/workflows/verify-phase.md +29 -26
  239. package/pp-core/workflows/verify-work.md +14 -10
  240. package/scripts/base64-scan.sh +7 -41
  241. package/scripts/changeset/cli.cjs +25 -5
  242. package/scripts/dev-env.cjs +462 -0
  243. package/scripts/lib/allowlist-ratchet.cjs +103 -1
  244. package/scripts/lib/size-budget.cjs +311 -0
  245. package/scripts/lint-neutrality-names.cjs +694 -0
  246. package/scripts/lint-org-coordinates.allowlist.json +35 -0
  247. package/scripts/lint-org-coordinates.cjs +426 -0
  248. package/scripts/lint-skill-deps.cjs +48 -9
  249. package/scripts/lint-test-file-count.cjs +17 -2
  250. package/scripts/prompt-injection-scan.sh +41 -20
  251. package/scripts/sync-manifest-versions.cjs +41 -7
  252. package/scripts/sync-runtime-launcher.cjs +106 -1
  253. package/scripts/update-size-baseline.cjs +274 -30
  254. package/scripts/workflow-size.cjs +61 -9
  255. package/commands/pp-build-handoff.md +0 -46
  256. package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +0 -94
@@ -69,9 +69,11 @@ Parse `$ARGUMENTS` before loading any context:
69
69
 
70
70
  - First positional token → `PHASE_ARG`
71
71
  - Optional `--wave N` → `WAVE_FILTER`
72
- - Optional `--gaps-only` keeps its current meaning
72
+ - Optional `--gaps-only` → `GAPS_ONLY=true` (only `gap_closure: true` plans)
73
+ - Optional `--tier light|standard|heavy` → `TIER_FLAG="--tier <value>"` (the phase's ceremony tier for this run; passed to init, dispatch plan and render-hooks)
73
74
  - Optional `--cross-ai` → `CROSS_AI_FORCE=true` (force all plans through cross-AI execution)
74
75
  - Optional `--no-cross-ai` → `CROSS_AI_DISABLED=true` (disable cross-AI for this run, overrides config and frontmatter)
76
+ - Optional `--unattended` → `UNATTENDED=true` — set by `/pp:autonomous`; prompt sites marked `U-En` apply the rules in `pp-core/references/autonomous-best-effort.md` (Read it at the first such site)
75
77
 
76
78
  If `--wave` is absent, preserve the current behavior of executing all incomplete waves in the phase.
77
79
  </step>
@@ -80,8 +82,8 @@ If `--wave` is absent, preserve the current behavior of executing all incomplete
80
82
  Load all context in one call:
81
83
 
82
84
  ```bash
83
- _PP_SHIM_NAME="pp-tools.cjs"; _PP_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; PP_TOOLS="${_PP_RUNTIME_ROOT}/pp-core/bin/${_PP_SHIM_NAME}"; if [ -f "$PP_TOOLS" ]; then pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif command -v pp-tools >/dev/null 2>&1; then PP_TOOLS="$(command -v pp-tools)"; pp_run() { "$PP_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}"; pp_run() { node "$PP_TOOLS" "$@"; }; else echo "ERROR: pp-tools.cjs not found at $PP_TOOLS and pp-tools is not on PATH. Run: npx -y @pareto4/pp-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${PP_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${PP_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
84
- INIT=$(pp_run query init.execute-phase "${PHASE_ARG}")
85
+ _PP_SHIM_NAME="pp-tools.cjs"; _pp_root() { ( for _v in $(env | sed -n 's/^\(GIT_[A-Za-z0-9_]*\)=.*/\1/p'); do unset "$_v"; done; _c=$(git rev-parse --git-common-dir 2>/dev/null); if [ "${_c##*/}" = .git ] && cd "$_c/.." 2>/dev/null; then pwd -P; else git rev-parse --show-toplevel 2>/dev/null || pwd; fi ); }; pp_run() { case "$PP_TOOLS" in *.cjs) node "$PP_TOOLS" "$@";; *) "$PP_TOOLS" "$@";; esac; }; _PP_RUNTIME_ROOT="${RUNTIME_DIR:-$(_pp_root)}"; PP_TOOLS="${_PP_RUNTIME_ROOT}/pp-core/bin/${_PP_SHIM_NAME}"; if [ -f "$PP_TOOLS" ]; then :; elif [ -f "${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}"; elif command -v pp-tools >/dev/null 2>&1; then PP_TOOLS="$(command -v pp-tools)"; else echo "ERROR: pp-tools.cjs not found at $PP_TOOLS and pp-tools is not on PATH. Run: npx -y @pareto4/pp-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${PP_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${PP_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
86
+ INIT=$(pp_run query init.execute-phase "${PHASE_ARG}" ${TIER_FLAG})
85
87
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
86
88
  AGENT_SKILLS=$(pp_run query agent-skills pp-executor)
87
89
  ```
@@ -95,7 +97,7 @@ Parse JSON for: `executor_model`, `verifier_model`, `commit_docs`, `parallelizat
95
97
  Read runtime/worktree config and fail closed before any executor dispatch:
96
98
 
97
99
  ```bash
98
- RUNTIME=$(pp_run query config-get runtime --default claude 2>/dev/null || echo "claude")
100
+ RUNTIME=$(pp_run query config-get runtime --default claude --raw 2>/dev/null || echo "claude")
99
101
  USE_WORKTREES=$(pp_run query config-get workflow.use_worktrees 2>/dev/null || echo "true")
100
102
  EXECUTOR_STALL_INTERVAL_MINUTES=$(pp_run query config-get executor.stall_detect_interval_minutes 2>/dev/null || echo "5")
101
103
  EXECUTOR_STALL_THRESHOLD_MINUTES=$(pp_run query config-get executor.stall_threshold_minutes 2>/dev/null || echo "10")
@@ -119,7 +121,7 @@ fi
119
121
  ```
120
122
  Codex maps subagents to `spawn_agent`, which has no direct Codex mapping for Claude Code's `isolation="worktree"` parameter. Failing closed prevents main-checkout edits while the workflow believes agents are isolated.
121
123
 
122
- If the project uses git submodules, worktree isolation is unsafe **only when a plan touches a submodule path** — the executor commit protocol cannot correctly handle submodule commits inside isolated worktrees. The previous behavior unconditionally disabled worktree isolation whenever `.gitmodules` existed, which penalised every plan in a submodule project even when the plan was nowhere near a submodule. Compute submodule paths once and intersect them per-plan with the plan's declared `files_modified` frontmatter.
124
+ If the project uses git submodules, worktree isolation is unsafe **only when a plan touches a submodule path** — the executor commit protocol cannot correctly handle submodule commits inside isolated worktrees. Compute submodule paths once and intersect them per-plan with the plan's declared `files_modified` frontmatter.
123
125
 
124
126
  ```bash
125
127
  # Parse submodule paths from .gitmodules once (empty if no .gitmodules).
@@ -131,11 +133,11 @@ else
131
133
  fi
132
134
  ```
133
135
 
134
- `SUBMODULE_PATHS` is exported to the `execute_waves` step, where the per-plan decision actually happens (see "Per-plan worktree decision" sub-step inside `execute_waves`). The decision is per-plan because different plans in the same wave can touch different files — only plans whose paths intersect a submodule must drop worktree isolation; plans nowhere near a submodule keep parallel isolation.
136
+ `SUBMODULE_PATHS` is exported to the `execute_waves` step, where the per-plan decision actually happens (see "Per-plan worktree decision" sub-step inside `execute_waves`). Only plans whose paths intersect a submodule drop isolation.
135
137
 
136
138
  When `USE_WORKTREES` (project-level) is `false`, all executor agents run without `isolation="worktree"` — they execute sequentially on the main working tree instead of in parallel worktrees. The per-plan decision below has no effect when worktrees are project-disabled.
137
139
 
138
- `USE_WORKTREES` is also automatically set to `false` for the duration of a run when `worktree base-check` detects that the orchestrator HEAD has diverged from the worktree fork base (the #683 condition — e.g. an unmerged milestone or feature branch). This check runs only when `RUNTIME=claude` because `isolation="worktree"` is a Claude Code-specific feature; other runtimes do not use it. The auto-degrade prints a one-line warning to stderr and falls through to the sequential path so executors do not hit the exit-42 worktree-branch-check halt. To restore parallel worktree execution, set `worktree.baseRef:"head"` in `.claude/settings.local.json` (or run `pp-tools worktree set-baseref`) — this makes the fork base track the live HEAD instead of a fixed remote ref. The `worktree-branch-check` exit-42 guard inside each executor remains in place as a backstop.
140
+ `USE_WORKTREES` is also automatically set to `false` for the duration of a run when `worktree base-check` detects that the orchestrator HEAD has diverged from the worktree fork base (the #683 condition — e.g. an unmerged milestone or feature branch). The auto-degrade prints a one-line warning to stderr and falls through to the sequential path so executors do not hit the exit-42 worktree-branch-check halt. To restore parallel worktree execution, set `worktree.baseRef:"head"` in `.claude/settings.local.json` (or run `pp-tools worktree set-baseref`) — this makes the fork base track the live HEAD instead of a fixed remote ref. The `worktree-branch-check` exit-42 guard inside each executor remains in place as a backstop.
139
141
 
140
142
  Read context window size for adaptive prompt enrichment:
141
143
 
@@ -143,10 +145,10 @@ Read context window size for adaptive prompt enrichment:
143
145
  CONTEXT_WINDOW=$(pp_run query config-get context_window 2>/dev/null || echo "200000")
144
146
  ```
145
147
 
146
- When `CONTEXT_WINDOW >= 500000` (1M-class models), subagent prompts include richer context:
147
- - Executor agents receive prior wave SUMMARY.md files and the phase CONTEXT.md/RESEARCH.md
148
- - Verifier agents receive all PLAN.md, SUMMARY.md, CONTEXT.md files plus REQUIREMENTS.md
149
- - This enables cross-phase awareness and history-aware verification
148
+ When `CONTEXT_WINDOW >= 500000` (1M-class models), subagent prompts ALSO include history:
149
+ - Executor agents also receive prior wave SUMMARY.md files
150
+ - Verifier agents also receive prior phases' VERIFICATION.md files (regression check)
151
+ - The phase CONTEXT.md and RESEARCH.md are NOT behind this gate: both agents get them at every window size, because an executor denied the locked decisions builds code that drifts from them (WorkNotes 8/17)
150
152
 
151
153
  When `CONTEXT_WINDOW < 200000` (sub-200K models), subagent prompts are thinned to reduce static overhead:
152
154
  - Executor agents omit extended deviation rule examples and checkpoint examples from inline prompt — load on-demand via @~/.claude/pp-core/references/executor-examples.md
@@ -181,7 +183,7 @@ Resolve `MVP_MODE` once via the centralized `phase.mvp-mode` query verb (precede
181
183
  MVP_FLAG_ARG=""
182
184
  if [[ "$ARGUMENTS" =~ (^|[[:space:]])--mvp([[:space:]]|$) ]]; then MVP_FLAG_ARG="--cli-flag"; fi
183
185
  MVP_MODE=$(pp_run query phase.mvp-mode "${PHASE_NUMBER}" $MVP_FLAG_ARG --pick active)
184
- EXECUTE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:post --raw)
186
+ EXECUTE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:post --raw --phase "${PHASE_NUMBER}" ${TIER_FLAG})
185
187
  TDD_MODE=$(pp_run loop render-hooks execute:post --active-cap tdd)
186
188
  ```
187
189
 
@@ -344,6 +346,10 @@ This updates Status, Last Activity, Current focus, Current Position, and plan co
344
346
  Read and execute `pp-core/workflows/execute-phase/steps/client-context-gate.md` — Pareto client-context gate (inert without `.platform-bindings.json`; confirms the Phase 9 CLAUDE.md block first).
345
347
  </step>
346
348
 
349
+ <step name="execute_pre_vault">
350
+ Before any executor: `EXECUTE_PRE_HOOKS_JSON=$(pp_run loop render-hooks execute:pre --raw)`. For an active `capId == "vault"` step, Read and execute `pp-core/workflows/execute-phase/steps/vault-fetch.md`; then, for an active `vault.status` gate, set `VAULT_GATE_POINT=execute` and Read and execute `pp-core/workflows/execute-phase/steps/vault-load-gate.md`. None active → skip.
351
+ </step>
352
+
347
353
  <step name="discover_and_group_plans">
348
354
  Load plan inventory with wave grouping in one call:
349
355
 
@@ -351,7 +357,7 @@ Load plan inventory with wave grouping in one call:
351
357
  PLAN_INDEX=$(pp_run query phase-plan-index "${PHASE_NUMBER}")
352
358
  ```
353
359
 
354
- Parse JSON for: `phase`, `plans[]` (each with `id`, `wave`, `autonomous`, `objective`, `files_modified`, `task_count`, `has_summary`), `waves` (map of wave number → plan IDs), `incomplete`, `has_checkpoints`.
360
+ Parse JSON for: `phase`, `plans[]` (each with `id`, `title`, `wave`, `serial_group`, `autonomous`, `objective`, `files_modified`, `task_count`, `has_summary`), `waves` (map of wave number → plan IDs), `serial_groups`, `incomplete`, `has_checkpoints`. A plan's `{plan_title}` is its `title` (legacy plans without one: its objective, 3-8 words).
355
361
 
356
362
  **Filtering:** Skip plans where `has_summary: true`. If `--gaps-only`: also skip non-gap_closure plans. If `WAVE_FILTER` is set: also skip plans whose `wave` does not equal `WAVE_FILTER`.
357
363
 
@@ -369,84 +375,19 @@ Report:
369
375
 
370
376
  | Wave | Plans | What it builds |
371
377
  |------|-------|----------------|
372
- | 1 | 01-01, 01-02 | {from plan objectives, 3-8 words} |
378
+ | 1 | 01-01, 01-02 | 01-01 {plan_title}; 01-02 {plan_title} |
373
379
  | 2 | 01-03 | ... |
374
380
  ```
375
381
  </step>
376
382
 
377
383
  <step name="cross_ai_delegation">
378
- **Optional step 2.5 — Delegate plans to an external AI runtime.**
379
-
380
- This step runs after plan discovery and before normal wave execution. It identifies plans
381
- that should be delegated to an external AI command and executes them via stdin-based prompt
382
- delivery. Plans handled here are removed from the execute_waves plan list so the normal
383
- executor skips them.
384
-
385
- **Activation logic:**
386
384
 
387
- 1. If `CROSS_AI_DISABLED` is true (`--no-cross-ai` flag): skip this step entirely.
388
- 2. If `CROSS_AI_FORCE` is true (`--cross-ai` flag): mark ALL incomplete plans for cross-AI execution.
389
- 3. Otherwise: check each plan's frontmatter for `cross_ai: true` AND verify config
390
- `workflow.cross_ai_execution` is `true`. Plans matching both conditions are marked for cross-AI.
391
-
392
- ```bash
393
- CROSS_AI_ENABLED=$(pp_run query config-get workflow.cross_ai_execution 2>/dev/null || echo "false")
394
- CROSS_AI_CMD=$(pp_run query config-get workflow.cross_ai_command 2>/dev/null || echo "")
395
- CROSS_AI_TIMEOUT=$(pp_run query config-get workflow.cross_ai_timeout 2>/dev/null || echo "300")
396
- ```
385
+ Read and execute `pp-core/workflows/execute-phase/steps/cross-ai-delegation.md`.
397
386
 
398
- **If no plans are marked for cross-AI:** Skip to execute_waves.
399
-
400
- **If plans are marked but `cross_ai_command` is empty:** Error — tell user to set
401
- `workflow.cross_ai_command` via `pp-tools.cjs query config-set workflow.cross_ai_command "<command>"`.
402
-
403
- **For each cross-AI plan (sequentially):**
404
-
405
- 1. **Construct the task prompt** from the plan file:
406
- - Extract `<objective>` and `<tasks>` sections from the PLAN.md
407
- - Append PROJECT.md context (project name, description, tech stack)
408
- - Format as a self-contained execution prompt
409
-
410
- 2. **Check for dirty working tree before execution:**
411
- ```bash
412
- if ! git diff --quiet HEAD 2>/dev/null; then
413
- echo "WARNING: dirty working tree detected — the external AI command may produce uncommitted changes that conflict with existing modifications"
414
- fi
415
- ```
416
-
417
- 3. **Run the external command** from the project root, writing the prompt to stdin.
418
- Never shell-interpolate the prompt — always pipe via stdin to prevent injection:
419
- ```bash
420
- echo "$TASK_PROMPT" | timeout "${CROSS_AI_TIMEOUT}s" ${CROSS_AI_CMD} > "$CANDIDATE_SUMMARY" 2>"$ERROR_LOG"
421
- EXIT_CODE=$?
422
- ```
423
-
424
- 4. **Evaluate the result:**
425
-
426
- **Success (exit 0 + valid summary):**
427
- - Read `$CANDIDATE_SUMMARY` and validate it contains meaningful content
428
- (not empty, has at least a heading and description — a valid SUMMARY.md structure)
429
- - Write it as the plan's SUMMARY.md file
430
- - Update STATE.md plan status to complete
431
- - Update ROADMAP.md progress
432
- - Mark plan as handled — skip it in execute_waves
433
-
434
- **Failure (non-zero exit or invalid summary):**
435
- - Display the error output and exit code
436
- - Warn: "The external command may have left uncommitted changes or partial edits
437
- in the working tree. Review `git status` and `git diff` before proceeding."
438
- - Offer three choices:
439
- - **retry** — run the same plan through cross-AI again
440
- - **skip** — fall back to normal executor for this plan (re-add to execute_waves list)
441
- - **abort** — stop execution entirely, preserve state for resume
442
-
443
- 5. **After all cross-AI plans processed:** Remove successfully handled plans from the
444
- incomplete plan list so execute_waves skips them. Any skipped-to-fallback plans remain
445
- in the list for normal executor processing.
446
387
  </step>
447
388
 
448
389
  <step name="execute_waves">
449
- Execute each selected wave in sequence. Within a wave: parallel if `PARALLELIZATION=true`, sequential if `false`.
390
+ Execute each selected wave in sequence. Within a wave, follow its `run`: `parallel` — worktree spawns run alongside each other, main-checkout spawns one at a time; `sequential` — one spawn at a time.
450
391
 
451
392
  **Orchestrator cwd-drift guard (FIRST ACTION at execute_waves entry — #48):**
452
393
 
@@ -477,6 +418,14 @@ export ORCHESTRATOR_WT
477
418
  cd "$ORCHESTRATOR_WT" || { echo "FATAL: cannot cd to orchestrator worktree '$ORCHESTRATOR_WT' (#48)." >&2; exit 1; }
478
419
  ```
479
420
 
421
+ **Dispatch plan (load once, after the cwd guard and cross-AI delegation):** what this run spawns, builds, tests and commits, computed by `phase.dispatch-plan`. Spawn exactly its spawns; never re-derive waves, serial groups, isolation or builds.
422
+
423
+ ```bash
424
+ DISPATCH_PLAN=$(pp_run query phase.dispatch-plan "${PHASE_NUMBER}" --use-worktrees "${USE_WORKTREES:-true}" ${WAVE_FILTER:+--wave "$WAVE_FILTER"} ${GAPS_ONLY:+--gaps-only} ${TIER_FLAG})
425
+ ```
426
+
427
+ `stages.execute.waves[]` in order, each with `spawns[]` (`kind` `serial-group`|`plan`, `plans[]` in run order with `id`, `title`, `build`, `touched_tests`; `isolation` `main-checkout`|`worktree`; `build`; `checkpoint`), `run`, `merge`, `build`, `suite_runs` (1), `tracking_commits` (1), `tracking.requirements`, `defects[]`. Report `totals` (spawns, suite runs, tracking commits). Non-empty `filters.lower_wave_incomplete` → STOP: finish the earlier waves first.
428
+
480
429
  **Stream-idle-timeout prevention — checkpoint heartbeats (#2410):**
481
430
 
482
431
  Multi-plan phases can accumulate enough subagent context that the Claude API
@@ -499,39 +448,14 @@ increases monotonically across waves. `{status}` is `complete` (success),
499
448
 
500
449
  **For each wave:**
501
450
 
502
- 1. **Intra-wave files_modified overlap check (BEFORE spawning):**
503
-
504
- Before spawning any agents for this wave, inspect the `files_modified` list of all plans
505
- in the wave. Check every pair of plans in the wave — if any two plans share even one file
506
- in their `files_modified` lists, those plans have an implicit dependency and MUST NOT run
507
- in parallel.
451
+ 1. **Intra-wave files_modified overlap check (BEFORE spawning — computed):** the wave's `defects[]` lists any two plans in it that share a source file, and any two plans in different spawns that share any file. Plans of one serial group share non-source files by design — not a defect; their one spawn runs them one after another.
508
452
 
509
- **Detection algorithm (pseudocode):**
510
- ```
511
- seen_files = {}
512
- overlapping_plans = []
513
- for each plan in wave_plans:
514
- for each file in plan.files_modified:
515
- if file in seen_files:
516
- overlapping_plans.add(plan, seen_files[file]) # both plans overlap on this file
517
- else:
518
- seen_files[file] = plan
519
- ```
520
-
521
- **If overlap is detected:**
522
- - Warn the user:
453
+ **If `defects` is non-empty:** warn the user with each defect's `message`:
523
454
  ```
524
455
  ⚠ Intra-wave files_modified overlap detected in Wave {N}:
525
- Plan {A} and Plan {B} both modify {file}
526
- Running these plans sequentially to avoid parallel worktree conflicts.
456
+ {defect.message}
527
457
  ```
528
- - Override `PARALLELIZATION` to `false` for this wave only — run all plans in the wave
529
- sequentially regardless of the global parallelization setting.
530
- - This is a safety net for plans that were incorrectly assigned to the same wave.
531
- The planner should have caught this; flag it as a planning defect so the user can
532
- replan the phase if desired.
533
-
534
- **If no overlap:** proceed normally (parallel if `PARALLELIZATION=true`).
458
+ The wave's `run` is then `sequential` — run its spawns one at a time — and the overlap is a planning defect the user may replan.
535
459
 
536
460
  2. **Describe what's being built (BEFORE spawning):**
537
461
 
@@ -557,21 +481,19 @@ increases monotonically across waves. `{status}` is `complete` (success),
557
481
  ---
558
482
  ## Wave {N}
559
483
 
560
- **{Plan ID}: {Plan Name}**
484
+ **{Plan ID}: {plan_title}**
561
485
  {2-3 sentences: what this builds, technical approach, why it matters}
562
486
 
563
- Spawning {count} agent(s)... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
487
+ Spawning {count} agent(s) — one per spawn in this wave... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
564
488
  ---
565
489
  ```
566
490
 
567
491
  - Bad: "Executing terrain generation plan"
568
492
  - Good: "Procedural terrain generator using Perlin noise — creates height maps, biome zones, and collision meshes. Required before vehicle physics can interact with ground."
569
493
 
570
- 2.5. **Per-plan worktree decision (run for each plan in this wave BEFORE its dispatch):**
494
+ 2.5. **Per-plan worktree decision (from the dispatch plan):** a spawn's `isolation` is the decision. `phase.dispatch-plan` makes it from `USE_WORKTREES` and `.gitmodules`: a serial group, a plan touching a submodule path, or a submodule-project plan with no `files_modified` gets `main-checkout`. For a `main-checkout` spawn set `USE_WORKTREES_FOR_PLAN=false`; for a `worktree` spawn leave it unset and append its plan ids to `WAVE_WORKTREE_PLANS`.
571
495
 
572
- Read and execute `pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md` for each plan. It extracts `PLAN_FILES` from the plan's JSON, intersects against `SUBMODULE_PATHS` (with normalization, bidirectional matching, and glob-prefix handling), and sets `USE_WORKTREES_FOR_PLAN` to `false` when the plan touches a submodule path. Append `plan_id` to a `WAVE_WORKTREE_PLANS` accumulator when `USE_WORKTREES_FOR_PLAN != false`.
573
-
574
- The dispatch branches in step 3 below MUST gate on `USE_WORKTREES_FOR_PLAN` for the current plan, not on the project-level `USE_WORKTREES`.
496
+ The dispatch branches in step 3 below MUST gate on `USE_WORKTREES_FOR_PLAN` for the current spawn, not on the project-level `USE_WORKTREES`.
575
497
 
576
498
  3. **Spawn executor agents:**
577
499
 
@@ -580,6 +502,8 @@ increases monotonically across waves. `{status}` is `complete` (success),
580
502
 
581
503
  `[checkpoint] phase {PHASE_NUMBER} wave {N}/{M} plan {plan_id} starting ({P}/{Q} plans done)`
582
504
 
505
+ **Serial-group spawn** (`kind: serial-group`): Read and execute `pp-core/workflows/execute-phase/steps/serial-group-dispatch.md` — ONE executor on the main checkout for the whole group. The rest of step 3 covers `kind: plan` spawns.
506
+
583
507
  Pass paths only — executors read files themselves with their fresh context window.
584
508
  For 200k models, this keeps orchestrator context lean (~10-15%).
585
509
  For 1M+ models (Opus 4.6, Sonnet 4.6), richer context can be passed directly.
@@ -616,7 +540,7 @@ increases monotonically across waves. `{status}` is `complete` (success),
616
540
  ```text
617
541
  Agent(
618
542
  subagent_type="pp-executor",
619
- description="Execute plan {plan_number} of phase {phase_number}",
543
+ description="Execute plan {plan_number} of phase {phase_number}: {plan_title}",
620
544
  # Only include model= when executor_model is an explicit model name.
621
545
  # When executor_model is "inherit", omit this parameter entirely so
622
546
  # Claude Code inherits the orchestrator model automatically.
@@ -624,11 +548,13 @@ increases monotonically across waves. `{status}` is `complete` (success),
624
548
  isolation="worktree",
625
549
  prompt="
626
550
  <objective>
627
- Execute plan {plan_number} of phase {phase_number}-{phase_name}.
551
+ Execute plan {plan_number} ({plan_title}) of phase {phase_number}-{phase_name}.
628
552
  Commit each task atomically. Create SUMMARY.md.
629
553
  Do NOT update STATE.md or ROADMAP.md — the orchestrator owns those writes after all worktree agents in the wave complete.
630
554
  </objective>
631
555
 
556
+ <dispatch tracking="orchestrator" suite="orchestrator" build="{spawn.build}" />
557
+
632
558
  <worktree_branch_check>
633
559
  ORCHESTRATOR build-time embed (NOT a sub-agent runtime step): before this dispatch, read `pp-core/references/worktree-branch-check.md`, substitute `{EXPECTED_BASE}` with the base SHA captured above ({EXPECTED_BASE}), and replace this note with that fragment's `<worktree_branch_check>` block so the dispatched prompt carries the runnable guard verbatim — do not pass this instruction through in its place.
634
560
  Per-commit HEAD/cwd-drift/path-guard: `agents/pp-executor.md` steps 0/0a/0b + `references/worktree-path-safety.md` (in <execution_context>).
@@ -664,19 +590,19 @@ increases monotonically across waves. `{status}` is `complete` (success),
664
590
  </execution_context>
665
591
 
666
592
  <files_to_read>
667
- Read these files at execution start using the Read tool.
593
+ MANDATORY: load every file listed here with the Read tool before you start the work — this block is your required reading.
668
594
  First resolve repo root so every path is anchored:
669
595
  \`PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)\`
670
596
  - ${PROJECT_ROOT}/{phase_dir}/{plan_file} (Plan)
671
597
  - ${PROJECT_ROOT}/.planning/PROJECT.md (Project context — core value, requirements, evolution rules)
672
598
  - ${PROJECT_ROOT}/.planning/STATE.md (State)
673
599
  - ${PROJECT_ROOT}/.planning/config.json (Config, if exists)
674
- ${CONTEXT_WINDOW >= 500000 ? `
675
- - ${PROJECT_ROOT}/${phase_dir}/*-CONTEXT.md (User decisions from discuss-phase — honors locked choices)
600
+ - ${PROJECT_ROOT}/${phase_dir}/*-CONTEXT.md (User decisions from discuss-phase — honor the locked choices at every context window)
676
601
  - ${PROJECT_ROOT}/${phase_dir}/*-RESEARCH.md (Technical research — pitfalls and patterns to follow)
602
+ ${CONTEXT_WINDOW >= 500000 ? `
677
603
  - ${PROJECT_ROOT}/${prior_wave_summaries} (SUMMARY.md files from earlier waves in this phase — what was already built)
678
604
  ` : ''}
679
- - ${PROJECT_ROOT}/CLAUDE.md (Project instructions, if exists — follow project-specific guidelines and coding conventions)
605
+ - ${PROJECT_ROOT}/CLAUDE.md or ${PROJECT_ROOT}/.claude/CLAUDE.md (Project instructions, if either exists — follow project-specific guidelines and coding conventions)
680
606
  - ${PROJECT_ROOT}/.claude/skills/ or ${PROJECT_ROOT}/.agents/skills/ (Project skills, if either exists — list skills, read SKILL.md for each, follow relevant rules during implementation)
681
607
  </files_to_read>
682
608
 
@@ -717,19 +643,18 @@ increases monotonically across waves. `{status}` is `complete` (success),
717
643
  </sequential_execution>
718
644
  ```
719
645
 
720
- 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:
646
+ Everything else is the worktree-mode prompt, `<dispatch>` tag included — the orchestrator owns tracking for every spawn:
721
647
 
722
648
  ```
723
649
  <success_criteria>
724
650
  - [ ] All tasks executed
725
651
  - [ ] Each task committed individually
726
652
  - [ ] SUMMARY.md created in plan directory
727
- - [ ] STATE.md updated with position and decisions
728
- - [ ] ROADMAP.md updated with plan progress (via `roadmap update-plan-progress`)
653
+ - [ ] No tracking-file writes (the orchestrator advances them once per wave)
729
654
  </success_criteria>
730
655
  ```
731
656
 
732
- 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.
657
+ 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 — isolated plans may still run alongside them. When the project-level `USE_WORKTREES=false`, all plans in the wave serialize regardless of the `PARALLELIZATION` setting.
733
658
 
734
659
  4. **Wait for all agents in wave to complete.**
735
660
 
@@ -768,7 +693,7 @@ increases monotonically across waves. `{status}` is `complete` (success),
768
693
  for activity. If no completion signal, no SUMMARY.md, and no expected-branch
769
694
  commits appear for `${EXECUTOR_STALL_THRESHOLD_MINUTES}` minutes, pause and
770
695
  ask for one recovery path: `continue waiting`, `kill and retry`, or
771
- `kill and switch to inline execution`.
696
+ `kill and switch to inline execution` (U-E7).
772
697
 
773
698
  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.
774
699
 
@@ -866,7 +791,7 @@ increases monotonically across waves. `{status}` is `complete` (success),
866
791
 
867
792
  **When to skip step 5.5:**
868
793
 
869
- **If no plan in this wave used worktree isolation** (project-level `USE_WORKTREES=false` OR every plan in the wave had `USE_WORKTREES_FOR_PLAN=false` — i.e. `WAVE_WORKTREE_PLANS` from step 2.5 is empty): all agents ran on the main working tree — skip this step entirely.
794
+ **If no spawn in this wave used worktree isolation** (the wave's `merge.cleanup` is false — `WAVE_WORKTREE_PLANS` from step 2.5 is empty): all agents ran on the main working tree — skip this step entirely.
870
795
 
871
796
  **If the orchestrator merged via custom messages (cross-wave-dependency deviation):** the templated cleanup loop above was not triggered for those merges. Run the cleanup-tail snippet above instead. After the snippet completes, proceed to step 5.6.
872
797
 
@@ -878,10 +803,12 @@ increases monotonically across waves. `{status}` is `complete` (success),
878
803
 
879
804
  5.6. **Post-merge build & test gate:**
880
805
 
881
- After merging all worktrees in a wave (parallel mode), or after the last plan completes
882
- (serial mode), run a build and then the project's test suite to catch cross-plan
883
- integration issues that individual worktree self-checks cannot detect (e.g., conflicting
884
- type definitions, removed exports, import changes, link errors).
806
+ Once per wave, after the merge step (whatever ran: worktrees, a serial group, main-checkout
807
+ plans), run a build and then the project's full test suite — exactly once per wave
808
+ (`suite_runs: 1`), by the orchestrator, never per plan. Skip the build (Step A) when the
809
+ wave's `build` is false (no plan in it touches source). This catches cross-plan integration
810
+ issues that per-plan checks cannot detect (e.g., conflicting type definitions, removed
811
+ exports, import changes, link errors).
885
812
 
886
813
  This addresses the Generator self-evaluation blind spot identified in Anthropic's
887
814
  harness engineering research: agents reliably report Self-Check: PASSED even when
@@ -889,26 +816,28 @@ increases monotonically across waves. `{status}` is `complete` (success),
889
816
 
890
817
  Read and execute `pp-core/workflows/execute-phase/steps/post-merge-gate.md`.
891
818
 
892
- 5.7. **Post-wave shared artifact update (when at least one plan used worktrees, skip if tests failed):**
819
+ 5.7. **Post-wave tracking (every wave, once, by the orchestrator; skip if tests failed):**
893
820
 
894
- When **any** executor agent in this wave ran with `isolation="worktree"`, that agent skipped STATE.md and ROADMAP.md updates to avoid last-merge-wins overwrites. The orchestrator is the single writer for these files. After worktrees are merged back, update shared artifacts once for every completed plan in the wave (worktree-mode plans **and** sequential plans that ran on the main tree but deferred to the orchestrator for tracking writes).
821
+ No executor writes tracking files under execute-phase (each prompt carries `<dispatch tracking="orchestrator">`), worktree or main checkout alike. After the merge and the suite, the orchestrator alone:
822
+ refreshes the plan rows and the Built state with `roadmap update-plan-progress`;
823
+ advances STATE, records the wave's `tracking.requirements` (`requirements.mark-complete`) and the `key-decisions` of its SUMMARY.md files (`state.add-decision`);
824
+ makes the wave's ONE tracking commit (`tracking_commits: 1`).
895
825
 
896
826
  **Only update tracking when tests passed (TEST_EXIT=0).**
897
827
  If tests failed or timed out, skip the tracking update — plans should
898
828
  not be marked as complete when integration tests are failing or inconclusive.
899
829
 
900
830
  ```bash
901
- # Guard: only update tracking if post-merge tests passed
902
- # Timeout (124) is treated as inconclusive — do NOT mark plans complete
831
+ # Timeout (124) is inconclusive — do NOT mark plans complete
903
832
  if [ "${TEST_EXIT}" -eq 0 ]; then
904
- # Update ROADMAP plan progress for each completed plan in this wave
905
- for plan_id in {completed_plan_ids}; do
906
- pp_run query roadmap.update-plan-progress "${PHASE_NUMBER}" "${plan_id}" "complete"
907
- done
908
-
909
- # Only commit tracking files if they actually changed
910
- if ! git diff --quiet .planning/ROADMAP.md .planning/STATE.md 2>/dev/null; then
911
- pp_run query commit "docs(phase-${PHASE_NUMBER}): update tracking after wave ${N}" --files .planning/ROADMAP.md .planning/STATE.md
833
+ # Plan rows and the Built state (D-08-12); phase completion is phase.complete's, in update_roadmap.
834
+ pp_run query roadmap.update-plan-progress "${PHASE_NUMBER}"
835
+ pp_run query state.update-progress
836
+ # WAVE_REQ_IDS: this wave's tracking.requirements from DISPATCH_PLAN, space-separated
837
+ [ -n "${WAVE_REQ_IDS:-}" ] && pp_run query requirements.mark-complete ${WAVE_REQ_IDS}
838
+ pp_run query state.record-session --stopped-at "Phase ${PHASE_NUMBER} wave ${N} complete" --resume-file "None"
839
+ if ! git diff --quiet .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md 2>/dev/null; then
840
+ pp_run query commit "docs(phase-${PHASE_NUMBER}): update tracking after wave ${N}" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md
912
841
  fi
913
842
  elif [ "${TEST_EXIT}" -eq 124 ]; then
914
843
  echo "⚠ Skipping tracking update — test suite timed out. Plans remain in-progress. Run tests manually to confirm."
@@ -917,10 +846,6 @@ increases monotonically across waves. `{status}` is `complete` (success),
917
846
  fi
918
847
  ```
919
848
 
920
- Where `WAVE_PLAN_IDS` is the space-separated list of plan IDs that completed in this wave.
921
-
922
- **If no plan in this wave used worktrees** (project-level `USE_WORKTREES=false` OR `WAVE_WORKTREE_PLANS` is empty): sequential agents already updated STATE.md and ROADMAP.md themselves — skip this step.
923
-
924
849
  5.75. **Execute:wave:post capability dispatch:**
925
850
 
926
851
  After worktree merge, post-merge tests, and tracking updates, dispatch capability hooks registered at `execute:wave:post`. The primary hook is the `ui.safety-gate` gate from the UI capability — it verifies that any frontend files changed in this wave conform to the UI-SPEC contract.
@@ -984,7 +909,7 @@ increases monotonically across waves. `{status}` is `complete` (success),
984
909
  ```
985
910
 
986
911
  Note: If `WAVE_FAILURE_COUNT > 1`, strongly recommend "Fix now" — compounding
987
- failures across multiple waves become exponentially harder to diagnose.
912
+ failures across multiple waves become exponentially harder to diagnose. (U-E2 — Fix now once, then Continue, record.)
988
913
 
989
914
  If "Fix now": diagnose failures (typically import conflicts, missing types,
990
915
  or changed function signatures from parallel plans modifying the same module).
@@ -1018,7 +943,7 @@ increases monotonically across waves. `{status}` is `complete` (success),
1018
943
  ---
1019
944
  ## Wave {N} Complete
1020
945
 
1021
- **{Plan ID}: {Plan Name}**
946
+ **{Plan ID}: {plan_title}**
1022
947
  {What was built — from SUMMARY.md}
1023
948
  {Notable deviations, if any}
1024
949
 
@@ -1048,61 +973,23 @@ increases monotonically across waves. `{status}` is `complete` (success),
1048
973
  2. Switch to a different runtime / model and resume
1049
974
  3. Abort phase and report partial state
1050
975
  ```
1051
- Re-run `/pp:execute-phase` after quota reset for Option 1.
976
+ Re-run `/pp:execute-phase` after quota reset for Option 1. (U-E3 — option 3, record.)
1052
977
  **Step 7.2 — `class == "classify-handoff-bug"`:**
1053
978
  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.
1054
979
  **Step 7.3 — `class == "unknown-failure"`:**
1055
- Report failed plan and ask Continue/Stop; continuing may cascade into dependent plan failures.
980
+ Report failed plan and ask Continue/Stop; continuing may cascade into dependent plan failures. (U-E4 — Stop, record.)
1056
981
 
1057
982
  7b. **Pre-wave dependency check (waves 2+ only):**
1058
983
  Before wave N+1, run `pp-tools.cjs query verify.key-links {phase_dir}/{plan}-PLAN.md` for each upcoming plan.
1059
984
  If any PRIOR-wave artifact link fails, present:
1060
985
  - `## Cross-Plan Wiring Gap` with plan/link/from/pattern rows
1061
- - Options: investigate+fix before continue, or continue with cascade risk
986
+ - Options: investigate+fix before continue, or continue with cascade risk (U-E5)
1062
987
  Skip key-links that reference files in the CURRENT (upcoming) wave.
1063
988
  8. **Execute checkpoint plans between waves** — see `<checkpoint_handling>`.
1064
989
  9. **Proceed to next wave.**
1065
990
  </step>
1066
991
  <step name="checkpoint_handling">
1067
- Plans with `autonomous: false` require user interaction.
1068
- **Auto-mode checkpoint handling:**
1069
- Read auto-advance config (chain flag OR user preference — same boolean as `check.auto-mode`):
1070
- ```bash
1071
- AUTO_MODE=$(pp_run query check auto-mode --pick active 2>/dev/null || echo "false")
1072
- ```
1073
-
1074
- When executor returns a checkpoint AND `AUTO_MODE` is `true`:
1075
- - **human-verify** → Auto-spawn continuation agent with `{user_response}` = `"approved"`. Log `⚡ Auto-approved checkpoint`.
1076
- - **decision** → Auto-spawn continuation agent with `{user_response}` = first option from checkpoint details. Log `⚡ Auto-selected: [option]`.
1077
- - **human-action** → Present to user (existing behavior below). Auth gates cannot be automated.
1078
-
1079
- **Standard flow (not auto-mode, or human-action type):**
1080
-
1081
- 1. Spawn agent for checkpoint plan
1082
- 2. Agent runs until checkpoint task or auth gate → returns structured state
1083
- 3. Agent return includes: completed tasks table, current task + blocker, checkpoint type/details, what's awaited
1084
- 4. **Present to user:**
1085
- ```
1086
- ## Checkpoint: [Type]
1087
-
1088
- **Plan:** 03-03 Dashboard Layout
1089
- **Progress:** 2/3 tasks complete
1090
-
1091
- [Checkpoint Details from agent return]
1092
- [Awaiting section from agent return]
1093
- ```
1094
- 5. User responds: "approved"/"done" | issue description | decision selection
1095
- 6. **Spawn continuation agent (NOT resume)** using continuation-prompt.md template:
1096
- - `{completed_tasks_table}`: From checkpoint return
1097
- - `{resume_task_number}` + `{resume_task_name}`: Current task
1098
- - `{user_response}`: What user provided
1099
- - `{resume_instructions}`: Based on checkpoint type
1100
- 7. Continuation agent verifies previous commits, continues from resume point
1101
- 8. Repeat until plan completes or user stops
1102
-
1103
- **Why fresh agent, not resume:** Resume relies on internal serialization that breaks with parallel tool calls. Fresh agents with explicit state are more reliable.
1104
-
1105
- **Checkpoints in parallel waves:** Agent pauses and returns while other parallel agents may complete. Present checkpoint, spawn continuation, wait for all before next wave.
992
+ Plans with `autonomous: false` require user interaction. When an executor returns a checkpoint, Read and execute `pp-core/workflows/execute-phase/steps/checkpoint-handling.md` (auto-mode rules, continuation-agent flow).
1106
993
  </step>
1107
994
 
1108
995
  <step name="aggregate_results">
@@ -1129,7 +1016,7 @@ After all waves:
1129
1016
 
1130
1017
  **Security gate check:**
1131
1018
  ```bash
1132
- VERIFY_POST_HOOKS_JSON=$(pp_run loop render-hooks verify:post --raw)
1019
+ VERIFY_POST_HOOKS_JSON=$(pp_run loop render-hooks verify:post --raw --phase "${PHASE_NUMBER}" ${TIER_FLAG})
1133
1020
  SECURITY_FILE=$(ls "${PHASE_DIR}"/*-SECURITY.md 2>/dev/null | head -1)
1134
1021
  ```
1135
1022
 
@@ -1187,7 +1074,7 @@ Selected wave finished successfully. This phase still has incomplete plans, so p
1187
1074
 
1188
1075
  **Capability gate:**
1189
1076
  ```bash
1190
- EXECUTE_POST_HOOKS_JSON=${EXECUTE_POST_HOOKS_JSON:-$(pp_run loop render-hooks execute:post --raw)}
1077
+ EXECUTE_POST_HOOKS_JSON=${EXECUTE_POST_HOOKS_JSON:-$(pp_run loop render-hooks execute:post --raw --phase "${PHASE_NUMBER}" ${TIER_FLAG})}
1191
1078
  ```
1192
1079
 
1193
1080
  Resolve active step hooks from `EXECUTE_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "code-review"`.
@@ -1309,27 +1196,21 @@ Collect all unique test file paths into `REGRESSION_FILES`.
1309
1196
  **Step 3: Run regression tests (if any found)**
1310
1197
 
1311
1198
  ```bash
1312
- # Resolve test command: project config > Makefile > language sniff
1313
- REG_TEST_CMD=$(pp_run query config-get workflow.test_command --default "" 2>/dev/null || true)
1199
+ # Test command: project config first, else the shared sniff ladder
1200
+ PP_GATE_BIN=$(printf '%s\n' "${PP_TOOLS:+${PP_TOOLS%/*}:}$PATH" | tr : '\n' | while IFS= read -r d; do if [ -r "$d/detect-build-commands.sh" ]; then printf %s "$d"; break; fi; done)
1201
+ REG_TEST_CMD=$(pp_run query config-get workflow.test_command --default "" --raw 2>/dev/null || true)
1314
1202
  if [ -z "$REG_TEST_CMD" ]; then
1315
- if [ -f "Makefile" ] && grep -q "^test:" Makefile; then
1316
- REG_TEST_CMD="make test"
1317
- elif [ -f "Justfile" ] || [ -f "justfile" ]; then
1318
- REG_TEST_CMD="just test"
1319
- elif [ -f "package.json" ]; then
1320
- REG_TEST_CMD="npm test"
1321
- elif [ -f "Cargo.toml" ]; then
1322
- REG_TEST_CMD="cargo test"
1323
- elif [ -f "go.mod" ]; then
1324
- REG_TEST_CMD="go test ./..."
1325
- elif [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
1326
- REG_TEST_CMD="python -m pytest ${REGRESSION_FILES} -q --tb=short"
1203
+ if [ -r "$PP_GATE_BIN/detect-build-commands.sh" ]; then
1204
+ . "$PP_GATE_BIN/detect-build-commands.sh"; REG_TEST_CMD=$(pp_detect_test_cmd "$REGRESSION_FILES")
1327
1205
  else
1328
- REG_TEST_CMD="true"
1206
+ echo "✗ pp-core sniff ladder not found beside pp-tools — cannot detect a test command"
1329
1207
  fi
1330
1208
  fi
1331
- # Detect test runner and run prior phase tests
1332
- eval "$REG_TEST_CMD" 2>&1
1209
+ if [ -z "$REG_TEST_CMD" ]; then
1210
+ echo "⚠ Regression tests NOT RUN — no test runner detected (not a pass, not a failure)"
1211
+ else
1212
+ eval "$REG_TEST_CMD" 2>&1
1213
+ fi
1333
1214
  ```
1334
1215
 
1335
1216
  **Step 4: Report results**
@@ -1356,12 +1237,14 @@ Options:
1356
1237
  3. Abort phase — roll back and re-plan
1357
1238
  ```
1358
1239
 
1359
- If `TEXT_MODE` is true, present as a plain-text numbered list and ask the user to type their choice number. Otherwise, use AskUserQuestion to present the options.
1240
+ If `TEXT_MODE` is true, present as a plain-text numbered list and ask the user to type their choice number. Otherwise, use AskUserQuestion to present the options. (U-E6 — option 1 once, then option 2, record.)
1360
1241
  </step>
1361
1242
 
1362
1243
  <step name="verify_phase_goal">
1363
1244
  Verify phase achieved its GOAL, not just completed tasks.
1364
1245
 
1246
+ **Tier gate:** spawn the verifier only when `DISPATCH_PLAN.stages.verify` lists `pp-verifier` (= `verifier_enabled`). Otherwise print `Verifier skipped (tier {phase_tier.tier})`, treat the phase as `passed` and go to `update_roadmap`. When it lists `verify-install` (heavy tier), first Read and execute `pp-core/workflows/execute-phase/steps/install-run.md`: the installed-product run the verifier judges on.
1247
+
1365
1248
  ```bash
1366
1249
  VERIFIER_SKILLS=$(pp_run query agent-skills pp-verifier)
1367
1250
  ```
@@ -1378,13 +1261,14 @@ Cross-reference requirement IDs from PLAN frontmatter against REQUIREMENTS.md
1378
1261
  Create VERIFICATION.md.
1379
1262
 
1380
1263
  <files_to_read>
1381
- Read these files before verification:
1264
+ MANDATORY: load every file listed here with the Read tool before you start the work — this block is your required reading.
1382
1265
  - {phase_dir}/*-PLAN.md (All plans — understand intent, check must_haves)
1383
1266
  - {phase_dir}/*-SUMMARY.md (All summaries — cross-reference claimed vs actual)
1384
1267
  - .planning/REQUIREMENTS.md (Requirement traceability)
1385
- ${CONTEXT_WINDOW >= 500000 ? `- {phase_dir}/*-CONTEXT.md (User decisions — verify they were honored)
1268
+ - {phase_dir}/*-CONTEXT.md (User decisions — verify they were honored)
1386
1269
  - {phase_dir}/*-RESEARCH.md (Known pitfalls — check for traps)
1387
- - Prior VERIFICATION.md files from earlier phases (regression check)
1270
+ ${INSTALL_RUN_FILE ? `- ${INSTALL_RUN_FILE} (installed-product run — judge user-facing behaviour on it, not on the repo)
1271
+ ` : ''}${CONTEXT_WINDOW >= 500000 ? `- Prior VERIFICATION.md files from earlier phases (regression check)
1388
1272
  ` : ''}
1389
1273
  </files_to_read>
1390
1274
 
@@ -1472,7 +1356,7 @@ When ready to run the tests:
1472
1356
  Verify-work will walk you through each item and mark the phase complete when all tests pass.
1473
1357
  ```
1474
1358
 
1475
- **Do NOT advance the phase from this branch.** Phase completion is handled by verify-work's auto-transition after UAT passes.
1359
+ **Do NOT advance the phase from this branch.** (U-E9 — present, do not wait, return.) Phase completion is handled by verify-work's auto-transition after UAT passes.
1476
1360
 
1477
1361
  **If user acknowledges without reporting issues (including "ok", "noted", "ack", "got it", "approved", "done", "yes", "pass", or similar):** Stop. The phase remains pending. No further orchestrator action — wait for the user to run `/pp:verify-work`.
1478
1362
 
@@ -1505,6 +1389,8 @@ Gap closure cycle: `/pp:plan-phase {X} --gaps ${GSD_WS}` reads VERIFICATION.md
1505
1389
  <step name="update_roadmap">
1506
1390
  **Mark phase complete and update all tracking files:**
1507
1391
 
1392
+ First, Read and execute `pp-core/workflows/execute-phase/steps/phase-close-rebaseline.md` (the phase's one size re-baseline; inert where no `size:baseline` script exists).
1393
+
1508
1394
  ```bash
1509
1395
  COMPLETION=$(pp_run query phase.complete "${PHASE_NUMBER}")
1510
1396
  ```