@pareto4/pp-core 1.20.0 → 1.21.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 (62) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/agents/pp-nyquist-auditor.md +19 -14
  3. package/agents/pp-plan-checker.md +59 -36
  4. package/agents/pp-planner.md +34 -53
  5. package/agents/pp-verifier.md +3 -52
  6. package/commands/pp-autonomous.md +2 -1
  7. package/commands/pp-plan-phase.md +2 -1
  8. package/commands/pp-plan-review-convergence.md +2 -1
  9. package/gemini-extension.json +1 -1
  10. package/package.json +1 -1
  11. package/pp-core/bin/lib/capability-activation.cjs +77 -0
  12. package/pp-core/bin/lib/capability-registry.cjs +14 -14
  13. package/pp-core/bin/lib/capability-state.cjs +8 -18
  14. package/pp-core/bin/lib/ceremony.cjs +1342 -0
  15. package/pp-core/bin/lib/check-command-router.cjs +62 -1
  16. package/pp-core/bin/lib/commands.cjs +29 -3
  17. package/pp-core/bin/lib/config.cjs +5 -0
  18. package/pp-core/bin/lib/init.cjs +50 -1
  19. package/pp-core/bin/lib/io.cjs +2 -0
  20. package/pp-core/bin/lib/loop-resolver.cjs +26 -12
  21. package/pp-core/bin/lib/phase.cjs +50 -8
  22. package/pp-core/bin/lib/plan-sizing.cjs +346 -0
  23. package/pp-core/bin/lib/state.cjs +1 -0
  24. package/pp-core/bin/lib/test-substance.cjs +3190 -0
  25. package/pp-core/bin/lib/timeline.cjs +605 -0
  26. package/pp-core/bin/pp-tools.cjs +71 -4
  27. package/pp-core/bin/shared/ceremony-gates.json +17 -0
  28. package/pp-core/bin/shared/config-schema.manifest.json +1 -0
  29. package/pp-core/references/ceremony.md +81 -0
  30. package/pp-core/references/few-shot-examples/plan-checker.md +8 -8
  31. package/pp-core/references/phase-timeline.md +107 -0
  32. package/pp-core/references/planner-antipatterns.md +32 -0
  33. package/pp-core/references/planner-guidance.md +17 -14
  34. package/pp-core/references/planner-revision.md +1 -1
  35. package/pp-core/references/planning-config.md +3 -2
  36. package/pp-core/references/test-substance.md +324 -0
  37. package/pp-core/references/verifier-stub-patterns.md +51 -0
  38. package/pp-core/templates/VALIDATION.md +1 -0
  39. package/pp-core/templates/phase-prompt.md +19 -7
  40. package/pp-core/templates/roadmap.md +1 -1
  41. package/pp-core/templates/verification-report.md +1 -1
  42. package/pp-core/workflows/audit-milestone.md +4 -1
  43. package/pp-core/workflows/autonomous.md +11 -8
  44. package/pp-core/workflows/code-review.md +21 -9
  45. package/pp-core/workflows/execute-phase/steps/check-query-gate.md +7 -7
  46. package/pp-core/workflows/execute-phase/steps/codebase-drift-gate.md +3 -2
  47. package/pp-core/workflows/execute-phase.md +15 -4
  48. package/pp-core/workflows/init/steps/client-context-capture.md +1 -1
  49. package/pp-core/workflows/plan-phase/steps/chunked-planning.md +7 -3
  50. package/pp-core/workflows/plan-phase/steps/prd-express.md +104 -0
  51. package/pp-core/workflows/plan-phase.md +47 -114
  52. package/pp-core/workflows/plan-review-convergence.md +6 -3
  53. package/pp-core/workflows/profile-user.md +2 -2
  54. package/pp-core/workflows/quick.md +1 -1
  55. package/pp-core/workflows/ship.md +3 -3
  56. package/pp-core/workflows/spec-phase.md +2 -2
  57. package/pp-core/workflows/stats.md +19 -4
  58. package/pp-core/workflows/validate-phase.md +19 -4
  59. package/pp-core/workflows/verify-phase.md +1 -1
  60. package/pp-core/workflows/verify-work.md +1 -1
  61. package/scripts/gen-capability-registry.cjs +43 -45
  62. package/scripts/run-tests.cjs +54 -30
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pp-core",
3
3
  "displayName": "PP Core",
4
- "version": "1.20.0",
4
+ "version": "1.21.1",
5
5
  "description": "PP Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
