@pareto4/pp-core 1.13.0 → 1.18.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 (204) hide show
  1. package/.claude-plugin/plugin.json +3 -3
  2. package/README.md +31 -12
  3. package/agents/pp-code-fixer.md +0 -11
  4. package/agents/pp-code-reviewer.md +1 -77
  5. package/agents/pp-debug-session-manager.md +9 -6
  6. package/agents/pp-executor.md +12 -29
  7. package/agents/pp-plan-checker.md +4 -4
  8. package/agents/pp-planner.md +34 -20
  9. package/agents/pp-vault-reviewer.md +100 -23
  10. package/agents/pp-verifier.md +1 -3
  11. package/bin/install.js +10 -3
  12. package/commands/pp-execute-phase.md +1 -3
  13. package/commands/pp-ns-manage.md +1 -1
  14. package/commands/pp-ns-review.md +1 -1
  15. package/commands/pp-plan-phase.md +1 -2
  16. package/commands/pp-vault-promote.md +7 -8
  17. package/commands/pp-vault-review.md +6 -5
  18. package/commands/pp-verify-work.md +1 -2
  19. package/gemini-extension.json +1 -1
  20. package/hooks/dist/pp-check-update.js +0 -0
  21. package/hooks/dist/pp-cursor-session-start.js +1 -1
  22. package/hooks/dist/pp-statusline.js +1 -1
  23. package/hooks/dist/pp-update-banner.js +0 -0
  24. package/hooks/pp-check-update.js +0 -0
  25. package/hooks/pp-cursor-session-start.js +1 -1
  26. package/hooks/pp-statusline.js +1 -1
  27. package/hooks/pp-update-banner.js +0 -0
  28. package/package.json +10 -18
  29. package/pareto-skills/_shared/create-project-board.sh +0 -0
  30. package/pareto-skills/pp-project-setup/SKILL.md +1 -1
  31. package/pp-core/bin/check-latest-version.cjs +0 -0
  32. package/pp-core/bin/detect-build-commands.sh +2 -2
  33. package/pp-core/bin/lib/capability-activation.cjs +83 -9
  34. package/pp-core/bin/lib/capability-registry.cjs +201 -229
  35. package/pp-core/bin/lib/capability-state.cjs +93 -1
  36. package/pp-core/bin/lib/capability-writer.cjs +3 -3
  37. package/pp-core/bin/lib/check-command-router.cjs +1906 -1514
  38. package/pp-core/bin/lib/clusters.cjs +3 -0
  39. package/pp-core/bin/lib/command-aliases.cjs +0 -35
  40. package/pp-core/bin/lib/commands.cjs +9 -4
  41. package/pp-core/bin/lib/compose-bindings.cjs +251 -88
  42. package/pp-core/bin/lib/config-loader.cjs +7 -103
  43. package/pp-core/bin/lib/config-schema.cjs +1 -1
  44. package/pp-core/bin/lib/config.cjs +151 -62
  45. package/pp-core/bin/lib/decisions.cjs +4 -4
  46. package/pp-core/bin/lib/discovery-vault-check.cjs +246 -0
  47. package/pp-core/bin/lib/frontmatter.cjs +1 -38
  48. package/pp-core/bin/lib/git-base-branch.cjs +11 -12
  49. package/pp-core/bin/lib/git-provider.cjs +9 -10
  50. package/pp-core/bin/lib/init-command-router.cjs +5 -8
  51. package/pp-core/bin/lib/init-contract.cjs +620 -738
  52. package/pp-core/bin/lib/init-interactive.cjs +62 -4
  53. package/pp-core/bin/lib/init.cjs +24 -51
  54. package/pp-core/bin/lib/install-profiles.cjs +1 -1
  55. package/pp-core/bin/lib/io.cjs +4 -2
  56. package/pp-core/bin/lib/loop-resolver.cjs +165 -129
  57. package/pp-core/bin/lib/org-profile.cjs +402 -161
  58. package/pp-core/bin/lib/package-identity.cjs +3 -3
  59. package/pp-core/bin/lib/phase-command-router.cjs +1 -29
  60. package/pp-core/bin/lib/phase-scope.cjs +1 -1
  61. package/pp-core/bin/lib/phase.cjs +11 -253
  62. package/pp-core/bin/lib/platform-bindings.cjs +40 -19
  63. package/pp-core/bin/lib/profile-output.cjs +1 -1
  64. package/pp-core/bin/lib/shell-command-projection.cjs +104 -1
  65. package/pp-core/bin/lib/state.cjs +11 -85
  66. package/pp-core/bin/lib/template.cjs +1 -1
  67. package/pp-core/bin/lib/vault-command-router.cjs +1682 -477
  68. package/pp-core/bin/lib/vault-coordinates.cjs +16 -7
  69. package/pp-core/bin/lib/vault-index.cjs +656 -0
  70. package/pp-core/bin/lib/vault-seal.cjs +1851 -0
  71. package/pp-core/bin/lib/vault-standards-promote.cjs +577 -0
  72. package/pp-core/bin/lib/vault-standards-review.cjs +293 -0
  73. package/pp-core/bin/lib/vault-standards.cjs +1504 -0
  74. package/pp-core/bin/lib/vault-trace.cjs +155 -2778
  75. package/pp-core/bin/lib/vault-update.cjs +10 -59
  76. package/pp-core/bin/lib/vault.cjs +2570 -950
  77. package/pp-core/bin/lib/verify.cjs +0 -11
  78. package/pp-core/bin/portable-timeout.sh +1 -1
  79. package/pp-core/bin/pp-tools.cjs +157 -54
  80. package/pp-core/bin/shared/config-defaults.manifest.json +0 -7
  81. package/pp-core/bin/shared/config-schema.manifest.json +0 -3
  82. package/pp-core/bin/shared/model-catalog.json +2 -2
  83. package/pp-core/bin/verify-reapply-patches.cjs +0 -0
  84. package/pp-core/org-profile.json +26 -0
  85. package/pp-core/references/autonomous-best-effort.md +8 -7
  86. package/pp-core/references/loop-hook-dispatch.md +0 -25
  87. package/pp-core/references/planner-gap-closure.md +0 -1
  88. package/pp-core/references/planner-tdd.md +0 -1
  89. package/pp-core/references/planner-vault-standards.md +311 -0
  90. package/pp-core/references/planning-config.md +0 -8
  91. package/pp-core/references/tdd.md +0 -1
  92. package/pp-core/templates/README.md +1 -0
  93. package/pp-core/templates/VAULT-REVIEW.md +56 -0
  94. package/pp-core/templates/phase-prompt.md +2 -6
  95. package/pp-core/workflows/_runtime-launcher.snippet.sh +0 -0
  96. package/pp-core/workflows/add-tests.md +55 -4
  97. package/pp-core/workflows/audit-fix.md +63 -2
  98. package/pp-core/workflows/audit-milestone.md +1 -1
  99. package/pp-core/workflows/autonomous.md +85 -11
  100. package/pp-core/workflows/check-todos.md +13 -2
  101. package/pp-core/workflows/code-review-fix.md +59 -3
  102. package/pp-core/workflows/code-review.md +10 -57
  103. package/pp-core/workflows/complete-milestone.md +1 -1
  104. package/pp-core/workflows/debug.md +54 -4
  105. package/pp-core/workflows/discovery-sprint/prefill.md +19 -7
  106. package/pp-core/workflows/discovery-sprint/prototype.md +46 -49
  107. package/pp-core/workflows/discovery-sprint/session-13-gates.md +2 -0
  108. package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +1 -3
  109. package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +1 -3
  110. package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +1 -3
  111. package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +20 -24
  112. package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +1 -3
  113. package/pp-core/workflows/discovery-sprint/sessions/06-security.md +1 -3
  114. package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +1 -3
  115. package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +1 -3
  116. package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +1 -3
  117. package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +1 -6
  118. package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +1 -3
  119. package/pp-core/workflows/discovery-sprint/sessions/12-delivery-model.md +1 -3
  120. package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +1 -3
  121. package/pp-core/workflows/discovery-sprint/templates/context-template.md +1 -1
  122. package/pp-core/workflows/discovery-sprint/vault-context.md +207 -0
  123. package/pp-core/workflows/discovery-sprint.md +7 -3
  124. package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +4 -4
  125. package/pp-core/workflows/discovery-to-build/templates/pp-handoff.md +43 -1
  126. package/pp-core/workflows/discovery-to-build.md +10 -2
  127. package/pp-core/workflows/discuss-phase.md +3 -10
  128. package/pp-core/workflows/execute-phase/steps/check-query-gate.md +327 -0
  129. package/pp-core/workflows/execute-phase/steps/client-context-gate.md +3 -2
  130. package/pp-core/workflows/execute-phase/steps/cross-ai-delegation.md +1 -1
  131. package/pp-core/workflows/execute-phase/steps/execute-pre-dispatch.md +78 -0
  132. package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
  133. package/pp-core/workflows/execute-phase/steps/post-merge-gate.md +6 -8
  134. package/pp-core/workflows/execute-phase/steps/vault-fetch.md +115 -14
  135. package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +219 -20
  136. package/pp-core/workflows/execute-phase/steps/verify-post-gate.md +147 -0
  137. package/pp-core/workflows/execute-phase.md +152 -128
  138. package/pp-core/workflows/execute-plan.md +54 -6
  139. package/pp-core/workflows/fast.md +53 -4
  140. package/pp-core/workflows/help/modes/full.md +3 -3
  141. package/pp-core/workflows/init/steps/client-context-capture.md +101 -0
  142. package/pp-core/workflows/init/steps/gitlab-provisioning.md +130 -0
  143. package/pp-core/workflows/init/steps/project-md-deferral-narration.md +66 -0
  144. package/pp-core/workflows/init/steps/reachability-outcome.md +70 -0
  145. package/pp-core/workflows/init.md +232 -272
  146. package/pp-core/workflows/new-project.md +31 -23
  147. package/pp-core/workflows/plan-phase.md +98 -45
  148. package/pp-core/workflows/quick.md +117 -3
  149. package/pp-core/workflows/secure-phase.md +1 -1
  150. package/pp-core/workflows/ship.md +57 -28
  151. package/pp-core/workflows/undo.md +1 -1
  152. package/pp-core/workflows/update.md +3 -3
  153. package/pp-core/workflows/validate-phase.md +58 -3
  154. package/pp-core/workflows/vault-review.md +161 -23
  155. package/pp-core/workflows/vault-write-back.md +73 -110
  156. package/pp-core/workflows/verify-work.md +12 -14
  157. package/scripts/changeset/cli.cjs +6 -5
  158. package/scripts/changeset/lint.cjs +0 -0
  159. package/scripts/changeset/new.cjs +33 -50
  160. package/scripts/dev-env.cjs +25 -85
  161. package/scripts/gen-capability-registry.cjs +120 -13
  162. package/scripts/lib/allowlist-ratchet.cjs +1 -103
  163. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -2
  164. package/scripts/lint-docs-required.cjs +0 -0
  165. package/scripts/lint-pr-check-project-dir.cjs +1 -3
  166. package/scripts/lint-test-file-count.allowlist.json +3 -19
  167. package/scripts/lint-test-file-count.cjs +5 -6
  168. package/scripts/prompt-injection-scan.sh +19 -17
  169. package/scripts/release-channel.cjs +0 -0
  170. package/scripts/sync-manifest-versions.cjs +5 -4
  171. package/scripts/sync-rulesets.sh +1 -1
  172. package/scripts/update-size-baseline.cjs +30 -274
  173. package/scripts/verify-opengsd-sweep.cjs +3 -5
  174. package/scripts/workflow-size.cjs +9 -61
  175. package/pp-core/bin/lib/dispatch-plan.cjs +0 -483
  176. package/pp-core/bin/lib/install-run.cjs +0 -536
  177. package/pp-core/bin/lib/loop-gates.cjs +0 -213
  178. package/pp-core/bin/lib/phase-manifest.cjs +0 -527
  179. package/pp-core/bin/lib/phase-tier.cjs +0 -480
  180. package/pp-core/bin/lib/plan-graph.cjs +0 -368
  181. package/pp-core/bin/lib/practices-review-check.cjs +0 -938
  182. package/pp-core/bin/lib/vault-audit.cjs +0 -2070
  183. package/pp-core/bin/lib/vault-practices.cjs +0 -1990
  184. package/pp-core/bin/lib/vault-review.cjs +0 -2359
  185. package/pp-core/bin/lib/vault-write-back.cjs +0 -877
  186. package/pp-core/references/executor-vault-trace.md +0 -47
  187. package/pp-core/references/planner-plan-graph.md +0 -66
  188. package/pp-core/references/planner-vault-practices.md +0 -112
  189. package/pp-core/templates/practices/README.md +0 -251
  190. package/pp-core/templates/practices/error-handling.md +0 -18
  191. package/pp-core/templates/practices/minimal-comments.md +0 -14
  192. package/pp-core/templates/practices/naming-convention.md +0 -18
  193. package/pp-core/templates/practices/practice-template.md +0 -23
  194. package/pp-core/workflows/discovery-sprint/vault-fetch.md +0 -37
  195. package/pp-core/workflows/execute-phase/steps/checkpoint-handling.md +0 -45
  196. package/pp-core/workflows/execute-phase/steps/install-run.md +0 -29
  197. package/pp-core/workflows/execute-phase/steps/phase-close-rebaseline.md +0 -23
  198. package/pp-core/workflows/execute-phase/steps/serial-group-dispatch.md +0 -73
  199. package/pp-core/workflows/execute-phase/steps/vault-door-gate.md +0 -19
  200. package/pp-core/workflows/plan-phase/steps/phase-tier.md +0 -43
  201. package/scripts/lib/size-budget.cjs +0 -311
  202. package/scripts/lint-neutrality-names.cjs +0 -694
  203. package/scripts/lint-org-coordinates.allowlist.json +0 -35
  204. package/scripts/lint-org-coordinates.cjs +0 -426
