pan-wizard 3.34.0 → 3.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +6 -6
  2. package/agents/pan-conductor.md +2 -2
  3. package/agents/pan-debugger.md +3 -1
  4. package/agents/pan-design-checker.md +1 -0
  5. package/agents/pan-executor.md +18 -1
  6. package/agents/pan-experiment-runner.md +1 -1
  7. package/agents/pan-hardener.md +1 -1
  8. package/agents/pan-meta-reviewer.md +1 -1
  9. package/agents/pan-phase-researcher.md +2 -2
  10. package/agents/pan-plan-checker.md +9 -8
  11. package/agents/pan-planner.md +3 -1
  12. package/agents/pan-project-researcher.md +1 -1
  13. package/agents/pan-research-synthesizer.md +1 -1
  14. package/agents/pan-reviewer.md +3 -2
  15. package/agents/pan-verifier.md +1 -1
  16. package/bin/install-lib.cjs +119 -16
  17. package/bin/install.js +34 -62
  18. package/commands/pan/cost.md +0 -4
  19. package/commands/pan/dashboard.md +0 -3
  20. package/commands/pan/design-phase.md +2 -2
  21. package/commands/pan/hud.md +1 -5
  22. package/commands/pan/knowledge.md +0 -1
  23. package/commands/pan/mcp-bridge.md +1 -3
  24. package/commands/pan/optimize.md +2 -0
  25. package/commands/pan/phase-tests.md +1 -1
  26. package/commands/pan/preview.md +1 -2
  27. package/commands/pan/report.md +1 -5
  28. package/commands/pan/research-phase.md +4 -4
  29. package/commands/pan/review-deep.md +0 -2
  30. package/commands/pan/what-if.md +1 -2
  31. package/hooks/dist/pan-context-monitor.js +12 -3
  32. package/hooks/dist/pan-guard.js +244 -0
  33. package/hooks/dist/pan-statusline.js +5 -2
  34. package/package.json +1 -1
  35. package/pan-wizard-core/bin/lib/commands.cjs +24 -2
  36. package/pan-wizard-core/bin/lib/config.cjs +5 -0
  37. package/pan-wizard-core/bin/lib/findings.cjs +126 -19
  38. package/pan-wizard-core/bin/lib/hygiene.cjs +11 -5
  39. package/pan-wizard-core/bin/lib/init.cjs +6 -0
  40. package/pan-wizard-core/bin/lib/optimize.cjs +13 -1
  41. package/pan-wizard-core/bin/lib/phase-gate.cjs +174 -0
  42. package/pan-wizard-core/bin/lib/phase.cjs +24 -0
  43. package/pan-wizard-core/bin/lib/preview.cjs +32 -31
  44. package/pan-wizard-core/bin/lib/verdict.cjs +140 -10
  45. package/pan-wizard-core/bin/lib/verify-integrity.cjs +181 -0
  46. package/pan-wizard-core/bin/lib/verify-plan-set.cjs +230 -0
  47. package/pan-wizard-core/bin/lib/verify-scope.cjs +6 -5
  48. package/pan-wizard-core/bin/lib/whatif.cjs +48 -6
  49. package/pan-wizard-core/bin/pan-tools.cjs +13 -4
  50. package/pan-wizard-core/mcp/merge-gate.cjs +14 -3
  51. package/pan-wizard-core/mcp/native-tools.cjs +3 -3
  52. package/pan-wizard-core/opencode/pan-wizard.js +36 -8
  53. package/pan-wizard-core/references/model-profiles.md +1 -1
  54. package/pan-wizard-core/references/planning-config.md +3 -3
  55. package/pan-wizard-core/references/verdict-contract.md +6 -1
  56. package/pan-wizard-core/templates/config.json +2 -6
  57. package/pan-wizard-core/templates/debug-subagent-prompt.md +2 -1
  58. package/pan-wizard-core/templates/phase-prompt.md +2 -0
  59. package/pan-wizard-core/templates/planner-subagent-prompt.md +2 -0
  60. package/pan-wizard-core/templates/preview-report.md +1 -1
  61. package/pan-wizard-core/templates/state.md +4 -4
  62. package/pan-wizard-core/workflows/diagnose-issues.md +4 -4
  63. package/pan-wizard-core/workflows/discuss-phase.md +2 -1
  64. package/pan-wizard-core/workflows/exec-phase.md +51 -40
  65. package/pan-wizard-core/workflows/milestone-gaps.md +2 -2
  66. package/pan-wizard-core/workflows/new-project.md +8 -16
  67. package/pan-wizard-core/workflows/plan-phase.md +22 -8
  68. package/pan-wizard-core/workflows/progress.md +1 -1
  69. package/pan-wizard-core/workflows/quick.md +2 -2
  70. package/pan-wizard-core/workflows/todo-check.md +3 -2
  71. package/pan-wizard-core/workflows/transition.md +4 -0
  72. package/pan-wizard-core/workflows/verify-phase.md +6 -6
  73. package/scripts/build-hooks.js +1 -0
  74. package/scripts/generate-skills-docs.py +2 -2
  75. package/scripts/prompt-lint.cjs +167 -0
  76. package/scripts/test-surface.cjs +1 -0
@@ -59,7 +59,7 @@ source: pan-previewer
59
59
  ## Hidden coupling
60
60
 
61
61
  <!-- phases mode only; may be "none found" -->
