@pareto4/pp-core 1.13.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/.claude-plugin/plugin.json +3 -3
  2. package/README.md +31 -12
  3. package/agents/pp-code-fixer.md +0 -11
  4. package/agents/pp-code-reviewer.md +1 -77
  5. package/agents/pp-debug-session-manager.md +9 -6
  6. package/agents/pp-executor.md +12 -29
  7. package/agents/pp-plan-checker.md +4 -4
  8. package/agents/pp-planner.md +34 -20
  9. package/agents/pp-vault-reviewer.md +100 -23
  10. package/agents/pp-verifier.md +1 -3
  11. package/bin/install.js +10 -3
  12. package/commands/pp-execute-phase.md +1 -3
  13. package/commands/pp-ns-manage.md +1 -1
  14. package/commands/pp-ns-review.md +1 -1
  15. package/commands/pp-plan-phase.md +1 -2
  16. package/commands/pp-vault-promote.md +7 -8
  17. package/commands/pp-vault-review.md +6 -5
  18. package/commands/pp-verify-work.md +1 -2
  19. package/gemini-extension.json +1 -1
  20. package/hooks/dist/pp-check-update.js +0 -0
  21. package/hooks/dist/pp-cursor-session-start.js +1 -1
  22. package/hooks/dist/pp-statusline.js +1 -1
  23. package/hooks/dist/pp-update-banner.js +0 -0
  24. package/hooks/pp-check-update.js +0 -0
  25. package/hooks/pp-cursor-session-start.js +1 -1
  26. package/hooks/pp-statusline.js +1 -1
  27. package/hooks/pp-update-banner.js +0 -0
  28. package/package.json +10 -18
  29. package/pareto-skills/_shared/create-project-board.sh +0 -0
  30. package/pareto-skills/pp-project-setup/SKILL.md +1 -1
  31. package/pp-core/bin/check-latest-version.cjs +0 -0
  32. package/pp-core/bin/detect-build-commands.sh +2 -2
  33. package/pp-core/bin/lib/capability-activation.cjs +83 -9
  34. package/pp-core/bin/lib/capability-registry.cjs +201 -229
  35. package/pp-core/bin/lib/capability-state.cjs +93 -1
  36. package/pp-core/bin/lib/capability-writer.cjs +3 -3
  37. package/pp-core/bin/lib/check-command-router.cjs +1906 -1514
  38. package/pp-core/bin/lib/clusters.cjs +3 -0
  39. package/pp-core/bin/lib/command-aliases.cjs +0 -35
  40. package/pp-core/bin/lib/commands.cjs +9 -4
  41. package/pp-core/bin/lib/compose-bindings.cjs +251 -88
  42. package/pp-core/bin/lib/config-loader.cjs +7 -103
  43. package/pp-core/bin/lib/config-schema.cjs +1 -1
  44. package/pp-core/bin/lib/config.cjs +151 -62
  45. package/pp-core/bin/lib/decisions.cjs +4 -4
  46. package/pp-core/bin/lib/discovery-vault-check.cjs +246 -0
  47. package/pp-core/bin/lib/frontmatter.cjs +1 -38
  48. package/pp-core/bin/lib/git-base-branch.cjs +11 -12
  49. package/pp-core/bin/lib/git-provider.cjs +9 -10
  50. package/pp-core/bin/lib/init-command-router.cjs +5 -8
  51. package/pp-core/bin/lib/init-contract.cjs +620 -738
  52. package/pp-core/bin/lib/init-interactive.cjs +62 -4
  53. package/pp-core/bin/lib/init.cjs +24 -51
  54. package/pp-core/bin/lib/install-profiles.cjs +1 -1
  55. package/pp-core/bin/lib/io.cjs +4 -2
  56. package/pp-core/bin/lib/loop-resolver.cjs +165 -129
  57. package/pp-core/bin/lib/org-profile.cjs +402 -161
  58. package/pp-core/bin/lib/package-identity.cjs +3 -3
  59. package/pp-core/bin/lib/phase-command-router.cjs +1 -29
  60. package/pp-core/bin/lib/phase-scope.cjs +1 -1
  61. package/pp-core/bin/lib/phase.cjs +11 -253
  62. package/pp-core/bin/lib/platform-bindings.cjs +40 -19
  63. package/pp-core/bin/lib/profile-output.cjs +1 -1
  64. package/pp-core/bin/lib/shell-command-projection.cjs +104 -1
  65. package/pp-core/bin/lib/state.cjs +11 -85
  66. package/pp-core/bin/lib/template.cjs +1 -1
  67. package/pp-core/bin/lib/vault-command-router.cjs +1682 -477
  68. package/pp-core/bin/lib/vault-coordinates.cjs +16 -7
  69. package/pp-core/bin/lib/vault-index.cjs +656 -0
  70. package/pp-core/bin/lib/vault-seal.cjs +1851 -0
  71. package/pp-core/bin/lib/vault-standards-promote.cjs +577 -0
  72. package/pp-core/bin/lib/vault-standards-review.cjs +293 -0
  73. package/pp-core/bin/lib/vault-standards.cjs +1504 -0
  74. package/pp-core/bin/lib/vault-trace.cjs +155 -2778
  75. package/pp-core/bin/lib/vault-update.cjs +10 -59
  76. package/pp-core/bin/lib/vault.cjs +2570 -950
  77. package/pp-core/bin/lib/verify.cjs +0 -11
  78. package/pp-core/bin/portable-timeout.sh +1 -1
  79. package/pp-core/bin/pp-tools.cjs +157 -54
  80. package/pp-core/bin/shared/config-defaults.manifest.json +0 -7
  81. package/pp-core/bin/shared/config-schema.manifest.json +0 -3
  82. package/pp-core/bin/shared/model-catalog.json +2 -2
  83. package/pp-core/bin/verify-reapply-patches.cjs +0 -0
  84. package/pp-core/org-profile.json +26 -0
  85. package/pp-core/references/autonomous-best-effort.md +8 -7
  86. package/pp-core/references/loop-hook-dispatch.md +0 -25
  87. package/pp-core/references/planner-gap-closure.md +0 -1
  88. package/pp-core/references/planner-tdd.md +0 -1
  89. package/pp-core/references/planner-vault-standards.md +311 -0
  90. package/pp-core/references/planning-config.md +0 -8
  91. package/pp-core/references/tdd.md +0 -1
  92. package/pp-core/templates/README.md +1 -0
  93. package/pp-core/templates/VAULT-REVIEW.md +56 -0
  94. package/pp-core/templates/phase-prompt.md +2 -6
  95. package/pp-core/workflows/_runtime-launcher.snippet.sh +0 -0
  96. package/pp-core/workflows/add-tests.md +55 -4
  97. package/pp-core/workflows/audit-fix.md +63 -2
  98. package/pp-core/workflows/audit-milestone.md +1 -1
  99. package/pp-core/workflows/autonomous.md +85 -11
  100. package/pp-core/workflows/check-todos.md +13 -2
  101. package/pp-core/workflows/code-review-fix.md +59 -3
  102. package/pp-core/workflows/code-review.md +10 -57
  103. package/pp-core/workflows/complete-milestone.md +1 -1
  104. package/pp-core/workflows/debug.md +54 -4
  105. package/pp-core/workflows/discovery-sprint/prefill.md +19 -7
  106. package/pp-core/workflows/discovery-sprint/prototype.md +46 -49
  107. package/pp-core/workflows/discovery-sprint/session-13-gates.md +2 -0
  108. package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +1 -3
  109. package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +1 -3
  110. package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +1 -3
  111. package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +20 -24
  112. package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +1 -3
  113. package/pp-core/workflows/discovery-sprint/sessions/06-security.md +1 -3
  114. package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +1 -3
  115. package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +1 -3
  116. package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +1 -3
  117. package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +1 -6
  118. package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +1 -3
  119. package/pp-core/workflows/discovery-sprint/sessions/12-delivery-model.md +1 -3
  120. package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +1 -3
  121. package/pp-core/workflows/discovery-sprint/templates/context-template.md +1 -1
  122. package/pp-core/workflows/discovery-sprint/vault-context.md +207 -0
  123. package/pp-core/workflows/discovery-sprint.md +7 -3
  124. package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +4 -4
  125. package/pp-core/workflows/discovery-to-build/templates/pp-handoff.md +43 -1
  126. package/pp-core/workflows/discovery-to-build.md +10 -2
  127. package/pp-core/workflows/discuss-phase.md +3 -10
  128. package/pp-core/workflows/execute-phase/steps/check-query-gate.md +327 -0
  129. package/pp-core/workflows/execute-phase/steps/client-context-gate.md +3 -2
  130. package/pp-core/workflows/execute-phase/steps/cross-ai-delegation.md +1 -1
  131. package/pp-core/workflows/execute-phase/steps/execute-pre-dispatch.md +78 -0
  132. package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
  133. package/pp-core/workflows/execute-phase/steps/post-merge-gate.md +6 -8
  134. package/pp-core/workflows/execute-phase/steps/vault-fetch.md +115 -14
  135. package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +219 -20
  136. package/pp-core/workflows/execute-phase/steps/verify-post-gate.md +147 -0
  137. package/pp-core/workflows/execute-phase.md +152 -128
  138. package/pp-core/workflows/execute-plan.md +54 -6
  139. package/pp-core/workflows/fast.md +53 -4
  140. package/pp-core/workflows/help/modes/full.md +3 -3
  141. package/pp-core/workflows/init/steps/client-context-capture.md +101 -0
  142. package/pp-core/workflows/init/steps/gitlab-provisioning.md +130 -0
  143. package/pp-core/workflows/init/steps/project-md-deferral-narration.md +66 -0
  144. package/pp-core/workflows/init/steps/reachability-outcome.md +70 -0
  145. package/pp-core/workflows/init.md +232 -272
  146. package/pp-core/workflows/new-project.md +31 -23
  147. package/pp-core/workflows/plan-phase.md +98 -45
  148. package/pp-core/workflows/quick.md +117 -3
  149. package/pp-core/workflows/secure-phase.md +1 -1
  150. package/pp-core/workflows/ship.md +57 -28
  151. package/pp-core/workflows/undo.md +1 -1
  152. package/pp-core/workflows/update.md +3 -3
  153. package/pp-core/workflows/validate-phase.md +58 -3
  154. package/pp-core/workflows/vault-review.md +161 -23
  155. package/pp-core/workflows/vault-write-back.md +73 -110
  156. package/pp-core/workflows/verify-work.md +12 -14
  157. package/scripts/changeset/cli.cjs +6 -5
  158. package/scripts/changeset/lint.cjs +0 -0
  159. package/scripts/changeset/new.cjs +33 -50
  160. package/scripts/dev-env.cjs +25 -85
  161. package/scripts/gen-capability-registry.cjs +120 -13
  162. package/scripts/lib/allowlist-ratchet.cjs +1 -103
  163. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -2
  164. package/scripts/lint-docs-required.cjs +0 -0
  165. package/scripts/lint-pr-check-project-dir.cjs +1 -3
  166. package/scripts/lint-test-file-count.allowlist.json +3 -19
  167. package/scripts/lint-test-file-count.cjs +5 -6
  168. package/scripts/prompt-injection-scan.sh +19 -17
  169. package/scripts/release-channel.cjs +0 -0
  170. package/scripts/sync-manifest-versions.cjs +5 -4
  171. package/scripts/sync-rulesets.sh +1 -1
  172. package/scripts/update-size-baseline.cjs +30 -274
  173. package/scripts/verify-opengsd-sweep.cjs +3 -5
  174. package/scripts/workflow-size.cjs +9 -61
  175. package/pp-core/bin/lib/dispatch-plan.cjs +0 -483
  176. package/pp-core/bin/lib/install-run.cjs +0 -536
  177. package/pp-core/bin/lib/loop-gates.cjs +0 -213
  178. package/pp-core/bin/lib/phase-manifest.cjs +0 -527
  179. package/pp-core/bin/lib/phase-tier.cjs +0 -480
  180. package/pp-core/bin/lib/plan-graph.cjs +0 -368
  181. package/pp-core/bin/lib/practices-review-check.cjs +0 -938
  182. package/pp-core/bin/lib/vault-audit.cjs +0 -2070
  183. package/pp-core/bin/lib/vault-practices.cjs +0 -1990
  184. package/pp-core/bin/lib/vault-review.cjs +0 -2359
  185. package/pp-core/bin/lib/vault-write-back.cjs +0 -877
  186. package/pp-core/references/executor-vault-trace.md +0 -47
  187. package/pp-core/references/planner-plan-graph.md +0 -66
  188. package/pp-core/references/planner-vault-practices.md +0 -112
  189. package/pp-core/templates/practices/README.md +0 -251
  190. package/pp-core/templates/practices/error-handling.md +0 -18
  191. package/pp-core/templates/practices/minimal-comments.md +0 -14
  192. package/pp-core/templates/practices/naming-convention.md +0 -18
  193. package/pp-core/templates/practices/practice-template.md +0 -23
  194. package/pp-core/workflows/discovery-sprint/vault-fetch.md +0 -37
  195. package/pp-core/workflows/execute-phase/steps/checkpoint-handling.md +0 -45
  196. package/pp-core/workflows/execute-phase/steps/install-run.md +0 -29
  197. package/pp-core/workflows/execute-phase/steps/phase-close-rebaseline.md +0 -23
  198. package/pp-core/workflows/execute-phase/steps/serial-group-dispatch.md +0 -73
  199. package/pp-core/workflows/execute-phase/steps/vault-door-gate.md +0 -19
  200. package/pp-core/workflows/plan-phase/steps/phase-tier.md +0 -43
  201. package/scripts/lib/size-budget.cjs +0 -311
  202. package/scripts/lint-neutrality-names.cjs +0 -694
  203. package/scripts/lint-org-coordinates.allowlist.json +0 -35
  204. package/scripts/lint-org-coordinates.cjs +0 -426