@@ -29,14 +29,12 @@ Orchestrator coordinates, not executes. Each subagent loads the full execute-pla
29
29
  Claude Code agent per #853, or a non-Claude runtime), use sequential inline execution as
30
30
  the fallback for executor parallelization only. If `Agent` IS available (top-level Claude
31
31
  Code), you MUST spawn pp-executor agents — inline execution is not authorized. Check for
32
- actual tool availability, not runtime name.
32
+ actual tool availability, not runtime name. Every inline path follows `EXECUTOR_HOOK_FRAGMENTS` as in `check_interactive_mode`.
33
33
 
34
34
  **Fallback rule:** If a spawned agent completes its work (commits visible, SUMMARY.md exists) but
35
35
  the orchestrator never receives the completion signal, treat it as successful based on spot-checks
36
36
  and continue to the next wave/plan. Never block indefinitely waiting for a signal — always verify
37
37
  via filesystem and git state.
38
-
39
- **Executor contributions (execute:pre `into: executor`):** every spawn injects its dispatch-plan `contributions[].fragment` verbatim after `${AGENT_SKILLS}`. Every inline path (interactive, Copilot, no `Agent`, a stalled executor switched to inline) follows `pp_run loop render-hooks execute:pre --into executor --phase "${PHASE_NUMBER}" ${TIER_FLAG}` the same way.
40
38
  </runtime_compatibility>
