@pareto4/pp-core 1.11.1 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) hide show
  1. package/.claude-plugin/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-activation.cjs +19 -9
  39. package/pp-core/bin/lib/capability-registry.cjs +65 -7
  40. package/pp-core/bin/lib/check-command-router.cjs +79 -38
  41. package/pp-core/bin/lib/clusters.cjs +2 -3
  42. package/pp-core/bin/lib/command-aliases.cjs +36 -0
  43. package/pp-core/bin/lib/command-arg-projection.cjs +99 -1
  44. package/pp-core/bin/lib/commands.cjs +21 -6
  45. package/pp-core/bin/lib/compose-bindings.cjs +70 -6
  46. package/pp-core/bin/lib/config-loader.cjs +151 -8
  47. package/pp-core/bin/lib/config-schema.cjs +16 -0
  48. package/pp-core/bin/lib/config.cjs +142 -27
  49. package/pp-core/bin/lib/core-utils.cjs +43 -7
  50. package/pp-core/bin/lib/discovery-input-check.cjs +218 -0
  51. package/pp-core/bin/lib/discovery-rebaseline.cjs +1372 -0
  52. package/pp-core/bin/lib/discovery-research-track.cjs +979 -0
  53. package/pp-core/bin/lib/discovery-rollup.cjs +476 -0
  54. package/pp-core/bin/lib/discovery-screens.cjs +1995 -0
  55. package/pp-core/bin/lib/discovery-sweep.cjs +390 -0
  56. package/pp-core/bin/lib/discovery-table.cjs +98 -0
  57. package/pp-core/bin/lib/dispatch-plan.cjs +472 -0
  58. package/pp-core/bin/lib/frontmatter.cjs +17 -2
  59. package/pp-core/bin/lib/init-command-router.cjs +8 -5
  60. package/pp-core/bin/lib/init-contract.cjs +93 -4
  61. package/pp-core/bin/lib/init.cjs +124 -134
  62. package/pp-core/bin/lib/install-profiles.cjs +5 -0
  63. package/pp-core/bin/lib/install-run.cjs +536 -0
  64. package/pp-core/bin/lib/io.cjs +15 -0
  65. package/pp-core/bin/lib/loop-resolver.cjs +40 -2
  66. package/pp-core/bin/lib/milestone.cjs +345 -48
  67. package/pp-core/bin/lib/phase-command-router.cjs +23 -1
  68. package/pp-core/bin/lib/phase-locator.cjs +15 -6
  69. package/pp-core/bin/lib/phase-scope.cjs +91 -0
  70. package/pp-core/bin/lib/phase-tier.cjs +467 -0
  71. package/pp-core/bin/lib/phase.cjs +247 -21
  72. package/pp-core/bin/lib/phases-command-router.cjs +2 -0
  73. package/pp-core/bin/lib/plan-graph.cjs +368 -0
  74. package/pp-core/bin/lib/planning-workspace.cjs +53 -0
  75. package/pp-core/bin/lib/platform-bindings.cjs +32 -2
  76. package/pp-core/bin/lib/profile-output.cjs +11 -3
  77. package/pp-core/bin/lib/prohibition-enforcement.cjs +112 -0
  78. package/pp-core/bin/lib/roadmap-parser.cjs +366 -99
  79. package/pp-core/bin/lib/roadmap.cjs +141 -39
  80. package/pp-core/bin/lib/runtime-hooks-surface.cjs +1 -1
  81. package/pp-core/bin/lib/shell-command-projection.cjs +24 -0
  82. package/pp-core/bin/lib/state-command-router.cjs +82 -13
  83. package/pp-core/bin/lib/state-document.cjs +124 -7
  84. package/pp-core/bin/lib/state.cjs +784 -257
  85. package/pp-core/bin/lib/template.cjs +22 -6
  86. package/pp-core/bin/lib/vault-command-router.cjs +57 -6
  87. package/pp-core/bin/lib/vault-practices.cjs +6 -36
  88. package/pp-core/bin/lib/vault-write-back.cjs +20 -4
  89. package/pp-core/bin/lib/vault.cjs +592 -23
  90. package/pp-core/bin/lib/verify.cjs +53 -31
  91. package/pp-core/bin/lib/workstream.cjs +1 -1
  92. package/pp-core/bin/lib/worktree-safety.cjs +26 -15
  93. package/pp-core/bin/portable-timeout.sh +89 -0
  94. package/pp-core/bin/pp-tools.cjs +149 -9
  95. package/pp-core/bin/shared/config-defaults.manifest.json +7 -0
  96. package/pp-core/bin/shared/config-schema.manifest.json +3 -0
  97. package/pp-core/references/autonomous-best-effort.md +461 -0
  98. package/pp-core/references/autonomous-lifecycle.md +146 -0
  99. package/pp-core/references/autonomous-smart-discuss.md +16 -12
  100. package/pp-core/references/checkpoints.md +1 -1
  101. package/pp-core/references/discovery-id-conventions.md +202 -0
  102. package/pp-core/references/discovery-rebaseline.md +254 -0
  103. package/pp-core/references/discovery-research-track.md +283 -0
  104. package/pp-core/references/discovery-traceability.md +400 -0
  105. package/pp-core/references/loop-hook-dispatch.md +14 -0
  106. package/pp-core/references/mandatory-initial-read.md +1 -1
  107. package/pp-core/references/planner-gap-closure.md +1 -0
  108. package/pp-core/references/planner-human-verify-mode.md +1 -1
  109. package/pp-core/references/planner-load-graph-context.md +1 -1
  110. package/pp-core/references/planner-plan-graph.md +66 -0
  111. package/pp-core/references/planner-tdd.md +1 -0
  112. package/pp-core/references/planning-config.md +8 -0
  113. package/pp-core/references/sketch-tooling.md +4 -0
  114. package/pp-core/references/tdd.md +1 -0
  115. package/pp-core/templates/claude-md.md +1 -1
  116. package/pp-core/templates/phase-prompt.md +6 -2
  117. package/pp-core/templates/prototype-review/review.js +303 -0
  118. package/pp-core/templates/state.md +6 -0
  119. package/pp-core/workflows/_runtime-launcher.snippet.sh +1 -1
  120. package/pp-core/workflows/add-backlog.md +1 -1
  121. package/pp-core/workflows/add-phase.md +1 -1
  122. package/pp-core/workflows/add-tests.md +1 -1
  123. package/pp-core/workflows/add-todo.md +1 -1
  124. package/pp-core/workflows/ai-integration-phase.md +2 -2
  125. package/pp-core/workflows/audit-fix.md +12 -16
  126. package/pp-core/workflows/audit-milestone.md +2 -2
  127. package/pp-core/workflows/audit-uat.md +1 -1
  128. package/pp-core/workflows/autonomous.md +68 -306
  129. package/pp-core/workflows/check-todos.md +1 -1
  130. package/pp-core/workflows/cleanup.md +1 -1
  131. package/pp-core/workflows/code-review-fix.md +2 -2
  132. package/pp-core/workflows/code-review.md +20 -8
  133. package/pp-core/workflows/complete-milestone.md +41 -60
  134. package/pp-core/workflows/debug.md +1 -1
  135. package/pp-core/workflows/diagnose-issues.md +1 -1
  136. package/pp-core/workflows/discovery-sprint/gap-analysis.md +140 -0
  137. package/pp-core/workflows/discovery-sprint/input-package.md +140 -0
  138. package/pp-core/workflows/discovery-sprint/prefill.md +92 -0
  139. package/pp-core/workflows/discovery-sprint/prototype.md +257 -0
  140. package/pp-core/workflows/discovery-sprint/rebaseline.md +276 -0
  141. package/pp-core/workflows/discovery-sprint/session-13-gates.md +24 -0
  142. package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +92 -0
  143. package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +98 -0
  144. package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +215 -0
  145. package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +146 -0
  146. package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +98 -0
  147. package/pp-core/workflows/discovery-sprint/sessions/06-security.md +107 -0
  148. package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +98 -0
  149. package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +85 -0
  150. package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +109 -0
  151. package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +119 -0
  152. package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +92 -0
  153. package/pp-core/workflows/discovery-sprint/sessions/12-delivery-model.md +98 -0
  154. package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +205 -0
  155. package/pp-core/workflows/discovery-sprint/templates/context-template.md +266 -0
  156. package/pp-core/workflows/discovery-sprint.md +79 -1714
  157. package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +5 -5
  158. package/pp-core/workflows/discovery-to-build/steps/screen-inventory-gate.md +70 -0
  159. package/pp-core/workflows/discovery-to-build/templates/discovery-references.md +54 -0
  160. package/pp-core/workflows/discovery-to-build/templates/pp-handoff.md +184 -0
  161. package/pp-core/workflows/discovery-to-build.md +21 -238
  162. package/pp-core/workflows/discuss-phase/modes/advisor.md +1 -1
  163. package/pp-core/workflows/discuss-phase/modes/auto.md +1 -1
  164. package/pp-core/workflows/discuss-phase/modes/chain.md +1 -1
  165. package/pp-core/workflows/discuss-phase-assumptions.md +1 -1
  166. package/pp-core/workflows/discuss-phase.md +11 -4
  167. package/pp-core/workflows/do.md +4 -4
  168. package/pp-core/workflows/docs-update.md +1 -1
  169. package/pp-core/workflows/edit-phase.md +1 -1
  170. package/pp-core/workflows/eval-review.md +1 -1
  171. package/pp-core/workflows/execute-phase/steps/checkpoint-handling.md +45 -0
  172. package/pp-core/workflows/execute-phase/steps/client-context-gate.md +1 -1
  173. package/pp-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
  174. package/pp-core/workflows/execute-phase/steps/cross-ai-delegation.md +90 -0
  175. package/pp-core/workflows/execute-phase/steps/install-run.md +29 -0
  176. package/pp-core/workflows/execute-phase/steps/phase-close-rebaseline.md +23 -0
  177. package/pp-core/workflows/execute-phase/steps/post-merge-gate.md +76 -77
  178. package/pp-core/workflows/execute-phase/steps/serial-group-dispatch.md +72 -0
  179. package/pp-core/workflows/execute-phase/steps/vault-fetch.md +5 -5
  180. package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +19 -112
  181. package/pp-core/workflows/execute-phase.md +104 -218
  182. package/pp-core/workflows/execute-plan.md +6 -2
  183. package/pp-core/workflows/explore.md +1 -1
  184. package/pp-core/workflows/extract-learnings.md +1 -1
  185. package/pp-core/workflows/forensics.md +4 -4
  186. package/pp-core/workflows/graduation.md +1 -1
  187. package/pp-core/workflows/health.md +1 -1
  188. package/pp-core/workflows/help/modes/brief.md +1 -0
  189. package/pp-core/workflows/help/modes/default.md +2 -1
  190. package/pp-core/workflows/help/modes/full.md +12 -5
  191. package/pp-core/workflows/import.md +1 -1
  192. package/pp-core/workflows/ingest-docs.md +1 -1
  193. package/pp-core/workflows/init.md +18 -2
  194. package/pp-core/workflows/insert-phase.md +1 -1
  195. package/pp-core/workflows/list-workspaces.md +1 -1
  196. package/pp-core/workflows/manager.md +3 -3
  197. package/pp-core/workflows/map-codebase.md +2 -2
  198. package/pp-core/workflows/milestone-summary.md +4 -4
  199. package/pp-core/workflows/mvp-phase.md +1 -1
  200. package/pp-core/workflows/new-milestone.md +7 -8
  201. package/pp-core/workflows/new-project.md +6 -1
  202. package/pp-core/workflows/new-workspace.md +1 -1
  203. package/pp-core/workflows/next.md +2 -2
  204. package/pp-core/workflows/note.md +2 -2
  205. package/pp-core/workflows/pause-work.md +1 -1
  206. package/pp-core/workflows/plan-milestone-gaps.md +1 -1
  207. package/pp-core/workflows/plan-phase/steps/chunked-planning.md +111 -0
  208. package/pp-core/workflows/plan-phase/steps/phase-tier.md +34 -0
  209. package/pp-core/workflows/plan-phase.md +43 -167
  210. package/pp-core/workflows/plan-review-convergence.md +2 -2
  211. package/pp-core/workflows/plant-seed.md +1 -1
  212. package/pp-core/workflows/pr-branch.md +1 -1
  213. package/pp-core/workflows/profile-user.md +1 -1
  214. package/pp-core/workflows/progress.md +3 -3
  215. package/pp-core/workflows/quick.md +4 -2
  216. package/pp-core/workflows/remove-phase.md +1 -1
  217. package/pp-core/workflows/remove-workspace.md +1 -1
  218. package/pp-core/workflows/resume-project.md +6 -12
  219. package/pp-core/workflows/review.md +1 -1
  220. package/pp-core/workflows/scan.md +1 -1
  221. package/pp-core/workflows/secure-phase.md +2 -2
  222. package/pp-core/workflows/settings-advanced.md +1 -1
  223. package/pp-core/workflows/settings-integrations.md +1 -1
  224. package/pp-core/workflows/settings.md +1 -1
  225. package/pp-core/workflows/ship.md +26 -9
  226. package/pp-core/workflows/sketch-wrap-up.md +1 -1
  227. package/pp-core/workflows/sketch.md +2 -1
  228. package/pp-core/workflows/spec-phase.md +1 -1
  229. package/pp-core/workflows/spike-wrap-up.md +1 -1
  230. package/pp-core/workflows/spike.md +1 -1
  231. package/pp-core/workflows/stats.md +2 -2
  232. package/pp-core/workflows/thread.md +1 -1
  233. package/pp-core/workflows/transition.md +5 -9
  234. package/pp-core/workflows/ui-phase.md +23 -2
  235. package/pp-core/workflows/ui-review.md +1 -1
  236. package/pp-core/workflows/ultraplan-phase.md +2 -2
  237. package/pp-core/workflows/validate-phase.md +2 -2
  238. package/pp-core/workflows/vault-write-back.md +1 -1
  239. package/pp-core/workflows/verify-phase.md +29 -26
  240. package/pp-core/workflows/verify-work.md +14 -10
  241. package/scripts/base64-scan.sh +7 -41
  242. package/scripts/changeset/cli.cjs +25 -5
  243. package/scripts/dev-env.cjs +462 -0
  244. package/scripts/lib/allowlist-ratchet.cjs +103 -1
  245. package/scripts/lib/size-budget.cjs +311 -0
  246. package/scripts/lint-neutrality-names.cjs +694 -0
  247. package/scripts/lint-org-coordinates.allowlist.json +35 -0
  248. package/scripts/lint-org-coordinates.cjs +426 -0
  249. package/scripts/lint-skill-deps.cjs +48 -9
  250. package/scripts/lint-test-file-count.cjs +17 -2
  251. package/scripts/prompt-injection-scan.sh +41 -20
  252. package/scripts/sync-manifest-versions.cjs +41 -7
  253. package/scripts/sync-runtime-launcher.cjs +106 -1
  254. package/scripts/update-size-baseline.cjs +274 -30
  255. package/scripts/workflow-size.cjs +61 -9
  256. package/commands/pp-build-handoff.md +0 -46
  257. package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +0 -94