@@ -267,18 +267,65 @@ PHASE_STATE=$(pp_run query init.phase-op ${PHASE_NUM})
267
267
 
268
268
  Check `has_context`. If false → go to handle_blocker: "Discuss for phase ${PHASE_NUM} did not produce CONTEXT.md."
269
269
 
270
- **3a.5. UI Design Contract (Frontend Phases)**
270
+ **3a.5. plan:pre dispatch — fetch, design contract, then gate**
271
+
272
+ Admission first (D-28): a config the gate cannot read renders no vault hook, so this runs before the render.
273
+
274
+ ```bash
275
+ VAULT_ADMIT_PRESENT=$(pp_run query platform-bindings --pick present 2>/dev/null || echo true)
276
+ VAULT_ADMIT=inert
277
+ if [ "$VAULT_ADMIT_PRESENT" = true ]; then VAULT_ADMIT=$(pp_run vault admission 2>/dev/null || echo unrecognised); fi
278
+ 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
279
+ ```
271
280
 
272
281
  Resolve active `plan:pre` hooks:
273
282
 
274
283
  ```bash
275
284
  UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1)
276
- HOOKS_JSON=$(pp_run loop render-hooks plan:pre --raw --phase "${PHASE_NUM}") || exit 1
285
+ HOOKS_JSON=$(pp_run loop render-hooks plan:pre --raw)
286
+ printf '%s' "$HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
277
287
  ```