41
39
 
42
40
  <required_reading>
@@ -71,8 +69,7 @@ Parse `$ARGUMENTS` before loading any context:
71
69
 
72
70
  - First positional token → `PHASE_ARG`
73
71
  - Optional `--wave N` → `WAVE_FILTER`
74
- - Optional `--gaps-only` → `GAPS_ONLY=true` (only `gap_closure: true` plans)
75
- - Optional `--tier light|standard|heavy` → `TIER_FLAG="--tier=<value>"` (one word, so zsh passes it as one argument; the phase's ceremony tier for this run; passed to init, dispatch plan and render-hooks)
72
+ - Optional `--gaps-only` keeps its current meaning
76
73
  - Optional `--cross-ai` → `CROSS_AI_FORCE=true` (force all plans through cross-AI execution)
77
74
  - Optional `--no-cross-ai` → `CROSS_AI_DISABLED=true` (disable cross-AI for this run, overrides config and frontmatter)
78
75
  - 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)
@@ -85,7 +82,7 @@ Load all context in one call:
85
82
 
86
83
  ```bash
87
84
  _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
88
- INIT=$(pp_run query init.execute-phase "${PHASE_ARG}" ${TIER_FLAG})
85
+ INIT=$(pp_run query init.execute-phase "${PHASE_ARG}")
89
86
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
90
87
  AGENT_SKILLS=$(pp_run query agent-skills pp-executor)
91
88
  ```
@@ -170,7 +167,7 @@ or absence of the `Agent()` subagent API. If running under Copilot, force sequen
170
167
  execution regardless of the `parallelization` setting — Copilot's subagent completion
171
168
  signals are unreliable (see `<runtime_compatibility>`). Set `COPILOT_SEQUENTIAL=true`
172
169
  internally and skip the `execute_waves` step in favor of `check_interactive_mode`'s
173
- inline path for each plan.
170
+ inline path for each plan. That inline path carries `EXECUTOR_HOOK_FRAGMENTS` as in `check_interactive_mode`.
174
171
 
175
172
  **REQUIRED — Sync chain flag with intent.** If user invoked manually (no `--auto`), clear the ephemeral chain flag from any previous interrupted `--auto` chain. This prevents stale `_auto_chain_active: true` from causing unwanted auto-advance. This does NOT touch `workflow.auto_advance` (the user's persistent settings preference). You MUST execute this bash block before any config reads:
176
173
  ```bash
@@ -185,10 +182,21 @@ Resolve `MVP_MODE` once via the centralized `phase.mvp-mode` query verb (precede
185
182
  MVP_FLAG_ARG=""
186
183
  if [[ "$ARGUMENTS" =~ (^|[[:space:]])--mvp([[:space:]]|$) ]]; then MVP_FLAG_ARG="--cli-flag"; fi
187
184
  MVP_MODE=$(pp_run query phase.mvp-mode "${PHASE_NUMBER}" $MVP_FLAG_ARG --pick active)
188
- EXECUTE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:post --raw --phase "${PHASE_NUMBER}" ${TIER_FLAG}) || exit 1
189
- TDD_MODE=$(pp_run loop render-hooks execute:post --active-cap tdd) || exit 1
185
+ EXECUTE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:post --raw)
186
+ TDD_MODE=$(pp_run loop render-hooks execute:post --active-cap tdd)
187
+ EXECUTE_PRE_HOOKS_JSON=$(pp_run loop render-hooks execute:pre --raw)
188
+ EXECUTOR_HOOK_FRAGMENTS=$(pp_run loop render-hooks execute:pre --into executor)
189
+ printf '%s' "$EXECUTE_PRE_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('EXECUTE_PRE_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
190
190
  ```
191
191
 
192
+ <step name="execute_pre_dispatch">
193
+ **`execute:pre` capability dispatch — fetch, then decide (GATE-03).**
194
+
195
+ Runs before `safe_resume_gate` — the first step that can spawn an executor — so the gate decides
196
+ before any code is written. Read and execute
197
+ `pp-core/workflows/execute-phase/steps/execute-pre-dispatch.md`.
198
+ </step>
199
+
192
200
  <step name="safe_resume_gate">
193
201
  Before trusting `STATE.md` or dispatching any executor, derive `CURRENT_PLAN_ID`
194
202
  from the active incomplete plan in `INIT`, then search recent history:
@@ -277,6 +285,9 @@ checkpoints between tasks. The user can review, modify, or redirect work at any
277
285
 
278
286
  c. **If "Execute":** Read and follow `~/.claude/pp-core/workflows/execute-plan.md` **inline**
279
287
  (do NOT spawn a subagent). Execute tasks one at a time.
288
+ The inline executor follows `EXECUTOR_HOOK_FRAGMENTS` (computed in the hooks fence above) as
289
+ its contract exactly as a spawned executor would: it is the vault's execute:pre executor
290
+ fragment.
280
291
 
281
292
  d. **After each task:** Pause briefly. If the user intervenes (types anything), stop and address
282
293
  their feedback before continuing. Otherwise proceed to next task.
@@ -348,12 +359,6 @@ This updates Status, Last Activity, Current focus, Current Position, and plan co
348
359
  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).