6
6
  "author": {
7
7
  "name": "pareto4",
@@ -31,6 +31,7 @@ For each gap in `<gaps>`: generate minimal behavioral test, run it, debug if fai
31
31
  - Treating "test file created" as "gap filled" before the test actually runs and passes
32
32
  - Marking gaps as SKIP without escalating — a skipped gap is an unverified requirement, not a resolved one
33
33
  - Debugging a failing test by weakening the assertion rather than fixing the implementation via ESCALATE
34
+ - Counting a test that asserts nothing as coverage
34
35
 
35
36
  **Required finding classification:**
36
37
  - **BLOCKER** — gap test fails after 3 iterations; requirement unmet; ESCALATE to developer
@@ -80,6 +81,9 @@ Action by gap type:
80
81
  - `no_test_file` → Create test file
81
82
  - `test_fails` → Diagnose and fix the test (not impl)
82
83
  - `no_automated_command` → Determine command, update map
84
+ - `asserts_nothing` → Read the case first; an assertion made inside a helper it calls clears it (report it covered, no edit). Otherwise add an assertion of the requirement's behaviour to the existing test. Never delete the test or weaken an assertion. An added assertion that still fails after the 3 debug iterations is an implementation bug → ESCALATE.
85
+
86
+ While reading tests, also report any case you find yourself that asserts nothing, as an `asserts_nothing` gap. Rules: `~/.claude/pp-core/references/test-substance.md` § Assertion-free tests at validation.
83
87
  </step>
84
88
 
85
89
  <step name="generate_tests">
@@ -117,8 +121,8 @@ After 3 failed iterations: ESCALATE with requirement, expected vs actual behavio
117
121
  </step>
118
122
 
119
123
  <step name="report">
120
- Resolved gaps: `{ task_id, requirement, test_type, automated_command, file_path, status: "green" }`
121
- Escalated gaps: `{ task_id, requirement, reason, debug_iterations, last_error }`
124
+ Resolved gaps: `{ task_id, requirement, gap_type, test_type, automated_command, file_path, status: "green" }`
125
+ Escalated gaps: `{ task_id, requirement, gap_type, reason, debug_iterations, last_error }`
122
126
 
123
127
  Return one of three formats below.
124
128
  </step>
@@ -141,9 +145,9 @@ Return one of three formats below.
141
145
  | 1 | {path} | {unit/integration/smoke} | `{cmd}` |
142
146
 
143
147
  ### Verification Map Updates
144
- | Task ID | Requirement | Command | Status |
145
- |---------|-------------|---------|--------|
146
- | {id} | {req} | `{cmd}` | green |
148
+ | Task ID | Requirement | Gap Type | Command | Status |
149
+ |---------|-------------|----------|---------|--------|
150
+ | {id} | {req} | {gap_type} | `{cmd}` | green |
147
151
 
148
152
  ### Files for Commit
149
153
  {test file paths}
@@ -158,14 +162,14 @@ Return one of three formats below.
158
162
  **Resolved:** {M}/{total} | **Escalated:** {K}/{total}
159
163
 
160
164
  ### Resolved
161
- | Task ID | Requirement | File | Command | Status |
162
- |---------|-------------|------|---------|--------|
163
- | {id} | {req} | {file} | `{cmd}` | green |
165
+ | Task ID | Requirement | Gap Type | File | Command | Status |
166
+ |---------|-------------|----------|------|---------|--------|
167
+ | {id} | {req} | {gap_type} | {file} | `{cmd}` | green |
164
168
 
165
169
  ### Escalated
166
- | Task ID | Requirement | Reason | Iterations |
167
- |---------|-------------|--------|------------|
168
- | {id} | {req} | {reason} | {N}/3 |
170
+ | Task ID | Requirement | Gap Type | Reason | Iterations |
171
+ |---------|-------------|----------|--------|------------|
172
+ | {id} | {req} | {gap_type} | {reason} | {N}/3 |
169
173
 
170
174
  ### Files for Commit
171
175
  {test file paths for resolved gaps}
@@ -180,9 +184,9 @@ Return one of three formats below.
180
184
  **Resolved:** 0/{total}
181
185
 
182
186
  ### Details
183
- | Task ID | Requirement | Reason | Iterations |
184
- |---------|-------------|--------|------------|
185
- | {id} | {req} | {reason} | {N}/3 |
187
+ | Task ID | Requirement | Gap Type | Reason | Iterations |
188
+ |---------|-------------|----------|--------|------------|
189
+ | {id} | {req} | {gap_type} | {reason} | {N}/3 |
186
190
 
187
191
  ### Recommendations
188
192
  - **{req}:** {manual test instructions or implementation fix needed}
@@ -197,6 +201,7 @@ Return one of three formats below.
197
201
  - [ ] Tests verify behavior, not structure
198
202
  - [ ] Every test executed — none marked passing without running
199
203
  - [ ] Implementation files never modified
204
+ - [ ] `asserts_nothing` gaps filled by adding assertions, never by deleting or weakening tests
200
205
  - [ ] Max 3 debug iterations per gap
201
206
  - [ ] Implementation bugs escalated, not fixed
202
207
  - [ ] Structured return provided (GAPS FILLED / PARTIAL / ESCALATE)
@@ -85,6 +85,7 @@ REVIEWS.md is audit trail and feedback input, not a hidden execution contract. /
85
85
  - Do not re-open historical findings that are already incorporated, explicitly deferred/rejected in PLAN.md, or marked fully resolved.
86
86
  - Verify each current actionable review finding appears in executable PLAN.md content: a task, `<action>`, `<acceptance_criteria>`, `<verify>`, `must_haves`, threat model, artifact list, stale-path correction, or explicit deferral/rejection rationale.
87
87
  - If a current actionable finding remains only in REVIEWS.md and would be invisible to /pp:execute-phase, return `## ISSUES FOUND`. Use WARNING by default; use BLOCKER when the missing incorporation can prevent the phase goal, create unsafe execution, or invalidate verification.
88
+ **Check mode.** When the prompt says `**Check mode:** blockers-only`, Read `~/.claude/pp-core/references/ceremony.md` § `## Blockers-only checker mode` before Step 1 and follow it: report BLOCKER issues only.
88
89
  </upstream_input>
89
90
 
90
91
  <core_principle>
@@ -244,37 +245,43 @@ issue:
244
245
 
245
246
  ## Dimension 5: Scope Sanity
246
247
 
247
- **Question:** Will plans complete within context budget?
248
+ **Question:** Will plans complete within context budget, and is every split justified?
248
249
 
249
250
  **Process:**
250
- 1. Count tasks per plan
251
- 2. Estimate files modified per plan
252
- 3. Check against thresholds
251
+ 1. Run `pp_run check plan-sizing "$phase_number" --raw` (reads every PLAN.md and `context_window`)
252
+ 2. Raise each `over_ceiling` plan with `has_summary` false and each `unjustified_splits` or `unestimated_serial` pair as a blocker, naming each `unparseable_estimate` value (fix: a bare integer or `60k`). `phase_found` false means the phase number is wrong: re-run with the right one before judging scope
253
+ 3. Compare each unexecuted plan's `percent_of_window` with the Total-context row
254
+ 4. Judge whether each `context_estimate` is plausible for its tasks and files (signals: planner-guidance.md Task Sizing)
255
+
256
+ **Executed plans:** a plan with `has_summary` true is executed. Report its task count and context as info, never as a warning or blocker, under every threshold and red flag below and in Step 8: the planner cannot split it.
253
257
 
254
258
  **Thresholds:**
255
259
  | Metric | Target | Warning | Blocker |
256
260
  |--------|--------|---------|---------|
257
- | Tasks/plan | 2-3 | 4 | 5+ |
258
- | Files/plan | 5-8 | 10 | 15+ |
259
- | Total context | ~50% | ~70% | 80%+ |
261
+ | Tasks/plan | 1-6 | — | 7+ |
262
+ | Total context (`context_estimate` vs `context_window`) | ~50% | ~70% | 80%+ |
263
+ | Serial split (`unjustified_splits`) | none | — | any pair |
264
+
265
+ Files per plan are a cross-check on the estimate, not a threshold: a plan in `estimate_files_mismatch` (many files, low estimate) is a warning. A plan above 50% but under 70% is info (the planner should have split it). A plan without `context_estimate` is judged on task count only: alone it is info; in an `unestimated_serial` pair (serial, merge fits 6 tasks, no estimate shows a budget reason) it is a blocker.
260
266
 
261
267
  **Red flags:**
262
- - Plan with 5+ tasks (quality degrades)
263
- - Plan with 15+ file modifications
268
+ - Unexecuted plan with 7+ tasks
269
+ - A serial pair, each plan alone in its wave, whose merge fits 6 tasks and the budget (a split with neither a parallelism nor a budget reason)
264
270
  - Single task with 10+ files
265
- - Complex work (auth, payments) crammed into one plan
271
+ - A context_estimate implausibly low for the plan's tasks and files
266
272
 
267
273
  **Example issue:**
268
274
  ```yaml
269
275
  issue:
270
276
  dimension: scope_sanity
271
- severity: warning
272
- description: "Plan 01 has 5 tasks - split recommended"
273
- plan: "01"
277
+ severity: blocker
278
+ description: "Plans 02 and 03 are a serial split with no reason: each alone in its wave, merged 4 tasks / 70000 tokens fits the 100000 budget"
279
+ plan: "02"
274
280
  metrics:
275
- tasks: 5
276
- files: 12
277
- fix_hint: "Split into 2 plans: foundation (01) and integration (02)"
281
+ merged_tasks: 4
282
+ merged_estimate: 70000
283
+ plan_budget_tokens: 100000
284
+ fix_hint: "Merge 03 into 02"
278
285
  ```
279
286
 
280
287
  ## Dimension 6: Verification Derivation
@@ -446,11 +453,17 @@ issue:
446
453
 
447
454
  ## Dimension 8: Nyquist Compliance
448
455
 
449
- Skip if: `workflow.nyquist_validation` is explicitly set to `false` in config.json (absent key = enabled), phase has no RESEARCH.md, or RESEARCH.md has no "Validation Architecture" section. Output: "Dimension 8: SKIPPED (nyquist_validation disabled or not applicable)"
456
+ Skip only if `workflow.nyquist_validation` is explicitly `false` in config.json (absent key = enabled; the verb then reports `enforced: false`). Output: "Dimension 8: SKIPPED (nyquist_validation disabled)". A missing RESEARCH.md never skips this dimension, at any tier, light included. Rules: Read `~/.claude/pp-core/references/test-substance.md`.
457
+
458
+ ### Check 8f — Test Substance (run first)
459
+
460
+ Run `pp_run check test-substance "$phase_number" --raw` (launcher bound in Step 1). `phase_found` false: re-run with the right phase. Raise every finding on a plan with `executed` false as a BLOCKER under its `code` and `detail` (every code is a blocker, so blockers-only mode keeps them). Then judge what code cannot:
461
+ - Does each `<behavior>` name what its `<automated>` command actually asserts? A statement about a different behaviour than the command tests is a BLOCKER.
462
+ - For each `tdd_candidates_without_tdd` task, apply the planner's TDD heuristic (`expect(fn(input)).toBe(output)` before `fn`): a confirmed business-logic task without `tdd="true"` is a BLOCKER; glue code that touches source files is not raised.
450
463
 
451
464
  ### Check 8e — VALIDATION.md Existence (Gate)
452
465
 
453
- Before running checks 8a-8d, verify VALIDATION.md exists:
466
+ Applies only when RESEARCH.md exists and has a `## Validation Architecture` section; otherwise skip 8e and run 8a-8d and 8f. Before checks 8a-8d, verify VALIDATION.md exists:
454
467
 
455
468
  ```bash
456
469
  [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
@@ -467,7 +480,7 @@ Skip checks 8a-8d entirely. Report Dimension 8 as FAIL with this single issue.
467
480
  For each `<task>` in each plan:
468
481
  - `<verify>` must contain `<automated>` command, OR a Wave 0 dependency that creates the test first
469
482
  - If `<automated>` is absent with no Wave 0 dependency → **BLOCKING FAIL**
470
- - If `<automated>` says "MISSING", a Wave 0 task must reference the same test file path → **BLOCKING FAIL** if link broken
483
+ - If `<automated>` says "MISSING" → **BLOCKING FAIL**: the executor cannot run the marker. A test file not yet written is listed by a `tdd="true"` task's own `<files>` or an earlier task of the same plan, which must be test infrastructure or `tdd="true"` (its own verify fails on the still-failing assertion), and `<automated>` runs that file's real command. Wave 0 plans carry test infrastructure only.
471
484
 
472
485
  ### Check 8b — Feedback Latency Assessment
473
486
 
@@ -482,9 +495,10 @@ Map tasks to waves. Per wave, any consecutive window of 3 implementation tasks m
482
495
 
483
496
  ### Check 8d — Wave 0 Completeness
484
497
 
485
- For each `<automated>MISSING</automated>` reference:
486
- - Wave 0 task must exist with matching `<files>` path
487
- - Wave 0 plan must execute before dependent task
498
+ For each test file an `<automated>` command runs that is not on disk yet. Check 8f's verb reports the order as `scaffold_uncreated` (`later_task`, `other_plan:<id>`, `no_creator`); raise those as in 8f, then judge what it accepts:
499
+ - The test file that carries the task's own assertion is listed by a `tdd="true"` task's own `<files>` or an earlier task of the same plan (test infrastructure or `tdd="true"`). Across plans it is accepted only when a Wave 0 test-infrastructure task (no behaviour assertion) has a matching `<files>` path
500
+ - The verb accepts any earlier-wave creator. Test infrastructure, or a test that passes with its own code in that wave, is fine; a plan that writes this task's assertion ahead of its code → **BLOCKING FAIL** (no wave merges a failing test)
501
+ - That creator executes before the dependent task
488
502
  - Missing match → **BLOCKING FAIL**
489
503
 
490
504
  ### Dimension 8 Output
@@ -492,10 +506,11 @@ For each `<automated>MISSING</automated>` reference:
492
506
  ```
493
507
  ## Dimension 8: Nyquist Compliance
494
508
 
495
- | Task | Plan | Wave | Automated Command | Status |
496
- |------|------|------|-------------------|--------|
497
- | {task} | {plan} | {wave} | `{command}` | ✅ / ❌ |
509
+ | Task | Plan | Wave | Automated Command | Behavior | Status |
510
+ |------|------|------|-------------------|----------|--------|
511
+ | {task} | {plan} | {wave} | `{command}` | {what it asserts} | ✅ / ❌ |
498
512
 
513
+ Test substance: {N} findings → ✅ / ❌
499
514
  Sampling: Wave {N}: {X}/{Y} verified → ✅ / ❌
500
515
  Wave 0: {test file} → ✅ present / ❌ MISSING
501
516
  Overall: ✅ PASS / ❌ FAIL
@@ -789,9 +804,10 @@ Missing: No mention of fetch/API call → Issue: Key link not planned
789
804
  ```bash
790
805
  pp_run query plan.task-structure "$PHASE_DIR/$PHASE-01-PLAN.md"
791
806
  pp_run query frontmatter.get "$PHASE_DIR/$PHASE-01-PLAN.md" files_modified
807
+ pp_run check plan-sizing "$phase_number" --raw
792
808
  ```
793
809
 
794
- Thresholds: 2-3 tasks/plan good, 4 warning, 5+ blocker (split required).
810
+ Thresholds (task count and percent_of_window apply to unexecuted plans only, `has_summary` false; an executed plan is info): 1-6 tasks/plan accepted, 7+ blocker (split). Every unjustified_splits pair: blocker (merge). Every unestimated_serial pair: blocker (estimate, or merge). percent_of_window above 50% info, ~70% warning, 80%+ blocker. A doubtful estimate: warning.
795
811
 
796
812
  ## Step 9: Verify must_haves Derivation
797
813
 
@@ -817,8 +833,9 @@ Severities: `blocker` (must fix), `warning` (should fix), `info` (suggestions).
817
833
 
818
834
  **Plan 01 analysis:**
819
835
  ```
820
- Tasks: 5
836
+ Tasks: 7
821
837
  Files modified: 12
838
+ context_estimate: 150000 (context_window: 200000, plan_budget_tokens: 100000)
822
839
  - prisma/schema.prisma
823
840
  - src/app/api/auth/login/route.ts
824
841
  - src/app/api/auth/logout/route.ts
@@ -833,19 +850,19 @@ Files modified: 12
833
850
  - src/types/auth.ts
834
851
  ```
835
852
 
836
- 5 tasks exceeds 2-3 target, 12 files is high, auth is complex domain → quality degradation risk.
853
+ 7 tasks exceed the 6-task ceiling and 150000 tokens is 75% of the window, over the 100000 per-plan budget.
837
854
 
838
855
  ```yaml
839
856
  issue:
840
857
  dimension: scope_sanity
841
858
  severity: blocker
842
- description: "Plan 01 has 5 tasks with 12 files - exceeds context budget"
859
+ description: "Plan 01 has 7 tasks and context_estimate 150000 - over the 6-task ceiling and the per-plan budget"
843
860
  plan: "01"
844
861
  metrics:
845
- tasks: 5
862
+ tasks: 7
846
863
  files: 12
847
- estimated_context: "~80%"
848
- fix_hint: "Split into: 01 (schema + API), 02 (middleware + lib), 03 (UI components)"
864
+ context_estimate: 150000
865
+ fix_hint: "Split into two plans of at most 6 tasks and 100000 tokens each: parallel when their files are disjoint, otherwise serial (justified by budget)"
849
866
  ```
850
867
 
851
868
  </examples>
@@ -870,15 +887,21 @@ issue:
870
887
  - Missing requirement coverage
871
888
  - Missing required task fields
872
889
  - Circular dependencies
873
- - Scope > 5 tasks per plan
890
+ - Scope > 6 tasks per plan (unexecuted, `has_summary` false)
891
+ - A split flagged by check plan-sizing (unjustified_splits, unestimated_serial)
892
+ - context_estimate at 80%+ of context_window (unexecuted plan)
893
+ - A `check test-substance` finding on an unexecuted plan, or a confirmed business-logic task without `tdd="true"`
874
894
 
875
895
  **warning** - Should fix, execution may work
876
- - Scope 4 tasks (borderline)
896
+ - context_estimate at ~70% of context_window (unexecuted plan)
897
+ - A doubtful estimate (implausible for its tasks and files, or listed in estimate_files_mismatch)
877
898
  - Implementation-focused truths
878
899
  - Minor wiring missing
879
900
 
880
901
  **info** - Suggestions for improvement
881
- - Could split for better parallelization
902
+ - Could split independent subsystems into parallel plans
903
+ - context_estimate above 50% of context_window
904
+ - Plan without context_estimate (not in a serial pair)
882
905
  - Could improve verification specificity
883
906
 
884
907
  Return all issues as a structured `issues:` YAML list (see dimension examples for format).
@@ -956,7 +979,7 @@ Plans verified. Run `/pp:execute-phase {phase}` to proceed.
956
979
 
957
980
  **DO NOT** skip dependency analysis. Circular/broken dependencies cause execution failures.
958
981
 
959
- **DO NOT** ignore scope. 5+ tasks/plan degrades quality. Report and split.
982
+ **DO NOT** ignore scope. 7+ tasks in an unexecuted plan or a flagged serial split is a blocker: report it — split the first, merge the second.
960
983
 
961
984
  **DO NOT** verify implementation details. Check that plans describe what to build.
962
985
 
@@ -26,7 +26,7 @@ Your job: Produce PLAN.md files that Claude executors can implement without inte
26
26
 
27
27
  **Core responsibilities:**
28
28
  - **FIRST: Parse and honor user decisions from CONTEXT.md** (locked decisions are NON-NEGOTIABLE)
29
- - Decompose phases into parallel-optimized plans with 2-3 tasks each
29
+ - Size plans by estimated context cost: up to 6 tasks, split only for parallelism or budget
30
30
  - Build dependency graphs and assign execution waves
31
31
  - Derive must-haves using goal-backward methodology
32
32
  - Handle both standard planning and gap closure mode
@@ -114,7 +114,7 @@ Exclusions (not gaps): Deferred Ideas in CONTEXT.md, items scoped to other phase
114
114
  The planner has no authority to judge a feature as too difficult, omit features because they seem challenging, or use "complex/difficult/non-trivial" to justify scope reduction.
115
115
 
116
116
  **Only three legitimate reasons to split or flag:**
117
- 1. **Context cost:** implementation would consume >50% of a single agent's context window
117
+ 1. **Context cost:** implementation would consume >50% of the configured context window (`plan_budget_tokens` from init)
118
118
  2. **Missing information:** required data not present in any source artifact
119
119
  3. **Dependency conflict:** feature cannot be built until another phase ships
120
120
 
@@ -162,7 +162,7 @@ For niche domains (3D/games/audio/shaders/ML), suggest `/pp:plan-phase --researc
162
162
 
163
163
  ## Task Anatomy
164
164
 
165
- Every task has four required fields:
165
+ Every task has five required fields:
166
166
 
167
167
  **<files>:** Exact file paths created or modified.
168
168
  - Good: `src/app/api/auth/login/route.ts`, `prisma/schema.prisma`
@@ -186,7 +186,7 @@ Every task has four required fields:
186
186
  - Bad: "It works", "Looks good", manual-only verification
187
187
  - Simple format also accepted: `npm test` passes, `curl -X POST /api/auth/login` returns 200
188
188
 
189
- **Nyquist Rule:** Every `<verify>` includes `<automated>`. If no test exists, set `<automated>MISSING — Wave 0 must create {test_file} first</automated>` and create that scaffold.
189
+ **Nyquist Rule:** Every `<verify>` includes `<automated>`, and every non-checkpoint task has a `<behavior>` naming what that command asserts as input → expected output (`tdd="true"`: its test cases; "tests pass", "works", "file exists" are not behaviours). With no test yet, list that test file, assertion included, in an earlier task of the plan or a `tdd="true"` task's own `<files>`; `<automated>` runs it, never `MISSING — Wave 0 must create {test_file} first`; never a vacuous scaffold. Rules: Read `~/.claude/pp-core/references/test-substance.md`.
190
190
 
191
191
  **Grep gate hygiene:** `grep -c` counts comments, so header prose can be self-invalidating. Use `grep -v '^#' | grep -c token`. Bare `== 0` gates on unfiltered files are forbidden.
192
192
 
@@ -212,37 +212,7 @@ See @~/.claude/pp-core/references/planner-guidance.md for Task Types table, Task
212
212
 
213
213
  **When `workflow.tdd_mode` is enabled:** Apply TDD heuristics aggressively — all eligible tasks MUST use `type: tdd`. Read @~/.claude/pp-core/references/tdd.md for gate enforcement rules and the end-of-phase review checkpoint format.
214
214
 
215
- **When `workflow.tdd_mode` is disabled (default):** Apply TDD heuristics opportunistically — use `type: tdd` only when the benefit is clear.
216
-
217
- **Heuristic:** Can you write `expect(fn(input)).toBe(output)` before writing `fn`?
218
- - Yes → Create a dedicated TDD plan (type: tdd)
219
- - No → Standard task in standard plan
220
-
221
- **TDD candidates (dedicated TDD plans):** Business logic with defined I/O, API endpoints with request/response contracts, data transformations, validation rules, algorithms, state machines.
222
-
223
- **Standard tasks:** UI layout/styling, configuration, glue code, one-off scripts, simple CRUD with no business logic.
224
-
225
- **Why TDD gets own plan:** TDD requires RED→GREEN→REFACTOR cycles consuming 40-50% context. Embedding in multi-task plans degrades quality.
226
-
227
- **Task-level TDD** (for code-producing tasks in standard plans): When a task creates or modifies production code, add `tdd="true"` and a `<behavior>` block to make test expectations explicit before implementation:
228
-
229
- ```xml
230
- <task type="auto" tdd="true">
231
- <name>Task: [name]</name>
232
- <files>src/feature.ts, src/feature.test.ts</files>
233
- <behavior>
234
- - Test 1: [expected behavior]
235
- - Test 2: [edge case]
236
- </behavior>
237
- <action>[Implementation after tests pass]</action>
238
- <verify>
239
- <automated>npm test -- --filter=feature</automated>
240
- </verify>
241
- <done>[Criteria]</done>
242
- </task>
243
- ```
244
-
245
- Exceptions where `tdd="true"` is not needed: `type="checkpoint:*"` tasks, configuration-only files, documentation, migration scripts, glue code wiring existing tested components, styling-only changes.
215
+ **When `workflow.tdd_mode` is disabled (default):** Heuristic: can you write `expect(fn(input)).toBe(output)` before writing `fn`? Candidates: business logic with defined I/O, API endpoints with request/response contracts, data transformations, validation rules, algorithms, state machines. A candidate gets `tdd="true"` and a `<behavior>` test-case list inside an ordinary plan (RED→GREEN); dedicated `type: tdd` plans stay `tdd_mode`'s. Not for `checkpoint:*`, configuration-only files, documentation, migration scripts, glue code wiring tested components, styling-only or test-only tasks. Example and rules: `~/.claude/pp-core/references/test-substance.md`.
246
216
 
247
217
  `workflow.human_verify_mode=end-of-phase`: no `checkpoint:human-verify`; use `<verify><human-check>`.
248
218
 
@@ -289,26 +259,18 @@ See @~/.claude/pp-core/references/planner-guidance.md for dependency graph build
289
259
 
290
260
  ## Context Budget Rules
291
261
 
292
- Plans should complete within ~50% context (not 80%). No context anxiety, quality maintained start to finish, room for unexpected complexity.
293
-
294
- **Each plan: 2-3 tasks maximum.**
262
+ Plans should complete within ~50% context (not 80%).
295
263
 
296
- | Context Weight | Tasks/Plan | Context/Task | Total |
297
- |----------------|------------|--------------|-------|
298
- | Light (CRUD, config) | 3 | ~10-15% | ~30-45% |
299
- | Medium (auth, payments) | 2 | ~20-30% | ~40-50% |
300
- | Heavy (migrations, multi-subsystem) | 1-2 | ~30-40% | ~30-50% |
264
+ **Each plan: up to 6 tasks** (`max_tasks_per_plan`), added while the summed estimate stays within `plan_budget_tokens` (50% of `context_window`, from init). The count is an outcome of the estimate, never a target. Tasks stay ~20-60k tokens (10–30% at 200k) at any window: a larger window fits more tasks, not larger ones. Estimate per planner-guidance.md Task Sizing; record each plan's sum as `context_estimate`.
301
265
 
302
266
  ## Split Signals
303
267
 
304
268
  **ALWAYS split if:**
305
- - More than 3 tasks
306
- - Multiple subsystems (DB + API + UI = separate plans)
307
- - Any task with >5 file modifications
308
- - Checkpoint + implementation in same plan
309
- - Discovery + implementation in same plan
269
+ - **Parallelism:** independent subsystems with disjoint `files_modified`, run in the same wave
270
+ - **Budget:** merged, the work would exceed `plan_budget_tokens` or 6 tasks (a dedicated TDD plan and discovery + implementation are budget cases)
271
+ - A task with >5 file modifications: split the task, not the plan
310
272
 
311
- **CONSIDER splitting:** >5 files total, natural semantic boundaries, context cost estimate exceeds 40% for a single plan. See `<planner_authority_limits>` for prohibited split reasons.
273
+ Never split serial single-concern work to fit a task count — see "Plan-Split Anti-Patterns" in @~/.claude/pp-core/references/planner-antipatterns.md. Phase splits and gap-closure plans are separate mechanisms. See `<planner_authority_limits>` for prohibited split reasons.
312
274
 
313
275
  See @~/.claude/pp-core/references/planner-guidance.md for Granularity Calibration table (Coarse/Standard/Fine plans-per-phase).
314
276
 
@@ -329,6 +291,7 @@ files_modified: [] # Files this plan touches
329
291
  autonomous: true # false if plan has checkpoints
330
292
  requirements: [] # REQUIRED — Requirement IDs from ROADMAP this plan addresses. MUST NOT be empty.
331
293
  user_setup: [] # Human-required setup (omit if empty)
294
+ context_estimate: N # REQUIRED — sum of task estimates in tokens: 90000 or 90k, no ~/units
332
295
 
333
296
  must_haves:
334
297
  truths: [] # Observable behaviors
@@ -372,6 +335,7 @@ The file's content verbatim, `<!-- discovery:auto -->` markers included; see <di
372
335
  <task type="auto">
373
336
  <name>Task 1: [Action-oriented name]</name>
374
337
  <files>path/to/file.ext</files>
338
+ <behavior>[What the verify command asserts: input → expected output]</behavior>
375
339
  <action>[Specific implementation]</action>
376
340
  <verify>[Command or check]</verify>
377
341
  <done>[Acceptance criteria]</done>
@@ -600,7 +564,7 @@ INIT=$(pp_run query init.plan-phase "${PHASE}")
600
564
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
601
565
  ```
602
566
 
603
- Extract from init JSON: `planner_model`, `researcher_model`, `checker_model`, `commit_docs`, `research_enabled`, `phase_dir`, `phase_number`, `has_research`, `has_context`.
567
+ Extract from init JSON: `planner_model`, `researcher_model`, `checker_model`, `commit_docs`, `research_enabled`, `phase_dir`, `phase_number`, `has_research`, `has_context`, `context_window`, `plan_budget_tokens`, `task_tokens_min`, `task_tokens_max`, `max_tasks_per_plan`.
604
568
 
605
569
  Also load planning state (position, decisions, blockers) via the SDK — **use `node` to invoke the CLI** (not `npx`):
606
570
  ```bash
@@ -789,7 +753,7 @@ Rules:
789
753
  1. Same-wave tasks with no file conflicts → parallel plans
790
754
  2. Shared files → same plan or sequential plans (shared file = implicit dependency → later wave)
791
755
  3. Checkpoint tasks → `autonomous: false`
792
- 4. Each plan: 2-3 tasks, single concern, ~50% context target
756
+ 4. Each plan: up to 6 tasks within `plan_budget_tokens`, single concern; split only for parallelism or budget
793
757
  </step>
794
758
 
795
759
  <step name="derive_must_haves">
@@ -811,7 +775,7 @@ UNREACHABLE (no path) → revise plan.
811
775
  </step>
812
776
 
813
777
  <step name="estimate_scope">
814
- Verify each plan fits context budget: 2-3 tasks, ~50% target. Split if necessary. Check granularity setting.
778
+ Sum each plan's task estimates into `context_estimate`; it must fit `plan_budget_tokens` with at most 6 tasks. Merge serial plans whose sum fits; split only for parallelism or budget. Check granularity setting.
815
779
  </step>
816
780
 
817
781
  <step name="confirm_breakdown">
@@ -894,6 +858,22 @@ Returns JSON: `{ valid, errors, warnings, task_count, tasks }`
894
858
  - Missing `<name>` in task → add name element
895
859
  - Missing `<action>` → add action element
896
860
  - Checkpoint/autonomous mismatch → update `autonomous: false`
861
+
862
+ Then check sizing across the phase:
863
+
864
+ ```bash
865
+ SIZING=$(pp_run check plan-sizing "$PHASE" --raw)
866
+ ```
867
+
868
+ `phase_found` false: wrong phase, stop. Merge only the first `unjustified_splits` pair, estimate each `unestimated_serial` pair (rewrite each `unparseable_estimate` as an integer), split each unexecuted `over_ceiling` / `over_budget` plan (see "Plan-Split Anti-Patterns"), re-run; repeat until `block` is false (expect `min_plans` plans).
869
+
870
+ Then:
871
+
872
+ ```bash
873
+ SUBSTANCE=$(pp_run check test-substance "$PHASE" --raw)
874
+ ```
875
+
876
+ Fix every finding on an unexecuted plan, re-run until `block` is false. Judge each `tdd_candidates_without_tdd` task by the heuristic; add `tdd="true"` to business logic. `enforced: false` (`nyquist_validation` off): findings advisory; still write `<behavior>`.
897
877
  </step>
898
878
 
899
879
  <step name="update_roadmap">
@@ -967,7 +947,8 @@ Phase planning complete when:
967
947
  - [ ] Each plan: depends_on, files_modified, autonomous, must_haves in frontmatter
968
948
  - [ ] Each plan: user_setup declared if external services involved
969
949
  - [ ] Each plan: Objective, context, tasks, verification, success criteria, output
970
- - [ ] Each plan: 2-3 tasks (~50% context)
950
+ - [ ] Each plan: ≤ 6 tasks within `plan_budget_tokens`; `check plan-sizing` reports `block: false`
951
+ - [ ] Each non-checkpoint task has a `<behavior>`; `check test-substance` reports `block: false`
971
952
  - [ ] Each task: Type, Files (if auto), Action, Verify, Done
972
953
  - [ ] Checkpoints properly structured
973
954
  - [ ] Wave structure maximizes parallelism
@@ -70,6 +70,8 @@ Then verify each level against the actual codebase.
70
70
 
71
71
  <verification_process>
72
72
 
73
+ **Depth.** When the prompt says `Verifier depth: light`, Read `~/.claude/pp-core/references/ceremony.md` § `## Verifier depth` before Step 0 and skip only the steps it names. Any other value, or none, is full depth.
74
+
73
75
  At verification decision points, apply structured reasoning:
74
76
  @~/.claude/pp-core/references/thinking-models-verification.md
75
77
 
@@ -463,7 +465,7 @@ grep -n -E "=\{(\[\]|\{\}|null|undefined|''|\"\")\}" "$file" 2>/dev/null
463
465
  grep -n -B 2 -A 2 "console\.log" "$file" 2>/dev/null | grep -E "^\s*(const|function|=>)"
464
466
  ```
465
467
 
466
- **Stub classification:** A grep match is a STUB only when the value flows to rendering or user-visible output AND no other code path populates it with real data. A test helper, type default, or initial state that gets overwritten by a fetch/store is NOT a stub. Check for data-fetching (useEffect, fetch, query, useSWR, useQuery, subscribe) that writes to the same variable before flagging.
468
+ **Stub classification:** A grep match is a STUB only when the value flows to rendering or user-visible output AND no other code path populates it with real data. A test helper, type default, or initial state that gets overwritten by a fetch/store is NOT a stub. Check for data-fetching (useEffect, fetch, query, useSWR, useQuery, subscribe) that writes to the same variable before flagging. Red-flag examples (component, API route and wiring stubs): `~/.claude/pp-core/references/verifier-stub-patterns.md`.
467
469
 
468
470
  **Debt marker gate:** Any `TBD`, `FIXME`, or `XXX` marker in a file modified by this phase is a 🛑 BLOCKER unless the same line references formal follow-up work (`issue #123`, `PR #123`, `#123`, or `DEF-*`). Unreferenced markers mean completion is not auditable; set `status: gaps_found` and list each marker under `gaps`.
469
471
 
@@ -907,57 +909,6 @@ Automated checks passed. Awaiting human verification.
907
909
 
908
910
  </critical_rules>
909
911
 
910
- <stub_detection_patterns>
911
-
912
- ## React Component Stubs
913
-
914
- ```javascript
915
- // RED FLAGS:
916
- return <div>Component</div>
917
- return <div>Placeholder</div>
918
- return <div>{/* TODO */}</div>
919
- return null
920
- return <></>
921
-
922
- // Empty handlers:
923
- onClick={() => {}}
924
- onChange={() => console.log('clicked')}
925
- onSubmit={(e) => e.preventDefault()} // Only prevents default
926
- ```
927
-
928
- ## API Route Stubs
929
-
930
- ```typescript
931
- // RED FLAGS:
932
- export async function POST() {
933
- return Response.json({ message: "Not implemented" });
934
- }
935
-
936
- export async function GET() {
937
- return Response.json([]); // Empty array with no DB query
938
- }
939
- ```
940
-
941
- ## Wiring Red Flags
942
-
943
- ```typescript
944
- // Fetch exists but response ignored:
945
- fetch('/api/messages') // No await, no .then, no assignment
946
-
947
- // Query exists but result not returned:
948
- await prisma.message.findMany()
949
- return Response.json({ ok: true }) // Returns static, not query result
950
-
951
- // Handler only prevents default:
952
- onSubmit={(e) => e.preventDefault()}
953
-
954
- // State exists but not rendered:
955
- const [messages, setMessages] = useState([])
956
- return <div>No messages</div> // Always shows "no messages"
957
- ```
958
-
959
- </stub_detection_patterns>
960
-
961
912
  <success_criteria>
962
913
 
963
914
  - [ ] Previous VERIFICATION.md checked (Step 0)
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: pp:autonomous
3
3
  description: Run the next phase autonomously (best-effort) — discuss→plan→execute; --from/--to for a range
4
- argument-hint: "[--from N] [--to N] [--only N] [--supervised] [--interactive] [--converge]"
4
+ argument-hint: "[--from N] [--to N] [--only N] [--supervised] [--interactive] [--converge] [--full]"
5
5
  effort: max
6
6
  allowed-tools:
7
7
  - Read
@@ -41,6 +41,7 @@ Optional flags:
41
41
  - `--interactive` — run discuss inline with questions (not auto-answered), then dispatch plan→execute as background agents. Keeps the main context lean while preserving user input on decisions.
42
42
  - `--converge` — run each phase's planning step through `pp-plan-review-convergence` instead of plain `pp-plan-phase`. Requires `workflow.plan_review_convergence=true`.
43
43
  - `--cross-ai` — compatibility alias for `--converge`.
44
+ - `--full` — plan every phase with the full gate stack: forwarded to every /pp-plan-phase call, through /pp-plan-review-convergence under --converge; never to execute. A later plan-phase run without --full re-classifies the phase (references/ceremony.md, Lifecycle).
44
45
 
45
46
  When `--converge` or `--cross-ai` is set, reviewer selector flags supported by `pp-plan-review-convergence` may be passed through: `--codex`, `--gemini`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`, and `--max-cycles N`.
46
47
 
@@ -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]"
4
+ argument-hint: "[phase] [--auto] [--research] [--skip-research] [--research-phase <N>] [--view] [--gaps] [--skip-verify] [--full] [--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
@@ -47,6 +47,7 @@ Phase number: $ARGUMENTS (optional — auto-detects next unplanned phase if omit
47
47
  - `--skip-research` — Skip research, go straight to planning
48
48
  - `--gaps` — Gap closure mode (reads VERIFICATION.md, skips research)
49
49
  - `--skip-verify` — Skip verification loop
50
+ - `--full` — Force every gate for this phase (ceremony mode full; rewrites the recorded verdict). Until the phase's first SUMMARY, a later plan-phase run without --full re-classifies it proportionally (D-12), so repeat --full on every re-plan that should stay full
50
51
  - `--prd <file>` — Use a PRD/acceptance criteria file instead of discuss-phase. Parses requirements into CONTEXT.md automatically. Skips discuss-phase entirely.
51
52
  - `--ingest <path-or-glob>` — Use one or more ADR files instead of discuss-phase. Parses locked decisions + scope fences into CONTEXT.md automatically. Skips discuss-phase entirely.
52
53
  - `--ingest-format <auto|nygard|madr|narrative>` — Optional ADR parser format override (`auto` default).
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: pp:plan-review-convergence
3
3
  description: "Cross-AI plan convergence - replan until review concerns are resolved."
4
- argument-hint: "<phase> [--codex] [--gemini] [--claude] [--opencode] [--ollama] [--lm-studio] [--llama-cpp] [--text] [--ws <name>] [--all] [--max-cycles N]"
4
+ argument-hint: "<phase> [--codex] [--gemini] [--claude] [--opencode] [--ollama] [--lm-studio] [--llama-cpp] [--text] [--ws <name>] [--all] [--max-cycles N] [--full]"
5
5
  allowed-tools:
6
6
  - Read
7
7
  - Write
@@ -49,6 +49,7 @@ Phase number: extracted from $ARGUMENTS (required)
49
49
  - `--llama-cpp` — Use local llama.cpp server as reviewer (OpenAI-compatible, default host `http://localhost:8080`; configure model via `review.models.llama_cpp`)
50
50
  - `--all` — Use all available CLIs and running local model servers
51
51
  - `--max-cycles N` — Maximum replan→review cycles (default: 3)
52
+ - `--full` — pass --full to the initial plan-phase run and to every --reviews replan, so the phase keeps the full gate stack
52
53
 
53
54
  **Feature gate:** This command requires `workflow.plan_review_convergence=true`. Enable with:
54
55
  `pp config-set workflow.plan_review_convergence true`
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pp-core",
3
- "version": "1.20.0",
3
+ "version": "1.21.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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pareto4/pp-core",
3
- "version": "1.20.0",
3
+ "version": "1.21.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",