62
- - Phase {{from}} → Phase {{to}} — inferred from prose mention; consider promoting to `depends_on:` frontmatter.
62
+ - Phase {{from}} → Phase {{to}} — inferred from prose mention; consider adding it to Phase {{to}}'s `**Depends on:**` line in the roadmap.
63
63
 
64
64
  ## Current state
65
65
 
@@ -35,10 +35,10 @@ See: .planning/project.md (updated [date])
35
35
  - Average duration: [X] min
36
36
  - Total execution time: [X.X] hours
37
37
 
38
- **By Phase:**
38
+ **By Plan:** (one row per plan, written by `state record-metric`)
39
39
 
40
- | Phase | Plans | Total | Avg/Plan |
41
- |-------|-------|-------|----------|
40
+ | Plan | Duration | Tasks | Files |
41
+ |------|----------|-------|-------|
42
42
  | - | - | - | - |
43
43
 
44
44
  **Recent Trend:**
@@ -139,7 +139,7 @@ Progress calculation: (completed plans) / (total plans across all phases) × 100
139
139
  Track velocity to understand execution patterns:
140
140
  - Total plans completed
141
141
  - Average duration per plan
142
- - Per-phase breakdown
142
+ - Per-plan rows (phase, plan, duration, tasks, files)
143
143
  - Recent trend (improving/stable/degrading)
144
144
 
145
145
  Updated after each plan completion.
@@ -81,6 +81,7 @@ For each gap, fill the debug-subagent-prompt template and spawn:
81
81
  Task(
82
82
  prompt=filled_debug_subagent_prompt + "\n\n<files_to_read>\n- {phase_dir}/{phase_num}-uat.md\n- .planning/state.md\n</files_to_read>",
83
83
  subagent_type="pan-debugger",
84
+ model="{debugger_model}", # node ~/.claude/pan-wizard-core/bin/pan-tools.cjs resolve-model pan-debugger --raw
84
85
  description="Debug: {issue_summary_short}"
85
86
  )
86
87
  ```
@@ -181,11 +182,10 @@ Display:
181
182
 
182
183
  Debug sessions: ${DEBUG_DIR}/
183
184
 
184
- Proceeding to plan fixes...
185
+ Next: /pan:plan-phase {phase_num} --gaps
185
186
  ```
186
187
 
187
- Return to verify-phase orchestrator for automatic planning.
188
- Do NOT offer manual next steps - verify-phase handles the rest.
188
+ No command runs this workflow as a sub-step, so end by giving the user the next step: `/pan:plan-phase {phase_num} --gaps` (it reads the diagnosed uat.md).
189
189
  </step>
190
190
 
191
191
  </process>
@@ -217,5 +217,5 @@ Agents only diagnose—plan-phase --gaps handles fixes (no fix application).
217
217
  - [ ] Root causes collected from all agents
218
218
  - [ ] uat.md gaps updated with artifacts and missing
219
219
  - [ ] Debug sessions saved to ${DEBUG_DIR}/
220
- - [ ] Hand off to verify-phase for automatic planning
220
+ - [ ] Next step shown: /pan:plan-phase {phase_num} --gaps
221
221
  </success_criteria>
@@ -130,7 +130,7 @@ Exit workflow.
130
130
  </step>
131
131
 
132
132
  <step name="auto_mode_bypass">
133
- **P-1803 fix (v3.7.8):** When `--auto` is set or `workflow.auto_advance: true`, **skip the entire question-driven discussion** and synthesize a minimal `context.md` directly from upstream artifacts. The unguarded `AskUserQuestion` calls in `check_existing`, `present_gray_areas` and `discuss_areas` all stall headless `claude -p` sessions immediately. Surfaced by the wookie autonomous build (v3.7.7): retry attempts via `/pan:discuss-phase 3 --auto` exited in 75s with $0.42 cost and zero commits before plan-phase auto-mode was patched to bypass discuss-phase entirely. This step makes discuss-phase itself auto-mode-safe, so it can be re-introduced into the auto pipeline cleanly.
133
+ **P-1803 fix (v3.7.8):** When `--auto` is set or `workflow.auto_advance: true`, **skip the entire question-driven discussion** and synthesize a minimal `context.md` directly from upstream artifacts. The unguarded `AskUserQuestion` calls in `check_existing`, `present_gray_areas` and `discuss_areas` all stall headless `claude -p` sessions immediately. Surfaced by the wookie autonomous build (v3.7.7): retry attempts via `/pan:discuss-phase 3 --auto` exited in 75s with 42 cents of cost and zero commits before plan-phase auto-mode was patched to bypass discuss-phase entirely. This step makes discuss-phase itself auto-mode-safe, so it can be re-introduced into the auto pipeline cleanly.
134
134
 
135
135
  Detect auto mode:
136
136
 
@@ -599,6 +599,7 @@ Task(
599
599
  </instructions>
600
600
  ",
601
601
  subagent_type="general-purpose",
602
+ model="$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs resolve-model pan-conductor --raw)",
602
603
  description="Plan Phase ${PHASE}"
603
604
  )
604
605
  ```
@@ -34,12 +34,24 @@ Load all context in one call:
34
34
  INIT=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs init execute-phase "${PHASE_ARG}")
35
35
  ```
36
36
 
