@pareto4/pp-core 1.12.1 → 1.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/.claude-plugin/plugin.json +3 -3
  2. package/README.md +26 -9
  3. package/agents/pp-code-reviewer.md +3 -2
  4. package/agents/pp-debug-session-manager.md +9 -6
  5. package/agents/pp-executor.md +7 -21
  6. package/agents/pp-plan-checker.md +4 -4
  7. package/agents/pp-planner.md +23 -9
  8. package/agents/pp-vault-reviewer.md +274 -0
  9. package/agents/pp-verifier.md +7 -3
  10. package/bin/install.js +10 -3
  11. package/commands/pp-execute-phase.md +1 -3
  12. package/commands/pp-ns-review.md +2 -1
  13. package/commands/pp-plan-phase.md +1 -2
  14. package/commands/pp-vault-review.md +35 -0
  15. package/commands/pp-verify-work.md +1 -2
  16. package/gemini-extension.json +1 -1
  17. package/hooks/dist/pp-check-update.js +0 -0
  18. package/hooks/dist/pp-cursor-session-start.js +1 -1
  19. package/hooks/dist/pp-statusline.js +1 -1
  20. package/hooks/dist/pp-update-banner.js +0 -0
  21. package/hooks/pp-check-update.js +0 -0
  22. package/hooks/pp-cursor-session-start.js +1 -1
  23. package/hooks/pp-statusline.js +1 -1
  24. package/hooks/pp-update-banner.js +0 -0
  25. package/package.json +14 -19
  26. package/pareto-skills/_shared/create-project-board.sh +0 -0
  27. package/pareto-skills/pp-project-setup/SKILL.md +1 -1
  28. package/pp-core/bin/check-latest-version.cjs +0 -0
  29. package/pp-core/bin/detect-build-commands.sh +2 -2
  30. package/pp-core/bin/lib/capability-activation.cjs +83 -9
  31. package/pp-core/bin/lib/capability-registry.cjs +526 -22
  32. package/pp-core/bin/lib/capability-state.cjs +160 -4
  33. package/pp-core/bin/lib/capability-writer.cjs +19 -5
  34. package/pp-core/bin/lib/check-command-router.cjs +3867 -274
  35. package/pp-core/bin/lib/clusters.cjs +4 -0
  36. package/pp-core/bin/lib/command-aliases.cjs +0 -28
  37. package/pp-core/bin/lib/commands.cjs +9 -4
  38. package/pp-core/bin/lib/compose-bindings.cjs +253 -76
  39. package/pp-core/bin/lib/config-loader.cjs +7 -103
  40. package/pp-core/bin/lib/config-schema.cjs +1 -1
  41. package/pp-core/bin/lib/config.cjs +154 -62
  42. package/pp-core/bin/lib/decisions.cjs +104 -27
  43. package/pp-core/bin/lib/discovery-vault-check.cjs +246 -0
  44. package/pp-core/bin/lib/frontmatter.cjs +1 -1
  45. package/pp-core/bin/lib/git-base-branch.cjs +138 -10
  46. package/pp-core/bin/lib/git-provider.cjs +4 -4
  47. package/pp-core/bin/lib/init-command-router.cjs +5 -8
  48. package/pp-core/bin/lib/init-contract.cjs +653 -629
  49. package/pp-core/bin/lib/init-interactive.cjs +77 -21
  50. package/pp-core/bin/lib/init.cjs +24 -51
  51. package/pp-core/bin/lib/install-profiles.cjs +1 -1
  52. package/pp-core/bin/lib/io.cjs +8 -0
  53. package/pp-core/bin/lib/loop-resolver.cjs +169 -47
  54. package/pp-core/bin/lib/org-profile.cjs +544 -53
  55. package/pp-core/bin/lib/package-identity.cjs +3 -3
  56. package/pp-core/bin/lib/phase-command-router.cjs +1 -23
  57. package/pp-core/bin/lib/phase-scope.cjs +1 -1
  58. package/pp-core/bin/lib/phase.cjs +11 -203
  59. package/pp-core/bin/lib/platform-bindings.cjs +40 -19
  60. package/pp-core/bin/lib/practices-review-check.cjs +15 -9
  61. package/pp-core/bin/lib/profile-output.cjs +1 -1
  62. package/pp-core/bin/lib/shell-command-projection.cjs +104 -1
  63. package/pp-core/bin/lib/state.cjs +11 -85
  64. package/pp-core/bin/lib/template.cjs +1 -1
  65. package/pp-core/bin/lib/vault-audit.cjs +2594 -0
  66. package/pp-core/bin/lib/vault-command-router.cjs +2756 -60
  67. package/pp-core/bin/lib/vault-coordinates.cjs +13 -4
  68. package/pp-core/bin/lib/vault-index.cjs +699 -0
  69. package/pp-core/bin/lib/vault-mode.cjs +235 -0
  70. package/pp-core/bin/lib/vault-practices.cjs +1194 -89
  71. package/pp-core/bin/lib/vault-review.cjs +2102 -0
  72. package/pp-core/bin/lib/vault-seal.cjs +1936 -0
  73. package/pp-core/bin/lib/vault-standards.cjs +1505 -0
  74. package/pp-core/bin/lib/vault-trace.cjs +3184 -0
  75. package/pp-core/bin/lib/vault-update.cjs +242 -0
  76. package/pp-core/bin/lib/vault-write-back.cjs +78 -31
  77. package/pp-core/bin/lib/vault.cjs +2713 -634
  78. package/pp-core/bin/lib/verify.cjs +0 -11
  79. package/pp-core/bin/portable-timeout.sh +1 -1
  80. package/pp-core/bin/pp-tools.cjs +184 -37
  81. package/pp-core/bin/shared/config-defaults.manifest.json +0 -7
  82. package/pp-core/bin/shared/config-schema.manifest.json +0 -3
  83. package/pp-core/bin/shared/model-catalog.json +1 -0
  84. package/pp-core/bin/verify-reapply-patches.cjs +0 -0
  85. package/pp-core/org-profile.json +26 -0
  86. package/pp-core/references/autonomous-best-effort.md +8 -7
  87. package/pp-core/references/loop-hook-dispatch.md +0 -14
  88. package/pp-core/references/planner-gap-closure.md +0 -1
  89. package/pp-core/references/planner-tdd.md +0 -1
  90. package/pp-core/references/planner-vault-practices.md +31 -3
  91. package/pp-core/references/planner-vault-standards.md +320 -0
  92. package/pp-core/references/planning-config.md +0 -8
  93. package/pp-core/references/practice-arithmetic-contract.md +121 -0
  94. package/pp-core/references/tdd.md +0 -1
  95. package/pp-core/references/verifier-practice-verdicts.md +263 -0
  96. package/pp-core/templates/README.md +1 -0
  97. package/pp-core/templates/VAULT-REVIEW.md +202 -0
  98. package/pp-core/templates/phase-prompt.md +2 -6
  99. package/pp-core/templates/practices/README.md +137 -11
  100. package/pp-core/templates/project-charter.md +226 -0
  101. package/pp-core/workflows/_runtime-launcher.snippet.sh +0 -0
  102. package/pp-core/workflows/add-tests.md +55 -0
  103. package/pp-core/workflows/audit-fix.md +63 -0
  104. package/pp-core/workflows/audit-milestone.md +1 -1
  105. package/pp-core/workflows/autonomous.md +85 -11
  106. package/pp-core/workflows/check-todos.md +13 -2
  107. package/pp-core/workflows/code-review-fix.md +59 -1
  108. package/pp-core/workflows/code-review.md +10 -1
  109. package/pp-core/workflows/complete-milestone.md +1 -1
  110. package/pp-core/workflows/debug.md +56 -2
  111. package/pp-core/workflows/discovery-sprint/prefill.md +21 -0
  112. package/pp-core/workflows/discovery-sprint/prototype.md +46 -48
  113. package/pp-core/workflows/discovery-sprint/session-13-gates.md +2 -0
  114. package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +1 -3
  115. package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +1 -3
  116. package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +1 -3
  117. package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +20 -24
  118. package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +1 -3
  119. package/pp-core/workflows/discovery-sprint/sessions/06-security.md +1 -3
  120. package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +1 -3
  121. package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +1 -3
  122. package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +1 -3
  123. package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +1 -6
  124. package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +1 -3
  125. package/pp-core/workflows/discovery-sprint/sessions/12-delivery-model.md +1 -3
  126. package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +1 -3
  127. package/pp-core/workflows/discovery-sprint/templates/context-template.md +1 -1
  128. package/pp-core/workflows/discovery-sprint/vault-context.md +213 -0
  129. package/pp-core/workflows/discovery-sprint.md +7 -3
  130. package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +4 -4
  131. package/pp-core/workflows/discovery-to-build/templates/pp-handoff.md +43 -1
  132. package/pp-core/workflows/discovery-to-build.md +9 -1
  133. package/pp-core/workflows/discuss-phase.md +3 -10
  134. package/pp-core/workflows/execute-phase/steps/check-query-gate.md +329 -0
  135. package/pp-core/workflows/execute-phase/steps/client-context-gate.md +3 -2
  136. package/pp-core/workflows/execute-phase/steps/cross-ai-delegation.md +1 -1
  137. package/pp-core/workflows/execute-phase/steps/execute-pre-dispatch.md +98 -0
  138. package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
  139. package/pp-core/workflows/execute-phase/steps/post-merge-gate.md +6 -8
  140. package/pp-core/workflows/execute-phase/steps/vault-fetch.md +115 -14
  141. package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +322 -18
  142. package/pp-core/workflows/execute-phase/steps/verifier-practice-payload.md +165 -0
  143. package/pp-core/workflows/execute-phase/steps/verify-post-gate.md +163 -0
  144. package/pp-core/workflows/execute-phase.md +154 -110
  145. package/pp-core/workflows/execute-plan.md +58 -4
  146. package/pp-core/workflows/fast.md +53 -0
  147. package/pp-core/workflows/help/modes/full.md +1 -0
  148. package/pp-core/workflows/init/steps/client-context-capture.md +101 -0
  149. package/pp-core/workflows/init/steps/gitlab-provisioning.md +130 -0
  150. package/pp-core/workflows/init/steps/project-md-deferral-narration.md +66 -0
  151. package/pp-core/workflows/init/steps/reachability-outcome.md +70 -0
  152. package/pp-core/workflows/init.md +232 -272
  153. package/pp-core/workflows/new-project.md +31 -23
  154. package/pp-core/workflows/plan-phase.md +99 -43
  155. package/pp-core/workflows/quick.md +120 -2
  156. package/pp-core/workflows/secure-phase.md +1 -1
  157. package/pp-core/workflows/ship.md +57 -24
  158. package/pp-core/workflows/update.md +3 -3
  159. package/pp-core/workflows/validate-phase.md +60 -1
  160. package/pp-core/workflows/vault-review.md +325 -0
  161. package/pp-core/workflows/verify-work.md +13 -12
  162. package/scripts/changeset/cli.cjs +6 -5
  163. package/scripts/changeset/lint.cjs +0 -0
  164. package/scripts/changeset/new.cjs +33 -50
  165. package/scripts/dev-env.cjs +25 -85
  166. package/scripts/gen-capability-registry.cjs +199 -0
  167. package/scripts/gen-practice-arithmetic-contract.cjs +412 -0
  168. package/scripts/lib/allowlist-ratchet.cjs +1 -103
  169. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -2
  170. package/scripts/lint-docs-required.cjs +0 -0
  171. package/scripts/lint-pr-check-project-dir.cjs +1 -3
  172. package/scripts/lint-test-file-count.allowlist.json +13 -2
  173. package/scripts/practice-arithmetic-contract.allow.json +35 -0
  174. package/scripts/prompt-injection-scan.sh +22 -15
  175. package/scripts/record-vault-mode-golden.cjs +89 -0
  176. package/scripts/release-channel.cjs +0 -0
  177. package/scripts/sync-manifest-versions.cjs +5 -4
  178. package/scripts/sync-rulesets.sh +1 -1
  179. package/scripts/update-size-baseline.cjs +30 -274
  180. package/scripts/vault-calibrate.cjs +996 -0
  181. package/scripts/verify-opengsd-sweep.cjs +3 -5
  182. package/scripts/workflow-size.cjs +9 -61
  183. package/pp-core/bin/lib/dispatch-plan.cjs +0 -472
  184. package/pp-core/bin/lib/install-run.cjs +0 -536
  185. package/pp-core/bin/lib/phase-tier.cjs +0 -467
  186. package/pp-core/bin/lib/plan-graph.cjs +0 -368
  187. package/pp-core/references/planner-plan-graph.md +0 -66
  188. package/pp-core/workflows/execute-phase/steps/checkpoint-handling.md +0 -45
  189. package/pp-core/workflows/execute-phase/steps/install-run.md +0 -29
  190. package/pp-core/workflows/execute-phase/steps/phase-close-rebaseline.md +0 -23
  191. package/pp-core/workflows/execute-phase/steps/serial-group-dispatch.md +0 -72
  192. package/pp-core/workflows/plan-phase/steps/phase-tier.md +0 -34
  193. package/scripts/lib/size-budget.cjs +0 -311
  194. package/scripts/lint-neutrality-names.cjs +0 -694
  195. package/scripts/lint-org-coordinates.allowlist.json +0 -35
  196. package/scripts/lint-org-coordinates.cjs +0 -426