349
360
  </step>
350
361
 
351
- <step name="execute_pre_vault">
352
- Before any executor: `EXECUTE_PRE_HOOKS_JSON=$(pp_run loop render-hooks execute:pre --raw) || exit 1`. 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.
353
-
354
- Then anchor the phase for `/pp-undo --phase`: `pp_run phase manifest start "${PHASE_NUMBER}" --raw` — print its line and continue whatever it says (write-once; a refusal leaves undo on its git-log fallback).
355
- </step>
356
-
357
362
  <step name="discover_and_group_plans">
358
363
  Load plan inventory with wave grouping in one call:
359
364
 
@@ -361,7 +366,7 @@ Load plan inventory with wave grouping in one call:
361
366
  PLAN_INDEX=$(pp_run query phase-plan-index "${PHASE_NUMBER}")
362
367
  ```
363
368
 
364
- 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).
369
+ 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`.
365
370
 
366
371
  **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`.
367
372
 
@@ -379,7 +384,7 @@ Report:
379
384
 
380
385
  | Wave | Plans | What it builds |
381
386
  |------|-------|----------------|
382
- | 1 | 01-01, 01-02 | 01-01 {plan_title}; 01-02 {plan_title} |
387
+ | 1 | 01-01, 01-02 | {from plan objectives, 3-8 words} |
383
388
  | 2 | 01-03 | ... |
384
389
  ```
385
390
  </step>
@@ -391,7 +396,7 @@ Read and execute `pp-core/workflows/execute-phase/steps/cross-ai-delegation.md`.
391
396
  </step>
392
397
 
393
398
  <step name="execute_waves">
394
- 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.
399
+ Execute each selected wave in sequence. Within a wave: parallel if `PARALLELIZATION=true`, sequential if `false`.
395
400
 
396
401
  **Orchestrator cwd-drift guard (FIRST ACTION at execute_waves entry — #48):**
397
402
 
@@ -422,14 +427,6 @@ export ORCHESTRATOR_WT
422
427
  cd "$ORCHESTRATOR_WT" || { echo "FATAL: cannot cd to orchestrator worktree '$ORCHESTRATOR_WT' (#48)." >&2; exit 1; }
423
428
  ```
424
429
 
425
- **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.
426
-
427
- ```bash
428
- 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})
429
- ```
430
-
431
- `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`; `contributions`), `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.
432
-
433
430
  **Stream-idle-timeout prevention — checkpoint heartbeats (#2410):**
434
431
 
435
432
  Multi-plan phases can accumulate enough subagent context that the Claude API
@@ -452,14 +449,39 @@ increases monotonically across waves. `{status}` is `complete` (success),
452
449
 
453
450
  **For each wave:**
454
451
 
455
- 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.
452
+ 1. **Intra-wave files_modified overlap check (BEFORE spawning):**
453
+
454
+ Before spawning any agents for this wave, inspect the `files_modified` list of all plans
455
+ in the wave. Check every pair of plans in the wave — if any two plans share even one file
456
+ in their `files_modified` lists, those plans have an implicit dependency and MUST NOT run
457
+ in parallel.
456
458
 
457
- **If `defects` is non-empty:** warn the user with each defect's `message`:
459
+ **Detection algorithm (pseudocode):**
460
+ ```
461
+ seen_files = {}
462
+ overlapping_plans = []
463
+ for each plan in wave_plans:
464
+ for each file in plan.files_modified:
465
+ if file in seen_files:
466
+ overlapping_plans.add(plan, seen_files[file]) # both plans overlap on this file
467
+ else:
468
+ seen_files[file] = plan
469
+ ```
470
+
471
+ **If overlap is detected:**
472
+ - Warn the user:
458
473
  ```
459
474
  ⚠ Intra-wave files_modified overlap detected in Wave {N}:
460
- {defect.message}
475
+ Plan {A} and Plan {B} both modify {file}
476
+ Running these plans sequentially to avoid parallel worktree conflicts.
461
477
  ```
462
- 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.
478
+ - Override `PARALLELIZATION` to `false` for this wave only — run all plans in the wave
479
+ sequentially regardless of the global parallelization setting.
480
+ - This is a safety net for plans that were incorrectly assigned to the same wave.
481
+ The planner should have caught this; flag it as a planning defect so the user can
482
+ replan the phase if desired.
483
+
484
+ **If no overlap:** proceed normally (parallel if `PARALLELIZATION=true`).
463
485
 
464
486
  2. **Describe what's being built (BEFORE spawning):**
465
487
 
@@ -485,19 +507,21 @@ increases monotonically across waves. `{status}` is `complete` (success),
485
507
  ---
486
508
  ## Wave {N}
487
509
 
488
- **{Plan ID}: {plan_title}**
510
+ **{Plan ID}: {Plan Name}**
489
511
  {2-3 sentences: what this builds, technical approach, why it matters}
490
512
 
491
- 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)
513
+ Spawning {count} agent(s)... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
492
514
  ---
493
515
  ```
494
516
 
495
517
  - Bad: "Executing terrain generation plan"
496
518
  - Good: "Procedural terrain generator using Perlin noise — creates height maps, biome zones, and collision meshes. Required before vehicle physics can interact with ground."
497
519
 
498
- 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`.
520
+ 2.5. **Per-plan worktree decision (run for each plan in this wave BEFORE its dispatch):**
521
+
522
+ 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`.
499
523
 
500
- 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`.
524
+ 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`.
501
525
 
502
526
  3. **Spawn executor agents:**
503
527
 
@@ -506,8 +530,6 @@ increases monotonically across waves. `{status}` is `complete` (success),
506
530
 
507
531
  `[checkpoint] phase {PHASE_NUMBER} wave {N}/{M} plan {plan_id} starting ({P}/{Q} plans done)`
508
532
 
509
- **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.
510
-
511
533
  Pass paths only — executors read files themselves with their fresh context window.
512
534
  For 200k models, this keeps orchestrator context lean (~10-15%).
513
535
  For 1M+ models (Opus 4.6, Sonnet 4.6), richer context can be passed directly.
@@ -544,7 +566,7 @@ increases monotonically across waves. `{status}` is `complete` (success),
544
566
  ```text