37
- Parse JSON for: `executor_model`, `verifier_model`, `reviewer_model`, `commit_docs`, `parallelization`, `branching_strategy`, `branch_name`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `plans`, `incomplete_plans`, `plan_count`, `incomplete_count`, `state_exists`, `roadmap_exists`, `phase_req_ids`, `verifier_enabled`.
37
+ Parse JSON for: `executor_model`, `verifier_model`, `reviewer_model`, `commit_docs`, `parallelization`, `branching_strategy`, `branch_name`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `plans`, `incomplete_plans`, `plan_count`, `incomplete_count`, `state_exists`, `roadmap_exists`, `phase_req_ids`, `verifier_enabled`, `plan_check`, `plan_drift`. In the shell steps below, `$PHASE_DIR` (and `$phase_dir`) is `phase_dir` and `$PHASE_NUMBER` is `phase_number`.
38
38
 
39
39
  **If `phase_found` is false:** Error — phase directory not found.
40
40
  **If `plan_count` is 0:** Error — no plans found in phase.
41
41
  **If `state_exists` is false but `.planning/` exists:** Offer reconstruct or continue.
42
42
 
43
+ **The plans must be the plans that passed the plan check** (`plan_check.status`):
44
+
45
+ | Status | Action |
46
+ |---|---|
47
+ | `ok`, `disabled` | Continue |
48
+ | `legacy` | Continue, and say: "the plan check predates plan hashing, so it cannot show these plans are unchanged" |
49
+ | `stale` | Stop: "The plans changed after they passed the plan check. Re-plan with `/pan:plan-phase {N} --skip-research`, which checks the new plans." Continue only if the user gives a reason, and record it: `pan-tools optimize trace log --type decision --category plan_check_overridden --description "<reason>"` |
50
+ | `failed` | Stop: "The last plan check found issues." Same override |
51
+ | `missing` | Stop: "No plan check is recorded for this phase." This includes plans made with `/pan:plan-phase --skip-verify` or with `workflow.plan_check` off after the fact. Same override |
52
+
53
+ **Drift.** For each `plan_drift` entry, tell the executor of that plan, in its prompt, which of its `files_modified` changed since it was planned (`files`), so it re-reads them before editing. An entry with `error` means its `planned_commit` is unknown: say so and continue.
54
+
43
55
  When `parallelization` is false, plans within a wave execute sequentially.
44
56
 
45
57
  **Circular optimization — start trace session for this exec:**
@@ -190,6 +202,8 @@ Execute each wave in sequence. Within a wave: parallel if `PARALLELIZATION=true`
190
202
 
191
203
  If ANY spot-check fails: report which plan failed, route to failure handler — ask "Retry plan?" or "Continue with remaining waves?"
192
204
 
205
+ **An executor that returned `## BLOCKED_SPEC_CONFLICT`** found a test it cannot satisfy without weakening it. It is not a failure to retry: show the user its Test, Requirement and Options and ask for a ruling. "Change the test" means a revised plan that declares the test file in `files_modified` (`/pan:plan-phase {N} --gaps` or an edit to the plan), then re-run that plan; "change the requirement" means updating the requirement and the plan. Never re-run the same plan unchanged: it would meet the same test. Declaring the file permits rewriting its expectations; deleting the test, skipping it or dropping assertions still fails `verify test-integrity`, so a ruling to do that also needs `phase complete --force --reason`.
206
+
193
207
  If pass:
194
208
  ```
195
209
  ---
@@ -319,7 +333,7 @@ After all waves:
319
333
 
320
334
  1. Record baseline test count:
321
335
  ```bash
322
- TEST_BASELINE=$(npm test 2>&1 | grep -E "^ℹ tests" | awk '{print $NF}')
336
+ TEST_BASELINE=$(npm test 2>&1 | grep -E "^(ℹ|#) tests" | awk '{print $NF}')
323
337
  ```
324
338
 
325
339
  2. Invoke phase-tests workflow for the completed phase:
@@ -331,7 +345,8 @@ Read each summary.md to understand what was built.
331
345
  Generate unit and integration tests for the new code.
332
346
  Discover the project's existing test patterns, directories, frameworks, and helpers before writing tests.
333
347
  Follow whatever conventions the project already uses.",
334
- subagent_type="general-purpose"
348
+ subagent_type="general-purpose",
349
+ model="{executor_model}",
335
350
  )
336
351
  ```
337
352
 
@@ -342,7 +357,7 @@ Alternatively, if the user's AI tool supports it, invoke the command directly:
342
357
 
343
358
  3. Record new test count:
344
359
  ```bash
345
- TEST_AFTER=$(npm test 2>&1 | grep -E "^ℹ tests" | awk '{print $NF}')
360
+ TEST_AFTER=$(npm test 2>&1 | grep -E "^(ℹ|#) tests" | awk '{print $NF}')
346
361
  ```
347
362
 
348
363
  4. Report:
@@ -353,6 +368,8 @@ TEST_AFTER=$(npm test 2>&1 | grep -E "^ℹ tests" | awk '{print $NF}')
353
368
  - New tests: +$((TEST_AFTER - TEST_BASELINE))
354
369
  ```
355
370
 
371
+ `ℹ tests N` (spec reporter) and `# tests N` (TAP, Node's default for piped output before Node 23) are the summary lines of Node's built-in test runner, and both greps above match either. With any other runner both counts come back empty, so report the runner's own summary line instead of `+0`.
372
+
356
373
  **If tests fail after generation:** Report failures but continue to next step. Test issues are caught by the verify-phase test gate.
357
374
  </step>
358
375
 
