@pareto4/pp-core 1.11.1 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +31 -0
  3. package/agents/pp-code-fixer.md +1 -1
  4. package/agents/pp-debug-session-manager.md +1 -1
  5. package/agents/pp-debugger.md +1 -1
  6. package/agents/pp-executor.md +20 -10
  7. package/agents/pp-intel-updater.md +1 -1
  8. package/agents/pp-phase-researcher.md +1 -1
  9. package/agents/pp-plan-checker.md +5 -5
  10. package/agents/pp-planner.md +10 -24
  11. package/agents/pp-project-researcher.md +1 -1
  12. package/agents/pp-research-synthesizer.md +1 -1
  13. package/agents/pp-ui-researcher.md +1 -1
  14. package/agents/pp-verifier.md +8 -4
  15. package/bin/install.js +429 -82
  16. package/commands/pp-autonomous.md +8 -6
  17. package/commands/pp-discovery-to-build.md +1 -1
  18. package/commands/pp-discovery.md +3 -2
  19. package/commands/pp-discuss-phase.md +2 -2
  20. package/commands/pp-execute-phase.md +3 -1
  21. package/commands/pp-graphify.md +5 -5
  22. package/commands/pp-import.md +1 -1
  23. package/commands/pp-map-codebase.md +1 -1
  24. package/commands/pp-ns-project.md +2 -3
  25. package/commands/pp-ns-workflow.md +1 -1
  26. package/commands/pp-plan-phase.md +2 -1
  27. package/commands/pp-verify-work.md +2 -1
  28. package/gemini-extension.json +1 -1
  29. package/hooks/dist/pp-cursor-session-start.js +2 -2
  30. package/hooks/dist/pp-session-state.sh +1 -1
  31. package/hooks/dist/pp-statusline.js +21 -2
  32. package/hooks/pp-cursor-session-start.js +2 -2
  33. package/hooks/pp-session-state.sh +1 -1
  34. package/hooks/pp-statusline.js +21 -2
  35. package/package.json +18 -5
  36. package/pareto-skills/pp-project-setup/SKILL.md +5 -63
  37. package/pp-core/bin/detect-build-commands.sh +182 -0
  38. package/pp-core/bin/lib/capability-activation.cjs +19 -9
  39. package/pp-core/bin/lib/capability-registry.cjs +65 -7
  40. package/pp-core/bin/lib/check-command-router.cjs +79 -38
  41. package/pp-core/bin/lib/clusters.cjs +2 -3
  42. package/pp-core/bin/lib/command-aliases.cjs +36 -0
  43. package/pp-core/bin/lib/command-arg-projection.cjs +99 -1
  44. package/pp-core/bin/lib/commands.cjs +21 -6
  45. package/pp-core/bin/lib/compose-bindings.cjs +70 -6
  46. package/pp-core/bin/lib/config-loader.cjs +151 -8
  47. package/pp-core/bin/lib/config-schema.cjs +16 -0
  48. package/pp-core/bin/lib/config.cjs +142 -27
  49. package/pp-core/bin/lib/core-utils.cjs +43 -7
  50. package/pp-core/bin/lib/discovery-input-check.cjs +218 -0
  51. package/pp-core/bin/lib/discovery-rebaseline.cjs +1372 -0
  52. package/pp-core/bin/lib/discovery-research-track.cjs +979 -0
  53. package/pp-core/bin/lib/discovery-rollup.cjs +476 -0
  54. package/pp-core/bin/lib/discovery-screens.cjs +1995 -0
  55. package/pp-core/bin/lib/discovery-sweep.cjs +390 -0
  56. package/pp-core/bin/lib/discovery-table.cjs +98 -0
  57. package/pp-core/bin/lib/dispatch-plan.cjs +472 -0
  58. package/pp-core/bin/lib/frontmatter.cjs +17 -2
  59. package/pp-core/bin/lib/init-command-router.cjs +8 -5
  60. package/pp-core/bin/lib/init-contract.cjs +93 -4
  61. package/pp-core/bin/lib/init.cjs +124 -134
  62. package/pp-core/bin/lib/install-profiles.cjs +5 -0
  63. package/pp-core/bin/lib/install-run.cjs +536 -0
  64. package/pp-core/bin/lib/io.cjs +15 -0
  65. package/pp-core/bin/lib/loop-resolver.cjs +40 -2
  66. package/pp-core/bin/lib/milestone.cjs +345 -48
  67. package/pp-core/bin/lib/phase-command-router.cjs +23 -1
  68. package/pp-core/bin/lib/phase-locator.cjs +15 -6
  69. package/pp-core/bin/lib/phase-scope.cjs +91 -0
  70. package/pp-core/bin/lib/phase-tier.cjs +467 -0
  71. package/pp-core/bin/lib/phase.cjs +247 -21
  72. package/pp-core/bin/lib/phases-command-router.cjs +2 -0
  73. package/pp-core/bin/lib/plan-graph.cjs +368 -0
  74. package/pp-core/bin/lib/planning-workspace.cjs +53 -0
  75. package/pp-core/bin/lib/platform-bindings.cjs +32 -2
  76. package/pp-core/bin/lib/profile-output.cjs +11 -3
  77. package/pp-core/bin/lib/prohibition-enforcement.cjs +112 -0
  78. package/pp-core/bin/lib/roadmap-parser.cjs +366 -99
  79. package/pp-core/bin/lib/roadmap.cjs +141 -39
  80. package/pp-core/bin/lib/runtime-hooks-surface.cjs +1 -1
  81. package/pp-core/bin/lib/shell-command-projection.cjs +24 -0
  82. package/pp-core/bin/lib/state-command-router.cjs +82 -13
  83. package/pp-core/bin/lib/state-document.cjs +124 -7
  84. package/pp-core/bin/lib/state.cjs +784 -257
  85. package/pp-core/bin/lib/template.cjs +22 -6
  86. package/pp-core/bin/lib/vault-command-router.cjs +57 -6
  87. package/pp-core/bin/lib/vault-practices.cjs +6 -36
  88. package/pp-core/bin/lib/vault-write-back.cjs +20 -4
  89. package/pp-core/bin/lib/vault.cjs +592 -23
  90. package/pp-core/bin/lib/verify.cjs +53 -31
  91. package/pp-core/bin/lib/workstream.cjs +1 -1
  92. package/pp-core/bin/lib/worktree-safety.cjs +26 -15
  93. package/pp-core/bin/portable-timeout.sh +89 -0
  94. package/pp-core/bin/pp-tools.cjs +149 -9
  95. package/pp-core/bin/shared/config-defaults.manifest.json +7 -0
  96. package/pp-core/bin/shared/config-schema.manifest.json +3 -0
  97. package/pp-core/references/autonomous-best-effort.md +461 -0
  98. package/pp-core/references/autonomous-lifecycle.md +146 -0
  99. package/pp-core/references/autonomous-smart-discuss.md +16 -12
  100. package/pp-core/references/checkpoints.md +1 -1
  101. package/pp-core/references/discovery-id-conventions.md +202 -0
  102. package/pp-core/references/discovery-rebaseline.md +254 -0
  103. package/pp-core/references/discovery-research-track.md +283 -0
  104. package/pp-core/references/discovery-traceability.md +400 -0
  105. package/pp-core/references/loop-hook-dispatch.md +14 -0
  106. package/pp-core/references/mandatory-initial-read.md +1 -1
  107. package/pp-core/references/planner-gap-closure.md +1 -0
  108. package/pp-core/references/planner-human-verify-mode.md +1 -1
  109. package/pp-core/references/planner-load-graph-context.md +1 -1
  110. package/pp-core/references/planner-plan-graph.md +66 -0
  111. package/pp-core/references/planner-tdd.md +1 -0
  112. package/pp-core/references/planning-config.md +8 -0
  113. package/pp-core/references/sketch-tooling.md +4 -0
  114. package/pp-core/references/tdd.md +1 -0
  115. package/pp-core/templates/claude-md.md +1 -1
  116. package/pp-core/templates/phase-prompt.md +6 -2
  117. package/pp-core/templates/prototype-review/review.js +303 -0
  118. package/pp-core/templates/state.md +6 -0
  119. package/pp-core/workflows/_runtime-launcher.snippet.sh +1 -1
  120. package/pp-core/workflows/add-backlog.md +1 -1
  121. package/pp-core/workflows/add-phase.md +1 -1
  122. package/pp-core/workflows/add-tests.md +1 -1
  123. package/pp-core/workflows/add-todo.md +1 -1
  124. package/pp-core/workflows/ai-integration-phase.md +2 -2
  125. package/pp-core/workflows/audit-fix.md +12 -16
  126. package/pp-core/workflows/audit-milestone.md +2 -2
  127. package/pp-core/workflows/audit-uat.md +1 -1
  128. package/pp-core/workflows/autonomous.md +68 -306
  129. package/pp-core/workflows/check-todos.md +1 -1
  130. package/pp-core/workflows/cleanup.md +1 -1
  131. package/pp-core/workflows/code-review-fix.md +2 -2
  132. package/pp-core/workflows/code-review.md +20 -8
  133. package/pp-core/workflows/complete-milestone.md +41 -60
  134. package/pp-core/workflows/debug.md +1 -1
  135. package/pp-core/workflows/diagnose-issues.md +1 -1
  136. package/pp-core/workflows/discovery-sprint/gap-analysis.md +140 -0
  137. package/pp-core/workflows/discovery-sprint/input-package.md +140 -0
  138. package/pp-core/workflows/discovery-sprint/prefill.md +92 -0
  139. package/pp-core/workflows/discovery-sprint/prototype.md +257 -0
  140. package/pp-core/workflows/discovery-sprint/rebaseline.md +276 -0
  141. package/pp-core/workflows/discovery-sprint/session-13-gates.md +24 -0
  142. package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +92 -0
  143. package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +98 -0
  144. package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +215 -0
  145. package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +146 -0
  146. package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +98 -0
  147. package/pp-core/workflows/discovery-sprint/sessions/06-security.md +107 -0
  148. package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +98 -0
  149. package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +85 -0
  150. package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +109 -0
  151. package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +119 -0
  152. package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +92 -0
  153. package/pp-core/workflows/discovery-sprint/sessions/12-delivery-model.md +98 -0
  154. package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +205 -0
  155. package/pp-core/workflows/discovery-sprint/templates/context-template.md +266 -0
  156. package/pp-core/workflows/discovery-sprint.md +79 -1714
  157. package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +5 -5
  158. package/pp-core/workflows/discovery-to-build/steps/screen-inventory-gate.md +70 -0
  159. package/pp-core/workflows/discovery-to-build/templates/discovery-references.md +54 -0
  160. package/pp-core/workflows/discovery-to-build/templates/pp-handoff.md +184 -0
  161. package/pp-core/workflows/discovery-to-build.md +21 -238
  162. package/pp-core/workflows/discuss-phase/modes/advisor.md +1 -1
  163. package/pp-core/workflows/discuss-phase/modes/auto.md +1 -1
  164. package/pp-core/workflows/discuss-phase/modes/chain.md +1 -1
  165. package/pp-core/workflows/discuss-phase-assumptions.md +1 -1
  166. package/pp-core/workflows/discuss-phase.md +11 -4
  167. package/pp-core/workflows/do.md +4 -4
  168. package/pp-core/workflows/docs-update.md +1 -1
  169. package/pp-core/workflows/edit-phase.md +1 -1
  170. package/pp-core/workflows/eval-review.md +1 -1
  171. package/pp-core/workflows/execute-phase/steps/checkpoint-handling.md +45 -0
  172. package/pp-core/workflows/execute-phase/steps/client-context-gate.md +1 -1
  173. package/pp-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
  174. package/pp-core/workflows/execute-phase/steps/cross-ai-delegation.md +90 -0
  175. package/pp-core/workflows/execute-phase/steps/install-run.md +29 -0
  176. package/pp-core/workflows/execute-phase/steps/phase-close-rebaseline.md +23 -0
  177. package/pp-core/workflows/execute-phase/steps/post-merge-gate.md +76 -77
  178. package/pp-core/workflows/execute-phase/steps/serial-group-dispatch.md +72 -0
  179. package/pp-core/workflows/execute-phase/steps/vault-fetch.md +5 -5
  180. package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +19 -112
  181. package/pp-core/workflows/execute-phase.md +104 -218
  182. package/pp-core/workflows/execute-plan.md +6 -2
  183. package/pp-core/workflows/explore.md +1 -1
  184. package/pp-core/workflows/extract-learnings.md +1 -1
  185. package/pp-core/workflows/forensics.md +4 -4
  186. package/pp-core/workflows/graduation.md +1 -1
  187. package/pp-core/workflows/health.md +1 -1
  188. package/pp-core/workflows/help/modes/brief.md +1 -0
  189. package/pp-core/workflows/help/modes/default.md +2 -1
  190. package/pp-core/workflows/help/modes/full.md +12 -5
  191. package/pp-core/workflows/import.md +1 -1
  192. package/pp-core/workflows/ingest-docs.md +1 -1
  193. package/pp-core/workflows/init.md +18 -2
  194. package/pp-core/workflows/insert-phase.md +1 -1
  195. package/pp-core/workflows/list-workspaces.md +1 -1
  196. package/pp-core/workflows/manager.md +3 -3
  197. package/pp-core/workflows/map-codebase.md +2 -2
  198. package/pp-core/workflows/milestone-summary.md +4 -4
  199. package/pp-core/workflows/mvp-phase.md +1 -1
  200. package/pp-core/workflows/new-milestone.md +7 -8
  201. package/pp-core/workflows/new-project.md +6 -1
  202. package/pp-core/workflows/new-workspace.md +1 -1
  203. package/pp-core/workflows/next.md +2 -2
  204. package/pp-core/workflows/note.md +2 -2
  205. package/pp-core/workflows/pause-work.md +1 -1
  206. package/pp-core/workflows/plan-milestone-gaps.md +1 -1
  207. package/pp-core/workflows/plan-phase/steps/chunked-planning.md +111 -0
  208. package/pp-core/workflows/plan-phase/steps/phase-tier.md +34 -0
  209. package/pp-core/workflows/plan-phase.md +43 -167
  210. package/pp-core/workflows/plan-review-convergence.md +2 -2
  211. package/pp-core/workflows/plant-seed.md +1 -1
  212. package/pp-core/workflows/pr-branch.md +1 -1
  213. package/pp-core/workflows/profile-user.md +1 -1
  214. package/pp-core/workflows/progress.md +3 -3
  215. package/pp-core/workflows/quick.md +4 -2
  216. package/pp-core/workflows/remove-phase.md +1 -1
  217. package/pp-core/workflows/remove-workspace.md +1 -1
  218. package/pp-core/workflows/resume-project.md +6 -12
  219. package/pp-core/workflows/review.md +1 -1
  220. package/pp-core/workflows/scan.md +1 -1
  221. package/pp-core/workflows/secure-phase.md +2 -2
  222. package/pp-core/workflows/settings-advanced.md +1 -1
  223. package/pp-core/workflows/settings-integrations.md +1 -1
  224. package/pp-core/workflows/settings.md +1 -1
  225. package/pp-core/workflows/ship.md +26 -9
  226. package/pp-core/workflows/sketch-wrap-up.md +1 -1
  227. package/pp-core/workflows/sketch.md +2 -1
  228. package/pp-core/workflows/spec-phase.md +1 -1
  229. package/pp-core/workflows/spike-wrap-up.md +1 -1
  230. package/pp-core/workflows/spike.md +1 -1
  231. package/pp-core/workflows/stats.md +2 -2
  232. package/pp-core/workflows/thread.md +1 -1
  233. package/pp-core/workflows/transition.md +5 -9
  234. package/pp-core/workflows/ui-phase.md +23 -2
  235. package/pp-core/workflows/ui-review.md +1 -1
  236. package/pp-core/workflows/ultraplan-phase.md +2 -2
  237. package/pp-core/workflows/validate-phase.md +2 -2
  238. package/pp-core/workflows/vault-write-back.md +1 -1
  239. package/pp-core/workflows/verify-phase.md +29 -26
  240. package/pp-core/workflows/verify-work.md +14 -10
  241. package/scripts/base64-scan.sh +7 -41
  242. package/scripts/changeset/cli.cjs +25 -5
  243. package/scripts/dev-env.cjs +462 -0
  244. package/scripts/lib/allowlist-ratchet.cjs +103 -1
  245. package/scripts/lib/size-budget.cjs +311 -0
  246. package/scripts/lint-neutrality-names.cjs +694 -0
  247. package/scripts/lint-org-coordinates.allowlist.json +35 -0
  248. package/scripts/lint-org-coordinates.cjs +426 -0
  249. package/scripts/lint-skill-deps.cjs +48 -9
  250. package/scripts/lint-test-file-count.cjs +17 -2
  251. package/scripts/prompt-injection-scan.sh +41 -20
  252. package/scripts/sync-manifest-versions.cjs +41 -7
  253. package/scripts/sync-runtime-launcher.cjs +106 -1
  254. package/scripts/update-size-baseline.cjs +274 -30
  255. package/scripts/workflow-size.cjs +61 -9
  256. package/commands/pp-build-handoff.md +0 -46
  257. package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +0 -94
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pareto4/pp-core",
3
- "version": "1.11.1",
3
+ "version": "1.12.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",
@@ -65,13 +65,22 @@
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.2.0",
68
+ "js-yaml": "^4.3.2",
69
69
  "typescript": "^6.0.3",