@@ -1,52 +1,45 @@
1
1
  # Step: post_merge_gate
2
2
 
3
- Post-merge build & test gate. Runs after all worktrees in a wave are merged
4
- (parallel mode), or after the last plan completes (serial mode). Catches
5
- cross-plan integration failures that individual worktree self-checks cannot
6
- detect.
3
+ Post-merge build & test gate. Runs exactly once per wave, after the wave's merge
4
+ step — the wave's one full-suite run (`suite_runs: 1` in the dispatch plan); no
5
+ executor runs the full suite. Catches cross-plan integration failures that
6
+ per-plan checks cannot detect.
7
7
 
8
- **Step A — Build gate:**
8
+ **Step A — Build gate:** run it only when the dispatch plan's wave `build` is true.
9
+ When it is false (no plan in the wave touches source), print
10
+ `⚠ Post-merge build gate skipped — no plan in this wave touches source` and go to Step B.
9
11
 
10
12
  ```bash
11
- _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
12
- # Resolve build command: project config > Xcode > Makefile > language sniff
13
- BUILD_CMD=$(pp_run query config-get workflow.build_command --default "" 2>/dev/null || true)
13
+ _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
14
+ # Resolve build command: project config first, else the shared sniff ladder
15
+ 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)
16
+ BUILD_CMD=$(pp_run query config-get workflow.build_command --default "" --raw 2>/dev/null || true)
14
17
  if [ -z "$BUILD_CMD" ]; then
15
- XCODEPROJ=$(find . -maxdepth 2 -name "*.xcodeproj" -not -path "*/node_modules/*" 2>/dev/null | head -1)
16
- if [ -n "$XCODEPROJ" ]; then
17
- # Xcode project: get first scheme from xcodebuild -list -json
18
- XCODE_SCHEME=$(xcodebuild -list -json -project "$XCODEPROJ" 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('project',{}).get('schemes',[None])[0] or '')" 2>/dev/null || true)
19
- if [ -n "$XCODE_SCHEME" ]; then
20
- BUILD_CMD="xcodebuild build -scheme '$XCODE_SCHEME' -destination 'platform=iOS Simulator,name=iPhone 16'"
21
- else
22
- BUILD_CMD="xcodebuild build -destination 'platform=iOS Simulator,name=iPhone 16'"
23
- fi
24
- elif [ -f "Makefile" ] && grep -q "^build:" Makefile; then
25
- BUILD_CMD="make build"
26
- elif [ -f "Justfile" ] || [ -f "justfile" ]; then
27
- BUILD_CMD="just build"
28
- elif [ -f "Cargo.toml" ]; then
29
- BUILD_CMD="cargo build"
30
- elif [ -f "go.mod" ]; then
31
- BUILD_CMD="go build ./..."
32
- elif [ -f "pyproject.toml" ] || [ -f "requirements.txt" ]; then
33
- BUILD_CMD="python -m py_compile $(find . -name '*.py' -not -path './.planning/*' -not -path './node_modules/*' | head -20 | tr '\n' ' ')"
34
- elif [ -f "package.json" ] && grep -q '"build"' package.json; then
35
- BUILD_CMD="npm run build"
18
+ if [ -r "$PP_GATE_BIN/detect-build-commands.sh" ]; then
19
+ . "$PP_GATE_BIN/detect-build-commands.sh"; BUILD_CMD=$(pp_detect_build_cmd)
36
20
  else
37
- BUILD_CMD=""
38
- echo "⚠ No build command detected — skipping build gate"
21
+ echo "✗ pp-core sniff ladder not found beside pp-tools — cannot detect a build command"
39
22
  fi
40
23
  fi
41
- # Run build with 5-minute timeout
24
+ # Run build through the shared portable timeout wrapper (5-minute budget)
42
25
  BUILD_EXIT=0
43
- if [ -n "$BUILD_CMD" ]; then
44
- timeout 300 bash -c "$BUILD_CMD" 2>&1
26
+ if [ -z "$BUILD_CMD" ]; then
27
+ echo "⚠ Post-merge build gate NOT RUN — no build command detected (not a pass, not a failure)"
28
+ elif [ ! -r "$PP_GATE_BIN/portable-timeout.sh" ]; then
29
+ echo "✗ Post-merge build gate NEVER RAN — portable-timeout.sh not found beside pp-tools; refusing to run unbounded (D-09-03)"
30
+ BUILD_EXIT=127
31
+ WAVE_FAILURE_COUNT=$((WAVE_FAILURE_COUNT + 1))
32
+ else
33
+ . "$PP_GATE_BIN/portable-timeout.sh"
34
+ run_with_timeout 300 bash -c "$BUILD_CMD" 2>&1
45
35
  BUILD_EXIT=$?
46
36
  if [ "${BUILD_EXIT}" -eq 0 ]; then
47
37
  echo "✓ Post-merge build gate passed"
48
- elif [ "${BUILD_EXIT}" -eq 124 ]; then
49
- echo "⚠ Post-merge build gate timed out after 5 minutes"
38
+ elif is_timeout_exit "${BUILD_EXIT}"; then
39
+ echo "⚠ Post-merge build gate timed out after 300 seconds (exit ${BUILD_EXIT}) — not counted as a failure"
40
+ elif [ "${BUILD_EXIT}" -eq 127 ]; then
41
+ echo "✗ Post-merge build gate NEVER RAN — command not found (exit 127): ${BUILD_CMD}"
42
+ WAVE_FAILURE_COUNT=$((WAVE_FAILURE_COUNT + 1))
50
43
  else
51
44
  echo "✗ Post-merge build gate failed (exit code ${BUILD_EXIT})"
52
45
  WAVE_FAILURE_COUNT=$((WAVE_FAILURE_COUNT + 1))
@@ -54,64 +47,70 @@ if [ -n "$BUILD_CMD" ]; then
54
47
  fi
55
48
  ```