278
288
 
279
- Read the `activeHooks` array directly from `HOOKS_JSON` (in-context — do NOT invoke a shell pipeline). **Compute the active UI step hooks** = entries from `activeHooks` where `kind == "step"` and `ref.skill` is set. **If there are NO active step hooks → skip silently to 3b.** (This covers `workflow.ui_phase=false` — including configurations where only a gate-only entry is present, e.g. `ui_phase=false` + `ui_safety_gate=true` produces `activeHooks=[{kind:"gate"}]`. Autonomous never runs the plan:pre gate — it is always pipeline mode — so a gate-only active set is equivalent to no active step and is silently skipped here. This matches OLD §3a.5 behaviour.)
289
+ Read the `activeHooks` array directly from the printed `HOOKS_JSON=` line (in-context — do NOT invoke a shell pipeline).
290
+
291
+ **Policy — pipeline mode is a reason to gate, not a reason to skip (D-VH-6).** Autonomous **runs**
292
+ the `plan:pre` gate, and its step filter admits `ref.command`-shaped hooks as well as `ref.skill`
293
+ ones. Both reverse what this section previously shipped. `--auto` dispatches every step-hook shape
294
+ it understands, then runs the gate, in that order.
295
+
296
+ Run the three sub-steps below **in order**. §3a.5-iii is reached on every path — the early exits in
297
+ §3a.5-ii skip to it, never past it.
298
+
299
+ **3a.5-i. Step hooks — fetch first.**
300
+
301
+ **Compute the active step hooks** = entries from `activeHooks` where `kind == "step"`. Route each by
302
+ the shape of its `ref`, in array order:
303
+
304
+ - **`ref.skill` is set** → a skill-shaped step hook; it is handled by §3a.5-ii below (this is the
305
+ UI-SPEC path and its existing behaviour is unchanged).
306
+ - **`ref.command` is set and `capId == "vault"`** → set `VAULT_FETCH_HOOKS_JSON=$HOOKS_JSON`,
307
+ then Read and execute
308
+ `pp-core/workflows/execute-phase/steps/vault-fetch.md`, the same bespoke `plan:pre` vault fetch +
309
+ summary dispatch `plan-phase.md` uses. Do not invent a second shape for it.
310
+ - **`ref.command` is set and `capId` is anything else** → not handled here. Display
311
+ `⚠ plan:pre step hook from capability '${capId}' has an unhandled ref shape (ref.command) and was skipped in autonomous mode.`
312
+ and continue — a silently dropped hook shape is the defect this section exists to fix.
313
+
314
+ **If there are NO active step hooks at all →** Continue to §3a.5-ii anyway: there is nothing to dispatch here, but §3a.5-ii owns `ui.plan-gate` on every activation set that renders it — the gate-only set included — while §3a.5-iii skips that entry unconditionally, and §3a.5-ii self-skips silently when no UI hook of either kind is active.
280
315
 
281
- (At least one active step hook ⇒ `workflow.ui_phase` is on.) Run the UI-SPEC gate:
316
+ **3a.5-ii. UI design contract (frontend phases).**
317
+
318
+ Let the **active UI step hooks** be the `kind == "step"` entries with `ref.skill` set, and the **UI
319
+ gate entry** be a `kind == "gate"` entry whose `check.query` is `ui.plan-gate`. Run this sub-step
320
+ whenever **any** `plan:pre` UI hook is active — step hooks, the gate entry, or both — mirroring
321
+ `plan-phase.md` §5.6's own rule. **If there is no active step hook AND no gate entry → skip silently
322
+ to 3a.5-iii** (`workflow.ui_phase` and `workflow.ui_safety_gate` both off; unchanged inertness).
323
+
324
+ This sub-step OWNS `ui.plan-gate` on every activation set that renders it — the gate-only set
325
+ (`ui_phase=false` + `ui_safety_gate=true`, producing `activeHooks=[{kind:"gate"}]`) included, where
326
+ there is no UI step to dispatch but the gate is still active and still gets run here.
327
+
328
+ Run the UI-SPEC gate:
282
329
 
