@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.
- package/.claude-plugin/plugin.json +3 -3
- package/README.md +31 -12
- package/agents/pp-code-fixer.md +0 -11
- package/agents/pp-code-reviewer.md +1 -77
- package/agents/pp-debug-session-manager.md +9 -6
- package/agents/pp-executor.md +12 -29
- package/agents/pp-plan-checker.md +4 -4
- package/agents/pp-planner.md +34 -20
- package/agents/pp-vault-reviewer.md +100 -23
- package/agents/pp-verifier.md +1 -3
- package/bin/install.js +10 -3
- package/commands/pp-execute-phase.md +1 -3
- package/commands/pp-ns-manage.md +1 -1
- package/commands/pp-ns-review.md +1 -1
- package/commands/pp-plan-phase.md +1 -2
- package/commands/pp-vault-promote.md +7 -8
- package/commands/pp-vault-review.md +6 -5
- package/commands/pp-verify-work.md +1 -2
- package/gemini-extension.json +1 -1
- package/hooks/dist/pp-check-update.js +0 -0
- package/hooks/dist/pp-cursor-session-start.js +1 -1
- package/hooks/dist/pp-statusline.js +1 -1
- package/hooks/dist/pp-update-banner.js +0 -0
- package/hooks/pp-check-update.js +0 -0
- package/hooks/pp-cursor-session-start.js +1 -1
- package/hooks/pp-statusline.js +1 -1
- package/hooks/pp-update-banner.js +0 -0
- package/package.json +10 -18
- package/pareto-skills/_shared/create-project-board.sh +0 -0
- package/pareto-skills/pp-project-setup/SKILL.md +1 -1
- package/pp-core/bin/check-latest-version.cjs +0 -0
- package/pp-core/bin/detect-build-commands.sh +2 -2
- package/pp-core/bin/lib/capability-activation.cjs +83 -9
- package/pp-core/bin/lib/capability-registry.cjs +201 -229
- package/pp-core/bin/lib/capability-state.cjs +93 -1
- package/pp-core/bin/lib/capability-writer.cjs +3 -3
- package/pp-core/bin/lib/check-command-router.cjs +1906 -1514
- package/pp-core/bin/lib/clusters.cjs +3 -0
- package/pp-core/bin/lib/command-aliases.cjs +0 -35
- package/pp-core/bin/lib/commands.cjs +9 -4
- package/pp-core/bin/lib/compose-bindings.cjs +251 -88
- package/pp-core/bin/lib/config-loader.cjs +7 -103
- package/pp-core/bin/lib/config-schema.cjs +1 -1
- package/pp-core/bin/lib/config.cjs +151 -62
- package/pp-core/bin/lib/decisions.cjs +4 -4
- package/pp-core/bin/lib/discovery-vault-check.cjs +246 -0
- package/pp-core/bin/lib/frontmatter.cjs +1 -38
- package/pp-core/bin/lib/git-base-branch.cjs +11 -12
- package/pp-core/bin/lib/git-provider.cjs +9 -10
- package/pp-core/bin/lib/init-command-router.cjs +5 -8
- package/pp-core/bin/lib/init-contract.cjs +620 -738
- package/pp-core/bin/lib/init-interactive.cjs +62 -4
- package/pp-core/bin/lib/init.cjs +24 -51
- package/pp-core/bin/lib/install-profiles.cjs +1 -1
- package/pp-core/bin/lib/io.cjs +4 -2
- package/pp-core/bin/lib/loop-resolver.cjs +165 -129
- package/pp-core/bin/lib/org-profile.cjs +402 -161
- package/pp-core/bin/lib/package-identity.cjs +3 -3
- package/pp-core/bin/lib/phase-command-router.cjs +1 -29
- package/pp-core/bin/lib/phase-scope.cjs +1 -1
- package/pp-core/bin/lib/phase.cjs +11 -253
- package/pp-core/bin/lib/platform-bindings.cjs +40 -19
- package/pp-core/bin/lib/profile-output.cjs +1 -1
- package/pp-core/bin/lib/shell-command-projection.cjs +104 -1
- package/pp-core/bin/lib/state.cjs +11 -85
- package/pp-core/bin/lib/template.cjs +1 -1
- package/pp-core/bin/lib/vault-command-router.cjs +1682 -477
- package/pp-core/bin/lib/vault-coordinates.cjs +16 -7
- package/pp-core/bin/lib/vault-index.cjs +656 -0
- package/pp-core/bin/lib/vault-seal.cjs +1851 -0
- package/pp-core/bin/lib/vault-standards-promote.cjs +577 -0
- package/pp-core/bin/lib/vault-standards-review.cjs +293 -0
- package/pp-core/bin/lib/vault-standards.cjs +1504 -0
- package/pp-core/bin/lib/vault-trace.cjs +155 -2778
- package/pp-core/bin/lib/vault-update.cjs +10 -59
- package/pp-core/bin/lib/vault.cjs +2570 -950
- package/pp-core/bin/lib/verify.cjs +0 -11
- package/pp-core/bin/portable-timeout.sh +1 -1
- package/pp-core/bin/pp-tools.cjs +157 -54
- package/pp-core/bin/shared/config-defaults.manifest.json +0 -7
- package/pp-core/bin/shared/config-schema.manifest.json +0 -3
- package/pp-core/bin/shared/model-catalog.json +2 -2
- package/pp-core/bin/verify-reapply-patches.cjs +0 -0
- package/pp-core/org-profile.json +26 -0
- package/pp-core/references/autonomous-best-effort.md +8 -7
- package/pp-core/references/loop-hook-dispatch.md +0 -25
- package/pp-core/references/planner-gap-closure.md +0 -1
- package/pp-core/references/planner-tdd.md +0 -1
- package/pp-core/references/planner-vault-standards.md +311 -0
- package/pp-core/references/planning-config.md +0 -8
- package/pp-core/references/tdd.md +0 -1
- package/pp-core/templates/README.md +1 -0
- package/pp-core/templates/VAULT-REVIEW.md +56 -0
- package/pp-core/templates/phase-prompt.md +2 -6
- package/pp-core/workflows/_runtime-launcher.snippet.sh +0 -0
- package/pp-core/workflows/add-tests.md +55 -4
- package/pp-core/workflows/audit-fix.md +63 -2
- package/pp-core/workflows/audit-milestone.md +1 -1
- package/pp-core/workflows/autonomous.md +85 -11
- package/pp-core/workflows/check-todos.md +13 -2
- package/pp-core/workflows/code-review-fix.md +59 -3
- package/pp-core/workflows/code-review.md +10 -57
- package/pp-core/workflows/complete-milestone.md +1 -1
- package/pp-core/workflows/debug.md +54 -4
- package/pp-core/workflows/discovery-sprint/prefill.md +19 -7
- package/pp-core/workflows/discovery-sprint/prototype.md +46 -49
- package/pp-core/workflows/discovery-sprint/session-13-gates.md +2 -0
- package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +20 -24
- package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/06-security.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +1 -6
- package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/12-delivery-model.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +1 -3
- package/pp-core/workflows/discovery-sprint/templates/context-template.md +1 -1
- package/pp-core/workflows/discovery-sprint/vault-context.md +207 -0
- package/pp-core/workflows/discovery-sprint.md +7 -3
- package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +4 -4
- package/pp-core/workflows/discovery-to-build/templates/pp-handoff.md +43 -1
- package/pp-core/workflows/discovery-to-build.md +10 -2
- package/pp-core/workflows/discuss-phase.md +3 -10
- package/pp-core/workflows/execute-phase/steps/check-query-gate.md +327 -0
- package/pp-core/workflows/execute-phase/steps/client-context-gate.md +3 -2
- package/pp-core/workflows/execute-phase/steps/cross-ai-delegation.md +1 -1
- package/pp-core/workflows/execute-phase/steps/execute-pre-dispatch.md +78 -0
- package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
- package/pp-core/workflows/execute-phase/steps/post-merge-gate.md +6 -8
- package/pp-core/workflows/execute-phase/steps/vault-fetch.md +115 -14
- package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +219 -20
- package/pp-core/workflows/execute-phase/steps/verify-post-gate.md +147 -0
- package/pp-core/workflows/execute-phase.md +152 -128
- package/pp-core/workflows/execute-plan.md +54 -6
- package/pp-core/workflows/fast.md +53 -4
- package/pp-core/workflows/help/modes/full.md +3 -3
- package/pp-core/workflows/init/steps/client-context-capture.md +101 -0
- package/pp-core/workflows/init/steps/gitlab-provisioning.md +130 -0
- package/pp-core/workflows/init/steps/project-md-deferral-narration.md +66 -0
- package/pp-core/workflows/init/steps/reachability-outcome.md +70 -0
- package/pp-core/workflows/init.md +232 -272
- package/pp-core/workflows/new-project.md +31 -23
- package/pp-core/workflows/plan-phase.md +98 -45
- package/pp-core/workflows/quick.md +117 -3
- package/pp-core/workflows/secure-phase.md +1 -1
- package/pp-core/workflows/ship.md +57 -28
- package/pp-core/workflows/undo.md +1 -1
- package/pp-core/workflows/update.md +3 -3
- package/pp-core/workflows/validate-phase.md +58 -3
- package/pp-core/workflows/vault-review.md +161 -23
- package/pp-core/workflows/vault-write-back.md +73 -110
- package/pp-core/workflows/verify-work.md +12 -14
- package/scripts/changeset/cli.cjs +6 -5
- package/scripts/changeset/lint.cjs +0 -0
- package/scripts/changeset/new.cjs +33 -50
- package/scripts/dev-env.cjs +25 -85
- package/scripts/gen-capability-registry.cjs +120 -13
- package/scripts/lib/allowlist-ratchet.cjs +1 -103
- package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -2
- package/scripts/lint-docs-required.cjs +0 -0
- package/scripts/lint-pr-check-project-dir.cjs +1 -3
- package/scripts/lint-test-file-count.allowlist.json +3 -19
- package/scripts/lint-test-file-count.cjs +5 -6
- package/scripts/prompt-injection-scan.sh +19 -17
- package/scripts/release-channel.cjs +0 -0
- package/scripts/sync-manifest-versions.cjs +5 -4
- package/scripts/sync-rulesets.sh +1 -1
- package/scripts/update-size-baseline.cjs +30 -274
- package/scripts/verify-opengsd-sweep.cjs +3 -5
- package/scripts/workflow-size.cjs +9 -61
- package/pp-core/bin/lib/dispatch-plan.cjs +0 -483
- package/pp-core/bin/lib/install-run.cjs +0 -536
- package/pp-core/bin/lib/loop-gates.cjs +0 -213
- package/pp-core/bin/lib/phase-manifest.cjs +0 -527
- package/pp-core/bin/lib/phase-tier.cjs +0 -480
- package/pp-core/bin/lib/plan-graph.cjs +0 -368
- package/pp-core/bin/lib/practices-review-check.cjs +0 -938
- package/pp-core/bin/lib/vault-audit.cjs +0 -2070
- package/pp-core/bin/lib/vault-practices.cjs +0 -1990
- package/pp-core/bin/lib/vault-review.cjs +0 -2359
- package/pp-core/bin/lib/vault-write-back.cjs +0 -877
- package/pp-core/references/executor-vault-trace.md +0 -47
- package/pp-core/references/planner-plan-graph.md +0 -66
- package/pp-core/references/planner-vault-practices.md +0 -112
- package/pp-core/templates/practices/README.md +0 -251
- package/pp-core/templates/practices/error-handling.md +0 -18
- package/pp-core/templates/practices/minimal-comments.md +0 -14
- package/pp-core/templates/practices/naming-convention.md +0 -18
- package/pp-core/templates/practices/practice-template.md +0 -23
- package/pp-core/workflows/discovery-sprint/vault-fetch.md +0 -37
- package/pp-core/workflows/execute-phase/steps/checkpoint-handling.md +0 -45
- package/pp-core/workflows/execute-phase/steps/install-run.md +0 -29
- package/pp-core/workflows/execute-phase/steps/phase-close-rebaseline.md +0 -23
- package/pp-core/workflows/execute-phase/steps/serial-group-dispatch.md +0 -73
- package/pp-core/workflows/execute-phase/steps/vault-door-gate.md +0 -19
- package/pp-core/workflows/plan-phase/steps/phase-tier.md +0 -43
- package/scripts/lib/size-budget.cjs +0 -311
- package/scripts/lint-neutrality-names.cjs +0 -694
- package/scripts/lint-org-coordinates.allowlist.json +0 -35
- package/scripts/lint-org-coordinates.cjs +0 -426
|
@@ -70,21 +70,9 @@ _PP_SHIM_NAME="pp-tools.cjs"; _pp_root() { ( for _v in $(env | sed -n 's/^\(GIT_
|
|
|
70
70
|
# Gate on presence via reader — absent file → {present:false} exit 0 (inert, step skipped, no jq)
|
|
71
71
|
if [ "$(pp_run query platform-bindings --pick present 2>/dev/null)" = "true" ]; then
|
|
72
72
|
PINNED=$(pp_run query platform-bindings --pick platform.tag)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
PLATFORM_REPO_URL="https://${PLATFORM_HOST}/${REPO}.git"
|
|
77
|
-
# Resolve latest STABLE tag from remote — never hard-block if offline (empty LATEST → skip drift check)
|
|
78
|
-
# Keep --refs to strip ^{} annotated-tag rows; --sort=-v:refname sorts server-side
|
|
79
|
-
# Stable filter fixes prerelease mis-ordering: git ranks v1.4.0-rc.1 after v1.4.0 (wrong by semver)
|
|
80
|
-
# semver-compare.cjs is the single blessed source for comparison — do NOT reimplement
|
|
81
|
-
REMOTE_TAGS=$(git ls-remote --tags --refs --sort=-v:refname "$PLATFORM_REPO_URL" 'v*' 2>/dev/null | sed 's#.*/##')
|
|
82
|
-
LATEST=$(printf '%s\n' "$REMOTE_TAGS" | node -e "
|
|
83
|
-
const sc = require('${PP_TOOLS%/*}/lib/semver-compare.cjs');
|
|
84
|
-
const lines = require('fs').readFileSync(0, 'utf-8').split('\n').map(s=>s.trim()).filter(Boolean);
|
|
85
|
-
const stable = lines.filter(sc.isStableTripletSemver).sort(sc.compareSemverCore);
|
|
86
|
-
process.stdout.write((stable[stable.length-1] || '') + '\n');
|
|
87
|
-
" 2>/dev/null)
|
|
73
|
+
# The owner is compose-bindings resolveLatestPlatformTag — the same lookup pp-tools init and check ship.platform-drift use — so the URL is never composed in shell.
|
|
74
|
+
# Tagless, offline and unreachable all print as empty: latest=<unresolved> and the drift comparison is skipped (never hard-block).
|
|
75
|
+
LATEST=$(pp_run query platform-latest-tag --pick latest 2>/dev/null)
|
|
88
76
|
echo "platform preflight: pinned=${PINNED:-<none>} latest=${LATEST:-<unresolved>}"
|
|
89
77
|
if [ -n "$LATEST" ] && [ -n "$PINNED" ] && [ "$PINNED" != "$LATEST" ]; then
|
|
90
78
|
echo "PP_PLATFORM_DRIFT=1"
|
|
@@ -102,15 +90,10 @@ choose:
|
|
|
102
90
|
- **Proceed on the older pin** — continue knowingly; record the deferral in
|
|
103
91
|
`PROJECT.md` so it's a conscious decision, not silent drift.
|
|
104
92
|
|
|
105
|
-
If `LATEST` was unresolved (
|
|
106
|
-
hard-block initiation on an
|
|
93
|
+
If `LATEST` was unresolved (no stable release tag, offline, or an unreachable
|
|
94
|
+
remote), note it and proceed — never hard-block initiation on an unresolved tag. For non-Pareto repos the block is
|
|
107
95
|
a no-op and this step is skipped entirely.
|
|
108
96
|
|
|
109
|
-
When the bindings file is present, also run `pp_run query init-contract --arm-vault`
|
|
110
|
-
(sets `vault.enabled` and `vault.required` to true, each only where absent; `ok:false` = no client vault bound — run
|
|
111
|
-
`/pp-init`) and `pp_run vault probe` (one reachability line; empty when the vault is
|
|
112
|
-
disabled). Show both outputs verbatim; neither blocks.
|
|
113
|
-
|
|
114
97
|
## 1. Setup
|
|
115
98
|
|
|
116
99
|
**MANDATORY FIRST STEP — Execute these checks before ANY user interaction:**
|
|
@@ -149,7 +132,7 @@ with "agent type not found" if `required_agents_installed` is false. Run the ins
|
|
|
149
132
|
|
|
150
133
|
Proceeding without research subagents — roadmap will be generated inline.
|
|
151
134
|
```
|
|
152
|
-
|
|
135
|
+
Continue through Steps 2–5.5 as normal. When you reach Step 6, skip Steps 6–7 (parallel research and synthesis) and go straight to roadmap creation in Step 8.
|
|
153
136
|
|
|
154
137
|
**Detect runtime and set instruction file name:**
|
|
155
138
|
|
|
@@ -453,6 +436,11 @@ Loop until "Create PROJECT.md" selected.
|
|
|
453
436
|
|
|
454
437
|
Synthesize all context into `.planning/PROJECT.md` using the template from `templates/project.md`.
|
|
455
438
|
|
|
439
|
+
**Init deferral (D-07-03, OD-2).** Before writing the file, Read
|
|
440
|
+
`pp-core/workflows/init/steps/project-md-deferral-narration.md` and follow it — the single
|
|
441
|
+
rendering of the reachability-proof deferral `/pp-init` recorded, silent when none is on
|
|
442
|
+
file. Do not restate its logic here.
|
|
443
|
+
|
|
456
444
|
**For greenfield projects:**
|
|
457
445
|
|
|
458
446
|
Initialize requirements as hypotheses:
|
|
@@ -887,6 +875,26 @@ Config changes are saved locally — no commit needed since `commit_docs` is `fa
|
|
|
887
875
|
|
|
888
876
|
Use models from init: `researcher_model`, `synthesizer_model`, `roadmapper_model`.
|
|
889
877
|
|
|
878
|
+
**Arm the client vault (both modes, every route).**
|
|
879
|
+
It sits here, not in Step 6, because Step 1's agents-not-installed note skips Steps 6–7, and this step must run on that route too.
|
|
880
|
+
|
|
881
|
+
```bash
|
|
882
|
+
ARM=$(pp_run query init-contract --arm-vault); ARM_EXIT=$?
|
|
883
|
+
echo "$ARM"
|
|
884
|
+
ARMED=$(printf '%s' "$ARM" | node -e 'let s="";process.stdin.on("data",d=>{s+=d}).on("end",()=>{try{process.stdout.write(String(JSON.parse(s).armed===true))}catch{process.stdout.write("false")}})')
|
|
885
|
+
if [ "$ARM_EXIT" -eq 0 ] && [ "$ARMED" = "true" ]; then
|
|
886
|
+
if [ -f .platform-bindings.json ]; then
|
|
887
|
+
pp_run query commit "chore: arm client vault from org profile" --files .planning/config.json .platform-bindings.json
|
|
888
|
+
else
|
|
889
|
+
pp_run query commit "chore: arm client vault from org profile" --files .planning/config.json
|
|
890
|
+
fi
|
|
891
|
+
fi
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
- `ok: false` (or `ARM_EXIT` is non-zero): **STOP.** Print the engine's `message` verbatim and tell the user to run `/pp-init` before continuing. Do not continue with the vault silently off.
|
|
895
|
+
- `armed: true` (the block above already committed it): tell the user, in one or two short lines, that a client-vault binding was composed from the org profile `<profile.packageName>@<profile.version>` without a prompt, and that setting `vault.enabled: false` in `.planning/config.json` opts out and is honoured by every later arming run.
|
|
896
|
+
- `armed: false`: nothing was written or committed and the vault is NOT armed — do not say it was. If `reason` is `vault_disabled`, tell the user the project's `vault.enabled` setting keeps the vault off. Continue.
|
|
897
|
+
|
|
890
898
|
## 6. Research Decision
|
|
891
899
|
|
|
892
900
|
**If auto mode:** Default to "Research first" without asking.
|
|
@@ -72,8 +72,7 @@ Load all context in one call (paths only to minimize orchestrator context):
|
|
|
72
72
|
```bash
|
|
73
73
|
_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
|
|
74
74
|
GRAN_PARAM=""; if [[ "$ARGUMENTS" =~ (^|[[:space:]])--granularity[[:space:]]+([^[:space:]-][^[:space:]]*) ]]; then GRAN_PARAM="--granularity ${BASH_REMATCH[2]}"; fi
|
|
75
|
-
|
|
76
|
-
INIT=$(pp_run query init.plan-phase "$PHASE" $GRAN_PARAM $TIER_FLAG)
|
|
75
|
+
INIT=$(pp_run query init.plan-phase "$PHASE" $GRAN_PARAM)
|
|
77
76
|
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
78
77
|
AGENT_SKILLS_RESEARCHER=$(pp_run query agent-skills pp-phase-researcher)
|
|
79
78
|
AGENT_SKILLS_PLANNER=$(pp_run query agent-skills pp-planner)
|
|
@@ -90,8 +89,6 @@ Parse JSON for: `researcher_model`, `planner_model`, `checker_model`, `research_
|
|
|
90
89
|
|
|
91
90
|
**If `response_language` is set:** Include `response_language: {value}` in all spawned subagent prompts so any user-facing output stays in the configured language.
|
|
92
91
|
|
|
93
|
-
**Ceremony tier:** Read and follow `pp-core/workflows/plan-phase/steps/phase-tier.md` now; every `render-hooks` call below passes `--phase "$PHASE" $TIER_FLAG`.
|
|
94
|
-
|
|
95
92
|
**File paths (for <files_to_read> blocks):** `state_path`, `roadmap_path`, `requirements_path`, `context_path`, `research_path`, `verification_path`, `uat_path`, `reviews_path`. These are null if files don't exist.
|
|
96
93
|
|
|
97
94
|
**If `planning_exists` is false:** Error — run `/pp:init` first.
|
|
@@ -141,7 +138,7 @@ The gate fires only on `Complete`. `Executed` and `Needs Review` are not gated
|
|
|
141
138
|
|
|
142
139
|
## 2. Parse and Normalize Arguments
|
|
143
140
|
|
|
144
|
-
Extract from $ARGUMENTS: phase number (integer or decimal like `2.1`), flags (`--research`, `--skip-research`, `--research-phase <N>`, `--gaps`, `--skip-verify`, `--skip-ui`, `--prd <filepath>`, `--ingest <path-or-glob>`, `--ingest-format <auto|nygard|madr|narrative>`, `--reviews`, `--text`, `--bounce`, `--skip-bounce`, `--chunked`, `--mvp`, `--tdd`, `--granularity <coarse|standard|fine>`, `--
|
|
141
|
+
Extract from $ARGUMENTS: phase number (integer or decimal like `2.1`), flags (`--research`, `--skip-research`, `--research-phase <N>`, `--gaps`, `--skip-verify`, `--skip-ui`, `--prd <filepath>`, `--ingest <path-or-glob>`, `--ingest-format <auto|nygard|madr|narrative>`, `--reviews`, `--text`, `--bounce`, `--skip-bounce`, `--chunked`, `--mvp`, `--tdd`, `--granularity <coarse|standard|fine>`, `--force` (override closed-phase gate, see §1.5), `--unattended`).
|
|
145
142
|
|
|
146
143
|
**`--research-phase <N>` — research-only mode (#3042 + #3044).** When this flag is present, parse `<N>` as the phase number (overrides any positional phase argument), set `RESEARCH_ONLY=true`, and treat the rest of this workflow as a research-dispatch only — the planner spawn (step 8), plan-checker, verification, gaps, bounce, and post-planning-gaps blocks all skip on `RESEARCH_ONLY`. Use this for cross-phase research, doc review before committing to a planning approach, and correction-without-replanning loops. Replaces the deleted `/pp-research-phase` command.
|
|
147
144
|
|
|
@@ -430,10 +427,6 @@ If `AI_SPEC_FILE` is non-empty, pass `AI_SPEC_PATH` and `FRAMEWORK_LINE` to the
|
|
|
430
427
|
|
|
431
428
|
## 5. Handle Research
|
|
432
429
|
|
|
433
|
-
### 5.00. plan:pre vault load — ALWAYS, before the skip rule below
|
|
434
|
-
|
|
435
|
-
Every path runs this before any agent: `PLAN_PRE_HOOKS_JSON=${PLAN_PRE_HOOKS_JSON:-$(pp_run loop render-hooks plan:pre --raw --phase "$PHASE" $TIER_FLAG)} || exit 1`. Then Read and execute `pp-core/workflows/execute-phase/steps/vault-fetch.md` (active only for a `capId == "vault"` step hook; writes `.planning/vault/SUMMARY.md`; `onError:skip`). Then, if an active plan:pre gate has `check.query == "vault.status"`, set `VAULT_GATE_POINT=plan` and Read and execute `pp-core/workflows/execute-phase/steps/vault-load-gate.md` — it relays the CLI's vault card and acts on its `action` only (`stop` halts planning in every mode; `confirm` asks, or logs under --auto/--chain). Skip silently when neither hook is active.
|
|
436
|
-
|
|
437
430
|
**Skip if:** `--gaps` flag or `--skip-research` flag or `--reviews` flag.
|
|
438
431
|
|
|
439
432
|
### 5.0. Research-Only Modifiers (`--view`, `--research`)
|
|
@@ -501,10 +494,32 @@ fi
|
|
|
501
494
|
```bash
|
|
502
495
|
PHASE_DESC=$(pp_run query roadmap.get-phase "${PHASE}" --pick section)
|
|
503
496
|
if [ -z "${PLAN_PRE_HOOKS_JSON:-}" ]; then
|
|
504
|
-
PLAN_PRE_HOOKS_JSON=$(pp_run loop render-hooks plan:pre --raw
|
|
497
|
+
PLAN_PRE_HOOKS_JSON=$(pp_run loop render-hooks plan:pre --raw)
|
|
505
498
|
fi
|
|
506
499
|
```
|
|
507
500
|
|
|
501
|
+
### plan:pre vault fetch + summary
|
|
502
|
+
|
|
503
|
+
Reached on **every** path through §5.1 — including the exits that reuse an existing RESEARCH.md or skip research. Those skip the researcher spawn, not this section: the vault load is not conditional on research. Scope: paths through §5.1 only — §5.0's research-only exits leave the workflow before §5.1 runs and are not build paths.
|
|
504
|
+
|
|
505
|
+
**Admission first (D-28, D-05):** a config the gate cannot read renders no vault hook at all, so this runs before the render; without bindings it is inert.
|
|
506
|
+
|
|
507
|
+
```bash
|
|
508
|
+
VAULT_ADMIT_PRESENT=$(pp_run query platform-bindings --pick present 2>/dev/null || echo true)
|
|
509
|
+
VAULT_ADMIT=inert
|
|
510
|
+
if [ "$VAULT_ADMIT_PRESENT" = true ]; then VAULT_ADMIT=$(pp_run vault admission 2>/dev/null || echo unrecognised); fi
|
|
511
|
+
case "$VAULT_ADMIT" in on) echo "VAULT_ADMIT=on" ;; off|inert) : ;; *) pp_run vault admission --explain; echo "PARETO_GATE_BLOCKED:vault.admission"; exit 1 ;; esac
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
```bash
|
|
515
|
+
PLAN_PRE_HOOKS_JSON=${PLAN_PRE_HOOKS_JSON:-$(pp_run loop render-hooks plan:pre --raw)}
|
|
516
|
+
printf '%s' "$PLAN_PRE_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('PLAN_PRE_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
Set `VAULT_FETCH_HOOKS_JSON=$PLAN_PRE_HOOKS_JSON`.
|
|
520
|
+
|
|
521
|
+
Read and execute `pp-core/workflows/execute-phase/steps/vault-fetch.md` — the bespoke plan:pre vault fetch + summary dispatch (active only for a `capId == "vault"` step hook; produces `.planning/vault/SUMMARY.md` for the researcher/planner read paths; `onError:skip`). Skip silently when none.
|
|
522
|
+
|
|
508
523
|
### into:researcher contributions
|
|
509
524
|
|
|
510
525
|
In `PLAN_PRE_HOOKS_JSON`, read active plan:pre entries where `kind == "contribution"` and `into == "researcher"` (in array order). If none, inject nothing. If present, append each entry's `fragment.inline` verbatim to `filled_research_hook_fragment` (or add it as a `<files_to_read>`/context line in the researcher prompt) — typically a pointer to `.planning/vault/SUMMARY.md` (the bounded vault index). Inject verbatim — do not paraphrase.
|
|
@@ -584,7 +599,7 @@ test -f "${PHASE_DIR}/${PADDED_PHASE}-VALIDATION.md" && echo "VALIDATION_CREATED
|
|
|
584
599
|
> Capability-driven dispatch. Resolves active `plan:pre` hooks via the capability registry; the security hook's `when` condition is evaluated by the registry.
|
|
585
600
|
|
|
586
601
|
```bash
|
|
587
|
-
PLAN_PRE_HOOKS_JSON=$(pp_run loop render-hooks plan:pre --raw
|
|
602
|
+
PLAN_PRE_HOOKS_JSON=$(pp_run loop render-hooks plan:pre --raw)
|
|
588
603
|
```
|
|
589
604
|
|
|
590
605
|
Resolve active contribution hooks from `PLAN_PRE_HOOKS_JSON` where `kind == "contribution"` and `capId == "security"`.
|
|
@@ -614,11 +629,12 @@ Continue to step 5.6. Security config is passed to the planner in step 8.
|
|
|
614
629
|
> **Config semantics (cutover fix):** `workflow.ui_phase` gates UI-SPEC *generation* (step); `workflow.ui_safety_gate` gates the *planning block* (gate). Both-on = identical to OLD §5.6. Intended change: `{ui_phase:true, ui_safety_gate:false}` now auto-generates in pipelines but does NOT block manual planning (each key controls exactly what its description says).
|
|
615
630
|
|
|
616
631
|
```bash
|
|
617
|
-
PLAN_PRE_HOOKS_JSON=${PLAN_PRE_HOOKS_JSON:-$(pp_run loop render-hooks plan:pre --raw
|
|
632
|
+
PLAN_PRE_HOOKS_JSON=${PLAN_PRE_HOOKS_JSON:-$(pp_run loop render-hooks plan:pre --raw)}
|
|
633
|
+
printf '%s' "$PLAN_PRE_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('PLAN_PRE_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
|
|
618
634
|
HOOKS_JSON="$PLAN_PRE_HOOKS_JSON"
|
|
619
635
|
```
|
|
620
636
|
|
|
621
|
-
Read the `activeHooks` array directly from `PLAN_PRE_HOOKS_JSON
|
|
637
|
+
Read the `activeHooks` array directly from the printed `PLAN_PRE_HOOKS_JSON=` line (in-context — do NOT invoke a shell pipeline).
|
|
622
638
|
|
|
623
639
|
**Branch 1 — all plan:pre hooks inactive (`activeHooks` is empty or absent):** Skip to step 6.
|
|
624
640
|
|
|
@@ -686,11 +702,30 @@ Output this markdown directly (not as a code block):
|
|
|
686
702
|
───────────────────────────────────────────────
|
|
687
703
|
Also available:
|
|
688
704
|
- `/pp:plan-phase {N} --skip-ui ${GSD_WS}` — plan without UI-SPEC (not recommended for frontend phases)
|
|
689
|
-
- Not a UI phase? Matched: {GATE.tokens}. Add `**UI:** none` on its own line in the ROADMAP phase section.
|
|
690
705
|
```
|
|
691
706
|
|
|
692
707
|
**Exit the plan-phase workflow. Do not continue.**
|
|
693
708
|
|
|
709
|
+
### plan:pre vault gate — enforce, then render
|
|
710
|
+
|
|
711
|
+
Reached on **every** path through §5.6. Branches 1-5 skip the UI work, not this section: their "skip/continue to step 6" passes THROUGH this section and the render sentence below it on the way to `## 6.`. Only Branch 6's explicit **EXIT the plan-phase workflow** stops before it. A §5.1-originating "skip to step 6" (use existing, or Skip research) likewise passes THROUGH the fetch section above and this section on its way to `## 6.`.
|
|
712
|
+
A researcher-return "continue to step 6" (the `## RESEARCH COMPLETE` arm) and a §5.5-originating "continue to step 6" (the research-disabled warning arm and the Nyquist-not-applicable arm) likewise pass THROUGH the fetch section above and this section on their way to `## 6.`.
|
|
713
|
+
|
|
714
|
+
**Admission again (D-28):** `--gaps`, `--skip-research` and `--reviews` skip §5, fetch section included, so the same check runs here before the gate lookup.
|
|
715
|
+
|
|
716
|
+
```bash
|
|
717
|
+
VAULT_ADMIT_PRESENT=$(pp_run query platform-bindings --pick present 2>/dev/null || echo true)
|
|
718
|
+
VAULT_ADMIT=inert
|
|
719
|
+
if [ "$VAULT_ADMIT_PRESENT" = true ]; then VAULT_ADMIT=$(pp_run vault admission 2>/dev/null || echo unrecognised); fi
|
|
720
|
+
case "$VAULT_ADMIT" in on) echo "VAULT_ADMIT=on" ;; off|inert) : ;; *) pp_run vault admission --explain; echo "PARETO_GATE_BLOCKED:vault.admission"; exit 1 ;; esac
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
In `PLAN_PRE_HOOKS_JSON` (already loaded), find active plan:pre entries where `kind == "gate"` and `check.query == "vault.status"`. If none, skip silently to step 6.
|
|
724
|
+
|
|
725
|
+
**Enforce first.** §5.6 already ran `ui.plan-gate` with its own positional and owns its outcome (Branch 6 blocks in manual mode; Branch 5 continues), so skip that entry — the enforcer never sees it. Set `GATE_POINT=plan:pre`, `GATE_HOOKS_JSON=$PLAN_PRE_HOOKS_JSON`, leave `GATE_POSITIONAL_ARG` empty deliberately (`vault.status` reads project state, not a phase; every plan:pre gate needing one is caller-handled — D-VH-7), then Read `pp-core/workflows/execute-phase/steps/check-query-gate.md` — the single generic enforcer (GATE-02); it owns the halt.
|
|
726
|
+
|
|
727
|
+
**Then render.** If still running, set `VAULT_GATE_POINT=plan` and Read `pp-core/workflows/execute-phase/steps/vault-load-gate.md` — it surfaces the §8 load-state message and decides nothing.
|
|
728
|
+
|
|
694
729
|
## 6. Check Existing Plans
|
|
695
730
|
|
|
696
731
|
```bash
|
|
@@ -816,7 +851,7 @@ Continue to step 8.
|
|
|
816
851
|
Run this Bash command to emit the branded Plan stage banner (renders on stderr, auto-degrades on non-TTY — do NOT print an inline ASCII banner, that would double-print):
|
|
817
852
|
```bash
|
|
818
853
|
pp_run banner plan "PLANNING PHASE {X}"
|
|
819
|
-
touch "${PHASE_DIR}/.planner-run-mark" #
|
|
854
|
+
touch "${PHASE_DIR}/.planner-run-mark" # step 9d examines only plans newer than this
|
|
820
855
|
```
|
|
821
856
|
|
|
822
857
|
Then announce the spawn:
|
|
@@ -970,7 +1005,7 @@ Read and execute `pp-core/workflows/plan-phase/steps/chunked-planning.md` — th
|
|
|
970
1005
|
|
|
971
1006
|
## 9. Handle Planner Return
|
|
972
1007
|
|
|
973
|
-
- **`## PLANNING COMPLETE`:**
|
|
1008
|
+
- **`## PLANNING COMPLETE`:** Run the step 9d gate first. Then display plan count. If `--skip-verify` or `plan_checker_enabled` is false (from init): skip to step 13. Otherwise: step 10.
|
|
974
1009
|
- **`## PHASE SPLIT RECOMMENDED`:** The planner determined the phase exceeds the context budget for full-fidelity implementation of all source items. Handle in step 9b.
|
|
975
1010
|
- **`## ⚠ Source Audit: Unplanned Items Found`:** The planner's multi-source coverage audit found items from REQUIREMENTS.md, RESEARCH.md, ROADMAP goal, or CONTEXT.md decisions that are not covered by any plan. Handle in step 9c.
|
|
976
1011
|
- **`## CHECKPOINT REACHED`:** Present to user, get response, spawn continuation (step 12) (U-P4 — hard stop)
|
|
@@ -1065,6 +1100,33 @@ Use AskUserQuestion for each gap (or batch if multiple gaps) (U-P7).
|
|
|
1065
1100
|
**If "Split":** Use `/pp:phase --insert` for overflow items, then replan.
|
|
1066
1101
|
**If "Defer":** Record in CONTEXT.md `## Deferred Ideas` with developer's confirmation. Proceed to step 10.
|
|
1067
1102
|
|
|
1103
|
+
## 9d. Threat Model Presence Gate
|
|
1104
|
+
|
|
1105
|
+
> Mechanical post-planner check. Active only when the security capability's `plan:pre` contribution is active — the same hook step 5.55 banners on; otherwise it prints `false` and changes nothing. Runs on every `## PLANNING COMPLETE` (including plans accepted through step 9a) before step 10 or step 13.
|
|
1106
|
+
|
|
1107
|
+
```bash
|
|
1108
|
+
PLAN_PRE_HOOKS_JSON=${PLAN_PRE_HOOKS_JSON:-$(pp_run loop render-hooks plan:pre --raw)}
|
|
1109
|
+
SEC_ON=$(printf '%s' "$PLAN_PRE_HOOKS_JSON" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const h=JSON.parse(s||"{}").activeHooks||[];process.stdout.write(h.some(x=>x.kind==="contribution"&&x.capId==="security")?"true":"false")})')
|
|
1110
|
+
MARK="${PHASE_DIR}/.planner-run-mark"
|
|
1111
|
+
[ -f "$MARK" ] || touch -t 197001010000 "$MARK"
|
|
1112
|
+
NO_TM=""
|
|
1113
|
+
if [ "$SEC_ON" = "true" ]; then
|
|
1114
|
+
for p in $(find "${PHASE_DIR}" -maxdepth 1 -name '*-PLAN.md' -newer "$MARK" | sort); do
|
|
1115
|
+
grep -q '<threat_model>' "$p" || NO_TM="${NO_TM} ${p##*/}"
|
|
1116
|
+
done
|
|
1117
|
+
fi
|
|
1118
|
+
echo "THREAT_MODEL_GATE=${SEC_ON}${NO_TM:+ MISSING:${NO_TM}}"
|
|
1119
|
+
```
|
|
1120
|
+
|
|
1121
|
+
**If the output carries `MISSING:`:** STOP. Do not proceed to step 10 or step 13. Display:
|
|
1122
|
+
|
|
1123
|
+
```text
|
|
1124
|
+
✗ Security enforcement is active, but these plans carry no <threat_model> block: {NO_TM}
|
|
1125
|
+
Remedy: re-spawn the planner (step 8) with the block required for each plan named above, then re-run this gate.
|
|
1126
|
+
```
|
|
1127
|
+
|
|
1128
|
+
**Otherwise:** continue with the step 9 branch (`false` means the security contribution is inactive and this gate examined nothing).
|
|
1129
|
+
|
|
1068
1130
|
## 10. Spawn pp-plan-checker Agent
|
|
1069
1131
|
|
|
1070
1132
|
Display banner:
|
|
@@ -1172,17 +1234,17 @@ Offer 3 options (U-P9):
|
|
|
1172
1234
|
|
|
1173
1235
|
**If `DISK_PLANS` is 0:** No plans on disk — something is seriously wrong. Display error and stop.
|
|
1174
1236
|
|
|
1175
|
-
## 12. Revision Loop (Max
|
|
1237
|
+
## 12. Revision Loop (Max 3 Iterations)
|
|
1176
1238
|
|
|
1177
1239
|
Track `iteration_count` (starts at 1 after initial plan + check).
|
|
1178
1240
|
Track `prev_issue_count` (initialized to `Infinity` before the loop begins).
|
|
1179
1241
|
Track `stall_reentry_count` (starts at 0; incremented each time "Adjust approach" re-enters step 8).
|
|
1180
1242
|
|
|
1181
|
-
**If iteration_count <
|
|
1243
|
+
**If iteration_count < 3:**
|
|
1182
1244
|
|
|
1183
1245
|
Parse issue count from checker return: count BLOCKER + WARNING entries in the YAML issues block (structured output from pp-plan-checker). If the checker's return contains no YAML issues block (i.e., the plan was approved with no issues), treat `issue_count` as 0 and skip the stall check — the plan passed. Proceed to step 13.
|
|
1184
1246
|
|
|
1185
|
-
Display: `Revision iteration {N}/
|
|
1247
|
+
Display: `Revision iteration {N}/3 -- {blocker_count} blockers, {warning_count} warnings`
|
|
1186
1248
|
|
|
1187
1249
|
**Stall detection (U-P16):** If `issue_count >= prev_issue_count`:
|
|
1188
1250
|
Display: `Revision loop stalled — issue count not decreasing ({issue_count} issues remain after {N} iterations)`
|
|
@@ -1241,7 +1303,7 @@ Agent(
|
|
|
1241
1303
|
|
|
1242
1304
|
After planner returns -> spawn checker again (step 10), increment iteration_count.
|
|
1243
1305
|
|
|
1244
|
-
**If iteration_count >=
|
|
1306
|
+
**If iteration_count >= 3:**
|
|
1245
1307
|
|
|
1246
1308
|
Display: `Max iterations reached. {N} issues remain:` + issue list
|
|
1247
1309
|
|
|
@@ -1251,7 +1313,7 @@ Offer: 1) Force proceed, 2) Provide guidance and retry, 3) Abandon (U-P10)
|
|
|
1251
1313
|
|
|
1252
1314
|
**Skip if:** `--skip-bounce` flag, `--gaps` flag, or bounce is not activated.
|
|
1253
1315
|
|
|
1254
|
-
**Activation:** Bounce runs when `--bounce` flag is present OR `
|
|
1316
|
+
**Activation:** Bounce runs when `--bounce` flag is present OR `workflow.plan_bounce` config is `true`. The `--skip-bounce` flag always wins (disables bounce even if config enables it). The `--gaps` flag also disables bounce (gap-closure mode should not modify plans externally).
|
|
1255
1317
|
|
|
1256
1318
|
**Prerequisites:** `workflow.plan_bounce_script` must be set to a valid script path. If bounce is activated but no script is configured, display warning and skip:
|
|
1257
1319
|
```
|
|
@@ -1477,31 +1539,22 @@ Proactive, non-blocking coverage report gated on `workflow.post_planning_gaps`
|
|
|
1477
1539
|
`<decisions>` and cross-references each REQ-ID / D-ID against `${PHASE_DIR}/*-PLAN.md`.
|
|
1478
1540
|
|
|
1479
1541
|
```bash
|
|
1480
|
-
PLAN_POST_HOOKS_JSON=$(pp_run loop render-hooks plan:post --raw
|
|
1481
|
-
|
|
1542
|
+
PLAN_POST_HOOKS_JSON=$(pp_run loop render-hooks plan:post --raw)
|
|
1543
|
+
printf '%s' "$PLAN_POST_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('PLAN_POST_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
|
|
1482
1544
|
PHASE_REQ_IDS=$(pp_run query init.plan-phase "$PHASE" --pick phase_req_ids 2>/dev/null || echo TBD)
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
`
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
If the check command failed (non-zero `CHECK_EXIT`, empty output, or unparseable JSON):
|
|
1497
|
-
- `onError == "halt"` → halt and surface command error.
|
|
1498
|
-
- `onError == "skip"` → log a warning and continue to the next hook.
|
|
1499
|
-
|
|
1500
|
-
**Step 2 — read `GATE_RESULT.block` (boolean).** Only reached when command succeeded.
|
|
1501
|
-
|
|
1502
|
-
- If `hook.blocking == true` and `GATE_RESULT.block == true`: halt. (gap-analysis is always `blocking: false` so this branch is informational only.)
|
|
1503
|
-
- If `hook.blocking == false` (advisory): if `GATE_RESULT.block == true` or non-empty `table`/`summary`, output the gap table and continue. Advisory gates never block phase completion.
|
|
1504
|
-
- If `hook.blocking == true` and `GATE_RESULT.block == false`: continue silently.
|
|
1545
|
+
echo "PHASE_REQ_IDS=$PHASE_REQ_IDS"
|
|
1546
|
+
```
|
|
1547
|
+
|
|
1548
|
+
Set `GATE_POINT=plan:post`, `GATE_HOOKS_JSON=$PLAN_POST_HOOKS_JSON`,
|
|
1549
|
+
`GATE_POSITIONAL_ARG="${PHASE_DIR}"`, `GATE_POSITIONAL_ARG_2="${PHASE_REQ_IDS}"`, `GATE_STAGE=plan`
|
|
1550
|
+
— this point validates plan artifacts, and without the scope the trace gate would demand an
|
|
1551
|
+
execute-stage trace from every historical SUMMARY.md in the phase directory, hard-halting any re-plan
|
|
1552
|
+
of an executed phase — and `GATE_WS` to the
|
|
1553
|
+
active workstream name (empty in flat mode), then Read and
|
|
1554
|
+
follow `pp-core/workflows/execute-phase/steps/check-query-gate.md` — the single generic `check.query`
|
|
1555
|
+
gate enforcer already used at `plan:pre`, `execute:pre` and `execute:post` (GATE-02, D-VH-7). It
|
|
1556
|
+
dispatches every active gate entry at this point, not only gap-analysis, and owns the two-step
|
|
1557
|
+
contract, the halt and the message passthrough. Do not restate its loop here.
|
|
1505
1558
|
|
|
1506
1559
|
## 14. Present Final Status
|
|
1507
1560
|
|
|
@@ -38,6 +38,7 @@ Parse `$ARGUMENTS` for:
|
|
|
38
38
|
- `--validate` flag → store `$VALIDATE_MODE=true`
|
|
39
39
|
- `--discuss` flag → store `$DISCUSS_MODE=true`
|
|
40
40
|
- `--research` flag → store `$RESEARCH_MODE=true`
|
|
41
|
+
- `--from-debug <slug>` → store `$FROM_DEBUG_SLUG` (D-08: `debug.md` hands a confirmed root cause to a quick task). Sanitise it exactly as `debug.md` does: strip whitespace, reject unless it matches `^[a-z0-9][a-z0-9-]*$`, max 30 chars, reject any `..`, `/` or `\`; if invalid, print `Invalid --from-debug slug` and stop. If `.planning/debug/${FROM_DEBUG_SLUG}.md` does not exist, print `No debug session found with slug: ${FROM_DEBUG_SLUG}` and stop. Otherwise Steps 5 and 6 add that file to the planner's and the executor's reading lists; nothing else changes.
|
|
41
42
|
- Remaining text → use as `$DESCRIPTION` if non-empty
|
|
42
43
|
|
|
43
44
|
After parsing, normalize: if `$DISCUSS_MODE` and `$RESEARCH_MODE` and `$VALIDATE_MODE` are all true, set `$FULL_MODE=true`. This ensures `--discuss --research --validate` is treated identically to `--full`.
|
|
@@ -176,7 +177,49 @@ Quick tasks can run mid-phase - validation only checks ROADMAP.md exists, not ph
|
|
|
176
177
|
|
|
177
178
|
---
|
|
178
179
|
|
|
179
|
-
**Step 2.4: Vault
|
|
180
|
+
**Step 2.4: Vault admission and load gate**
|
|
181
|
+
|
|
182
|
+
Runs here because Step 2.5 is the first step that writes anything — it creates the quick-task branch
|
|
183
|
+
— and the gate has to decide before code can be written, not after.
|
|
184
|
+
|
|
185
|
+
Quick renders the loop points' own hooks (`plan:pre` here, `plan:post` in Step 5.55, `execute:pre`
|
|
186
|
+
for the executor prompt, `execute:post` in Step 6.1) and keeps only the `vault`
|
|
187
|
+
hooks, mechanically in each fence (D-30): no other capability's gate, step or
|
|
188
|
+
fragment is run or injected by quick. The vault's gates
|
|
189
|
+
therefore reach quick with no second copy of any rule (D-01). The renders pass no `--ws`: every
|
|
190
|
+
`pp_run` call here resolves the same workstream ladder as the admission verb, and each trace gate's
|
|
191
|
+
positional is the quick directory, which carries its own partition (D-73).
|
|
192
|
+
|
|
193
|
+
Admission first (D-28): bindings first, then every config file the gate reads is parsed. With
|
|
194
|
+
bindings present, a config the gate cannot read halts here, naming the file and the repair (D-05).
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
VAULT_ADMIT_PRESENT=$(pp_run query platform-bindings --pick present 2>/dev/null || echo true)
|
|
198
|
+
VAULT_ADMIT=inert
|
|
199
|
+
if [ "$VAULT_ADMIT_PRESENT" = true ]; then VAULT_ADMIT=$(pp_run vault admission 2>/dev/null || echo unrecognised); fi
|
|
200
|
+
case "$VAULT_ADMIT" in on) echo "VAULT_ADMIT=on" ;; off|inert) : ;; *) pp_run vault admission --explain; echo "PARETO_GATE_BLOCKED:vault.admission"; exit 1 ;; esac
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**If the fence printed no `VAULT_ADMIT=on` line** (`off` and `inert` print nothing): skip the rest of this step and the vault sub-steps below
|
|
204
|
+
(the planner fragments, Step 5.55, the anchor and executor fragments in Step 6, Step 6.1) silently
|
|
205
|
+
and continue to Step 2.5. Print nothing: a non-Pareto or `vault.enabled=false` project runs this
|
|
206
|
+
workflow byte-identically to how it ran before this gate existed (GATE-04).
|
|
207
|
+
|
|
208
|
+
**Otherwise, fetch and load-gate at `plan:pre`:**
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
QUICK_PLAN_PRE_HOOKS_JSON=$(pp_run loop render-hooks plan:pre --raw | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const j=JSON.parse(d);j.activeHooks=(j.activeHooks||[]).filter((x)=>x&&x.capId==='vault');process.stdout.write(JSON.stringify(j));}catch{process.stdout.write('');}")
|
|
212
|
+
printf '%s' "$QUICK_PLAN_PRE_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('QUICK_PLAN_PRE_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Set `VAULT_FETCH_HOOKS_JSON=$QUICK_PLAN_PRE_HOOKS_JSON`, then Read and execute
|
|
216
|
+
`pp-core/workflows/execute-phase/steps/vault-fetch.md` (hook mode). Then, in the
|
|
217
|
+
`QUICK_PLAN_PRE_HOOKS_JSON=` line that fence printed, find active entries where `kind == "gate"` and `check.query ==
|
|
218
|
+
"vault.status"`; if none, skip silently. Otherwise set `GATE_POINT=plan:pre` and
|
|
219
|
+
`GATE_HOOKS_JSON=$QUICK_PLAN_PRE_HOOKS_JSON`, leave `GATE_POSITIONAL_ARG`, `GATE_WS` and
|
|
220
|
+
`GATE_STAGE` empty (`vault.status` reads project state), then Read and follow
|
|
221
|
+
`pp-core/workflows/execute-phase/steps/check-query-gate.md`. That single enforcer (GATE-02) owns the
|
|
222
|
+
two-step contract, the halt and the message passthrough; none of them are restated here.
|
|
180
223
|
|
|
181
224
|
---
|
|
182
225
|
|
|
@@ -464,6 +507,16 @@ If research file not found, warn but continue: "Research agent did not produce o
|
|
|
464
507
|
|
|
465
508
|
**If NOT `$VALIDATE_MODE`:** Use standard `quick` mode.
|
|
466
509
|
|
|
510
|
+
Vault fragments for the planner: the `plan:pre` contributions `into: planner`, re-rendered and
|
|
511
|
+
filtered in this fence (a shell variable from Step 2.4 does not survive into this call). Skip unless
|
|
512
|
+
Step 2.4 printed `VAULT_ADMIT=on`. The fence prints the fragments; put that printed text verbatim where
|
|
513
|
+
the prompt says `${QUICK_PLANNER_HOOK_FRAGMENTS}` (nothing when it printed nothing).
|
|
514
|
+
|
|
515
|
+
```bash
|
|
516
|
+
QUICK_PLANNER_HOOK_FRAGMENTS=$(pp_run loop render-hooks plan:pre --raw | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const j=JSON.parse(d);j.activeHooks=(j.activeHooks||[]).filter((x)=>x&&x.capId==='vault');process.stdout.write(JSON.stringify(j));}catch{process.stdout.write('');}" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const h=(JSON.parse(d).activeHooks||[]).filter((x)=>x&&x.kind==='contribution'&&x.into==='planner'&&x.fragment&&typeof x.fragment.inline==='string');process.stdout.write(h.map((x)=>x.fragment.inline).join('\n\n'));}catch{process.stdout.write('');}")
|
|
517
|
+
if [ -n "$QUICK_PLANNER_HOOK_FRAGMENTS" ]; then printf '%s\n' "$QUICK_PLANNER_HOOK_FRAGMENTS"; fi
|
|
518
|
+
```
|
|
519
|
+
|
|
467
520
|
Display: `◆ Spawning planner... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
|
|
468
521
|
|
|
469
522
|
```
|
|
@@ -480,10 +533,13 @@ Agent(
|
|
|
480
533
|
- ./CLAUDE.md or ./.claude/CLAUDE.md (if exists — follow project-specific guidelines)
|
|
481
534
|
${DISCUSS_MODE ? '- ' + QUICK_DIR + '/' + quick_id + '-CONTEXT.md (User decisions — locked, do not revisit)' : ''}
|
|
482
535
|
${RESEARCH_MODE ? '- ' + QUICK_DIR + '/' + quick_id + '-RESEARCH.md (Research findings — use to inform implementation choices)' : ''}
|
|
536
|
+
${FROM_DEBUG_SLUG ? '- .planning/debug/' + FROM_DEBUG_SLUG + '.md (Debug session from --from-debug — the confirmed root cause this task fixes)' : ''}
|
|
483
537
|
</files_to_read>
|
|
484
538
|
|
|
485
539
|
${AGENT_SKILLS_PLANNER}
|
|
486
540
|
|
|
541
|
+
${QUICK_PLANNER_HOOK_FRAGMENTS}
|
|
542
|
+
|
|
487
543
|
**Project skills:** Check .claude/skills/ or .agents/skills/ directory (if either exists) — read SKILL.md files, plans should account for project skill rules
|
|
488
544
|
|
|
489
545
|
</planning_context>
|
|
@@ -633,6 +689,26 @@ Offer: 1) Force proceed, 2) Abort
|
|
|
633
689
|
|
|
634
690
|
---
|
|
635
691
|
|
|
692
|
+
**Step 5.55: plan:post trace gate (runs before Step 5.6)**
|
|
693
|
+
|
|
694
|
+
Skip silently unless Step 2.4 printed `VAULT_ADMIT=on`. Runs after the planner (and the checker under
|
|
695
|
+
`$VALIDATE_MODE`) and BEFORE Step 5.6, so a malformed or absent record halts the task with nothing
|
|
696
|
+
committed and no executor spawned (D-02, D-34).
|
|
697
|
+
|
|
698
|
+
```bash
|
|
699
|
+
QUICK_PLAN_POST_HOOKS_JSON=$(pp_run loop render-hooks plan:post --raw | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const j=JSON.parse(d);j.activeHooks=(j.activeHooks||[]).filter((x)=>x&&x.capId==='vault');process.stdout.write(JSON.stringify(j));}catch{process.stdout.write('');}")
|
|
700
|
+
printf '%s' "$QUICK_PLAN_POST_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('QUICK_PLAN_POST_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
In the `QUICK_PLAN_POST_HOOKS_JSON=` line that fence printed, find active entries where `kind == "gate"` and `check.query ==
|
|
704
|
+
"vault.trace"`; if none, skip silently. Otherwise set `GATE_POINT=plan:post`,
|
|
705
|
+
`GATE_HOOKS_JSON=$QUICK_PLAN_POST_HOOKS_JSON`, `GATE_POSITIONAL_ARG="${QUICK_DIR}"` and
|
|
706
|
+
`GATE_STAGE=plan` (the plan stage, tolerant: nothing has run yet, D-03), leave `GATE_WS` empty (a
|
|
707
|
+
quick directory carries its own partition), then Read and follow
|
|
708
|
+
`pp-core/workflows/execute-phase/steps/check-query-gate.md`; it owns the halt.
|
|
709
|
+
|
|
710
|
+
---
|
|
711
|
+
|
|
636
712
|
**Step 5.6: Pre-dispatch plan commit (worktree mode only)**
|
|
637
713
|
|
|
638
714
|
When `USE_WORKTREES !== "false"`, commit PLAN.md to the current branch **before** spawning the executor. This ensures the worktree inherits PLAN.md at its branch HEAD so the executor can read it via a worktree-rooted path — avoiding the main-repo path priming that triggers CC #36182 path-resolution drift.
|
|
@@ -674,9 +750,10 @@ fi
|
|
|
674
750
|
|
|
675
751
|
**Step 6: Spawn executor**
|
|
676
752
|
|
|
677
|
-
Capture current HEAD before spawning (used for worktree branch check):
|
|
753
|
+
Capture current HEAD before spawning (used for worktree branch check, and as the vault START anchor):
|
|
678
754
|
```bash
|
|
679
755
|
EXPECTED_BASE=$(git rev-parse HEAD)
|
|
756
|
+
pp_run vault anchor start "${QUICK_DIR}" --raw
|
|
680
757
|
if [ "${USE_WORKTREES:-true}" != "false" ]; then
|
|
681
758
|
QUICK_WORKTREE_MANIFEST=$(mktemp "${TMPDIR:-/tmp}/pp-quick-worktree-XXXXXX.json")
|
|
682
759
|
printf '{"worktrees":[]}\n' > "$QUICK_WORKTREE_MANIFEST"
|
|
@@ -684,6 +761,20 @@ if [ "${USE_WORKTREES:-true}" != "false" ]; then
|
|
|
684
761
|
fi
|
|
685
762
|
```
|
|
686
763
|
|
|
764
|
+
`vault anchor start` records HEAD (this `EXPECTED_BASE`) as the quick directory's START anchor
|
|
765
|
+
(D-31); the executor's record verb reads it, so the SUMMARY carries start and end. The verb prints
|
|
766
|
+
nothing and writes nothing unless `vault admission` answers `on`, so it needs no guard.
|
|
767
|
+
|
|
768
|
+
Vault fragments for the executor: the `execute:pre` contributions `into: executor`, from a filtered
|
|
769
|
+
render (never the unfiltered `--into` form of the render, which no capability filter narrows). Skip unless
|
|
770
|
+
Step 2.4 printed `VAULT_ADMIT=on`. The fence prints the fragments; put that printed text verbatim where the
|
|
771
|
+
prompt says `${QUICK_EXECUTOR_HOOK_FRAGMENTS}` (nothing when it printed nothing).
|
|
772
|
+
|
|
773
|
+
```bash
|
|
774
|
+
QUICK_EXECUTOR_HOOK_FRAGMENTS=$(pp_run loop render-hooks execute:pre --raw | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const j=JSON.parse(d);j.activeHooks=(j.activeHooks||[]).filter((x)=>x&&x.capId==='vault');process.stdout.write(JSON.stringify(j));}catch{process.stdout.write('');}" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const h=(JSON.parse(d).activeHooks||[]).filter((x)=>x&&x.kind==='contribution'&&x.into==='executor'&&x.fragment&&typeof x.fragment.inline==='string');process.stdout.write(h.map((x)=>x.fragment.inline).join('\n\n'));}catch{process.stdout.write('');}")
|
|
775
|
+
if [ -n "$QUICK_EXECUTOR_HOOK_FRAGMENTS" ]; then printf '%s\n' "$QUICK_EXECUTOR_HOOK_FRAGMENTS"; fi
|
|
776
|
+
```
|
|
777
|
+
|
|
687
778
|
Spawn pp-executor with plan reference:
|
|
688
779
|
|
|
689
780
|
```
|
|
@@ -717,10 +808,13 @@ MANDATORY: load every file listed here with the Read tool before you start the w
|
|
|
717
808
|
- .planning/STATE.md (Project state)
|
|
718
809
|
- ./CLAUDE.md or ./.claude/CLAUDE.md (Project instructions, if exists)
|
|
719
810
|
- .claude/skills/ or .agents/skills/ (Project skills, if either exists — list skills, read SKILL.md for each, follow relevant rules during implementation)
|
|
811
|
+
${FROM_DEBUG_SLUG ? '- .planning/debug/' + FROM_DEBUG_SLUG + '.md (Debug session from --from-debug — the confirmed root cause this task fixes)' : ''}
|
|
720
812
|
</files_to_read>
|
|
721
813
|
|
|
722
814
|
${AGENT_SKILLS_EXECUTOR}
|
|
723
815
|
|
|
816
|
+
${QUICK_EXECUTOR_HOOK_FRAGMENTS}
|
|
817
|
+
|
|
724
818
|
<submodule_commit_guard>
|
|
725
819
|
SUBMODULE_PATHS for this project: ${SUBMODULE_PATHS}
|
|
726
820
|
|
|
@@ -806,13 +900,33 @@ Note: For quick tasks producing multiple plans (rare), spawn executors in parall
|
|
|
806
900
|
|
|
807
901
|
---
|
|
808
902
|
|
|
903
|
+
**Step 6.1: execute:post trace gate**
|
|
904
|
+
|
|
905
|
+
Skip silently unless Step 2.4 printed `VAULT_ADMIT=on`. Strict, because a quick task is complete here: one plan,
|
|
906
|
+
one SUMMARY, nothing pending (D-03). Runs before code review, verification and the STATE.md update,
|
|
907
|
+
so a blocked task never gets a STATE.md row and never reaches the final commit (D-34); task commits
|
|
908
|
+
the executor already made stay in history, and the SEAL-01 check names them (D-02).
|
|
909
|
+
|
|
910
|
+
```bash
|
|
911
|
+
QUICK_EXECUTE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:post --raw | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const j=JSON.parse(d);j.activeHooks=(j.activeHooks||[]).filter((x)=>x&&x.capId==='vault');process.stdout.write(JSON.stringify(j));}catch{process.stdout.write('');}")
|
|
912
|
+
printf '%s' "$QUICK_EXECUTE_POST_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('QUICK_EXECUTE_POST_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
|
|
913
|
+
```
|
|
914
|
+
|
|
915
|
+
In the `QUICK_EXECUTE_POST_HOOKS_JSON=` line that fence printed, find active entries where `kind == "gate"` and `check.query ==
|
|
916
|
+
"vault.trace"`; if none, skip silently. Otherwise set `GATE_POINT=execute:post`,
|
|
917
|
+
`GATE_HOOKS_JSON=$QUICK_EXECUTE_POST_HOOKS_JSON`, `GATE_POSITIONAL_ARG="${QUICK_DIR}"` and
|
|
918
|
+
`GATE_UNPAIRED=strict`, leave `GATE_STAGE` and `GATE_WS` empty, then Read and follow
|
|
919
|
+
`pp-core/workflows/execute-phase/steps/check-query-gate.md`; it owns the halt.
|
|
920
|
+
|
|
921
|
+
---
|
|
922
|
+
|
|
809
923
|
**Step 6.25: Code review (auto)**
|
|
810
924
|
|
|
811
925
|
Skip this step entirely if `$FULL_MODE` is false.
|
|
812
926
|
|
|
813
927
|
**Capability gate:**
|
|
814
928
|
```bash
|
|
815
|
-
EXECUTE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:post --raw)
|
|
929
|
+
EXECUTE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:post --raw)
|
|
816
930
|
```
|
|
817
931
|
|
|
818
932
|
Resolve active step hooks from `EXECUTE_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "code-review"`.
|
|
@@ -26,7 +26,7 @@ Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`.
|
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
28
|
AUDITOR_MODEL=$(pp_run query resolve-model pp-security-auditor --raw)
|
|
29
|
-
VERIFY_POST_HOOKS_JSON=$(pp_run loop render-hooks verify:post --raw)
|
|
29
|
+
VERIFY_POST_HOOKS_JSON=$(pp_run loop render-hooks verify:post --raw)
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
Resolve active step hooks from `VERIFY_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "secure-phase"`.
|