70
70
  "typescript-eslint": "^8.60.0"
71
71
  },
72
72
  "overrides": {
73
- "qs": ">=6.15.2",
74
- "@hono/node-server": ">=2.0.5"
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"
75
84
  },
76
85
  "optionalDependencies": {
77
86
  "fallow": "^2.70.0"
@@ -79,6 +88,10 @@
79
88
  "scripts": {
80
89
  "sync:launcher": "node scripts/sync-runtime-launcher.cjs",
81
90
  "check:env": "node scripts/check-env.cjs",
91
+ "setup": "node scripts/dev-env.cjs stable",
92
+ "dev:setup": "node scripts/dev-env.cjs dev-setup",
93
+ "dev:install": "node scripts/dev-env.cjs install",
94
+ "dev:claude": "node scripts/dev-env.cjs claude",
82
95
  "check:alias-drift": "node scripts/check-alias-drift.cjs",
83
96
  "check:identity-drift": "node scripts/lint-package-identity-drift.cjs",
84
97
  "check:integrity": "node scripts/check-npm-integrity.cjs",
@@ -99,7 +112,7 @@
99
112
  "pretest:coverage": "npm run build:lib && npm run lint:skill-deps",
100
113
  "lint": "eslint . --cache --cache-location node_modules/.cache/eslint/",
101
114
  "lint:fix": "eslint . --fix",
102
- "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",
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",
103
116
  "lint:allow-test-rule-refs": "node scripts/lint-allow-test-rule-refs.cjs",
104
117
  "lint:windows-test-portability": "node scripts/lint-windows-test-portability.cjs",
105
118
  "lint:regression-names": "node scripts/lint-regression-test-names.cjs",
@@ -19,7 +19,6 @@ This skill bootstraps a new Pareto project and hands it off to `/pp-discovery` t
19
19
 
20
20
  **What it delivers:**
21
21
  - GitHub repository created and configured
22
- - Prototype folder structure (interactive HTML prototype, created during Discovery after Session 4)
23
22
  - Obsidian vault configured for project documentation
24
23
  - Requirements templates (functional requirements, user stories, test cases)
25
24
  - Project Definition template
@@ -120,7 +119,7 @@ Summarise everything before running any commands:
120
119
  >
121
120
  > I'll:
122
121
  > 1. Create the GitHub repo
123
- > 2. Scaffold the project structure (requirements + docs + prototype)
122
+ > 2. Scaffold the project structure (requirements + docs)
124
123
  > 3. Set up the Project Definition and requirements templates
125
124
  > 4. Configure Obsidian vault for project documentation
126
125
  > 5. Configure GitHub project board, labels, and milestone
@@ -153,10 +152,6 @@ cd [PROJECT_NAME]
153
152
 
154
153
  ```bash
155
154
  mkdir -p \
156
- prototype/src/components \
157
- prototype/src/pages \
158
- prototype/src/styles \
159
- prototype/src/assets \
160
155
  requirements \
161
156
  Inputs/docs \
162
157
  docs/architecture \
@@ -164,7 +159,7 @@ mkdir -p \
164
159
  .obsidian
165
160
  ```
166
161
 
167
- Discovery Sprint artifacts are not scaffolded here — `/pp-discovery` creates `.planning/discovery/` itself on first run (session files, `_progress.md`, `_context.md`).
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.
168
163
 
169
164
  #### 4c. Scaffold Project Definition & Requirements Templates
170
165
 
@@ -486,59 +481,7 @@ _Test cases are added here as user stories are defined during the Discovery Spri
486
481
  | | | | | | |
487
482
  ```
488
483
 
489
- ##### 4c.3 Prototype README
490
-
491
- Generate `prototype/README.md`:
492
-
493
- ```markdown
494
- # Interactive Prototype — [PROJECT_NAME]
495
-
496
- This folder contains the interactive HTML prototype for [PROJECT_NAME].
497
- The prototype is a core Discovery Sprint deliverable — it makes abstract requirements tangible
498
- and gives stakeholders something concrete to react to.
499
-
500
- ## When It Gets Built
501
-
502
- The prototype is **created after Discovery Session 4** (UX Design Principles) and
503
- **iteratively updated** after Sessions 5, 7, and 8. By Session 13, it reflects the full MVP scope.
504
-
505
- | Trigger Session | What Happens |
506
- |----------------|--------------|
507
- | Session 4 (UX Design) | **Create** — key screens, navigation, user flows based on personas, EPICs, and UX principles |
508
- | Session 5 (Architecture) | **Update** — reflect architecture decisions (component structure, data flow) |
509
- | Session 7 (Identity) | **Update** — add role-based views, login flow, permission-gated UI |
510
- | Session 8 (Integration) | **Update** — add integration touchpoints (document uploads, external system indicators) |
511
-
512
- ## Structure
513
-
514
- ```
515
- prototype/
516
- ├── index.html # Entry point — links to all screens
517
- ├── src/
518
- │ ├── components/ # Reusable UI components (header, sidebar, cards, etc.)
519
- │ ├── pages/ # Individual screen HTML files
520
- │ ├── styles/
521
- │ │ ├── tokens.css # Design tokens (colors, fonts, spacing) from brand
522
- │ │ ├── global.css # Base styles, resets, typography
523
- │ │ └── components.css # Component-specific styles
524
- │ └── assets/ # Images, icons, logos
525
- └── README.md # This file
526
- ```
527
-
528
- ## How to View
529
-
530
- Open `index.html` in any browser. No build tools or dependencies required.
531
-
532
- ## Principles
533
-
534
- 1. **Interactive, not static** — working navigation, hover states, clickable elements
535
- 2. **Realistic content** — domain-specific placeholder data, not Lorem ipsum
536
- 3. **Progressive fidelity** — starts with layout/navigation, gains detail with each session
537
- 4. **Annotated** — subtle references to requirement IDs (FR-xxx, US-xxx) for traceability
538
- 5. **Branded** — uses the customer's brand tokens (colors, typography, logo)
539
- ```
540
-
541
- ##### 4c.4 Input Documents
484
+ ##### 4c.3 Input Documents
542
485
 
543
486
  Create `Inputs/docs/.gitkeep` (empty file — placeholder for input documents, architecture notes, and reference materials gathered during discovery).
544
487
 
@@ -729,14 +672,13 @@ Run `/pp-discovery 1` to begin. `/pp-discovery` facilitates all 13 Discovery Spr
729
672
  | [Project Definition]([PROJECT_NAME]-Project-Definition.md) | Consolidated output document |
730
673
  | `.planning/discovery/_progress.md` | Session progress tracker (created by `/pp-discovery`) |
731
674
  | `.planning/discovery/_context.md` | Cross-session context accumulator (created by `/pp-discovery`) |
732
- | [prototype/](prototype/) | Interactive HTML prototype (created after Session 4) |
675
+ | `.planning/discovery/prototype/` | Interactive prototype (built by `/pp-discovery prototype` after Session 4) |
733
676
 
734
677
  ## Project Structure
735
678
  ```
736
679
  [PROJECT_NAME]/
737
680
  .obsidian/ Obsidian vault configuration
738
- .planning/discovery/ Discovery Sprint outputs (created by /pp-discovery)
739
- prototype/ Interactive HTML prototype (built during Discovery)
681
+ .planning/discovery/ Discovery Sprint outputs and the prototype (created by /pp-discovery)
740
682
  requirements/ Functional requirements, user stories, test cases
741
683
  Inputs/docs/ Input documents and reference materials
742
684
  docs/ Architecture decisions and guides
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env bash
2
+ # detect-build-commands.sh — THE build/test command sniff ladder (D-09-02, D-09-05).
3
+ #
4
+ # SOURCED, never executed. bash 3.2-compatible (macOS ships 3.2.57): no
5
+ # associative arrays, no mapfile, no ${var,,}. Sets no `set -e`/`set -u`,
6
+ # because it is sourced into shells that may or may not use them.
7
+ #
8
+ # ## Contract
9
+ #
10
+ # pp_detect_build_cmd -> prints ONE build command on stdout
11
+ # pp_detect_test_cmd [targets] -> prints ONE test command on stdout
12
+ #
13
+ # Both ALWAYS exit 0. When no tool is detected they print NOTHING — and the
14
+ # CALLER, not the ladder, decides how to report that. D-09-05: it must be
15
+ # reported as NOT RUN, never as a pass (`true`) and never as a failure
16
+ # (`false`). The four shipped ladders disagreed here — post-merge-gate,
17
+ # execute-phase and audit-fix emitted `true` (a green gate on a project with no
18
+ # runner) while verify-phase emitted `false` and then printed
19
+ # "Test suite failed (exit code 1)" for a project that simply had no tests.
20
+ # Emitting nothing makes the ambiguity impossible to reproduce at the callers.
21
+ #
22
+ # `workflow.build_command` / `workflow.test_command` still win over this
23
+ # ladder; they are read by the caller, which only enters the ladder when the
24
+ # configured value is empty. The ladder itself reads no configuration.
25
+ #
26
+ # ## Why one owner
27
+ #
28
+ # Four ladders shipped and they had already drifted from each other: only
29
+ # post-merge-gate carried the Xcode arm; post-merge-gate's build and test
30
+ # ladders put package.json in different positions; the pytest flags differed at
31
+ # every site (-x at two, plain at one, ${REGRESSION_FILES} at another) and the
32
+ # `uv run` fallback existed at only two. Adding a fifth divergent .NET arm to
33
+ # each copy would repeat the prose-drift pattern this workstream has hit four
34
+ # times, so D-09-02's discretion is exercised as: ONE owner, sourced by every
35
+ # site. Plan 09-02 wires the five call sites:
36
+ # pp-core/workflows/execute-phase/steps/post-merge-gate.md (Step A and Step B)
37
+ # pp-core/workflows/verify-phase.md (test suite step)
38
+ # pp-core/workflows/execute-phase.md (regression step)
39
+ # pp-core/workflows/audit-fix.md (per-fix test run)
40
+ #
41
+ # ## Where .NET sits, and why
42
+ #
43
+ # A .NET repository routinely carries a package.json for its front-end assets,
44
+ # so a package.json arm placed first SHADOWS the solution and runs `npm test`
45
+ # on a repo whose tests are MSTest/xUnit. The .NET arm therefore sits
46
+ # IMMEDIATELY BEFORE the package.json arm in both ladders — after Justfile in
47
+ # the test ladder, after the Python arm in the build ladder, matching where
48
+ # package.json already sat in each. The relative order of every pre-existing
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
51
+ # ("PLACEMENT RUNG"), which swaps the two arms in a scratch copy and asserts
52
+ # the shadowing reappears.
53
+ #
54
+ # ## Convergence choices made where the four sites disagreed
55
+ #
56
+ # * pytest loses the `-x` that two of the four carried: verify-phase.md
57
+ # reports total/passed/failed counts, and fail-fast truncates them.
58
+ # * pytest keeps the `uv run ...` fallback that two of the four carried: it is
59
+ # strictly more likely to find a runner and costs nothing when uv is absent.
60
+ # * the Xcode arm, which only post-merge-gate had, now applies everywhere.
61
+ #
62
+ # ## Security note (T-09-01)
63
+ #
64
+ # The emitted string is later run by the caller under `bash -c`. The .NET target
65
+ # is a path `find` produced inside the project and is single-quoted in the
66
+ # emitted command; a filename containing a single quote breaks the quoting
67
+ # rather than escaping it, which is the pre-existing behaviour of every arm that
68
+ # interpolates a discovered path (the Xcode arm does the same with its scheme).
69
+ # The pytest `targets` argument is caller-supplied (execute-phase's
70
+ # REGRESSION_FILES, derived from SUMMARY frontmatter) and is interpolated
71
+ # unquoted exactly as it is today — deliberately, because it is a LIST of paths.
72
+ # No new trust boundary is introduced here.
73
+
74
+ # Emit one command line. Kept as a function so every arm is a single line and
75
+ # the placement rung has an unambiguous two-line anchor to swap.
76
+ _pp_emit() { printf '%s\n' "$1"; }
77
+
78
+ # ─── .NET detection ──────────────────────────────────────────────────────────
79
+
80
+ # Print the best .NET target, or nothing. A solution at the repository root
81
+ # wins; failing that, the first project file.
82
+ #
83
+ # -maxdepth 3 on the csproj probe, and the depth is MEASURED rather than
84
+ # guessed: the canonical .NET layout is src/<Project>/<Project>.csproj, which
85
+ # `find` counts at depth 3 (./src, ./src/App, ./src/App/App.csproj). A
86
+ # -maxdepth 2 probe covers ./App.csproj and ./App/App.csproj but misses the
87
+ # canonical one entirely, which would silently hand a .NET repository back to
88
+ # the package.json arm. All three layouts are pinned as a matrix in
89
+ # tests/gate-shell-owners.test.cjs.
90
+ #
91
+ # The solution probe stays at depth 1: a .sln nested deeper falls through to
92
+ # the project probe, which still yields a correct `dotnet test`, whereas a
93
+ # deeper search risks picking an unrelated solution out of a vendored tree.
94
+ _pp_dotnet_target() {
95
+ local found
96
+ found=$(find . -maxdepth 1 -name '*.sln' 2>/dev/null | head -1)
97
+ if [ -n "$found" ]; then printf '%s\n' "$found"; return 0; fi
98
+ found=$(find . -maxdepth 3 -name '*.csproj' -not -path '*/node_modules/*' 2>/dev/null | head -1)
99
+ if [ -n "$found" ]; then printf '%s\n' "$found"; return 0; fi
100
+ return 0
101
+ }
102
+
103
+ # True when this looks like a .NET repository. global.json and
104
+ # Directory.Build.props mark one even when no .sln/.csproj sits shallow enough
105
+ # for the probe above to find it.
106
+ _pp_is_dotnet() {
107
+ if [ -n "$(_pp_dotnet_target)" ]; then return 0; fi
108
+ if [ -f "global.json" ]; then return 0; fi
109
+ if [ -f "Directory.Build.props" ]; then return 0; fi
110
+ return 1
111
+ }
112
+
113
+ # Emit `dotnet <verb>` against the best target, or bare when there is none —
114
+ # `dotnet` searches the current directory itself in that case.
115
+ _pp_dotnet_cmd() {
116
+ local verb="$1" target
117
+ target=$(_pp_dotnet_target)
118
+ if [ -n "$target" ]; then
119
+ _pp_emit "dotnet $verb '$target'"
120
+ else
121
+ _pp_emit "dotnet $verb"
122
+ fi
123
+ }
124
+
125
+ # ─── Xcode detection ─────────────────────────────────────────────────────────
126
+
127
+ # Emit an xcodebuild command for <build|test>, or nothing when there is no
128
+ # xcodeproj. The scheme probe is best-effort: with no Xcode installed
129
+ # (CI, or a Command Line Tools-only Mac) it fails silently and the bare,
130
+ # scheme-less form is emitted.
131
+ _pp_xcode_cmd() {
132
+ local verb="$1" proj scheme
133
+ proj=$(find . -maxdepth 2 -name "*.xcodeproj" -not -path "*/node_modules/*" 2>/dev/null | head -1)
134
+ if [ -z "$proj" ]; then return 0; fi
135
+ scheme=$(xcodebuild -list -json -project "$proj" 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('project',{}).get('schemes',[None])[0] or '')" 2>/dev/null || true)
136
+ if [ -n "$scheme" ]; then
137
+ _pp_emit "xcodebuild $verb -scheme '$scheme' -destination 'platform=iOS Simulator,name=iPhone 16'"
138
+ else
139
+ _pp_emit "xcodebuild $verb -destination 'platform=iOS Simulator,name=iPhone 16'"
140
+ fi
141
+ }
142
+
143
+ # ─── The build ladder ────────────────────────────────────────────────────────
144
+
145
+ pp_detect_build_cmd() {
146
+ local xcode
147
+ xcode=$(_pp_xcode_cmd build)
148
+ if [ -n "$xcode" ]; then _pp_emit "$xcode"; return 0; fi
149
+ if [ -f "Makefile" ] && grep -q "^build:" Makefile; then _pp_emit "make build"; return 0; fi
150
+ if [ -f "Justfile" ] || [ -f "justfile" ]; then _pp_emit "just build"; return 0; fi
151
+ if [ -f "Cargo.toml" ]; then _pp_emit "cargo build"; return 0; fi
152
+ if [ -f "go.mod" ]; then _pp_emit "go build ./..."; return 0; fi
153
+ if [ -f "pyproject.toml" ] || [ -f "requirements.txt" ]; then
154
+ _pp_emit "python -m py_compile $(find . -name '*.py' -not -path './.planning/*' -not -path './node_modules/*' | head -20 | tr '\n' ' ')"
155
+ return 0
156
+ fi
157
+ if _pp_is_dotnet; then _pp_dotnet_cmd build; return 0; fi
158
+ if [ -f "package.json" ] && grep -q '"build"' package.json; then _pp_emit "npm run build"; return 0; fi
159
+ return 0
160
+ }
161
+
162
+ # ─── The test ladder ─────────────────────────────────────────────────────────
163
+
164
+ # $1 (optional): a space-separated list of test targets, used only by the
165
+ # Python arm (execute-phase's REGRESSION_FILES). Every other arm ignores it,
166
+ # exactly as the four shipped ladders did.
167
+ pp_detect_test_cmd() {
168
+ local targets="${1:-}" xcode
169
+ xcode=$(_pp_xcode_cmd test)
170
+ if [ -n "$xcode" ]; then _pp_emit "$xcode"; return 0; fi
171
+ if [ -f "Makefile" ] && grep -q "^test:" Makefile; then _pp_emit "make test"; return 0; fi
172
+ if [ -f "Justfile" ] || [ -f "justfile" ]; then _pp_emit "just test"; return 0; fi
173
+ if _pp_is_dotnet; then _pp_dotnet_cmd test; return 0; fi
174
+ if [ -f "package.json" ]; then _pp_emit "npm test"; return 0; fi
175
+ if [ -f "Cargo.toml" ]; then _pp_emit "cargo test"; return 0; fi
176
+ if [ -f "go.mod" ]; then _pp_emit "go test ./..."; return 0; fi
177
+ if [ -f "pyproject.toml" ] || [ -f "requirements.txt" ]; then
178
+ _pp_emit "python -m pytest ${targets:+$targets }-q --tb=short 2>&1 || uv run python -m pytest ${targets:+$targets }-q --tb=short"
179
+ return 0
180
+ fi
181
+ return 0
182
+ }
@@ -55,6 +55,20 @@ function _readRawConfigKey(filePath, dotKey) {
55
55
  return { found: false, value: undefined };
56
56
  }
57
57
  }
58
+ /**
59
+ * The raw config files levels 2 and 3 read, in read order: the active
60
+ * `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.
66
+ */
67
+ function activationConfigFilesFor(cwd) {
68
+ const wsConfigPath = node_path_1.default.join(planningDir(cwd), 'config.json');
69
+ const rootConfigPath = node_path_1.default.join(planningRoot(cwd), 'config.json');
70
+ return wsConfigPath !== rootConfigPath ? [wsConfigPath, rootConfigPath] : [wsConfigPath];
71
+ }
58
72
  /**
59
73
  * Resolve the raw value for a dotted config key using the four-level precedence
60
74
  * walk. Returns { found, value } with the RAW value (not coerced to boolean),
@@ -76,15 +90,10 @@ function resolveConfigKey(dotKey, opts) {
76
90
  return { found: true, value: fromConfig.value };
77
91
  // Level 2 + 3: raw config.json files (only when cwd is available)
78
92
  if (cwd) {
79
- const wsConfigPath = node_path_1.default.join(planningDir(cwd), 'config.json');
80
- const rootConfigPath = node_path_1.default.join(planningRoot(cwd), 'config.json');
81
- const fromWs = _readRawConfigKey(wsConfigPath, dotKey);
82
- if (fromWs.found)
83
- return { found: true, value: fromWs.value };
84
- if (wsConfigPath !== rootConfigPath) {
85
- const fromRoot = _readRawConfigKey(rootConfigPath, dotKey);
86
- if (fromRoot.found)
87
- return { found: true, value: fromRoot.value };
93
+ for (const filePath of activationConfigFilesFor(cwd)) {
94
+ const fromFile = _readRawConfigKey(filePath, dotKey);
95
+ if (fromFile.found)
96
+ return { found: true, value: fromFile.value };
88
97
  }
89
98
  }
90
99
  // Level 4: registry configSchema default
@@ -110,4 +119,5 @@ module.exports = {
110
119
  _readRawConfigKey,
111
120
  _resolveActivationValue,
112
121
  resolveConfigKey,
122
+ activationConfigFilesFor,
113
123
  };
@@ -1931,7 +1931,7 @@ const capabilities = {
1931
1931
  "id": "vault",
1932
1932
  "role": "feature",
1933
1933
  "title": "Client vault load",
1934
- "description": "Fetches client-specific knowledge (standards, patterns, conventions) from a provider-selected git host vault repo at a pinned ref before plan and execute. Inert unless vault.enabled and .platform-bindings.json + client.vaultRepo are present. Advisory: fetch failure falls back to cached copy and warns; never blocks.",
1934
+ "description": "Fetches client-specific knowledge (standards, patterns, conventions) from a provider-selected git host vault repo at a pinned ref before plan and execute. Inert unless vault.enabled is true. The vault.status gate reports one verdict (loaded / degraded) from a single owner; it confirms a degraded load and blocks only when vault.required is true. Fetch failure falls back to the cached copy and warns.",
1935
1935
  "tier": "full",
1936
1936
  "requires": [],
1937
1937
  "runtimeCompat": {
@@ -1949,6 +1949,11 @@ const capabilities = {
1949
1949
  "default": false,
1950
1950
  "description": "Enable client vault load. When false, all steps and gates are inert."
1951
1951
  },
1952
+ "vault.required": {
1953
+ "type": "boolean",
1954
+ "default": false,
1955
+ "description": "Make the client vault load gate blocking. When true (and vault.enabled is true), plan:pre and execute:pre stop unless the client vault is loaded at its pinned ref. Must be a JSON boolean; any other value is treated as false and named on the gate card."
1956
+ },
1952
1957
  "vault.provider": {
1953
1958
  "type": "string",
1954
1959
  "default": "gitlab",
@@ -2005,6 +2010,18 @@ const capabilities = {
2005
2010
  "consumes": [],
2006
2011
  "when": "vault.enabled",
2007
2012
  "onError": "skip"
2013
+ },
2014
+ {
2015
+ "point": "execute:pre",
2016
+ "ref": {
2017
+ "command": "vault fetch"
2018
+ },
2019
+ "produces": [
2020
+ ".planning/vault/"
2021
+ ],
2022
+ "consumes": [],
2023
+ "when": "vault.enabled",
2024
+ "onError": "skip"
2008
2025
  }
2009
2026
  ],
2010
2027
  "contributions": [
@@ -2036,8 +2053,17 @@ const capabilities = {
2036
2053
  "query": "vault.status"
2037
2054
  },
2038
2055
  "when": "vault.enabled",
2039
- "blocking": false,
2040
- "onError": "skip"
2056
+ "blocking": true,
2057
+ "onError": "halt"
2058
+ },
2059
+ {
2060
+ "point": "execute:pre",
2061
+ "check": {
2062
+ "query": "vault.status"
2063
+ },
2064
+ "when": "vault.enabled",
2065
+ "blocking": true,
2066
+ "onError": "halt"
2041
2067
  }
2042
2068
  ]
2043
2069
  },
@@ -2437,8 +2463,8 @@ const byLoopPoint = {
2437
2463
  "query": "vault.status"
2438
2464
  },
2439
2465
  "when": "vault.enabled",
2440
- "blocking": false,
2441
- "onError": "skip"
2466
+ "blocking": true,
2467
+ "onError": "halt"
2442
2468
  }
2443
2469
  ]
2444
2470
  },
@@ -2473,9 +2499,34 @@ const byLoopPoint = {
2473
2499
  ]
2474
2500
  },
2475
2501
  "execute:pre": {
2476
- "steps": [],
2502
+ "steps": [
2503
+ {
2504
+ "capId": "vault",
2505
+ "point": "execute:pre",
2506
+ "ref": {
2507
+ "command": "vault fetch"
2508
+ },
2509
+ "produces": [
2510
+ ".planning/vault/"
2511
+ ],
2512
+ "consumes": [],
2513
+ "when": "vault.enabled",
2514
+ "onError": "skip"
2515
+ }
2516
+ ],
2477
2517
  "contributions": [],
2478
- "gates": []
2518
+ "gates": [
2519
+ {
2520
+ "capId": "vault",
2521
+ "point": "execute:pre",
2522
+ "check": {
2523
+ "query": "vault.status"
2524
+ },
2525
+ "when": "vault.enabled",
2526
+ "blocking": true,
2527
+ "onError": "halt"
2528
+ }
2529
+ ]
2479
2530
  },
2480
2531
  "execute:wave:pre": {
2481
2532
  "steps": [],
@@ -2764,6 +2815,7 @@ const configKeys = {
2764
2815
  "workflow.ui_review": "ui",
2765
2816
  "workflow.ui_safety_gate": "ui",
2766
2817
  "vault.enabled": "vault",
2818
+ "vault.required": "vault",
2767
2819
  "vault.provider": "vault",
2768
2820
  "vault.cache_ttl_hours": "vault",
2769
2821
  "vault.fallback_repo": "vault",
@@ -3006,6 +3058,12 @@ const configSchema = {
3006
3058
  "default": false,
3007
3059
  "description": "Enable client vault load. When false, all steps and gates are inert."
3008
3060
  },
3061
+ "vault.required": {
3062
+ "owner": "vault",
3063
+ "type": "boolean",
3064
+ "default": false,
3065
+ "description": "Make the client vault load gate blocking. When true (and vault.enabled is true), plan:pre and execute:pre stop unless the client vault is loaded at its pinned ref. Must be a JSON boolean; any other value is treated as false and named on the gate card."
3066
+ },
3009
3067
  "vault.provider": {
3010
3068
  "owner": "vault",
3011
3069
  "type": "string",