283
330
  ```bash
284
331
  GATE=$(pp_run check ui-plan-gate "${PHASE_NUM}" --raw)
@@ -286,17 +333,19 @@ GATE=$(pp_run check ui-plan-gate "${PHASE_NUM}" --raw)
286
333
 
287
334
  Read `frontend` and `hasUiSpec` from `GATE` (in-context).
288
335
 
289
- **If `frontend` is false:** Skip silently to 3b.
336
+ **If `frontend` is false:** Skip silently to 3a.5-iii.
290
337
 
291
- **If `hasUiSpec` is true (UI-SPEC already exists):** Skip silently to 3b.
338
+ **If `hasUiSpec` is true (UI-SPEC already exists):** Skip silently to 3a.5-iii.
292
339
 
293
- **Otherwise (frontend phase + no UI-SPEC):** For each active step hook (the `kind == "step"` set from above, in array order):
340
+ **Otherwise (frontend phase + no UI-SPEC) with no active step hook — the gate-only set:** Display warning `Phase ${PHASE_NUM}: no active UI step hook can generate the missing UI-SPEC — continuing without design contract.` and proceed to 3a.5-iii. NON-BLOCKING, the pipeline-mode outcome `plan-phase.md` Branch 5 is designed for.
341
+
342
+ **Otherwise (frontend phase + no UI-SPEC) with active step hooks:** For each active step hook (the `kind == "step"` set from above, in array order):
294
343
 
295
344
  ```
296
345
  Skill(skill="pp-${ref.skill}", args="${PHASE_NUM}")
297
346
  ```
298
347
 
299
- (Prepend `pp-` to `ref.skill` — so `ui-phase` → `pp-ui-phase`. Bare `${PHASE_NUM}` args — autonomous style, same pattern as the verify:post dispatch.) Entries where `kind == "gate"` are silently ignored — autonomous is always pipeline mode, there is no blocking gate here.
348
+ (Prepend `pp-` to `ref.skill` — so `ui-phase` → `pp-ui-phase`. Bare `${PHASE_NUM}` args — autonomous style, same pattern as the verify:post dispatch.) Entries where `kind == "gate"` are not dispatched *here*; they are handled by §3a.5-iii below, which owns every gate at this point except `ui.plan-gate` — this sub-step owns that one, on every activation set that renders it.
300
349
 
301
350
  After all step hooks return, re-read:
302
351
 
@@ -304,7 +353,32 @@ After all step hooks return, re-read:
304
353
  UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1)
305
354
  ```
306
355
 
307
- **If `UI_SPEC_FILE` is still empty:** Display warning `Phase ${PHASE_NUM}: UI-SPEC generation did not produce output — continuing without design contract.` and proceed to 3b. NON-BLOCKING.
356
+ **If `UI_SPEC_FILE` is still empty:** Display warning `Phase ${PHASE_NUM}: UI-SPEC generation did not produce output — continuing without design contract.` and proceed to 3a.5-iii. NON-BLOCKING.
357
+
358
+ **3a.5-iii. The plan:pre gate.**
359
+
360
+ Reached on every path through §3a.5, including the ones that skipped the UI work. It runs *after*
361
+ §3a.5-i so the vault fetch has already been attempted — fetch first, then decide (GATE-03), so a
362
+ fresh clone with a reachable vault passes rather than being blocked for a cache it never had a
363
+ chance to populate.
364
+
365
+ `ui.plan-gate` is handled *before* this dispatch — §3a.5-ii ran it with its own `${PHASE_NUM}`
366
+ positional and owns its outcome on every activation set that renders it — so skip that entry; the
367
+ enforcer never sees it.
368
+
369
+ Set `GATE_POINT=plan:pre`, `GATE_HOOKS_JSON=$HOOKS_JSON` (the array already rendered above) and
370
+ leave `GATE_POSITIONAL_ARG` empty deliberately (`vault.status` reads project state, not a phase;
371
+ every plan:pre gate needing one is caller-handled — D-VH-7), then Read and follow
372
+ `pp-core/workflows/execute-phase/steps/check-query-gate.md` — the single generic `check.query` gate
373
+ enforcer (GATE-02). It owns the halt decision, the two-step contract and the message passthrough;
374
+ do not restate any of them here.
375
+
376
+ If no `kind == "gate"` entry is active, the enforcer's own inertness guard returns immediately and
377
+ prints nothing, so a project with the capability off is unaffected. When a gate does block, the
378
+ enforcer prints its named token and runs `exit 1`, stopping the unattended chain rather than
379
+ building the phase with no client standards loaded.
380
+
381
+ Then proceed to 3b.
308
382
 
309
383
  **3b. Plan**
310
384
 
@@ -406,7 +480,7 @@ Auto-invoke code review and fix chain. Autonomous mode chains both review and fi
406
480
 
407
481
  **Capability dispatch:**
408
482
  ```bash
409
- EXECUTE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:post --raw --phase "${PHASE_NUM}") || exit 1
483
+ EXECUTE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:post --raw)
410
484
  ```
411
485
 
412
486
  Resolve active step hooks from `EXECUTE_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "code-review"`.
@@ -481,7 +555,7 @@ Resolve the active post-verification hooks and the UI-SPEC gate:
481
555
 
482
556
  ```bash
483
557
  UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1)
484
- HOOKS_JSON=$(pp_run loop render-hooks verify:post --raw --phase "${PHASE_NUM}") || exit 1
558
+ HOOKS_JSON=$(pp_run loop render-hooks verify:post --raw)
485
559
  ```
486
560
 
487
561
  Read the `activeHooks` array directly from the `HOOKS_JSON` value already in context (do not invoke a shell `jq` pipeline — parse as the JSON object it is). **If `activeHooks` is empty or absent:** skip silently to the iterate step.
@@ -127,11 +127,22 @@ Use AskUserQuestion:
127
127
  </step>
128
128
 
129
129
  <step name="execute_action">
130
- **Work on it now:** first Read and execute `pp-core/workflows/execute-phase/steps/vault-door-gate.md`; a stop leaves the todo pending and ends here. Then:
130
+ **Work on it now:** admission first (D-11, D-12, D-28):
131
+
132
+ ```bash
133
+ VAULT_ADMIT_PRESENT=$(pp_run query platform-bindings --pick present 2>/dev/null || echo true)
134
+ VAULT_ADMIT=inert
135
+ if [ "$VAULT_ADMIT_PRESENT" = true ]; then VAULT_ADMIT=$(pp_run vault admission 2>/dev/null || echo unrecognised); fi
136
+ 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
137
+ ```
138
+
131
139
  ```bash
132
140
  mv ".planning/todos/pending/[filename]" ".planning/todos/completed/"
133
141
  ```