@@ -365,11 +382,14 @@ TEST_AFTER=$(npm test 2>&1 | grep -E "^ℹ tests" | awk '{print $NF}')
365
382
  ```bash
366
383
  # Read each summary.md and extract key-files.created + key-files.modified
367
384
  for summary in "$PHASE_DIR"/*-summary.md; do
368
- grep -A 50 "key-files" "$summary" | grep -E "^\s*-" | sed 's/^\s*- //'
385
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs summary-extract "$summary" --fields key_files | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{const k=JSON.parse(s).key_files||{};for(const f of [...(k.created||[]),...(k.modified||[])])console.log(f)})"
369
386
  done | sort -u > /tmp/review-files.txt
370
387
  ```
371
388
 
372
- 2. Spawn pan-reviewer:
389
+ 2. Collect the reviewer's earlier open findings on this phase (empty on a first review), then spawn pan-reviewer:
390
+ ```bash
391
+ OPEN_REVIEW_FINDINGS=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs findings list --phase "${PHASE_NUMBER}" --agent pan-reviewer --status open 2>/dev/null)
392
+ ```
373
393
  ```
374
394
  Task(
375
395
  subagent_type="pan-reviewer",
@@ -391,6 +411,10 @@ Task(
391
411
  Phase: ${PHASE_NUMBER} - ${PHASE_NAME}
392
412
  Phase directory: ${phase_dir}
393
413
  </context>
414
+
415
+ <open_findings>
416
+ ${OPEN_REVIEW_FINDINGS}
417
+ </open_findings>
394
418
  "
395
419
  )
396
420
  ```
@@ -426,7 +450,7 @@ The fallback reads the word under `### Verdict` when the report carries no valid
426
450
  node ~/.claude/pan-wizard-core/bin/pan-tools.cjs findings dispose --phase "${PHASE_NUMBER}" --agent pan-reviewer --open --as deferred --reason "accepted at review: PASS_WITH_WARNINGS"
427
451
  ```
428
452
  - **The user chooses "Continue anyway"** at `NEEDS_FIXES`: the same command with `--reason "continued past NEEDS_FIXES at the user's choice"`, then proceed to verification.
429
- - **The user chooses "Fix before verification"**: apply the fixes, then run the review once more (steps 2–4). The new record closes the findings it no longer reports.
453
+ - **The user chooses "Fix before verification"**: apply the fixes, then run the review once more (steps 2–4). The re-review answers each earlier finding in its `resolutions`; the record closes the ones it answers `resolved` with evidence, and one it neither reports nor answers stays open.
430
454
 
431
455
  5. **No separate trace logging.** The record logs `verdict_passed` or `verdict_failed` for the reviewer on every runtime. The `reviewer_correction` and `reviewer_warnings` trace calls that used to sit here read the error count from a shell variable nothing ever set.
432
456
 
@@ -553,7 +577,7 @@ VERIF_FILE=$(ls "$PHASE_DIR"/*-verification.md 2>/dev/null | head -1)
553
577
  VERIF_STATUS=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs findings record --phase "${PHASE_NUMBER}" --file "$VERIF_FILE" --raw 2>/dev/null) \
554
578
  || VERIF_STATUS=$(grep "^status:" "$VERIF_FILE" | cut -d: -f2 | tr -d ' ')
555
579
  ```
556
- `findings record` reads the verdict from the verification frontmatter (`status`, `gaps`, `human_verification`, `unrequested`) and adds its findings to the ledger. A re-verification after a fix round is the next attempt: the gaps it no longer reports are closed, and the retry is logged. Recording the same file twice is a no-op, so verify-phase recording it too is safe. The grep fallback keeps the old reading when the record cannot parse the file.
580
+ `findings record` reads the verdict from the verification frontmatter (`status`, `gaps`, `human_verification`, `unrequested`) and adds its findings to the ledger. A re-verification after a fix round is the next attempt: the gaps it lists under `re_verification.gaps_closed` are closed, a gap it neither reports nor answers stays open (listed in `unaddressed`), and the retry is logged. Recording the same file twice is a no-op, so verify-phase recording it too is safe. The grep fallback keeps the old reading when the record cannot parse the file.
557
581
 
558
582
  **Trace logging happens in the record.** The record above logs the verification outcome (`verdict_passed`, `verdict_failed` or `verdict_needs_human`) here, after the verifier returns. That covers inline verification too, which is the reason P-1806 moved the trace call here (v3.7.8). No separate `optimize trace log` call is needed.
559
583
 
@@ -599,12 +623,26 @@ Gap closure cycle: `/pan:plan-phase {X} --gaps` reads verification.md → create
599
623
  </step>
600
624
 
601
625
  <step name="update_roadmap">
602
- **Mark phase complete and update all tracking files:**
626
+ **Mark phase complete and update all tracking files.** `phase complete` runs the phase gate first, on every path (this step runs before `offer_next`, with or without `--no-transition`). The gate checks in code what this workflow used to ask for in prose: every plan has a summary, the verification passes (a failed test gate lowers it to gaps), human items have a recorded approval, the verification is fresh, reconcile finds no contradiction, no critical or high finding is left open, no stub was committed, and no test was weakened.
603
627
 