56
49
 
57
- **If `BUILD_EXIT` is 0 (pass):** `✓ Build gate passed` → proceed to Test gate.
50
+ The gate reports five distinct outcomes; do not collapse them.
58
51
 
59
- **If `BUILD_EXIT` is 124 (timeout):** Log warning, treat as non-blocking, continue to Test gate.
52
+ **`NOT RUN`:** no build command was configured and the sniff ladder found no tool. This is neither a pass nor a failure — `WAVE_FAILURE_COUNT` is untouched. Proceed to the Test gate.
60
53
 
61
- **If `BUILD_EXIT` is non-zero (build failure):** Increment `WAVE_FAILURE_COUNT` (same semantics as test failures). Present failure output and offer "Fix now" or "Continue" options (same as step 5.8).
54
+ **`BUILD_EXIT` 0 (pass):** `✓ Build gate passed` → proceed to Test gate.
55
+
56
+ **`BUILD_EXIT` 124 or 142 (timeout — GNU `timeout` reports 124, the perl `alarm` fallback reports 142; `is_timeout_exit` accepts both):** Log warning, treat as non-blocking, do NOT increment `WAVE_FAILURE_COUNT`, continue to Test gate.
57
+
58
+ **`BUILD_EXIT` 127 (`NEVER RAN`):** The command was not found, or the timeout wrapper itself was missing so nothing was launched. A build that never ran is not a passing build: increment `WAVE_FAILURE_COUNT` and report the command text, never "failed".
59
+
60
+ **`BUILD_EXIT` any other non-zero (build failure):** Increment `WAVE_FAILURE_COUNT` (same semantics as test failures). Present failure output and offer "Fix now" or "Continue" options (same as step 5.8).
62
61
 