134
- Update STATE.md todo count. Present problem/solution context. Begin work or ask how to proceed.
142
+ Update STATE.md todo count. **If the admission fence printed `VAULT_ADMIT=on`:** do not do the work inline; invoke
143
+ `/pp-quick "[todo title]"` via SlashCommand, so the work carries the vault mode's record and the trace
144
+ gates (no artifact here could hold a door record; quick owns ad-hoc governed source), then continue
145
+ below. **Otherwise:** present problem/solution context and begin work or ask how to proceed, as before.
135
146
 
136
147
  **Add to phase plan:**
137
148
  Note todo reference in phase planning notes. Keep in pending. Return to list or exit.
@@ -77,7 +77,7 @@ FIX_REPORT_PATH="${PHASE_DIR}/${PADDED_PHASE}-REVIEW-FIX.md"
77
77
  Check if code review is active via the capability registry:
78
78
 
79
79
  ```bash
80
- EXECUTE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:post --raw) || exit 1
80
+ EXECUTE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:post --raw)
81
81
  ```
82
82
 
83
83
  Resolve active step hooks from `EXECUTE_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "code-review"`.
@@ -182,9 +182,47 @@ done < <(REVIEW_PATH="${REVIEW_PATH}" node -e "
182
182
  If REVIEW.md contains a `files_reviewed_list` frontmatter field, use that as the re-review scope. If not present, fall back to re-reviewing the full phase (same behavior as initial code-review).
183
183
  </step>
184
184
 
185
- <step name="spawn_fixer">
186
- Before the first fixer spawn, Read and execute `pp-core/workflows/execute-phase/steps/vault-door-gate.md`; a stop ends this run with no fix applied.
185
+ <step name="vault_admission_gate">
186
+ Vault admission and load gate (D-11, D-12, D-28): runs before the fixer commits anything. A config the gate cannot
187
+ read halts here with the bindings present (D-05); without bindings, or with `vault.enabled` false,
188
+ nothing below prints or writes anything (D-13).
189
+
190
+ ```bash
191
+ VAULT_ADMIT_PRESENT=$(pp_run query platform-bindings --pick present 2>/dev/null || echo true)
192
+ VAULT_ADMIT=inert
193
+ if [ "$VAULT_ADMIT_PRESENT" = true ]; then VAULT_ADMIT=$(pp_run vault admission 2>/dev/null || echo unrecognised); fi
194
+ 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
195
+ ```
196
+
197
+ **If the fence printed no `VAULT_ADMIT=on` line** (`off` and `inert` print nothing): skip the rest of this block silently. Otherwise run the load
198
+ gate on the `execute:pre` payload, filtered in the fence to the `vault`
199
+ capability (D-30):
200
+
201
+ ```bash
202
+ CRF_EXECUTE_PRE_HOOKS_JSON=$(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('');}")
203
+ printf '%s' "$CRF_EXECUTE_PRE_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('CRF_EXECUTE_PRE_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
204
+ ```
205
+
206
+ Set `VAULT_FETCH_HOOKS_JSON=$CRF_EXECUTE_PRE_HOOKS_JSON`, then Read and execute
207
+ `pp-core/workflows/execute-phase/steps/vault-fetch.md` (hook mode). Then, in the
208
+ `CRF_EXECUTE_PRE_HOOKS_JSON=` line that fence printed, find active entries where `kind == "gate"` and `check.query ==
209
+ "vault.status"`; if none, skip silently. Otherwise set `GATE_POINT=execute:pre` and
210
+ `GATE_HOOKS_JSON=$CRF_EXECUTE_PRE_HOOKS_JSON`, leave `GATE_POSITIONAL_ARG`, `GATE_WS` and
211
+ `GATE_STAGE` empty, then Read and follow `pp-core/workflows/execute-phase/steps/check-query-gate.md`;
212
+ it owns the halt.
187
213
 
214
+ Then record the door's START anchor, before the first `pp-code-fixer` spawn (`code-review --fix` reaches this file, so it inherits the gate and the record) (D-31):
215
+
216
+ ```bash
217
+ pp_run vault door-record --begin --door code-review-fix --raw
218
+ ```
219
+
220
+ It records HEAD in `.planning/.vault-door-starts.json`, where the record step reads it back: a shell
221
+ variable would not survive into that later step, and the agent never types a sha. It prints nothing
222
+ and writes nothing unless `vault admission` answers `on`.
223
+ </step>
224
+
225
+ <step name="spawn_fixer">
188
226
  Spawn the pp-code-fixer agent with config (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze):
189
227
 
190
228
  ```bash
@@ -388,6 +426,24 @@ fi
388
426
  This commit happens ONCE at the end of the workflow, after all iterations (if --auto) complete. Not per-iteration.
389
427
  </step>
390
428
 
429
+ <step name="vault_door_record">
430
+ One record per run, after all iterations (the fixer commits each finding itself).
431
+
432
+ Vault door record (D-12): after the door's last source commit, set `DOOR_DIR="${PHASE_DIR}"`,
433
+ `DOOR_PADDED="${PADDED_PHASE}"` and `DOOR_PHASE="${PHASE}"`, then run:
434
+
435
+ ```bash
436
+ DOOR_RUN=$(date -u +%Y%m%dT%H%M%SZ)
437
+ pp_run vault door-record --door code-review-fix --artifact "${DOOR_DIR}/${DOOR_PADDED}-door-${DOOR_RUN}-REVIEW-FIX.md" --phase "$DOOR_PHASE" --raw
438
+ ```
439
+
440
+ The verb writes a `## Vault Door Record` (mode, vault ref and sha, governing phase, the start `--begin`
441
+ recorded and the end commit; the agent never types a sha) into a fresh per-run artifact, because it refuses a second record
442
+ in one file (D-57) and a rewritten report would drop the earlier run's coverage (D-79). It prints
443
+ nothing and writes nothing unless `vault admission` answers `on`. When it wrote the file and
444
+ `commit_docs` is true, commit the `artifact` path it printed: `pp_run query commit "docs(${PADDED_PHASE}): vault door record for code-review-fix" --files "<that artifact>"`.
445
+ </step>
446
+
391
447
  <step name="present_results">
392
448
  Parse REVIEW-FIX.md frontmatter and present formatted summary to user.
393
449
 
@@ -75,10 +75,19 @@ fi
75
75
  </step>
76
76
 
77
77
  <step name="check_config_gate">
78
+ Admission first (D-28): a config the gate cannot read halts here, before the render; without bindings it is inert.
79
+
80
+ ```bash
81
+ VAULT_ADMIT_PRESENT=$(pp_run query platform-bindings --pick present 2>/dev/null || echo true)
82
+ VAULT_ADMIT=inert
83
+ if [ "$VAULT_ADMIT_PRESENT" = true ]; then VAULT_ADMIT=$(pp_run vault admission 2>/dev/null || echo unrecognised); fi
84
+ 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
85
+ ```
86
+
78
87
  Check if code review is active via the capability registry:
79
88
 
80
89
  ```bash
81
- EXECUTE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:post --raw) || exit 1
90
+ EXECUTE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:post --raw)
82
91
  ```
83
92
 
84
93
  Resolve active step hooks from `EXECUTE_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "code-review"`.
@@ -90,14 +99,6 @@ Code review skipped (code-review capability inactive)
90
99
  Exit workflow.
91
100
 
92
101
  Default is active through the Capability Registry schema — only skip when the registry resolves no active code-review step hook. This check runs AFTER phase validation so invalid phase errors are shown first.
93
-
94
- Resolve the practices contribution independently, from the SAME `EXECUTE_POST_HOOKS_JSON` variable already fetched above — do not add a second `pp_run loop render-hooks` call:
95
-
96
- ```bash
97
- PRACTICES_CONTRIBUTION_FRAGMENT=""
98
- ```
99
-
100
- Resolve active entries in `EXECUTE_POST_HOOKS_JSON` where `kind == "contribution"` and `into == "pp-code-reviewer"`, and capture that entry's `fragment.inline` verbatim into `PRACTICES_CONTRIBUTION_FRAGMENT`. When no such entry is active, `PRACTICES_CONTRIBUTION_FRAGMENT` stays empty and the review runs exactly as it does today — the practices dimension is inert, not degraded.
101
102
  </step>
102
103
 
103
104
  <step name="resolve_depth">
@@ -497,16 +498,6 @@ if [ -n "$FALLOW_JSON_PATH" ] && [ -f "$FALLOW_JSON_PATH" ]; then
497
498
  fi
498
499
  ```
499
500
 
500
- Build practices contribution block for agent:
501
- ```bash
502
- PRACTICES_CONTRIBUTION_BLOCK=""
503
- if [ -n "$PRACTICES_CONTRIBUTION_FRAGMENT" ]; then
504
- # Escape any literal closing tag before embedding; the closing tag literal is escaped so text arriving from outside this workflow cannot end the block early and steer the reviewer.
505
- SAFE_PRACTICES_FRAGMENT=$(echo "$PRACTICES_CONTRIBUTION_FRAGMENT" | sed 's#</practices_contribution>#<\/practices_contribution>#g')
506
- PRACTICES_CONTRIBUTION_BLOCK=$(printf '<practices_contribution>\n%s\n</practices_contribution>\n' "$SAFE_PRACTICES_FRAGMENT")
507
- fi
508
- ```
509
-
510
501
  Spawn the pp-code-reviewer agent:
511
502
 
512
503
  Print: `◆ Spawning code reviewer... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
@@ -519,8 +510,6 @@ ${FILES_TO_READ}
519
510
 
520
511
  ${STRUCTURAL_FINDINGS_BLOCK}
521
512
 
522
- ${PRACTICES_CONTRIBUTION_BLOCK}
523
-
524
513
  <config>
525
514
  depth: ${REVIEW_DEPTH}
526
515
  phase_dir: ${PHASE_DIR}
@@ -581,30 +570,6 @@ fi
581
570
  ```
582
571
  </step>
583
572
 
584
- <step name="check_practice_boundaries">
585
- This is a safety report about untrusted client vault text already written to `${REVIEW_PATH}`, ahead of `dispatch_fix`, and never skipped when `--fix` short-circuits `present_results`. A boundary shortfall is a defect in the report, not the reviewed code, so this check never changes an exit status — failing the review would punish the wrong artifact. The detection logic lives in `src/practices-review-check.cts`, a compiled module whose own test suite (`tests/practices-review-check.test.cjs`) pins the property that a malformed finding can only ever change its own verdict, never a sibling's.
586
-
587
- ```bash
588
- pp_run check practices-review --review "${REVIEW_PATH}" --boundaries 2>/dev/null || true
589
- ```
590
- </step>
591
-
592
- <step name="check_unfenced_vault_quotes">
593
- Safety report about client vault text already in `${REVIEW_PATH}`, scoped to the WHOLE file — the sibling above cannot see a verbatim client quote unfenced in narrative prose. The comparison corpus is the client's own words from inside the boundary lines only, never the fixed reference-data sentences the check itself prepends to every excerpt. Reports findings only and never changes an exit status — a quote shortfall is a defect in the review, not the reviewed code. The detection logic lives in the same compiled `src/practices-review-check.cts` module as the sibling step above, with its own pinned regression tests.
594
-
595
- **Resolve and compare in one block**, deliberately: the block resolves and consumes the corpus in one invocation AND decides whether to attempt the resolution from inside that same invocation, because a gate read from another fenced block is the identical failure the merge exists to prevent. `REVIEW_FILES` and `REVIEW_PATH` are still read from earlier in the workflow — they are this step's actual inputs, not its gate — and both now degrade visibly rather than silently: an empty `REVIEW_PATH` produces an operator-visible usage line instead of a byte-identical clean result (the CLI seam's empty-value guard, T-27-R8-05), and an empty or unset `REVIEW_FILES` produces its own one-line notice from inside this same block, before the corpus is ever resolved — an unresolved comparison corpus is never mistaken for a clean result. A test harness can supply both `REVIEW_PATH` and `VAULT_QUOTE_CORPUS` directly, no vault/matcher/model:
596
-
597
- ```bash
598
- VAULT_QUOTE_CORPUS=""
599
- if [ -z "${REVIEW_FILES[@]+x}" ]; then
600
- echo "practices quote check: no review files in scope — corpus not resolved"
601
- elif ! VAULT_QUOTE_CORPUS=$(pp_run vault practices match "${REVIEW_FILES[@]}" --raw 2>/dev/null); then
602
- VAULT_QUOTE_CORPUS=""
603
- fi
604
- VAULT_QUOTE_CORPUS="${VAULT_QUOTE_CORPUS}" pp_run check practices-review --review "${REVIEW_PATH}" --quotes 2>/dev/null || true
605
- ```
606
- </step>
607
-
608
573
  <step name="dispatch_fix">
609
574
  If the `--fix` flag was passed (`FIX_FLAG=true`), delegate to the `code-review-fix.md` workflow
610
575
  to auto-apply findings from the REVIEW.md that was just written (or that already existed).
@@ -668,15 +633,6 @@ INFO=$(echo "$FRONTMATTER" | grep "info:" | head -1 | cut -d: -f2 | xargs)
668
633
  TOTAL=$(echo "$FRONTMATTER" | grep "total:" | head -1 | cut -d: -f2 | xargs)
669
634
  ```