@@ -108,8 +108,6 @@ grep -E "^| $PHASE_NUM" .planning/REQUIREMENTS.md 2>/dev/null
108
108
 
109
109
  Extract phase goal from ROADMAP.md — this is the outcome to verify, not the tasks.
110
110
 
111
- **Install run (heavy tier):** when your files include `*-INSTALL-RUN.json`, judge user-facing truths on its `commands` (run against the INSTALLED product), not on the repo. `verdict: fail` → each `failures[]` entry is a blocker gap (status `gaps_found`); never re-run it.
112
-
113
111
  ## Step 2: Establish Must-Haves (Initial Mode Only)
114
112
 
115
113
  In re-verification mode, must-haves come from Step 0.
@@ -151,7 +149,7 @@ must_haves:
151
149
  **Also extract `must_haves.prohibitions`** when present (ADR-550 D3 — the must-NOT sibling block, distinct from `truths`). Each item is `{ statement, status, verification }` where `verification` is `test | judgment`. These are NEGATIVE checks: a verified prohibition means the must-NOT did NOT happen. Route them by verification tier in the verdict assembly (ADR-550 D4, the "B-with-guard" 2026-06-12 maintainer decision):
152
150
 
153
151
  - **judgment-tier prohibitions → mode-dependent soft-gate.** Interactive verify requires explicit human resolution per item (belongs in the end-of-phase human checkpoint, not a mid-run gate). Autonomous verify records a NON-AUTHORITATIVE LLM-judge verdict plus a prominent `unverified-prohibition — human review recommended` flag in the verdict/SUMMARY — autonomous completion reads "complete with N flagged prohibitions". NEVER a silent pass; NEVER a hard halt of an AFK run.