604
628
  ```bash
605
629
  COMPLETION=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs phase complete "${PHASE_NUMBER}")
630
+ COMPLETION_EXIT=$?
631
+ ```
632
+
633
+ | Result | Action |
634
+ |---|---|
635
+ | exit 1, `error: phase_gate_refused` (`workflow.phase_gate: enforce`) | The phase was NOT marked complete. Show each `gate.reasons` entry (`code`: `detail`) with its fix, and stop: no commit, no auto-advance. The user may complete anyway with a reason (below) |
636
+ | exit 0, `gate.ok` false (`warn`, the default) | The phase was marked complete. Show the reasons as warnings, run the rest of this step, and do NOT auto-advance (`offer_next` reads `GATE_OK`) |
637
+ | exit 0, `gate.ok` true | Continue |
638
+
639
+ **Completing past a refusal** is the user's decision, never yours, and needs their reason. It records a `decision` for every open finding the gate counted:
640
+ ```bash
641
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs phase complete "${PHASE_NUMBER}" --force --reason "<the user's reason>"
606
642
  ```
607
643
 
644
+ Set `GATE_OK` to `gate.ok` from `COMPLETION` (`false` when the gate refused).
645
+
608
646
  The CLI handles:
609
647
  - Marking phase checkbox `[x]` with completion date
610
648
  - Updating Progress table (Status → Complete, date)
@@ -659,7 +697,7 @@ Parse `--no-transition` flag from $ARGUMENTS.
659
697
  **If `--no-transition` flag present:**
660
698
 
661
699
  Execute-phase was spawned by plan-phase's auto-advance. Do NOT run transition.md.
662
- If verification found gaps, return `## GAPS FOUND` with the phase, score and gap summaries (plan-phase and discuss-phase stop the chain on it). After verification passes and roadmap is updated, return completion status to parent:
700
+ If verification found gaps, or `GATE_OK` is false, return `## GAPS FOUND` with the phase, score and the gap summaries or the gate's reasons (plan-phase and discuss-phase stop the chain on it). After the gate passes, return completion status to parent:
663
701
 