545
567
  Agent(
546
568
  subagent_type="pp-executor",
547
- description="Execute plan {plan_number} of phase {phase_number}: {plan_title}",
569
+ description="Execute plan {plan_number} of phase {phase_number}",
548
570
  # Only include model= when executor_model is an explicit model name.
549
571
  # When executor_model is "inherit", omit this parameter entirely so
550
572
  # Claude Code inherits the orchestrator model automatically.
@@ -552,13 +574,11 @@ increases monotonically across waves. `{status}` is `complete` (success),
552
574
  isolation="worktree",
553
575
  prompt="
554
576
  <objective>
555
- Execute plan {plan_number} ({plan_title}) of phase {phase_number}-{phase_name}.
577
+ Execute plan {plan_number} of phase {phase_number}-{phase_name}.
556
578
  Commit each task atomically. Create SUMMARY.md.
557
579
  Do NOT update STATE.md or ROADMAP.md — the orchestrator owns those writes after all worktree agents in the wave complete.
558
580
  </objective>
559
581
 
560
- <dispatch tracking="orchestrator" suite="orchestrator" build="{spawn.build}" />
561
-
562
582
  <worktree_branch_check>
563
583
  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.
564
584
  Per-commit HEAD/cwd-drift/path-guard: `agents/pp-executor.md` steps 0/0a/0b + `references/worktree-path-safety.md` (in <execution_context>).
@@ -611,7 +631,7 @@ increases monotonically across waves. `{status}` is `complete` (success),
611
631
  </files_to_read>
612
632
 
613
633
  ${AGENT_SKILLS}
614
- {spawn.contributions[].fragment — each verbatim, blank-line separated; nothing when empty}
634
+ ${EXECUTOR_HOOK_FRAGMENTS}
615
635
 
616
636
  <mcp_tools>
617
637
  If CLAUDE.md or project instructions reference MCP tools (e.g. jCodeMunch, context7,
@@ -648,14 +668,15 @@ increases monotonically across waves. `{status}` is `complete` (success),
648
668
  </sequential_execution>
649
669
  ```
650
670
 
651
- Everything else is the worktree-mode prompt, `<dispatch>` tag included — the orchestrator owns tracking for every spawn:
671
+ 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:
652
672
 
653
673
  ```
654
674
  <success_criteria>
655
675
  - [ ] All tasks executed
656
676
  - [ ] Each task committed individually
657
677
  - [ ] SUMMARY.md created in plan directory
658
- - [ ] No tracking-file writes (the orchestrator advances them once per wave)
678
+ - [ ] STATE.md updated with position and decisions
679
+ - [ ] ROADMAP.md updated with plan progress (via `roadmap update-plan-progress`)
659
680
  </success_criteria>
660
681
  ```
661
682
 
@@ -698,7 +719,7 @@ increases monotonically across waves. `{status}` is `complete` (success),
698
719
  for activity. If no completion signal, no SUMMARY.md, and no expected-branch
699
720
  commits appear for `${EXECUTOR_STALL_THRESHOLD_MINUTES}` minutes, pause and
700
721
  ask for one recovery path: `continue waiting`, `kill and retry`, or
701
- `kill and switch to inline execution` (U-E7).
722
+ `kill and switch to inline execution` (U-E7). The inline switch follows `EXECUTOR_HOOK_FRAGMENTS` too.
702
723
 
703
724
  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.
704
725
 
@@ -796,7 +817,7 @@ increases monotonically across waves. `{status}` is `complete` (success),
796
817
 
797
818
  **When to skip step 5.5:**
798
819
 
799
- **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.
820
+ **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.
800
821
 
801
822
  **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.
802
823
 
@@ -808,12 +829,10 @@ increases monotonically across waves. `{status}` is `complete` (success),
808
829
 
809
830
  5.6. **Post-merge build & test gate:**
810
831
 
811
- Once per wave, after the merge step (whatever ran: worktrees, a serial group, main-checkout
812
- plans), run a build and then the project's full test suite — exactly once per wave
813
- (`suite_runs: 1`), by the orchestrator, never per plan. Skip the build (Step A) when the
814
- wave's `build` is false (no plan in it touches source). This catches cross-plan integration
815
- issues that per-plan checks cannot detect (e.g., conflicting type definitions, removed
816
- exports, import changes, link errors).
832
+ After merging all worktrees in a wave (parallel mode), or after the last plan completes
833
+ (serial mode), run a build and then the project's test suite to catch cross-plan
834
+ integration issues that individual worktree self-checks cannot detect (e.g., conflicting
835
+ type definitions, removed exports, import changes, link errors).
817
836
 
818
837
  This addresses the Generator self-evaluation blind spot identified in Anthropic's
819
838
  harness engineering research: agents reliably report Self-Check: PASSED even when
@@ -821,79 +840,62 @@ increases monotonically across waves. `{status}` is `complete` (success),
821
840
 
822
841
  Read and execute `pp-core/workflows/execute-phase/steps/post-merge-gate.md`.
823
842
 
824
- 5.7. **Post-wave tracking (every wave, once, by the orchestrator; skip if tests failed):**
843
+ 5.7. **Post-wave shared artifact update (when at least one plan used worktrees, skip if tests failed):**
825
844
 
826
- 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:
827
- refreshes the plan rows and the Built state with `roadmap update-plan-progress`;
828
- advances STATE, records the wave's `tracking.requirements` (`requirements.mark-complete`) and the `key-decisions` of its SUMMARY.md files (`state.add-decision`);
829
- makes the wave's ONE tracking commit (`tracking_commits: 1`).
845
+ 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).
830
846
 
831
847
  **Only update tracking when tests passed (TEST_EXIT=0).**
832
848
  If tests failed or timed out, skip the tracking update — plans should
833
849
  not be marked as complete when integration tests are failing or inconclusive.
834
850
 
835
851
  ```bash
836
- # Timeout (124) is inconclusive — do NOT mark plans complete
852
+ # Guard: only update tracking if post-merge tests passed
853
+ # Timeout (124) is treated as inconclusive — do NOT mark plans complete
837
854
  if [ "${TEST_EXIT}" -eq 0 ]; then
838
- # Plan rows and the Built state (D-08-12); phase completion is phase.complete's, in update_roadmap.
855
+ # Refresh plan rows and the Built state from disk (D-08-12). Phase completion is NOT
856
+ # written here — phase.complete does that in update_roadmap, after the execute:post gate.
839
857
  pp_run query roadmap.update-plan-progress "${PHASE_NUMBER}"
840
- pp_run query state.update-progress
841
- # WAVE_REQ_IDS: this wave's tracking.requirements from DISPATCH_PLAN, space-separated
842
- [ -n "${WAVE_REQ_IDS:-}" ] && pp_run query requirements.mark-complete ${WAVE_REQ_IDS}
843
- pp_run query state.record-session --stopped-at "Phase ${PHASE_NUMBER} wave ${N} complete" --resume-file "None"
844
- if ! git diff --quiet .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md 2>/dev/null; then
845
- pp_run query commit "docs(phase-${PHASE_NUMBER}): update tracking after wave ${N}" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md
858
+
859
+ # Only commit tracking files if they actually changed
860
+ if ! git diff --quiet .planning/ROADMAP.md .planning/STATE.md 2>/dev/null; then
861
+ pp_run query commit "docs(phase-${PHASE_NUMBER}): update tracking after wave ${N}" --files .planning/ROADMAP.md .planning/STATE.md
846
862
  fi
847
863
  elif [ "${TEST_EXIT}" -eq 124 ]; then
848
864
  echo "⚠ Skipping tracking update — test suite timed out. Plans remain in-progress. Run tests manually to confirm."
849
865
  else
850
866
  echo "⚠ Skipping tracking update — post-merge tests failed (exit ${TEST_EXIT}). Plans remain in-progress until tests pass."
851
867
  fi
852
- pp_run phase manifest record "${PHASE_NUMBER}" --raw # .phase-manifest.json for /pp-undo --phase; never stops the run
853
868
  ```
854
869
 
870
+ **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.
871
+
855
872
  5.75. **Execute:wave:post capability dispatch:**
856
873
 
857
874
  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.
858
875
 
859
876
  ```bash
860
- WAVE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:wave:post --raw) || exit 1
877
+ WAVE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:wave:post --raw)
878
+ printf '%s' "$WAVE_POST_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('WAVE_POST_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
861
879
  ```
862
880
 
863
- Read the `activeHooks` array from `WAVE_POST_HOOKS_JSON` in-context (do NOT pipe through a shell parser).
881
+ Read the `activeHooks` array from the printed `WAVE_POST_HOOKS_JSON=` line, in-context (do NOT pipe through a shell parser).
864
882
 
865
883
  **If `activeHooks` is empty or absent:** Skip silently to step 5.8.
866
884
 
867
- **For each active entry where `kind == "gate"`** (process in array order), run the gate check:
868
-
869
- ```bash
870
- GATE_RESULT=$(pp_run check ${hook.check.query} "${PHASE_NUMBER}" --raw)
871
- CHECK_EXIT=$?
872
- ```
873
-
874
- **Step 1 — did the CHECK COMMAND itself succeed?**
875
-
876
- If the check command failed (non-zero `CHECK_EXIT`, empty output, or unparseable JSON):
877
- - `onError == "halt"` → treat as a fatal error: stop wave completion, do NOT proceed to step 5.8, and surface: `⚠ Gate check command failed ({hook.capId}): command error. Resolve before continuing.`
878
- - `onError == "skip"` → log a warning and continue to the next hook. Do NOT read `GATE_RESULT.block`.
879
-
880
- **Step 2 — read `GATE_RESULT.block` (boolean).** This step is only reached when the command succeeded.
881
-
882
- - **Blocking gate (`hook.blocking == true`) AND `GATE_RESULT.block == true`:** HALT — stop wave completion, do NOT proceed to step 5.8, and present:
883
-
884
- ```
885
- ⚠ Wave {N} blocked by capability gate ({hook.capId}): {GATE_RESULT.message}
886
- Resolve before continuing to next wave.
887
- ```
888
-
889
- This halt is **not** bypassed by `onError` — `onError` only covers command errors (step 1 above), not the gate's block decision.
890
-
891
- - **Non-blocking gate (`hook.blocking == false`):** never halts. If `GATE_RESULT.block` is `true` (or non-empty `message`), print `⚠ {hook.capId} advisory (wave {N}): {GATE_RESULT.message}`, then:
892
- - If `GATE_RESULT.spawn_mapper == true` OR `GATE_RESULT.directive == "auto-remap"`: spawn `pp-codebase-mapper` per `execute-phase/steps/codebase-drift-gate.md`; pass `--paths {GATE_RESULT.affected_paths}`. Continue regardless (wave NOT failed by remap failure).
893
- - Otherwise: continue after advisory.
894
- - If block `false` and no `message`: continue silently.
895
-
896
- - **Blocking gate (`hook.blocking == true`) AND `GATE_RESULT.block == false`:** continue silently.
885
+ **Otherwise**, set `GATE_POINT=execute:wave:post`, `GATE_HOOKS_JSON=$WAVE_POST_HOOKS_JSON`,
886
+ `GATE_POSITIONAL_ARG="${PHASE_NUMBER}"` — preserving the positional phase-number argument this
887
+ call site has always passed — and `GATE_WS` to the active workstream name (empty in flat mode),
888
+ without which a phase-number positional cannot resolve on a partitioned project, then Read and follow
889
+ `pp-core/workflows/execute-phase/steps/check-query-gate.md`. That file is the single generic
890
+ `check.query` gate enforcer (GATE-02, D-VH-7): it owns the two-step contract (did the command
891
+ succeed? → then read the boolean `block`) and the halt. Do not restate its loop here.
892
+
893
+ **After the enforcer returns without halting**, perform this call site's own advisory follow-up
894
+ for each non-blocking entry it reported: if the verdict carried `spawn_mapper == true` OR
895
+ `directive == "auto-remap"`, spawn `pp-codebase-mapper` per
896
+ `execute-phase/steps/codebase-drift-gate.md`, passing `--paths {affected_paths}`. Continue
897
+ regardless — a remap failure never fails the wave. The enforcer owns the halt decision; this
898
+ directive handling is the host's, not the enforcer's.
897
899
 
898
900
  **When all active gates are processed without a blocking halt:** continue to step 5.8.
899
901
 
@@ -949,7 +951,7 @@ increases monotonically across waves. `{status}` is `complete` (success),
949
951
  ---
950
952
  ## Wave {N} Complete
951
953
 
952
- **{Plan ID}: {plan_title}**
954
+ **{Plan ID}: {Plan Name}**
953
955
  {What was built — from SUMMARY.md}
954
956
  {Notable deviations, if any}
955
957
 
@@ -995,7 +997,45 @@ increases monotonically across waves. `{status}` is `complete` (success),
995
997
  9. **Proceed to next wave.**
996
998
  </step>
997
999
  <step name="checkpoint_handling">
998
- 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).
1000
+ Plans with `autonomous: false` require user interaction.
1001
+ **Auto-mode checkpoint handling:**
1002
+ Read auto-advance config (chain flag OR user preference — same boolean as `check.auto-mode`):
1003
+ ```bash
1004
+ AUTO_MODE=$(pp_run query check auto-mode --pick active 2>/dev/null || echo "false")
1005
+ ```
1006
+
1007
+ When executor returns a checkpoint AND (`UNATTENDED` or `AUTO_MODE`) is true (U-E1):
1008
+ - **human-action**, or package legitimacy — ANY of `**Gate:** blocking-human` in the return (the executor copies the task's `gate` attribute there), `gate="blocking-human"`, or `what-built` begins `Package`; the last two are the fallback for a return that predates the `Gate:` line → hard stop: present to user (below).
1009
+ - **human-verify** (other) → continuation with `{user_response}` = `"DEFERRED — not verified by a human (unattended run); record this checkpoint as not done in the SUMMARY and continue"`; log `⏭ Checkpoint deferred (recorded, not approved)`.
1010
+ - **decision** → continuation with the option marked recommended, else the first; log `⚡ Auto-selected: [option]`.
1011
+
1012
+ **Standard flow (neither flag, human-action, or blocking-human):**
1013
+
1014
+ 1. Spawn agent for checkpoint plan
1015
+ 2. Agent runs until checkpoint task or auth gate → returns structured state
1016
+ 3. Agent return includes: completed tasks table, current task + blocker, checkpoint type/details, what's awaited
1017
+ 4. **Present to user:**
1018
+ ```
1019
+ ## Checkpoint: [Type]
1020
+
1021
+ **Plan:** 03-03 Dashboard Layout
1022
+ **Progress:** 2/3 tasks complete
1023
+
1024
+ [Checkpoint Details from agent return]
1025
+ [Awaiting section from agent return]
1026
+ ```
1027
+ 5. User responds: "approved"/"done" | issue description | decision selection
1028
+ 6. **Spawn continuation agent (NOT resume)** using continuation-prompt.md template:
1029
+ - `{completed_tasks_table}`: From checkpoint return
1030
+ - `{resume_task_number}` + `{resume_task_name}`: Current task
1031
+ - `{user_response}`: What user provided
1032
+ - `{resume_instructions}`: Based on checkpoint type
1033
+ 7. Continuation agent verifies previous commits, continues from resume point
1034
+ 8. Repeat until plan completes or user stops
1035
+
1036
+ **Fresh agent, not resume:** resume breaks with parallel tool calls.
1037
+
1038
+ **Checkpoints in parallel waves:** Agent pauses and returns while other parallel agents may complete. Present checkpoint, spawn continuation, wait for all before next wave.
999
1039
  </step>
1000
1040
 
1001
1041
  <step name="aggregate_results">
@@ -1022,10 +1062,13 @@ After all waves:
1022
1062
 
1023
1063
  **Security gate check:**
1024
1064
  ```bash