63
62
  **Step B — Test gate:**
64
63
 
65
64
  ```bash
66
- # Resolve test command: project config > Xcode > Makefile > language sniff
67
- TEST_CMD=$(pp_run query config-get workflow.test_command --default "" 2>/dev/null || true)
65
+ # Resolve test command: project config first, else the shared sniff ladder
66
+ 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)
67
+ TEST_CMD=$(pp_run query config-get workflow.test_command --default "" --raw 2>/dev/null || true)
68
68
  if [ -z "$TEST_CMD" ]; then
69
- XCODEPROJ=$(find . -maxdepth 2 -name "*.xcodeproj" -not -path "*/node_modules/*" 2>/dev/null | head -1)
70
- if [ -n "$XCODEPROJ" ]; then
71
- # Xcode project: reuse scheme detected above (or re-detect)
72
- if [ -z "${XCODE_SCHEME:-}" ]; then
73
- XCODE_SCHEME=$(xcodebuild -list -json -project "$XCODEPROJ" 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('project',{}).get('schemes',[None])[0] or '')" 2>/dev/null || true)
74
- fi
75
- if [ -n "$XCODE_SCHEME" ]; then
76
- TEST_CMD="xcodebuild test -scheme '$XCODE_SCHEME' -destination 'platform=iOS Simulator,name=iPhone 16'"
77
- else
78
- TEST_CMD="xcodebuild test -destination 'platform=iOS Simulator,name=iPhone 16'"
79
- fi
80
- elif [ -f "Makefile" ] && grep -q "^test:" Makefile; then
81
- TEST_CMD="make test"
82
- elif [ -f "Justfile" ] || [ -f "justfile" ]; then
83
- TEST_CMD="just test"
84
- elif [ -f "package.json" ]; then
85
- TEST_CMD="npm test"
86
- elif [ -f "Cargo.toml" ]; then
87
- TEST_CMD="cargo test"
88
- elif [ -f "go.mod" ]; then
89
- TEST_CMD="go test ./..."
90
- elif [ -f "pyproject.toml" ] || [ -f "requirements.txt" ]; then
91
- TEST_CMD="python -m pytest -x -q --tb=short 2>&1 || uv run python -m pytest -x -q --tb=short"
69
+ if [ -r "$PP_GATE_BIN/detect-build-commands.sh" ]; then
70
+ . "$PP_GATE_BIN/detect-build-commands.sh"; TEST_CMD=$(pp_detect_test_cmd)
92
71
  else
93
- TEST_CMD="true"
94
- echo "⚠ No test runner detected — skipping post-merge test gate"
72
+ echo "✗ pp-core sniff ladder not found beside pp-tools — cannot detect a test command"
95
73
  fi
96
74
  fi
97
- # Run test suite with 5-minute timeout
75
+ # Run test suite through the shared portable timeout wrapper (5-minute budget)
98
76
  TEST_EXIT=0
99
- timeout 300 bash -c "$TEST_CMD" 2>&1
100
- TEST_EXIT=$?
101
- if [ "${TEST_EXIT}" -eq 0 ]; then
102
- echo "✓ Post-merge test gate passed — no cross-plan conflicts"
103
- elif [ "${TEST_EXIT}" -eq 124 ]; then
104
- echo "⚠ Post-merge test gate timed out after 5 minutes"
105
- else
106
- echo "✗ Post-merge test gate failed (exit code ${TEST_EXIT})"
77
+ if [ -z "$TEST_CMD" ]; then
78
+ echo "⚠ Post-merge test gate NOT RUN — no test runner detected (not a pass, not a failure)"
79
+ elif [ ! -r "$PP_GATE_BIN/portable-timeout.sh" ]; then
80
+ echo "✗ Post-merge test gate NEVER RAN — portable-timeout.sh not found beside pp-tools; refusing to run unbounded (D-09-03)"
81
+ TEST_EXIT=127
107
82
  WAVE_FAILURE_COUNT=$((WAVE_FAILURE_COUNT + 1))
83
+ else
84
+ . "$PP_GATE_BIN/portable-timeout.sh"
85
+ run_with_timeout 300 bash -c "$TEST_CMD" 2>&1
86
+ TEST_EXIT=$?
87
+ if [ "${TEST_EXIT}" -eq 0 ]; then
88
+ echo "✓ Post-merge test gate passed — no cross-plan conflicts"
89
+ elif is_timeout_exit "${TEST_EXIT}"; then
90
+ echo "⚠ Post-merge test gate timed out after 300 seconds (exit ${TEST_EXIT}) — not counted as a failure"
91
+ elif [ "${TEST_EXIT}" -eq 127 ]; then
92
+ echo "✗ Post-merge test gate NEVER RAN — command not found (exit 127): ${TEST_CMD}"
93
+ WAVE_FAILURE_COUNT=$((WAVE_FAILURE_COUNT + 1))
94
+ else
95
+ echo "✗ Post-merge test gate failed (exit code ${TEST_EXIT})"
96
+ WAVE_FAILURE_COUNT=$((WAVE_FAILURE_COUNT + 1))
97
+ fi
108
98
  fi
109
99
  ```