664
702
  ```
665
703
  ## PHASE COMPLETE
@@ -675,37 +713,10 @@ STOP. Do not proceed to auto-advance or transition.
675
713
 
676
714
  **If `--no-transition` flag is NOT present:**
677
715
 
678
- **Verification gate check (before auto-advance):**
679
-
680
- If `workflow.verifier` is true in config, confirm the current phase has a passing verification:
681
-
682
- ```bash
683
- VERIF=$(ls "$phase_dir"/*-verification.md 2>/dev/null | head -1)
684
- VERIF_STATUS=""
685
- if [ -n "$VERIF" ]; then
686
- VERIF_STATUS=$(grep "^status:" "$VERIF" | awk '{print $2}')
687
- fi
688
- ```
689
-
690
- **Cross-check the written verdict against the mechanical signals (anti-rubber-stamp, ADR-0036).** The `status:` string above is authored by the verifier agent; `reconcile` re-derives the artifact/key-link checks from disk and exits non-zero when a claimed pass contradicts them:
691
- ```bash
692
- node ~/.claude/pan-wizard-core/bin/pan-tools.cjs verify reconcile "${PHASE_NUMBER}" --raw
693
- RECONCILE_EXIT=$?
694
- ```
695
- If `RECONCILE_EXIT` is non-zero:
696
- ```
697
- ⚠ Reconcile gate: Phase ${PHASE_NUMBER} verification says "passed" but the mechanical
698
- checks disagree — artifacts fail substance checks or key-links are unwired.
699
- This is a rubber-stamped verification. Do NOT auto-advance.
700
- Re-run /pan:verify-phase and fix the failing artifacts/key-links.
701
- ```
702
- STOP — do not auto-advance. Return to user.
703
-
704
- If `VERIF_STATUS` is not `passed`:
716
+ **Gate check (before auto-advance).** The phase gate already ran inside `phase complete` (`update_roadmap`), and it covers the verification status, reconcile (anti-rubber-stamp, ADR-0036), freshness, open findings, stubs and test integrity. If `GATE_OK` is false:
705
717
  ```
706
- ⚠ Verification gate: Phase ${PHASE_NUMBER} verification status is "${VERIF_STATUS:-missing}"
707
- Cannot auto-advance without passing verification.
708
- Run /pan:verify-phase to verify this phase first.
718
+ ⚠ Phase gate: Phase ${PHASE_NUMBER} may not advance — {each gate reason: code and detail}.
719
+ Fix the reasons (or close the gaps with /pan:plan-phase ${PHASE_NUMBER} --gaps), then re-run.
709
720
  ```
710
721
  STOP — do not auto-advance. Return to user.
711
722
 
@@ -64,8 +64,8 @@ Gap: Flow "View dashboard" broken at data fetch
64
64
 
65
65
  Find highest existing phase:
66
66
  ```bash
67
- # Get sorted phase list, extract last one
68
- HIGHEST=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs phases list --raw | tail -1)
67
+ # Highest phase number in roadmap.md — the same source `phase add` numbers from
68
+ HIGHEST=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs roadmap analyze | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{const n=JSON.parse(s).phases.map(p=>parseInt(p.number,10)).filter(Number.isFinite);console.log(n.length?Math.max(...n):0)})")
69
69
  ```
70
70
 
71
71
  New phases continue from there:
@@ -525,9 +525,7 @@ Display spawning indicator:
525
525
  Spawn 4 parallel pan-project-researcher agents with path references:
526
526
 
527
527
  ```
528
- Task(prompt="First, read ~/.claude/agents/pan-project-researcher.md for your role and instructions.
529
-
530
- <research_type>
528
+ Task(prompt="<research_type>
531
529
  Project Research — Stack dimension for [domain].
532
530
  </research_type>
533
531
 
@@ -563,11 +561,9 @@ Your stack.md feeds into roadmap creation. Be prescriptive:
563
561
  Write to: .planning/research/stack.md
564
562
  Use template: ~/.claude/pan-wizard-core/templates/research-project/stack.md
565
563
  </output>
566
- ", subagent_type="general-purpose", model="{researcher_model}", description="Stack research")
567
-
568
- Task(prompt="First, read ~/.claude/agents/pan-project-researcher.md for your role and instructions.
564
+ ", subagent_type="pan-project-researcher", model="{researcher_model}", description="Stack research")
569
565
 
570
- <research_type>
566
+ Task(prompt="<research_type>
571
567
  Project Research — Features dimension for [domain].
572
568
  </research_type>
573
569
 
@@ -603,11 +599,9 @@ Your features.md feeds into requirements definition. Categorize clearly:
603
599
  Write to: .planning/research/features.md
604
600
  Use template: ~/.claude/pan-wizard-core/templates/research-project/features.md
605
601
  </output>
606
- ", subagent_type="general-purpose", model="{researcher_model}", description="Features research")
602
+ ", subagent_type="pan-project-researcher", model="{researcher_model}", description="Features research")
607
603
 
608
- Task(prompt="First, read ~/.claude/agents/pan-project-researcher.md for your role and instructions.
609
-
610
- <research_type>
604
+ Task(prompt="<research_type>
611
605
  Project Research — Architecture dimension for [domain].
612
606
  </research_type>
613
607
 
@@ -643,11 +637,9 @@ Your architecture.md informs phase structure in roadmap. Include:
643
637
  Write to: .planning/research/architecture.md
644
638
  Use template: ~/.claude/pan-wizard-core/templates/research-project/architecture.md
645
639
  </output>
646
- ", subagent_type="general-purpose", model="{researcher_model}", description="Architecture research")
647
-
648
- Task(prompt="First, read ~/.claude/agents/pan-project-researcher.md for your role and instructions.
640
+ ", subagent_type="pan-project-researcher", model="{researcher_model}", description="Architecture research")
649
641
 
650
- <research_type>
642
+ Task(prompt="<research_type>
651
643
  Project Research — Pitfalls dimension for [domain].
652
644
  </research_type>
653
645
 
@@ -683,7 +675,7 @@ Your pitfalls.md prevents mistakes in roadmap/planning. For each pitfall:
683
675
  Write to: .planning/research/pitfalls.md
684
676
  Use template: ~/.claude/pan-wizard-core/templates/research-project/pitfalls.md
685
677
  </output>
686
- ", subagent_type="general-purpose", model="{researcher_model}", description="Pitfalls research")
678
+ ", subagent_type="pan-project-researcher", model="{researcher_model}", description="Pitfalls research")
687
679
  ```
688
680
 
689
681
  After all 4 agents complete, spawn synthesizer to create summary.md:
@@ -280,8 +280,8 @@ Write to: {phase_dir}/{padded_phase}-research.md
280
280
 
281
281
  ```
282
282
  Task(
283
- prompt="First, read ~/.claude/agents/pan-phase-researcher.md for your role and instructions.\n\n" + research_prompt,
284
- subagent_type="general-purpose",
283
+ prompt=research_prompt,
284
+ subagent_type="pan-phase-researcher",
285
285
  model="{researcher_model}",
286
286
  description="Research Phase {phase}"
287
287
  )
@@ -383,8 +383,8 @@ Output consumed by /pan:exec-phase. Plans need:
383
383
 
384
384
  ```
385
385
  Task(
386
- prompt="First, read ~/.claude/agents/pan-planner.md for your role and instructions.\n\n" + filled_prompt,
387
- subagent_type="general-purpose",
386
+ prompt=filled_prompt,
387
+ subagent_type="pan-planner",
388
388
  model="{planner_model}",
389
389
  description="Plan Phase {phase}"
390
390
  )
@@ -392,12 +392,21 @@ Task(
392
392
 
393
393
  ## 9. Handle Planner Return
394
394
 
395
- - **`## PLANNING COMPLETE`:** Display plan count. If `--skip-verify` or `plan_checker_enabled` is false (from init): skip to step 13. Otherwise: step 10.
395
+ - **`## PLANNING COMPLETE`:** Display plan count. If `--skip-verify` or `plan_checker_enabled` is false (from init): still run the code checks at the start of step 10 (`verify plan-set`; they cost no model call), send any errors back to the planner (step 12), then skip to step 13. Otherwise: step 10.
396
396
  - **`## GAP CLOSURE PLANS CREATED`:** (`--gaps` mode) Handle as `## PLANNING COMPLETE`.
397
397
  - **`## CHECKPOINT REACHED`:** Present to user, get response, spawn a fresh planner (step 8's Task) with the response added to its prompt
398
398
 
399
399
  ## 10. Spawn pan-plan-checker Agent
400
400
 
401
+ **First, the checks code can make.** Run them before spending a checker:
402
+
403
+ ```bash
404
+ PLAN_SET=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs verify plan-set "${PHASE_NUMBER}")
405
+ PLAN_SET_EXIT=$?
406
+ ```
407
+
408
+ Exit 1 means the plan set is broken in a way no review can wave through: a roadmap requirement no plan lists, two plans in one wave modifying the same file, a `depends_on` that names no plan or a plan in the same or a later wave, or a cycle. Send `PLAN_SET`'s `errors` to the planner as the revision context (step 12; it counts as an iteration) and do not spawn the checker for this set. Exit 0: continue, and pass any `warnings` to the checker.
409
+
401
410
  Display banner:
402
411
  ```
403
412
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -427,6 +436,10 @@ Checker prompt:
427
436
  **Project skills:** Check .agents/skills/ directory (if exists) — verify plans account for project skill rules
428
437
  </verification_context>
429
438
 
439
+ <open_findings>
440
+ {output of `pan-tools findings list --phase {phase_number} --agent pan-plan-checker --status open`: empty on the first check; on a re-check, answer each in `resolutions`}
441
+ </open_findings>
442
+
430
443
  <expected_output>
431
444
  - ## VERIFICATION PASSED — all checks pass
432
445
  - ## ISSUES FOUND — structured issue list
@@ -457,7 +470,7 @@ The fallback reads the heading when the report carries no valid `pan-verdict` bl
457
470
  - **`passed`:** Display confirmation, proceed to step 13.
458
471
  - **`issues_found`:** Display issues, check iteration count, proceed to step 12.
459
472
 
460
- Each re-check in the revision loop overwrites the same file and is recorded again as the next attempt. The issues a revision resolved are closed by that record.
473
+ Each re-check in the revision loop overwrites the same file and is recorded again as the next attempt. The checker answers each earlier issue in `resolutions`; the record closes the ones it answers `resolved` with evidence, and one it neither reports nor answers stays open.
461
474
 
462
475
  ## 12. Revision Loop (At Most 2 Revisions, 3 Checks)
463
476
 
@@ -491,8 +504,8 @@ Return what changed.
491
504
 
492
505
  ```
493
506
  Task(
494
- prompt="First, read ~/.claude/agents/pan-planner.md for your role and instructions.\n\n" + revision_prompt,
495
- subagent_type="general-purpose",
507
+ prompt=revision_prompt,
508
+ subagent_type="pan-planner",
496
509
  model="{planner_model}",
497
510
  description="Revise Phase {phase} plans"
498
511
  )
@@ -590,6 +603,7 @@ Task(
590
603
  </instructions>
591
604
  ",
592
605
  subagent_type="general-purpose",
606
+ model="$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs resolve-model pan-conductor --raw)",
593
607
  description="Execute Phase ${PHASE}"
594
608
  )
595
609
  ```
@@ -54,7 +54,7 @@ ROADMAP=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs roadmap analyze)
54
54
  ```
55
55
 
56
56
  This returns structured JSON with:
57
- - All phases with disk status (complete/partial/planned/empty/no_directory)
57
+ - All phases with disk status (complete/partial/planned/researched/discussed/empty/no_directory)
58
58
  - Goal and dependencies per phase
59
59
  - Plan and summary counts per phase
60
60
  - Aggregated stats: total plans, summaries, progress percent
@@ -229,8 +229,8 @@ Return what changed.
229
229
 
230
230
  ```
231
231
  Task(
232
- prompt="First, read ~/.claude/agents/pan-planner.md for your role and instructions.\n\n" + revision_prompt,
233
- subagent_type="general-purpose",
232
+ prompt=revision_prompt,
233
+ subagent_type="pan-planner",
234
234
  model="{planner_model}",
235
235
  description="Revise quick plan: ${DESCRIPTION}"
236
236
  )
@@ -12,7 +12,8 @@ Read all files referenced by the invoking prompt's execution_context before star
12
12
  Load todo context:
13
13
 
14
14
  ```bash
15
- INIT=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs init todos)
15
+ AREA="" # the area argument when one was given: /pan:todo-check api → AREA="api"; empty lists every todo
16
+ INIT=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs init todos "$AREA")
16
17
  ```
17
18
 
18
19
  Extract from init JSON: `todo_count`, `todos`, `pending_dir`.
@@ -35,7 +36,7 @@ Exit.
35
36
  </step>
36
37
 
37
38
  <step name="parse_filter">
38
- Check for area filter in arguments:
39
+ The area filter was applied in init_context (AREA):
39
40
  - `/pan:todo-check` → show all
40
41
  - `/pan:todo-check api` → filter to area:api only
41
42
  </step>
@@ -155,6 +155,8 @@ If found, delete them — phase is complete, handoffs are stale.
155
155
  TRANSITION=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs phase complete "${current_phase}") # skip when exec-phase invoked this workflow: its `phase complete` already ran — reuse that result
156
156
  ```
157
157
 
158
+ `phase complete` runs the phase gate first. Exit 1 with `error: phase_gate_refused` (`workflow.phase_gate: enforce`) means the phase was not marked complete: show `gate.reasons` and stop the transition. With `gate.ok` false under `warn`, the phase was marked complete: show the reasons as warnings before continuing.
159
+
158
160
  The CLI handles:
159
161
  - Marking the phase checkbox as `[x]` complete with today's date
160
162
  - Updating plan count to final (e.g., "3/3 plans complete")
@@ -453,6 +455,7 @@ Task(
453
455
  </instructions>
454
456
  ",
455
457
  subagent_type="general-purpose",
458
+ model="$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs resolve-model pan-conductor --raw)",
456
459
  description="Plan Phase ${NEXT_PHASE}"
457
460
  )
458
461
  ```
@@ -495,6 +498,7 @@ Task(
495
498
  </instructions>
496
499
  ",
497
500
  subagent_type="general-purpose",
501
+ model="$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs resolve-model pan-conductor --raw)",
498
502
  description="Discuss Phase ${NEXT_PHASE}"
499
503
  )
500
504
  ```
@@ -105,15 +105,15 @@ HAS_TEST=$(node -e "try{const p=require('./package.json');process.stdout.write(p
105
105
  ```bash
106
106
  TEST_OUTPUT=$(npm test 2>&1)
107
107
  TEST_EXIT=$?
108
- TEST_COUNT=$(echo "$TEST_OUTPUT" | grep -E "^ℹ tests" | awk '{print $NF}')
109
- TEST_PASS=$(echo "$TEST_OUTPUT" | grep -E "^ℹ pass" | awk '{print $NF}')
110
- TEST_FAIL=$(echo "$TEST_OUTPUT" | grep -E "^ℹ fail" | awk '{print $NF}')
108
+ TEST_COUNT=$(echo "$TEST_OUTPUT" | grep -E "^(ℹ|#) tests" | awk '{print $NF}')
109
+ TEST_PASS=$(echo "$TEST_OUTPUT" | grep -E "^(ℹ|#) pass" | awk '{print $NF}')
110
+ TEST_FAIL=$(echo "$TEST_OUTPUT" | grep -E "^(ℹ|#) fail" | awk '{print $NF}')
111
111
  ```
112
112
 
113
113
  3. Evaluate results.
114
114
 
115
115
  **Check `TEST_EXIT` FIRST, before any count.** A suite that did not run emits no
116
- `ℹ fail` line at all, so `TEST_FAIL` comes back EMPTY — not `0`. Reading an empty
116
+ `ℹ fail` / `# fail` line at all, so `TEST_FAIL` comes back EMPTY — not `0`. Reading an empty
117
117
  value as "no failures" scores a crashed suite as a pass, which is the worst
118
118
  direction this gate can fail in: a phase ships green on a project whose tests never
119
119
  executed. Empty is not zero. Judge the exit code, then the counts.
@@ -121,7 +121,7 @@ executed. Empty is not zero. Judge the exit code, then the counts.
121
121
  | Condition | Action |
122
122
  |-----------|--------|
123
123
  | `TEST_EXIT` = 0 **and** `TEST_FAIL` = 0 (a real number) | Record counts, continue to must-haves |
124
- | `TEST_EXIT` = 0 **and** no `ℹ` count lines (a runner other than Node's built-in one) | Set `test_gate_status: passed`; record the runner's own summary line as the counts |
124
+ | `TEST_EXIT` = 0 **and** no `ℹ`/`#` count lines (a runner other than Node's built-in one) | Set `test_gate_status: passed`; record the runner's own summary line as the counts |
125
125
  | `TEST_EXIT` ≠ 0 **and** failures were reported | Set `test_gate_status: failed`, include failure details |
126
126
  | `TEST_EXIT` ≠ 0 **and** `TEST_FAIL` is empty/absent — the suite CRASHED or could not run (syntax error, missing module, bad import, no runner) | Set `test_gate_status: failed`, and record the reason as `suite did not run`. **Never `skipped`, never `passed`.** A suite that cannot execute is stronger evidence of a broken phase than one that runs and fails |
127
127
  | `HAS_TEST` = `no` (handled in step 1) | Record as `test_gate_status: skipped`, continue. This is the ONLY legitimate route to `skipped` |
@@ -328,7 +328,7 @@ If human_needed: list items requiring human testing.
328
328
 
329
329
  Orchestrator routes: `passed` → update_roadmap | `gaps_found` → create/execute fixes, re-verify | `human_needed` → present to user.
330
330
 
331
- **Record the verification.** The record adds its findings to the ledger and logs the outcome to the trace (`verdict_passed`, `verdict_failed` or `verdict_needs_human`). A re-verification is the next attempt, and it closes the gaps it no longer reports:
331
+ **Record the verification.** The record adds its findings to the ledger and logs the outcome to the trace (`verdict_passed`, `verdict_failed` or `verdict_needs_human`). A re-verification is the next attempt. It closes the gaps it lists under `re_verification.gaps_closed`; a gap it neither reports nor answers stays open:
332
332
  ```bash
333
333
  node ~/.claude/pan-wizard-core/bin/pan-tools.cjs findings record --phase "${phase_number}" --file "$REPORT_PATH" 2>/dev/null || true
334
334
  ```
@@ -18,6 +18,7 @@ const DIST_DIR = path.join(HOOKS_DIR, 'dist');
18
18
  // Hooks to copy (pure Node.js, no bundling needed)
19
19
  const HOOKS_TO_COPY = [
20
20
  'pan-check-update.js',
21
+ 'pan-guard.js',
21
22
  'pan-context-monitor.js',
22
23
  'pan-statusline.js',
23
24
  'pan-cost-logger.js',
@@ -391,11 +391,11 @@ def generate_reference(shipped: list[Skill], dev: list[Skill], version: str) ->
391
391
  w(s.description)
392
392
  w("")
393
393
  if s.argument_hint:
394
- w(f"```")
394
+ w("```text")
395
395
  w(f"{s.command} {s.argument_hint}")
396
396
  w(f"```")
397
397
  else:
398
- w(f"```")
398
+ w("```text")
399
399
  w(f"{s.command}")
400
400
  w(f"```")
401
401
  w("")