1025
- VERIFY_POST_HOOKS_JSON=$(pp_run loop render-hooks verify:post --raw --phase "${PHASE_NUMBER}" ${TIER_FLAG}) || exit 1
1065
+ VERIFY_POST_HOOKS_JSON=$(pp_run loop render-hooks verify:post --raw)
1066
+ printf '%s' "$VERIFY_POST_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('VERIFY_POST_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
1026
1067
  SECURITY_FILE=$(ls "${PHASE_DIR}"/*-SECURITY.md 2>/dev/null | head -1)
1027
1068
  ```
1028
1069
 
1070
+ **Trace gate.** Read `pp-core/workflows/execute-phase/steps/verify-post-gate.md`.
1071
+
1029
1072
  Resolve active step hooks from `VERIFY_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "secure-phase"`.
1030
1073
 
1031
1074
  If no active secure-phase step hook exists: skip.
@@ -1073,20 +1116,15 @@ Selected wave finished successfully. This phase still has incomplete plans, so p
1073
1116
  **If no incomplete plans remain after the selected wave finishes:**
1074
1117
  - continue with the normal phase-level verification and completion flow below
1075
1118
  - this means the selected wave happened to be the last remaining work in the phase
1076
-
1077
- **verify:post gates** — every run that reaches this point (a partial run stopped above, so no planned plan is still waiting):
1078
- ```bash
1079
- VERIFY_POST_GATES_JSON=$(pp_run loop run-gates verify:post --phase "${PHASE_NUMBER}" ${TIER_FLAG}) || exit 1
1080
- ```
1081
- `loop run-gates` runs every active `verify:post` gate and owns the halt: exit 1 (a `⛔` line) stops the phase here — relay it; do not verify or mark the phase complete. `⚠` advisories: relay, continue.
1082
1119
  </step>
1083
1120
 
1084
1121
  <step name="code_review_gate" required="true">
1085
- **This step is REQUIRED to evaluate the capability hook.** When the code-review capability is active, auto-invoke code review on the phase's source changes. The review is advisory — it never blocks execution flow. Also dispatches the execute:post gate hooks: advisory ones (e.g. tdd.review-checkpoint) and the blocking `vault.trace` gate.
1122
+ **This step is REQUIRED to evaluate the capability hook.** When the code-review capability is active, auto-invoke code review on the phase's source changes. Advisory only — never blocks execution flow. Also dispatches advisory execute:post gate hooks (e.g. tdd.review-checkpoint).
1086
1123
 
1087
1124
  **Capability gate:**
1088
1125
  ```bash
1089
- EXECUTE_POST_HOOKS_JSON=${EXECUTE_POST_HOOKS_JSON:-$(pp_run loop render-hooks execute:post --raw --phase "${PHASE_NUMBER}" ${TIER_FLAG})} || exit 1
1126
+ EXECUTE_POST_HOOKS_JSON=${EXECUTE_POST_HOOKS_JSON:-$(pp_run loop render-hooks execute:post --raw)}
1127
+ printf '%s' "$EXECUTE_POST_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('EXECUTE_POST_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
1090
1128
  ```
1091
1129
 
1092
1130
  Resolve active step hooks from `EXECUTE_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "code-review"`.
@@ -1113,21 +1151,11 @@ Code review found issues. Consider running:
1113
1151
 
1114
1152
  **Error handling:** If the Skill invocation fails or throws, catch the error, display "Code review encountered an error (non-blocking): {error}" and proceed to gate dispatch. Review failures must never block execution.
1115
1153
 
1116
- **Execute:post gate hook dispatch.** After code review, run the blocking trace gate in code — exit 1 (a `⛔` line) stops the phase here; relay it and do not proceed:
1117
- ```bash
1118
- TRACE_GATE_JSON=$(pp_run loop run-gates execute:post --phase "${PHASE_NUMBER}" ${TIER_FLAG} --query vault.trace) || exit 1
1119
- ```
1120
- Then dispatch every other active gate hook from `EXECUTE_POST_HOOKS_JSON` where `kind == "gate"` (skip `check.query == "vault.trace"`):
1121
-
1122
- For each such gate hook:
1123
- ```bash
1124
- GATE_RESULT=$(pp_run check ${hook.check.query} "${PHASE_NUMBER}" --raw)
1125
- CHECK_EXIT=$?
1126
- ```
1154
+ **Execute:post gate hook dispatch.** After code review, dispatch all active gate hooks from `EXECUTE_POST_HOOKS_JSON` where `kind == "gate"`. If none are active, skip silently.
1127
1155
 
1128
- **Gate evaluation** uses the same two-step contract as `execute:wave:post` above: **Step 1** — if the check command failed (non-zero `CHECK_EXIT`, empty/unparseable output), `onError == "halt"` stops and surfaces the error, `onError == "skip"` warns and continues to the next hook (do not read `block`). **Step 2** (command succeeded) — a blocking gate (`hook.blocking == true`) halts on `GATE_RESULT.block == true` with its message/table (never bypassed by `onError`); an advisory gate (`hook.blocking == false`) shows its `table`/summary when `block == true` or `message` is non-empty, then continues; a blocking gate with `block == false` continues silently.
1156
+ Set `GATE_POINT=execute:post`, `GATE_HOOKS_JSON=$EXECUTE_POST_HOOKS_JSON`, `GATE_POSITIONAL_ARG="${PHASE_NUMBER}"` and `GATE_WS` to the active workstream name (empty in flat mode) — without it the phase-number positional cannot resolve on a partitioned project, and this is the point where the blocking `vault.trace` gate is declared — then Read and follow `pp-core/workflows/execute-phase/steps/check-query-gate.md` — the same single generic `check.query` gate enforcer used at `execute:pre` and `execute:wave:post` (GATE-02, D-VH-7). It owns the two-step contract (did the command succeed? → then read the boolean `block`) and the halt. Do not restate its loop here.
1129
1157
 
1130
- **TDD review escalation (overrides the advisory default for the `tdd.review-checkpoint` gate only).** The tdd `execute:post` gate is declared `blocking: false`, so by the generic contract above it displays its `message`/table and continues. There is ONE documented exception (see `~/.claude/pp-core/references/execute-mvp-tdd.md`): when `MVP_MODE=true` AND `TDD_MODE=true` AND `GATE_RESULT.block == true` (one or more TDD plans miss a RED or GREEN gate commit), the end-of-phase TDD review escalates from advisory to **blocking under MVP+TDD** — refuse to mark the phase complete and present:
1158
+ **TDD review escalation (overrides the advisory default for the `tdd.review-checkpoint` gate only).** The tdd `execute:post` gate is declared `blocking: false`, so the enforcer displays its `message`/table and continues. There is ONE documented exception (see `~/.claude/pp-core/references/execute-mvp-tdd.md`), applied by this host workflow *after* the enforcer returns: when `MVP_MODE=true` AND `TDD_MODE=true` AND the enforcer reported a `true` block verdict for `tdd.review-checkpoint` (one or more TDD plans miss a RED or GREEN gate commit), the end-of-phase TDD review escalates from advisory to **blocking under MVP+TDD** — refuse to mark the phase complete and present:
1131
1159
 
1132
1160
  ```
1133
1161
  Phase blocked: {N} TDD plan(s) violate the RED→GREEN gate sequence under MVP+TDD.
@@ -1136,7 +1164,7 @@ Resolve and re-run /pp:execute-phase, or override with /pp:execute-phase {phase}
1136
1164
 
1137
1165
  (`--force-mvp-gate` is the documented, not-yet-implemented escape hatch.) Outside MVP+TDD, TDD-review violations remain advisory (table shown, execution continues).
1138
1166
 
1139
- **Proceed rule:** If `MVP_MODE && TDD_MODE && GATE_RESULT.block == true` for `tdd.review-checkpoint`: STOP — do NOT proceed to `close_parent_artifacts`, `regression_gate`, `verify_phase_goal`, or `phase.complete`. Otherwise proceed normally.
1167
+ **Proceed rule:** If `MVP_MODE && TDD_MODE` and the enforcer's reported block verdict for `tdd.review-checkpoint` is `true`: STOP — do NOT proceed to `close_parent_artifacts`, `regression_gate`, `verify_phase_goal`, or `phase.complete`. Otherwise proceed normally.
1140
1168
  </step>
1141
1169
 
1142
1170
  <step name="close_parent_artifacts">
@@ -1259,8 +1287,6 @@ If `TEXT_MODE` is true, present as a plain-text numbered list and ask the user t
1259
1287
  <step name="verify_phase_goal">
1260
1288
  Verify phase achieved its GOAL, not just completed tasks.
1261
1289
 
1262
- **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. When it lists `verify-vault-review` (heavy tier, vault practices on), after the verifier returns, set `FORCE=1` and Read and execute `pp-core/workflows/vault-review.md` for this phase: it reports and never changes the route.
1263
-
1264
1290
  ```bash
1265
1291
  VERIFIER_SKILLS=$(pp_run query agent-skills pp-verifier)
1266
1292
  ```
@@ -1283,8 +1309,7 @@ MANDATORY: load every file listed here with the Read tool before you start the w
1283
1309
  - .planning/REQUIREMENTS.md (Requirement traceability)
1284
1310
  - {phase_dir}/*-CONTEXT.md (User decisions — verify they were honored)
1285
1311
  - {phase_dir}/*-RESEARCH.md (Known pitfalls — check for traps)
1286
- ${INSTALL_RUN_FILE ? `- ${INSTALL_RUN_FILE} (installed-product run — judge user-facing behaviour on it, not on the repo)
1287
- ` : ''}${CONTEXT_WINDOW >= 500000 ? `- Prior VERIFICATION.md files from earlier phases (regression check)
1312
+ ${CONTEXT_WINDOW >= 500000 ? `- Prior VERIFICATION.md files from earlier phases (regression check)
1288
1313
  ` : ''}
1289
1314
  </files_to_read>
1290
1315
 
@@ -1405,7 +1430,7 @@ Gap closure cycle: `/pp:plan-phase {X} --gaps ${GSD_WS}` reads VERIFICATION.md
1405
1430
  <step name="update_roadmap">
1406
1431
  **Mark phase complete and update all tracking files:**
1407
1432
 
1408
- 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).
1433
+ Reached only after the `execute:post` gate dispatch above returned without halting and `verify_phase_goal` reported `passed` — completion follows that outcome, never a plan or SUMMARY count (D-08-13). `phase.complete` writes ROADMAP.md, REQUIREMENTS.md and STATE.md in one transaction with rollback: both move or neither does (D-08-14). Until here the phase reads `Built` (D-08-15).
1409
1434
 
1410
1435
  ```bash
1411
1436
  COMPLETION=$(pp_run query phase.complete "${PHASE_NUMBER}")
@@ -1432,7 +1457,6 @@ These items are tracked and will appear in `/pp:progress` and `/pp:audit-uat`.
1432
1457
 
1433
1458
  ```bash
1434
1459
  pp_run query commit "docs(phase-{X}): complete phase execution" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md {phase_dir}/*-VERIFICATION.md
1435
- pp_run phase manifest record "${PHASE_NUMBER}" --raw # the completion commit joins the /pp-undo --phase list
1436
1460
  ```
1437
1461
  </step>
1438
1462