110
100
 
101
+ **If the `NOT RUN` line printed:** no runner was configured and none was detected. Record the
102
+ gate as skipped — not passed, not failed — and leave `WAVE_FAILURE_COUNT` alone.
103
+
111
104
  **If `TEST_EXIT` is 0 (pass):** `✓ Post-merge test gate: {N} tests passed — no cross-plan conflicts` → continue to orchestrator tracking update.
112
105
 
113
- **If `TEST_EXIT` is 124 (timeout):** Log warning, treat as non-blocking, continue. Tests may need a longer budget or manual run.
106
+ **If `TEST_EXIT` is 124 or 142 (timeout — 124 from GNU `timeout`, 142 from the perl `alarm`
107
+ fallback; `is_timeout_exit` accepts both):** Log warning, treat as non-blocking, do NOT
108
+ increment `WAVE_FAILURE_COUNT`, continue. Tests may need a longer budget or manual run.
109
+
110
+ **If `TEST_EXIT` is 127 (`NEVER RAN`):** The runner was not found, or the timeout wrapper was
111
+ missing so nothing was launched. Report the command text and increment `WAVE_FAILURE_COUNT` —
112
+ a suite that never ran is not a green suite, and it must never be reported as a plain failure.
114
113
 
115
- **If `TEST_EXIT` is non-zero (test failure):** Increment `WAVE_FAILURE_COUNT` to track
114
+ **If `TEST_EXIT` is any other non-zero (test failure):** Increment `WAVE_FAILURE_COUNT` to track
116
115
  cumulative failures across waves. Subsequent waves should report:
117
116
  `⚠ Note: ${WAVE_FAILURE_COUNT} prior wave(s) had test failures`