670
635
 
671
- The six lines above take the first match over the whole frontmatter and therefore read the bugs/security numbers only — this is why the practices key below is read from its own slice and written after the existing counts (D-07):
672
-
673
- ```bash
674
- # Scoped read: the practices: block only, so its total: line can never collide with
675
- # the bugs/security first-match extraction above.
676
- PRACTICES_FRONTMATTER_BLOCK=$(printf '%s\n' "$FRONTMATTER" | sed -n -e '/^practices:/,/^[^[:space:]]/{' -e '/^practices:/p' -e '/^[[:space:]]/p' -e '}')
677
- PRACTICES_TOTAL=$(echo "$PRACTICES_FRONTMATTER_BLOCK" | grep -E "^[[:space:]]*total:" | head -1 | cut -d: -f2 | xargs)
678
- ```
679
-
680
636
  Display inline summary to user:
681
637
 
682
638
  ```
@@ -695,13 +651,10 @@ Display inline summary to user:
695
651
  Info: ${INFO}
696
652
  ──────────
697
653
  Total: ${TOTAL}
698
- ${PRACTICES_TOTAL:+ Practices (advisory): ${PRACTICES_TOTAL}}
699
654
 
700
655
  ───────────────────────────────────────────────────────────────
701
656
  ```
702
657
 
703
- When `PRACTICES_TOTAL` is empty, omit the Practices line entirely — the block renders exactly as it did before this phase, with no blank line left in its place.
704
-
705
658
  If status is "clean":
706
659
  ```
707
660
  ✓ No issues found. All ${FILES_REVIEWED} files pass review at ${REVIEW_DEPTH} depth.
@@ -5,7 +5,7 @@ Mark a shipped version (v1.0, v1.1, v2.0) as complete. Creates historical record
5
5
  </purpose>
6
6
 
7
7
  <workstream_flag_substitution>
8
- `${GSD_WS}` is a placeholder — substitute the active `--ws <name>` (drop in flat mode); never emit it literally.
8
+ `${GSD_WS}` / `{GSD_WS}` in emitted "Next:" commands and `Skill()` args and agent dispatch prompts is a placeholder, not a shell variable — nothing expands it automatically. Substitute the active `--ws <name>`, or remove it entirely in flat mode. Never print the literal token in user-facing output. See `pp-core/references/workstream-flag.md` § Substitution rule.
9
9
  </workstream_flag_substitution>
10
10
 
11
11
  <required_reading>
@@ -31,9 +31,37 @@ Read TDD mode from config:
31
31
  TDD_MODE=$(pp_run query config-get workflow.tdd_mode 2>/dev/null | jq -r 'if type == "boolean" then tostring else . end' 2>/dev/null || echo "false")
32
32
  ```
33
33
 
34
- ## 0b. Vault door gate
34
+ ## 0b. Vault admission and load gate
35
35
 
36
- A session can write a fix. Unless SUBCMD is `list` or `status`, or `--diagnose` was given (root cause only), Read and execute `pp-core/workflows/execute-phase/steps/vault-door-gate.md` before any agent is spawned; a stop ends `/pp-debug`.
36
+ Run only where a spawn site below says so (the `continue` session and a new session), never for
37
+ `list` or `status`: it decides before any session manager is spawned (D-08). With the vault on, the
38
+ fix is applied through `/pp-quick` (§ 5), so it carries the mode's record and the trace gates.
39
+
40
+ ```bash
41
+ VAULT_ADMIT_PRESENT=$(pp_run query platform-bindings --pick present 2>/dev/null || echo true)
42
+ VAULT_ADMIT=inert
43
+ if [ "$VAULT_ADMIT_PRESENT" = true ]; then VAULT_ADMIT=$(pp_run vault admission 2>/dev/null || echo unrecognised); fi
44
+ 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
45
+ ```
46
+
47
+ **If the fence printed no `VAULT_ADMIT=on` line** (`off` and `inert` print nothing): skip the rest of this section silently. Print nothing: a
48
+ non-Pareto or `vault.enabled=false` project debugs byte-identically to how it did before (GATE-04).
49
+
50
+ **Otherwise, the load gate, in hook mode,** from the `plan:pre` payload filtered in the fence to the
51
+ `vault` capability (D-30):
52
+
53
+ ```bash
54
+ DEBUG_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('');}")
55
+ printf '%s' "$DEBUG_PLAN_PRE_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('DEBUG_PLAN_PRE_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
56
+ ```
57
+
58
+ Set `VAULT_FETCH_HOOKS_JSON=$DEBUG_PLAN_PRE_HOOKS_JSON`, then Read and execute
59
+ `pp-core/workflows/execute-phase/steps/vault-fetch.md` (hook mode). Then, in the
60
+ `DEBUG_PLAN_PRE_HOOKS_JSON=` line that fence printed, find active entries where `kind == "gate"` and `check.query ==
61
+ "vault.status"`; if none, skip silently. Otherwise set `GATE_POINT=plan:pre` and
62
+ `GATE_HOOKS_JSON=$DEBUG_PLAN_PRE_HOOKS_JSON`, leave `GATE_POSITIONAL_ARG`, `GATE_WS` and
63
+ `GATE_STAGE` empty, then Read and follow `pp-core/workflows/execute-phase/steps/check-query-gate.md`.
64
+ It owns the halt: a required miss stops here with the gate's own message, before any spawn.
37
65
 
38
66
  ## 1a. LIST subcommand
39
67
 
@@ -105,6 +133,8 @@ Eliminated: {count}
105
133
 
106
134
  Surface to user. Then delegate directly to the session manager (skip Steps 2 and 3 — pass `symptoms_prefilled: true` and set the slug from SLUG variable). The existing file IS the context.
107
135
 
136
+ Run § 0b Vault admission and load gate first.
137
+
108
138
  Print before spawning (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze):