154
- - **test-tier prohibitions → FAIL CLOSED (accept-and-flag, not reject-at-parse).** Accept the `verification: test` value (the SPEC↔must_haves.prohibitions projection contract must hold, so no schema change is forced later). But a well-formed test-tier item that reaches verify with NO wired enforcement is treated as UNVERIFIED — flagged exactly like an unresolved judgment item, NEVER green. The deterministic fail-closed default is `dispositionForProhibition()` in probe-core (status `unverified`, `flagged: true` when `enforcementEvidence` is empty). Do NOT wire a real fail-first negative-test hard gate here — that enforcement MECHANISM defers to a follow-up PR.
152
+ - **test-tier prohibitions → FAIL CLOSED (accept-and-flag, not reject-at-parse).** Accept the `verification: test` value (the SPEC↔must_haves.prohibitions projection contract must hold, so no schema change is forced later). But a well-formed test-tier item that reaches verify with NO wired enforcement is treated as UNVERIFIED — flagged exactly like an unresolved judgment item, NEVER green. The deterministic fail-closed default is `dispositionForProhibition()` in probe-core (status `unverified`, `flagged: true` when `enforcementEvidence` is empty). Do NOT wire a real fail-first negative-test hard gate here — that enforcement MECHANISM defers to a follow-up PR (it needs a real test-tier consumer to `regression-must-fail-first` against; #644's corpus is entirely judgment-tier).
155
153
 
156
154
  A flagged prohibition counts as a human-verification item (status `human_needed`) or a gap (status `gaps_found`) per the existing decision tree — it must never be silently absorbed into a `passed` verdict.
157
155
 
@@ -646,6 +644,12 @@ Parse the JSON to extract all phases. Identify phases with `number > current_pha
646
644
  - If the gaps list is now empty but human verification items exist → `human_needed`
647
645
  - If the gaps list still has items → `gaps_found`
648
646
 
647
+ ## Step 9c: Practice Verdicts (agent-judged)
648
+
649
+ If a vault practice-verdict input was supplied in the prompt, follow
650
+ @~/.claude/pp-core/references/verifier-practice-verdicts.md.
651
+ Its verdicts are inputs to NOTHING in Step 9 — never truths, artifacts, links, gaps or human-verification items, and never `score:` or `status:`.
652
+
649
653
  ## Step 10: Structure Gap Output (If Gaps Found)
650
654
 
651
655
  Before writing VERIFICATION.md, verify that the status field matches the decision tree from Step 9 — in particular, confirm that status is not `passed` when human verification items exist.
package/bin/install.js CHANGED
@@ -620,7 +620,7 @@ function computePathPrefix({ isGlobal, isOpencode, isWindowsHost: _isWindowsHost
620
620
  *
621
621
  * MEASURED 2026-09-19, `09-PROBE.md` arm B: **yes** — a personal skill whose
622
622
  * body contained `${CLAUDE_PROJECT_DIR}` was delivered to the model as
623
- * `B: [<the project root>]`. (`$HOME`, `~` and
623
+ * `B: [/Users/hp/Documents/Projects/pareto-pp-core]`. (`$HOME`, `~` and
624
624
  * `${VAR:-default}` are NOT substituted — arms E, G, D.)
625
625
  *
626
626
  * true → the dispatcher emits the literal `${CLAUDE_PROJECT_DIR}` and needs no
@@ -8699,7 +8699,7 @@ function uninstall(isGlobal, runtime = 'claude') {
8699
8699
  'github-release-notes.cjs', 'lint.cjs', 'new.cjs',
8700
8700
  'README.md', // documentation only — not user-authored
8701
8701
  ];
8702
- const GSD_SCRIPTS_LIB_FILES = ['cli-exit.cjs', 'allowlist-ratchet.cjs', 'size-budget.cjs'];
8702
+ const GSD_SCRIPTS_LIB_FILES = ['cli-exit.cjs', 'allowlist-ratchet.cjs'];
8703
8703
 
8704
8704
  const changesetUninstallDir = path.join(targetDir, 'scripts', 'changeset');
8705
8705
  if (fs.existsSync(changesetUninstallDir)) {
@@ -10582,6 +10582,13 @@ function install(isGlobal, runtime = 'claude', options = {}) {
10582
10582
  const savedGsdArtifacts = preserveUserArtifacts(skillDest, USER_OWNED_ARTIFACTS);
10583
10583
  copyWithPathReplacement(skillSrc, skillDest, pathPrefix, runtime, false, isGlobal);
10584
10584
  restoreUserArtifacts(skillDest, savedGsdArtifacts);
10585
+ // D-122: the pp_run launcher must land executable. The workflow preamble's
10586
+ // CLAUDE_ENV_FILE export puts this bin dir first on PATH, but a PATH search
10587
+ // skips a file without an exec bit, so a 0644 pp_run hands every prose
10588
+ // `pp_run …` step to whichever pp_run comes next (a stale global engine).
10589
+ // copyFileSync keeps the source mode, which a checkout or tarball can lose.
10590
+ // This is the one place every runtime, local and global, copies pp-core/bin.
10591
+ try { fs.chmodSync(path.join(skillDest, 'bin', 'pp_run'), 0o755); } catch { /* Windows */ }
10585
10592
  if (verifyInstalled(skillDest, 'pp-core')) {
10586
10593
  console.log(` ${green}✓${reset} Installed workflow assets`);
10587
10594
  } else {
@@ -11833,7 +11840,7 @@ function install(isGlobal, runtime = 'claude', options = {}) {
11833
11840
  };
11834
11841
  }
11835
11842
 
11836
- // The ONE owner of "how to start a project" in the installer. Every
11843
+ // PBI 75232 — the ONE owner of "how to start a project" in the installer. Every
11837
11844
  // runtime's Done! line names the init front door (git init, remote wiring, vault
11838
11845
  // binding, then handoff to /pp-discovery or /pp-new-project), derived from this
11839
11846
  // single stem so no runtime can drift back to naming the second step.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: pp:execute-phase
3
3
  description: Execute all plans in a phase with wave-based parallelization
4
- argument-hint: "<phase-number> [--wave N] [--gaps-only] [--interactive] [--tdd] [--tier light|standard|heavy]"
4
+ argument-hint: "<phase-number> [--wave N] [--gaps-only] [--interactive] [--tdd]"
5
5
  effort: max
6
6
  allowed-tools:
7
7
  - Read
@@ -47,14 +47,12 @@ Phase: $ARGUMENTS
47
47
  **Available optional flags (documentation only — not automatically active):**
48
48
  - `--wave N` — Execute only Wave `N` in the phase. Use when you want to pace execution or stay inside usage limits.
49
49
  - `--gaps-only` — Execute only gap closure plans (plans with `gap_closure: true` in frontmatter). Use after verify-work creates fix plans.
50
- - `--tier light|standard|heavy` — Ceremony tier for this run (overrides the phase's ROADMAP `**Tier:**` line and `phase.tier`): decides whether the verifier and code review run.
51
50
  - `--interactive` — Execute plans sequentially inline (no subagents) with user checkpoints between tasks. Lower token usage, pair-programming style. Best for small phases, bug fixes, and verification gaps.
52
51
 
53
52
  **Active flags must be derived from `$ARGUMENTS`:**
54
53
  - `--wave N` is active only if the literal `--wave` token is present in `$ARGUMENTS`
55
54
  - `--gaps-only` is active only if the literal `--gaps-only` token is present in `$ARGUMENTS`
56
55
  - `--interactive` is active only if the literal `--interactive` token is present in `$ARGUMENTS`
57
- - `--tier` is active only if the literal `--tier` token is present in `$ARGUMENTS`
58
56
  - If none of these tokens appear, run the standard full-phase execution flow with no flag-specific filtering
59
57
  - Do not infer that a flag is active just because it is documented in this prompt
60
58
 
@@ -5,7 +5,7 @@ argument-hint: ""
5
5
  allowed-tools:
6
6
  - Read
7
7
  - Skill
8
- requires: [code-review, audit-uat, secure-phase, eval-review, ui-review, validate-phase, debug, forensics, audit-fix, review, ui-phase]
8
+ requires: [code-review, audit-uat, secure-phase, eval-review, ui-review, vault-review, validate-phase, debug, forensics, audit-fix, review, ui-phase]
9
9
  ---
10
10
 
11
11
  Route to the appropriate quality / review skill based on the user's intent.
@@ -19,6 +19,7 @@ Route to the appropriate quality / review skill based on the user's intent.
19
19
  | Security review of a phase | pp-secure-phase |
20
20
  | Evaluate AI response quality | pp-eval-review |
21
21
  | Review UI for design and accessibility | pp-ui-review |
22
+ | Retroactive vault-practice verdict review of a phase | pp-vault-review |
22
23
  | Validate phase outputs | pp-validate-phase |
23
24
  | Debug a failing feature or error | pp-debug |
24
25
  | Forensic investigation of a broken system | pp-forensics |
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: pp:plan-phase
3
3
  description: Create detailed phase plan (PLAN.md) with verification loop
4
- argument-hint: "[phase] [--auto] [--research] [--skip-research] [--research-phase <N>] [--view] [--gaps] [--skip-verify] [--prd <file>] [--ingest <path-or-glob>] [--ingest-format <auto|nygard|madr|narrative>] [--reviews] [--text] [--tdd] [--mvp] [--tier light|standard|heavy]"
4
+ argument-hint: "[phase] [--auto] [--research] [--skip-research] [--research-phase <N>] [--view] [--gaps] [--skip-verify] [--prd <file>] [--ingest <path-or-glob>] [--ingest-format <auto|nygard|madr|narrative>] [--reviews] [--text] [--tdd] [--mvp]"
5
5
  effort: max
6
6
  allowed-tools:
7
7
  - Read
@@ -52,7 +52,6 @@ Phase number: $ARGUMENTS (optional — auto-detects next unplanned phase if omit
52
52
  - `--ingest-format <auto|nygard|madr|narrative>` — Optional ADR parser format override (`auto` default).
53
53
  - `--reviews` — Replan incorporating cross-AI review feedback from REVIEWS.md (produced by `/pp:review`)
54
54
  - `--text` — Use plain-text numbered lists instead of TUI menus (required for `/rc` remote sessions)
55
- - `--tier light|standard|heavy` — Ceremony tier for this phase; overrides the ROADMAP `**Tier:**` line and `phase.tier`, and is recorded for execute and verify. light = planner + executor only; standard = + verifier, code review, one plan-check pass; heavy = every gate.
56
55
  - `--mvp` — Vertical MVP mode. Planner organizes tasks as feature slices (UI→API→DB) instead of horizontal layers. On Phase 1 of a new project, also emits `SKELETON.md` (Walking Skeleton). Can be persisted on a phase via `**Mode:** mvp` in ROADMAP.md.
57
56
 
58
57
  Normalize phase input in step 2 before any directory lookups.
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: pp:vault-review
3
+ description: Retroactive per-practice client-vault review of a phase — reports, never gates
4
+ argument-hint: "[phase]"
5
+ allowed-tools:
6
+ - Read
7
+ - Write
8
+ - Bash
9
+ - Glob
10
+ - Grep
11
+ - Agent
12
+ - AskUserQuestion
13
+ requires: [phase]
14
+ ---
15
+ <objective>
16
+ Review a completed phase against the client vault's practices, one verdict per practice
17
+ (PASS / FAIL / N-A / INCONCLUSIVE) with a stated reason for every non-verdict. Derived facts come
18
+ from `pp-tools check vault-review`; the agent judges only the remainder. Reports counts by verdict —
19
+ never a score, and never a halt.
20
+ Output: {phase_num}-VAULT-REVIEW.md
21
+ </objective>
22
+
23
+ <execution_context>
24
+ @~/.claude/pp-core/workflows/vault-review.md
25
+ @~/.claude/pp-core/references/verifier-practice-verdicts.md
26
+ </execution_context>
27
+
28
+ <context>
29
+ Phase: $ARGUMENTS — optional, defaults to the last completed phase.
30
+ </context>
31
+
32
+ <process>
33
+ Execute end-to-end.
34
+ Inert on a project with the vault practices capability off.
35
+ </process>
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: pp:verify-work
3
3
  description: Validate built features through conversational UAT
4
- argument-hint: "[phase number, e.g., '4'] [--ws <name>] [--tier light|standard|heavy]"
4
+ argument-hint: "[phase number, e.g., '4'] [--ws <name>]"
5
5
  allowed-tools:
6
6
  - Read
7
7
  - Bash
@@ -29,7 +29,6 @@ Output: {phase_num}-UAT.md tracking all test results. If issues found: diagnosed
29
29
  Phase: $ARGUMENTS (optional)
30
30
  - If provided: Test specific phase (e.g., "4")
31
31
  - If not provided: Check for active sessions or prompt for phase
32
- - `--tier light|standard|heavy` (optional): ceremony tier for this run; decides the plan-check passes on fix plans and the security / validation steps
33
32
 
34
33
  Context files are resolved inside the workflow (`init verify-work`) and delegated via `<files_to_read>` blocks.
35
34
  </context>
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pp-core",
3
- "version": "1.12.1",
3
+ "version": "1.17.1",
4
4
  "description": "PP Core — a meta-prompting, context engineering, and spec-driven development system for AI coding agents. Loads pp-core's operating context into every Gemini CLI session.",
5
5
  "contextFileName": "GEMINI.md"
6
6
  }
File without changes
@@ -15,7 +15,7 @@
15
15
  //
16
16
  // Behaviour:
17
17
  // - If .planning/STATE.md is present, injects a brief state reminder.
18
- // - If absent, nudges the user toward /pp-init (the init front door).
18
+ // - If absent, nudges the user toward /pp-init (PBI 75232: the init front door).
19
19
  // - Fails open: any error silently exits 0 so a hook bug never wedges Cursor.
20
20
  //
21
21
  // Cursor docs: https://cursor.com/docs/hooks
@@ -524,7 +524,7 @@ function evaluateUpdateCache(cache) {
524
524
  return { showUpdate, staleWarning };
525
525
  }
526
526
 
527
- // `npm run dev:install` leaves pp-dev-build.json in the profile it installs,
527
+ // FORK-ONLY (PBI 74336): `npm run dev:install` leaves pp-dev-build.json in the profile it installs,
528
528
  // next to this hook's hooks/ folder; a stable install never has one, so its statusline is unchanged.
529
529
  function readDevBuild(configDir = path.join(__dirname, '..')) {
530
530
  try {
File without changes
File without changes
@@ -15,7 +15,7 @@
15
15
  //
16
16
  // Behaviour:
17
17
  // - If .planning/STATE.md is present, injects a brief state reminder.
18
- // - If absent, nudges the user toward /pp-init (the init front door).
18
+ // - If absent, nudges the user toward /pp-init (PBI 75232: the init front door).
19
19
  // - Fails open: any error silently exits 0 so a hook bug never wedges Cursor.
20
20
  //
21
21
  // Cursor docs: https://cursor.com/docs/hooks
@@ -524,7 +524,7 @@ function evaluateUpdateCache(cache) {
524
524
  return { showUpdate, staleWarning };
525
525
  }
526
526
 
527
- // `npm run dev:install` leaves pp-dev-build.json in the profile it installs,
527
+ // FORK-ONLY (PBI 74336): `npm run dev:install` leaves pp-dev-build.json in the profile it installs,
528
528
  // next to this hook's hooks/ folder; a stable install never has one, so its statusline is unchanged.
529
529
  function readDevBuild(configDir = path.join(__dirname, '..')) {
530
530
  try {
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pareto4/pp-core",
3
- "version": "1.12.1",
3
+ "version": "1.17.1",
4
4
  "description": "Pareto pp-core — The Pareto Project's AI-assisted engineering framework: meta-prompting, context engineering, and spec-driven development for AI coding agents.",
5
5
  "bin": {
6
6
  "pp-core": "bin/install.js",
@@ -38,11 +38,11 @@
38
38
  "license": "MIT",
39
39
  "repository": {
40
40
  "type": "git",
41
- "url": "git+https://gitlab.com/pareto4/pp-core.git"
41
+ "url": "git+https://github.com/pareto000/pp-core.git"
42
42
  },
43
- "homepage": "https://gitlab.com/pareto4/pp-core",
43
+ "homepage": "https://github.com/pareto000/pp-core",
44
44
  "bugs": {
45
- "url": "https://gitlab.com/pareto4/pp-core/-/issues"
45
+ "url": "https://github.com/pareto000/pp-core/issues"
46
46
  },
47
47
  "publishConfig": {
48
48
  "access": "public"
@@ -52,7 +52,7 @@
52
52
  "npm": ">=10.0.0"
53
53
  },
54
54
  "dependencies": {
55
- "@anthropic-ai/claude-agent-sdk": "^0.3.218",
55
+ "@anthropic-ai/claude-agent-sdk": "^0.3.251",
56
56
  "ws": "^8.21.0"
57
57
  },
58
58
  "devDependencies": {
@@ -65,22 +65,13 @@
65
65
  "eslint-plugin-no-only-tests": "^3.4.0",
66
66
  "fast-check": "^4.8.0",
67
67
  "globals": "^16.5.0",
68
- "js-yaml": "^4.3.2",
68
+ "js-yaml": "^4.2.0",
69
69
  "typescript": "^6.0.3",
70
70
  "typescript-eslint": "^8.60.0"
71
71
  },
72
72
  "overrides": {
73
73
  "qs": ">=6.16.0",
74
- "@hono/node-server": ">=2.0.5",
75
- "@modelcontextprotocol/sdk": "^1.31.0",
76
- "fast-uri": "^3.1.8",
77
- "hono": "^4.13.7",
78
- "ip-address": "^10.7.1",
79
- "proxy-addr": "^2.0.8",
80
- "brace-expansion@^1.1.0": "^1.1.21",
81
- "brace-expansion@^5.0.0": "^5.0.12",
82
- "browserslist": "^4.28.7",
83
- "baseline-browser-mapping": "^2.11.0"
74
+ "@hono/node-server": ">=2.0.5"
84
75
  },
85
76
  "optionalDependencies": {
86
77
  "fallow": "^2.70.0"
@@ -88,7 +79,7 @@
88
79
  "scripts": {
89
80
  "sync:launcher": "node scripts/sync-runtime-launcher.cjs",
90
81
  "check:env": "node scripts/check-env.cjs",
91
- "setup": "node scripts/dev-env.cjs stable",
82
+ "setup": "node scripts/dev-env.cjs setup",
92
83
  "dev:setup": "node scripts/dev-env.cjs dev-setup",
93
84
  "dev:install": "node scripts/dev-env.cjs install",
94
85
  "dev:claude": "node scripts/dev-env.cjs claude",
@@ -103,6 +94,7 @@
103
94
  "gen:capability-registry": "node scripts/gen-capability-registry.cjs --write",
104
95
  "gen:platform-bindings-schema": "node scripts/gen-platform-bindings-schema.cjs --write",
105
96
  "check:platform-bindings-schema": "node scripts/gen-platform-bindings-schema.cjs --check",
97
+ "check:inventory-manifest": "node scripts/gen-inventory-manifest.cjs --check",
106
98
  "gen:commands-reference": "node scripts/gen-commands-reference.cjs --write",
107
99
  "prepack": "npm run build:lib",
108
100
  "prepare": "npm run build:lib",
@@ -112,7 +104,7 @@
112
104
  "pretest:coverage": "npm run build:lib && npm run lint:skill-deps",
113
105
  "lint": "eslint . --cache --cache-location node_modules/.cache/eslint/",
114
106
  "lint:fix": "eslint . --fix",
115
- "lint:ci": "npm run lint && npm run lint:skill-deps && node scripts/lint-test-file-count.cjs && node scripts/lint-command-contract.cjs && node scripts/lint-pr-check-project-dir.cjs && npm run lint:legacy-name && node scripts/lint-regression-test-names.cjs && node scripts/lint-windows-test-portability.cjs && node scripts/lint-allow-test-rule-refs.cjs && npm run check:platform-bindings-schema && node scripts/lint-org-coordinates.cjs && node scripts/lint-neutrality-names.cjs",
107
+ "lint:ci": "npm run lint && npm run lint:skill-deps && node scripts/lint-test-file-count.cjs && node scripts/lint-command-contract.cjs && node scripts/lint-pr-check-project-dir.cjs && npm run lint:legacy-name && node scripts/lint-regression-test-names.cjs && node scripts/lint-windows-test-portability.cjs && node scripts/lint-allow-test-rule-refs.cjs && npm run check:platform-bindings-schema && npm run check:practice-arithmetic-contract && npm run check:inventory-manifest && npm run rename-guard",
116
108
  "lint:allow-test-rule-refs": "node scripts/lint-allow-test-rule-refs.cjs",
117
109
  "lint:windows-test-portability": "node scripts/lint-windows-test-portability.cjs",
118
110
  "lint:regression-names": "node scripts/lint-regression-test-names.cjs",
@@ -127,6 +119,7 @@
127
119
  "rename-guard:baseline": "node scripts/verify-rename-guard.cjs --update-baseline",
128
120
  "ci:test-scope": "node scripts/ci-test-scope.cjs",
129
121
  "size:baseline": "node scripts/update-size-baseline.cjs",
122
+ "vault:calibrate": "node scripts/vault-calibrate.cjs",
130
123
  "changeset": "node scripts/changeset/new.cjs",
131
124
  "changelog:render": "node scripts/changeset/cli.cjs render",
132
125
  "test": "node scripts/run-tests.cjs",
@@ -141,6 +134,8 @@
141
134
  "test:coverage:unit": "c8 --check-coverage --lines 70 --branches 60 --reporter text --include 'pp-core/bin/lib/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs --suite unit && c8 check-coverage --per-file --lines 0 --functions 0 --statements 0 --branches 70 --include 'pp-core/bin/lib/state.cjs' --include 'pp-core/bin/lib/phase.cjs' --include 'pp-core/bin/lib/verify.cjs' --include 'pp-core/bin/lib/init.cjs' --exclude 'tests/**'",
142
135
  "test:coverage:all": "npm run test:coverage",
143
136
  "test:mutation": "stryker run",
144
- "test:mutation:since": "stryker run --incremental --since origin/next"
137
+ "test:mutation:since": "stryker run --incremental --since origin/next",
138
+ "gen:practice-arithmetic-contract": "node scripts/gen-practice-arithmetic-contract.cjs --write",
139
+ "check:practice-arithmetic-contract": "node scripts/gen-practice-arithmetic-contract.cjs --check"
145
140
  }
146
141
  }
File without changes
@@ -159,7 +159,7 @@ mkdir -p \
159
159
  .obsidian
160
160
  ```
161
161
 
162
- Discovery Sprint artifacts are not scaffolded here — `/pp-discovery` creates `.planning/discovery/` itself on first run (session files, `_progress.md`, `_context.md`). The interactive prototype is built by `/pp-discovery prototype` into `.planning/discovery/prototype/`, on the UI kit the client vault declares when there is one, otherwise on the kit recorded in Session 4.
162
+ Discovery Sprint artifacts are not scaffolded here — `/pp-discovery` creates `.planning/discovery/` itself on first run (session files, `_progress.md`, `_context.md`). The interactive prototype is built by `/pp-discovery prototype` into `.planning/discovery/prototype/`, on the UI kit the client vault declares.
163
163
 
164
164
  #### 4c. Scaffold Project Definition & Requirements Templates
165
165
 
File without changes
@@ -47,7 +47,7 @@
47
47
  # the test ladder, after the Python arm in the build ladder, matching where
48
48
  # package.json already sat in each. The relative order of every pre-existing
49
49
  # arm is unchanged. That placement is load-bearing and is proven by an executed
50
- # mutation rung in tests/gate-shell-owners.test.cjs
50
+ # mutation rung in tests/feat-73988-gate-shell-owners.test.cjs
51
51
  # ("PLACEMENT RUNG"), which swaps the two arms in a scratch copy and asserts
52
52
  # the shadowing reappears.
53
53
  #
@@ -86,7 +86,7 @@ _pp_emit() { printf '%s\n' "$1"; }
86
86
  # -maxdepth 2 probe covers ./App.csproj and ./App/App.csproj but misses the
87
87
  # canonical one entirely, which would silently hand a .NET repository back to
88
88
  # the package.json arm. All three layouts are pinned as a matrix in
89
- # tests/gate-shell-owners.test.cjs.
89
+ # tests/feat-73988-gate-shell-owners.test.cjs.
90
90
  #
91
91
  # The solution probe stays at depth 1: a .sln nested deeper falls through to
92
92
  # the project probe, which still yields a correct `dotnet test`, whereas a
@@ -13,11 +13,19 @@ const node_path_1 = __importDefault(require("node:path"));
13
13
  // eslint-disable-next-line @typescript-eslint/no-require-imports
14
14
  const planningWorkspaceMod = require("./planning-workspace.cjs");
15
15
  const { planningDir, planningRoot } = planningWorkspaceMod;
16
+ /**
17
+ * Segments that must never be walked or matched, on either key form.
18
+ * Extracted so the nested walk and the flat fallback cannot drift into
19
+ * disagreeing about what a pollution attempt looks like.
20
+ */
21
+ function _isRejectedKeySegment(seg) {
22
+ return seg === '__proto__' || seg === 'constructor' || seg === 'prototype';
23
+ }
16
24
  function _getNestedConfigValue(config, dotKey) {
17
25
  const segments = dotKey.split('.');
18
26
  let current = config;
19
27
  for (const seg of segments) {
20
- if (seg === '__proto__' || seg === 'constructor' || seg === 'prototype') {
28
+ if (_isRejectedKeySegment(seg)) {
21
29
  return { found: false, value: undefined };
22
30
  }
23
31
  if (typeof current !== 'object' || current === null) {
@@ -31,6 +39,65 @@ function _getNestedConfigValue(config, dotKey) {
31
39
  }
32
40
  return { found: true, value: current };
33
41
  }
42
+ /**
43
+ * GATE-05: look the WHOLE dotted string up as a single own property.
44
+ *
45
+ * An operator hand-pasting a gate key into a config.json they did not write
46
+ * writes `{"vault.required": true}` at least as often as the three-line nested
47
+ * form. Before this existed, that flat shape resolved nowhere — the nested walk
48
+ * looked up `config['vault']`, found nothing, and the key silently fell through
49
+ * to its default. For an enforcement gate that is a fail-open with no error
50
+ * message, which is exactly the failure GATE-05 exists to close.
51
+ *
52
+ * Performs NO traversal: one own-property check on a string already in hand.
53
+ * The rejected-segment guard is applied to every segment of the dotted string
54
+ * anyway (T-02-13) so the flat path can never become the bypass the nested
55
+ * path already closes, and `hasOwnProperty` is required (T-02-14) so an
56
+ * inherited property is never mistaken for configuration.
57
+ *
58
+ * A flat own property valued `undefined` is reported NOT-found on purpose: it
59
+ * cannot come from JSON, and treating it as configured would let a
60
+ * programmatically built object shadow the schema default with nothing.
61
+ */
62
+ function _getFlatConfigValue(config, dotKey) {
63
+ for (const seg of dotKey.split('.')) {
64
+ if (_isRejectedKeySegment(seg))
65
+ return { found: false, value: undefined };
66
+ }
67
+ if (typeof config !== 'object' || config === null) {
68
+ return { found: false, value: undefined };
69
+ }
70
+ if (!Object.prototype.hasOwnProperty.call(config, dotKey)) {
71
+ return { found: false, value: undefined };
72
+ }
73
+ const value = config[dotKey];
74
+ if (value === undefined)
75
+ return { found: false, value: undefined };
76
+ return { found: true, value };
77
+ }
78
+ /**
79
+ * GATE-05: resolve a dotted key in EITHER form against one config object.
80
+ *
81
+ * PRECEDENCE — nested first, flat only as a fallback. This ordering is the
82
+ * decision, not an implementation detail: when both forms are present for the
83
+ * same key the NESTED form wins. Chosen because every shipped example and every
84
+ * project configured to date is nested, so a nested-first fallback cannot move
85
+ * the resolution of any key that resolves today — the flat form resolves
86
+ * nowhere at present, so adding it below the nested walk is strictly additive.
87
+ * A flat-first ordering would silently change behaviour for any project that
88
+ * later adds a flat key alongside a nested one. Pinned by the
89
+ * "both forms present … NESTED wins" tests in
90
+ * tests/capability-precedence-parity.test.cjs; invert this and they go red.
91
+ *
92
+ * Called from the leaf of every precedence level, so levels 1-3 inherit the
93
+ * fallback without any change to the four-level walk itself.
94
+ */
95
+ function getConfigValueEitherForm(config, dotKey) {
96
+ const nested = _getNestedConfigValue(config, dotKey);
97
+ if (nested.found)
98
+ return nested;
99
+ return _getFlatConfigValue(config, dotKey);
100
+ }
34
101
  const _warnedRawConfigPaths = new Set();
35
102
  function _readRawConfigKey(filePath, dotKey) {
36
103
  try {
@@ -49,7 +116,9 @@ function _readRawConfigKey(filePath, dotKey) {
49
116
  }
50
117
  return { found: false, value: undefined };
51
118
  }
52
- return _getNestedConfigValue(parsed, dotKey);
119
+ // GATE-05: levels 2 and 3 read raw config.json files — the surface an
120
+ // operator hand-edits — so they need both key forms, nested first.
121
+ return getConfigValueEitherForm(parsed, dotKey);
53
122
  }
54
123
  catch {
55
124
  return { found: false, value: undefined };
@@ -58,11 +127,11 @@ function _readRawConfigKey(filePath, dotKey) {
58
127
  /**
59
128
  * The raw config files levels 2 and 3 read, in read order: the active
60
129
  * `planningDir(cwd)/config.json`, then the root `planningRoot(cwd)/config.json`
61
- * when it is a different file. Exported so `unreadableConfigFiles`
62
- * (src/config-loader.cts) parses every file the hook resolver reads — this list
63
- * beside `configFilesFor`, the loader's — without restating either. Both levels
64
- * skip an unparseable file with a stderr warning and read on, which is the
65
- * swallow a gate-governing caller must refuse.
130
+ * when it is a different file (16-04, D-28). Exported so the door-admission
131
+ * verdict (`vaultAdmissionVerdict` in src/vault.cts) parses every file the gate
132
+ * reads — this list beside `configFilesFor`, the loader's — without restating
133
+ * either. Both levels skip an unparseable file with a stderr warning and read
134
+ * on, which is the swallow the verdict exists to refuse.
66
135
  */
67
136
  function activationConfigFilesFor(cwd) {
68
137
  const wsConfigPath = node_path_1.default.join(planningDir(cwd), 'config.json');
@@ -84,8 +153,8 @@ function activationConfigFilesFor(cwd) {
84
153
  */
85
154
  function resolveConfigKey(dotKey, opts) {
86
155
  const { config, cwd, registry } = opts;
87
- // Level 1: loadConfig result
88
- const fromConfig = _getNestedConfigValue(config, dotKey);
156
+ // Level 1: loadConfig result (GATE-05: nested form first, flat form as fallback)
157
+ const fromConfig = getConfigValueEitherForm(config, dotKey);
89
158
  if (fromConfig.found)
90
159
  return { found: true, value: fromConfig.value };
91
160
  // Level 2 + 3: raw config.json files (only when cwd is available)
@@ -116,6 +185,11 @@ function _resolveActivationValue(dotKey, config, cwd, registry) {
116
185
  }
117
186
  module.exports = {
118
187
  _getNestedConfigValue,
188
+ // GATE-05: exported so src/config.cts's cmdConfigGet reuses this exact flat
189
+ // lookup rather than growing a second, driftable copy of the rule.
190
+ _getFlatConfigValue,
191
+ _isRejectedKeySegment,
192
+ getConfigValueEitherForm,
119
193
  _readRawConfigKey,
120
194
  _resolveActivationValue,
121
195
  resolveConfigKey,