@@ -0,0 +1,72 @@
1
+ # Serial-group dispatch — execute-phase step 3 (`kind: serial-group` spawns)
2
+
3
+ A serial group is a set of plans in one wave that share only non-source files (a test file, a size
4
+ baseline, a changeset, a doc). `phase.dispatch-plan` gives the group ONE spawn with
5
+ `isolation: main-checkout` and its `plans[]` in run order. Spawn exactly one executor for it — never
6
+ one per plan, never in a worktree (no `isolation=` parameter). Main-checkout spawns run one at a time;
7
+ the wave's worktree spawns may run alongside.
8
+
9
+ Emit the plan-start heartbeat for the group's first plan, then dispatch (runs in a subagent — no output until the whole group returns; expected, not a freeze):
10
+
11
+ ```text
12
+ Agent(
13
+ subagent_type="pp-executor",
14
+ description="Execute serial group {serial_group} of phase {phase_number}: {plan count} plans",
15
+ model="{executor_model}", # omit this line when executor_model == "inherit"
16
+ prompt="
17
+ <objective>
18
+ Execute these plans of phase {phase_number}-{phase_name} on the main checkout, one after another, in this order:
19
+ {for each entry of spawn.plans, numbered:}
20
+ {n}. {plan.id} — {plan.title} — ${PROJECT_ROOT}/{phase_dir}/{plan file} — touched tests: {plan.touched_tests or "none"} — build: {plan.build}
21
+ For each plan in turn: execute its tasks with their own atomic commits, write and commit its own SUMMARY.md, run its touched test files, then start the next plan.
22
+ </objective>
23
+
24
+ <dispatch tracking="orchestrator" suite="orchestrator" build="{spawn.build}" />
25
+
26
+ <serial_group_rules>
27
+ - One plan at a time, in the listed order. Each plan gets its own task commits and its own `{plan_id}-SUMMARY.md`, committed before the next plan starts.
28
+ - Tests: per plan, run only the test files that plan touches (listed above) and its narrower `<verify>` commands. Never the full suite — the orchestrator runs it once after the wave.
29
+ - Build: only before the tests of a plan whose `build` is true. When the group's `build` is false, run no build at all.
30
+ - Never call `state.*`, `roadmap.update-plan-progress` or `requirements.mark-complete`, and never stage STATE.md, ROADMAP.md or REQUIREMENTS.md: the orchestrator advances them once per wave.
31
+ - Never run `size:baseline`; the phase's closing commit re-baselines.
32
+ - Halt: when a plan cannot finish (verification still failing after repair, a Rule 4 stop, a checkpoint), stop the group at that plan — do not start the next one — and return `## GROUP HALTED` with `**Halted at:** {plan_id}`, the reason, the completed plans with their SUMMARY paths, and the plans not started.
33
+ - Otherwise return `## GROUP COMPLETE` with one `## PLAN COMPLETE` block per plan, in order.
34
+ </serial_group_rules>
35
+
36
+ <sequential_execution>
37
+ You are running as a SEQUENTIAL executor agent on the main working tree.
38
+ Use normal git commits (with hooks). Do NOT use --no-verify.
39
+ REQUIRED ORDER, per plan: Write SUMMARY.md → commit → only then any narration.
40
+ </sequential_execution>
41
+
42
+ <execution_context>
43
+ @~/.claude/pp-core/workflows/execute-plan.md
44
+ @~/.claude/pp-core/templates/summary.md
45
+ @~/.claude/pp-core/references/checkpoints.md
46
+ @~/.claude/pp-core/references/tdd.md
47
+ </execution_context>
48
+
49
+ <files_to_read>
50
+ MANDATORY: load every file listed here with the Read tool before you start the work — this block is your required reading.
51
+ First resolve repo root: `PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)`
52
+ - Every plan file listed in <objective> (read the next one again before starting it)
53
+ - ${PROJECT_ROOT}/.planning/PROJECT.md, ${PROJECT_ROOT}/.planning/STATE.md, ${PROJECT_ROOT}/.planning/config.json (if exists)
54
+ - ${PROJECT_ROOT}/${phase_dir}/*-CONTEXT.md and *-RESEARCH.md (if they exist)
55
+ - ${PROJECT_ROOT}/CLAUDE.md or ${PROJECT_ROOT}/.claude/CLAUDE.md, and project skills (if any)
56
+ </files_to_read>
57
+
58
+ ${AGENT_SKILLS}
59
+
60
+ <success_criteria>
61
+ - [ ] Every listed plan executed in order, or the group halted with the halting plan named
62
+ - [ ] Each task committed individually; one committed SUMMARY.md per completed plan
63
+ - [ ] No tracking-file writes (the orchestrator advances them once per wave)
64
+ </success_criteria>
65
+ "
66
+ )
67
+ ```
68
+
69
+ **On return:**
70
+ - `## GROUP COMPLETE` → emit a plan-complete heartbeat per plan and go on to step 4 (spot-checks use the spawn's `expected_summaries`).
71
+ - `## GROUP HALTED` → the plans before the halt are done (their SUMMARY.md counts for this wave's suite run and tracking commit). Route the halting plan to step 7 (handle failures). The plans after it are not started; they stay incomplete, so a re-run of `phase.dispatch-plan --wave {N}` lists only them.
72
+ - A checkpoint at a plan → `checkpoint_handling`; once resolved, re-run `phase.dispatch-plan --wave {N}` and dispatch the remaining spawn.
@@ -1,15 +1,15 @@
1
- # plan:pre vault fetch + summary (bespoke step dispatch — a0)
1
+ # Vault fetch + summary (plan:pre and execute:pre step dispatch)
2
2
 
3
- Capability-driven dispatch for an active plan:pre step hook where `kind == "step"` and `capId == "vault"`. Runs `vault fetch` then `vault summary` so `.planning/vault/SUMMARY.md` exists on the researcher and planner read paths before the researcher Agent() spawn. The generic step contract dispatches only `ref.skill`/`ref.agent` hooks — not `ref.command` — so this bespoke block owns the `vault fetch` command run. The registry evaluates `when: vault.enabled`; an inert capability yields no hook. `onError: skip` — any failure logs a warning and planning continues; never hard-fails.
3
+ Capability-driven dispatch for an active step hook where `kind == "step"` and `capId == "vault"`, at plan:pre (hooks in `PLAN_PRE_HOOKS_JSON`) or execute:pre (hooks in `EXECUTE_PRE_HOOKS_JSON`). Runs `vault fetch` then `vault summary` so `.planning/vault/SUMMARY.md` exists on the researcher and planner read paths, and so the `vault.status` gate that follows judges a fresh fetch. The generic step contract dispatches only `ref.skill`/`ref.agent` hooks — not `ref.command` — so this bespoke block owns the `vault fetch` command run. The registry evaluates `when: vault.enabled`; an inert capability yields no hook. `onError: skip` — a failed fetch logs a warning and continues; the gate after it decides whether a missing client vault may proceed (it stops only when `vault.required` is true).
4
4
 
5
- Read the active plan:pre step hook from `PLAN_PRE_HOOKS_JSON` (in-context) where `kind == "step"` and `capId == "vault"`.
5
+ Read the active step hook from the point's hooks JSON (in-context) where `kind == "step"` and `capId == "vault"`.
6
6
 
7
- **If no active vault step hook exists:** skip (non-Pareto project, `vault.enabled` false, or vault bindings absent).
7
+ **If no active vault step hook exists:** skip (`vault.enabled` is not true).
8
8
 
9
9
  **If an active vault step hook exists** (recognizable by `capId == "vault"` + `ref.command == "vault fetch"`):
10
10
 
11
11
  ```bash
12
- _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
12
+ _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
13
13
  # vault fetch: populates .planning/vault/ cache + manifest
14
14
  if ! pp_run vault fetch 2>&1; then
15
15
  echo "⚠ vault fetch failed — continuing without vault context (onError:skip)" >&2
@@ -1,119 +1,26 @@
1
- # Vault load gate — advisory (plan:pre + execute:pre)
1
+ # Vault load gate (plan:pre + execute:pre)
2
2
 
3
- Advisory gate that confirms vault load state before planning or build. The host sets
4
- `VAULT_GATE_POINT` to `plan` (for plan:pre) or `execute` (for execute:pre) before
5
- executing this step — **one file serves both call sites** (D-05). The §8 message table
6
- (design §8) column is selected by this parameter.
7
-
8
- Gated entirely on `.platform-bindings.json`: when no bindings file is present, this gate
9
- is a **no-op** — fully inert for non-Pareto projects. The verdict is read from
10
- `pp_run check vault.status --raw` — a pure manifest read that never fetches, never errors,
11
- and degrades to `{"present":false}` on any problem (D-02).
12
-
13
- ```bash
14
- _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
15
- VAULT_GATE_PRESENT=$(pp_run query platform-bindings --pick present 2>/dev/null || echo false)
16
- ```
17
-
18
- **If `VAULT_GATE_PRESENT` != `true`:** skip entirely (non-Pareto project — fully inert).
3
+ One file serves both call sites: the host sets `VAULT_GATE_POINT` to `plan` (plan:pre) or
4
+ `execute` (execute:pre) before executing this step. The verdict, its wording and whether it
5
+ blocks are decided by the CLI — `computeVaultVerdict` is the only owner. This step relays the
6
+ card verbatim and reads one field; it never re-derives any part of the verdict.
19
7
 
20
8
  ```bash
21
- VAULT_VERDICT=$(pp_run check vault.status --raw 2>/dev/null || echo '{"present":false}')
22
- VAULT_STATUS=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{process.stdout.write(JSON.parse(d).status||'miss');}catch{process.stdout.write('miss');}")
23
- VAULT_TIER=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{process.stdout.write(JSON.parse(d).tier||'');}catch{process.stdout.write('');}")
24
- VAULT_FALLBACK_REASON=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{process.stdout.write(JSON.parse(d).fallbackReason||'');}catch{process.stdout.write('');}")
25
- VAULT_REPO=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const p=JSON.parse(d);process.stdout.write(p.repo||p.source||'');}catch{process.stdout.write('');}")
26
- VAULT_REF=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{process.stdout.write(JSON.parse(d).ref||'');}catch{process.stdout.write('');}")
27
- VAULT_SHA=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const s=JSON.parse(d).resolvedSha||'';process.stdout.write(s.slice(0,8));}catch{process.stdout.write('');}")
28
- VAULT_FILE_COUNT=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{process.stdout.write(String(JSON.parse(d).fileCount??0));}catch{process.stdout.write('0');}")
29
- VAULT_STALE=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{process.stdout.write(String(!!JSON.parse(d).stale));}catch{process.stdout.write('false');}")
30
- VAULT_FETCHED_AT=$(printf '%s' "$VAULT_VERDICT" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{process.stdout.write(JSON.parse(d).fetchedAt||'');}catch{process.stdout.write('');}")
31
- # Compute human-readable cache age when stale
32
- VAULT_AGE=""
33
- if [ "$VAULT_STALE" = "true" ] && [ -n "$VAULT_FETCHED_AT" ]; then
34
- VAULT_AGE=$(VAULT_FETCHED_AT="$VAULT_FETCHED_AT" node -e "const ms=Date.now()-new Date(process.env.VAULT_FETCHED_AT).getTime();const d=Math.floor(ms/86400000);const h=Math.floor((ms%86400000)/3600000);process.stdout.write(d>0?d+'d':h+'h');")
35
- fi
36
- # Detect --auto / --chain in host $ARGUMENTS (non-interactive pipeline mode — D-08)
37
- AUTO_MODE=false
38
- if echo "${ARGUMENTS:-}" | grep -qE -- '--auto|--chain'; then AUTO_MODE=true; fi
9
+ _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
10
+ VAULT_CARD=$(pp_run check vault.status --card --point "${VAULT_GATE_POINT:-plan}")
11
+ VAULT_ACTION=$(pp_run check vault.status --pick action)
39
12
  ```
40
13
 
41
- Select message based on `VAULT_STATUS`, `VAULT_TIER`, and `VAULT_GATE_POINT`, then handle confirmation.
42
-
43
- ---
44
-
45
- ## §8 Message table — plan:pre column (`VAULT_GATE_POINT` == `plan`)
46
-
47
- **`fetched` + `tier: client`:**
48
-
49
- > Client vault loaded from `` `${VAULT_REPO}@${VAULT_REF}` `` (`` `${VAULT_FILE_COUNT}` `` files, sha `` `${VAULT_SHA}` ``). Planning will apply client standards.
50
-
51
- Surface this message and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE). Advisory checkpoint, not a hard block.
52
-
53
- **`fetched` + `tier: fallback` (intentionally more prominent — design §8):**
54
-
55
- > ℹ Loaded **shared Pareto vault** `` `${VAULT_REPO}@${VAULT_REF}` `` (`` `${VAULT_FILE_COUNT}` `` files) — *${VAULT_FALLBACK_REASON}*. Planning will apply Pareto defaults, not client-specific standards. Proceed?
56
-
57
- Surface this message and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE). The fallback confirmation is deliberately more prominent than the client tier: proceeding on Pareto defaults instead of the client's own standards is a state the user should consciously acknowledge.
58
-
59
- **`cache` (all tiers failed, using cached copy):**
60
-
61
- > ⚠ Could not reach client or shared vault — using cached copy from `` `${VAULT_FETCHED_AT}` `` (tier `` `${VAULT_TIER}` ``, may be stale). Proceed?
62
-
63
- Surface this warning and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE).
64
-
65
- **`miss` (no vault reachable, no cached copy):**
66
-
67
- > ⚠ No vault reachable (client or shared) and no cached copy. Planning will proceed WITHOUT vault context.
68
-
69
- Surface this warning and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE).
70
-
71
- ---
72
-
73
- ## §8 Message table — execute:pre column (`VAULT_GATE_POINT` == `execute`)
74
-
75
- **`fetched` + `tier: client`:**
76
-
77
- > Client vault present (`` `${VAULT_REPO}@${VAULT_REF}` ``). Build will apply client patterns.
78
-
79
- Surface this message and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE). Advisory checkpoint, not a hard block.
80
-
81
- **`fetched` + `tier: fallback` (intentionally more prominent — design §8):**
82
-
83
- > ℹ Using shared Pareto vault — *${VAULT_FALLBACK_REASON}*. Build applies Pareto defaults. Proceed?
84
-
85
- Surface this message and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE). The fallback confirmation is deliberately more prominent than the client tier.
86
-
87
- **`cache` (all tiers failed, using cached copy):**
88
-
89
- > ⚠ Could not reach client or shared vault — using cached copy from `` `${VAULT_FETCHED_AT}` `` (tier `` `${VAULT_TIER}` ``, may be stale). Proceed?
90
-
91
- Surface this warning and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE).
92
-
93
- **`miss` (no vault reachable, no cached copy):**
94
-
95
- > ⚠ No vault reachable (client or shared) and no cached copy. Build will proceed WITHOUT vault context.
96
-
97
- Surface this warning and require an explicit `confirmed` acknowledgment (`AskUserQuestion`, or a typed `confirmed` in TEXT_MODE).
98
-
99
- ---
100
-
101
- ## Stale suffix (applies to all statuses)
102
-
103
- When `VAULT_STALE` is `true`, append ` (cache is \`${VAULT_AGE}\` old)` to the selected message before surfacing it to the user.
104
-
105
- ---
106
-
107
- ## --auto / --chain behavior (D-08)
108
-
109
- When `AUTO_MODE` is `true`: **do not display an interactive prompt**. Instead, print the selected message (including stale suffix when applicable) as a log line, then continue without requiring `confirmed`. This ensures a non-interactive pipeline run leaves an auditable record that Pareto defaults / cache / miss were in effect — especially important for the `tier: fallback`, `cache`, and `miss` cases. Never hard-blocks.
110
-
111
- ---
112
-
113
- ## Confirmation (interactive mode)
114
-
115
- When `AUTO_MODE` is `false`:
14
+ **If either command fails** (non-zero exit, or `VAULT_ACTION` is empty): the gate is
15
+ declared `onError: halt` — STOP and report that the vault gate could not be evaluated. A pure
16
+ read that crashed is never treated as a pass.
116
17
 
117
- Use `AskUserQuestion` to surface the selected message and await `confirmed`. In TEXT_MODE (`--text` in `$ARGUMENTS`), replace `AskUserQuestion` with a plain-text prompt and accept a typed `confirmed`. This is an advisory checkpoint only — the gate **never hard-blocks**; proceeding after `confirmed` (or with a timeout / empty input) is always allowed.
18
+ **Otherwise relay `VAULT_CARD` to the user verbatim** (when non-empty), then act on
19
+ `VAULT_ACTION` only:
118
20
 
119
- `TEXT_MODE` follows the same rule as the host workflow (`--text` in `$ARGUMENTS`): replace `AskUserQuestion` with a plain-text numbered prompt.
21
+ | `VAULT_ACTION` | What to do |
22
+ |---|---|
23
+ | `none` | The vault is disabled — continue silently. |
24
+ | `proceed` | The client vault is loaded — show the card and continue. |
25
+ | `confirm` | Degraded and `vault.required` is false. Interactive: ask for an explicit `confirmed` (`AskUserQuestion`; in TEXT_MODE — `--text` in `$ARGUMENTS` — a plain-text prompt accepting a typed `confirmed`), then continue. With `--auto` / `--chain` in `$ARGUMENTS`: log the card and continue without prompting. |
26
+ | `stop` | `vault.required` is true and the client vault is not loaded. **STOP** — do not plan or build, in any mode (including `--auto` / `--chain`). The card names the remedy; the operator re-runs the command after fixing it. |