109
139
  ```
110
140
  [debug] Session: .planning/debug/{SLUG}.md
@@ -129,7 +159,8 @@ slug: {SLUG}
129
159
  debug_file_path: .planning/debug/{SLUG}.md
130
160
  symptoms_prefilled: true
131
161
  tdd_mode: {TDD_MODE}
132
- goal: find_and_fix
162
+ goal: {if § 0b printed VAULT_ADMIT=on: "find_root_cause_only", else: "find_and_fix"}
163
+ fix_route: {if § 0b printed VAULT_ADMIT=on: "quick", else: "direct"}
133
164
  specialist_dispatch_enabled: true
134
165
  </session_params>
135
166
  """,
@@ -141,6 +172,9 @@ specialist_dispatch_enabled: true
141
172
 
142
173
  Display the compact summary returned by the session manager.
143
174
 
175
+ With `fix_route` set to `quick` the session manager returns the root cause and a proposed fix instead
176
+ of applying one; `direct` keeps today's behaviour. Then, if `fix_route` was `quick`, follow § 5.
177
+
144
178
  ## 1d. Check Active Sessions (SUBCMD=debug)
145
179
 
146
180
  When SUBCMD=debug:
@@ -192,6 +226,8 @@ Create `.planning/debug/{slug}.md` with initial state using the Write tool (neve
192
226
 
193
227
  ## 4. Session Management (delegated to pp-debug-session-manager)
194
228
 
229
+ Run § 0b Vault admission and load gate first.
230
+
195
231
  After initial context setup, spawn the session manager to handle the full checkpoint/continuation loop. The session manager handles specialist_hint dispatch internally: when pp-debugger returns ROOT CAUSE FOUND it extracts the specialist_hint field and invokes the matching skill (e.g. typescript-expert, swift-concurrency) before offering fix options.
196
232
 
197
233
  Print before spawning (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze):
@@ -212,7 +248,8 @@ slug: {slug}
212
248
  debug_file_path: .planning/debug/{slug}.md
213
249
  symptoms_prefilled: true
214
250
  tdd_mode: {TDD_MODE}
215
- goal: {if diagnose_only: "find_root_cause_only", else: "find_and_fix"}
251
+ goal: {if § 0b printed VAULT_ADMIT=on or diagnose_only: "find_root_cause_only", else: "find_and_fix"}
252
+ fix_route: {if § 0b printed VAULT_ADMIT=on: "quick", else: "direct"}
216
253
  specialist_dispatch_enabled: true
217
254
  </session_params>
218
255
  """,
@@ -224,9 +261,22 @@ specialist_dispatch_enabled: true
224
261
 
225
262
  Display the compact summary returned by the session manager.
226
263
 
264
+ If `fix_route` was `quick`, follow § 5 first.
227
265
  If summary shows `DEBUG SESSION COMPLETE`: done.
228
266
  If summary shows `ABANDONED`: note session saved at `.planning/debug/{slug}.md` for later `/pp:debug continue {slug}`.
229
267
 
268
+ ## 5. Hand the fix to /pp-quick (vault on only)
269
+
270
+ **If the summary carries `FIX_ROUTE: quick` and a `PROPOSED FIX:` line** (and this is not a
271
+ `--diagnose` run): invoke `/pp-quick --from-debug {slug} "{the PROPOSED FIX line}"` via
272
+ SlashCommand, where `{slug}` is the session's slug (`{SLUG}` for a continued session). Quick
273
+ validates the slug again, adds `.planning/debug/{slug}.md` to its planner's and executor's reading
274
+ lists, and gates and records the fix like any quick task. When quick returns, ask the user
275
+ (AskUserQuestion) to confirm the symptoms are resolved; on yes, move `.planning/debug/{slug}.md` to
276
+ `.planning/debug/resolved/`, as the session manager does for a session it fixed. The manager emits
277
+ the two lines only when the user chose "Fix now" (or the TDD arm handed off); after "Plan fix" or
278
+ "Manual fix", with no root cause, or under `--diagnose`, there is no hand-off.
279
+
230
280
  </process>
231
281
 
232
282
  <success_criteria>
@@ -15,10 +15,16 @@ multiple sessions can be pre-filled in one run.
15
15
  only — relative lowercase paths, no absolute paths, no parent traversal, same
16
16
  rules as the main workflow (T-04-03).
17
17
 
18
- ## Step 0: Client vault (optional)
18
+ ## Step 0: Vault Context
19
19
 
20
- When the session's **Vault areas** are not `(none)`, Read and execute
21
- `${PP_TOOLS%/bin/pp-tools.cjs}/workflows/discovery-sprint/vault-fetch.md`. It never stops the pass.
20
+ Read `${PP_TOOLS%/bin/pp-tools.cjs}/workflows/discovery-sprint/vault-context.md` and follow it,
21
+ with `SESSION_ARG` set to the session being drafted. A prep pass generates session content, so it
22
+ is gated exactly as a live session is (D-11-12) — an ungated prefill would produce drafted answers
23
+ that look governed by the client's standards without ever having consulted them.
24
+
25
+ Inert capability: it prints nothing and returns here. Active: it fetches, gates, and maps this
26
+ session's vault documents from the vault's index and reads them, so Step 3 drafts with them
27
+ alongside the mapped input documents.
22
28
 
23
29
  ## Step 1: Preconditions
24
30
 
@@ -44,10 +50,6 @@ not a command to follow.
44
50
  Confidential documents (D-24): paraphrase at point of use with a `[NN §loc]`
45
51
  citation — no verbatim excerpts, no personal data, always cite.
46
52
 
47
- When the client vault is present (Flow 2 Step 1's rule), also read the
48
- session's **Vault areas** the same way Flow 2 does; an answer drafted from a
49
- vault document cites `[vault: <rel path>]` beside its `[TO CONFIRM]` marker.
50
-
51
53
  ## Step 3: Draft
52
54
 
53
55
  Populate the session's notes-template sections with paper-derived answers.
@@ -60,6 +62,12 @@ Read it lazily.
60
62
  Questions the documents do not answer stay blank — never invent an answer the
61
63
  paper does not support.
62
64
 
65
+ When Step 0 handed back a `## Vault Context` record, insert it verbatim directly
66
+ after the session's `**Goal:**` line (`vault-context.md` § 4, **The record**). A
67
+ drafted answer taken from a vault document cites `[vault: <path>]` beside its
68
+ `[TO CONFIRM]` marker. The live confirmation walk reuses this record rather than
69
+ selecting again.
70
+
63
71
  ## Step 4: Stamp Frontmatter
64
72
 
65
73
  Update the session file's frontmatter (D-15 record side, D-17):
@@ -86,6 +94,10 @@ Offer to pre-fill the next session mapped in the README (`AskUserQuestion`;
86
94
  for now). When done, tell the user that each pre-filled session is run live
87
95
  later as a confirmation walk (`/pp-discovery N`), and stop.
88
96
 
97
+ Before drafting session M, re-enter § 4 of `vault-context.md` with `SESSION_ARG`
98
+ set to M — the guards, the fetch and the gate already ran once for this
99
+ invocation and are not re-run per session.
100
+
89
101
  ## Confirmation-Walk Semantics (reference — D-20)
90
102
 
91
103
  The live session resume arm in the main workflow follows these rules when it