pan-wizard 3.30.0 → 3.32.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.
- package/README.md +30 -26
- package/agents/pan-design-checker.md +18 -0
- package/agents/pan-optimizer.md +5 -1
- package/agents/pan-plan-checker.md +23 -0
- package/agents/pan-reviewer.md +19 -0
- package/agents/pan-verifier.md +23 -0
- package/bin/install-lib.cjs +129 -33
- package/bin/install.js +16 -9
- package/commands/pan/army.md +4 -4
- package/commands/pan/design-phase.md +8 -0
- package/commands/pan/exec-phase.md +1 -1
- package/commands/pan/git.md +2 -2
- package/commands/pan/learn.md +2 -0
- package/commands/pan/optimize.md +14 -2
- package/commands/pan/review-deep.md +5 -5
- package/commands/pan/verify-phase.md +8 -9
- package/hooks/dist/pan-check-update.js +53 -2
- package/hooks/dist/pan-context-monitor.js +42 -1
- package/hooks/dist/pan-cost-logger.js +132 -11
- package/hooks/dist/pan-state-reinject.js +158 -0
- package/hooks/dist/pan-stop-guard.js +50 -4
- package/hooks/dist/pan-trace-logger.js +324 -18
- package/package.json +1 -1
- package/pan-wizard-core/bin/lib/commands.cjs +22 -5
- package/pan-wizard-core/bin/lib/config.cjs +2 -0
- package/pan-wizard-core/bin/lib/constants.cjs +31 -1
- package/pan-wizard-core/bin/lib/context-budget.cjs +27 -2
- package/pan-wizard-core/bin/lib/core.cjs +232 -23
- package/pan-wizard-core/bin/lib/cost-rebuild.cjs +11 -0
- package/pan-wizard-core/bin/lib/cost.cjs +135 -46
- package/pan-wizard-core/bin/lib/findings.cjs +381 -0
- package/pan-wizard-core/bin/lib/focus.cjs +72 -19
- package/pan-wizard-core/bin/lib/foreign-planning.cjs +24 -6
- package/pan-wizard-core/bin/lib/frontmatter.cjs +5 -2
- package/pan-wizard-core/bin/lib/hygiene.cjs +12 -2
- package/pan-wizard-core/bin/lib/init.cjs +4 -1
- package/pan-wizard-core/bin/lib/memory-optimize.cjs +12 -6
- package/pan-wizard-core/bin/lib/memory-rebuild.cjs +9 -2
- package/pan-wizard-core/bin/lib/optimize.cjs +349 -21
- package/pan-wizard-core/bin/lib/phase-report.cjs +4 -1
- package/pan-wizard-core/bin/lib/review-deep.cjs +36 -0
- package/pan-wizard-core/bin/lib/roadmap.cjs +87 -18
- package/pan-wizard-core/bin/lib/state.cjs +93 -24
- package/pan-wizard-core/bin/lib/suggest.cjs +21 -9
- package/pan-wizard-core/bin/lib/template.cjs +6 -3
- package/pan-wizard-core/bin/lib/verdict.cjs +431 -0
- package/pan-wizard-core/bin/lib/verify-deploy.cjs +19 -2
- package/pan-wizard-core/bin/lib/verify-preflight.cjs +4 -2
- package/pan-wizard-core/bin/lib/verify-scope.cjs +156 -0
- package/pan-wizard-core/bin/lib/verify.cjs +25 -2
- package/pan-wizard-core/bin/pan-tools.cjs +69 -6
- package/pan-wizard-core/learnings/README.md +10 -7
- package/pan-wizard-core/mcp/tool-registry.cjs +16 -4
- package/pan-wizard-core/references/verdict-contract.md +101 -0
- package/pan-wizard-core/templates/verification-report.md +16 -0
- package/pan-wizard-core/workflows/exec-phase.md +73 -47
- package/pan-wizard-core/workflows/health.md +2 -0
- package/pan-wizard-core/workflows/help.md +2 -2
- package/pan-wizard-core/workflows/learn.md +4 -2
- package/pan-wizard-core/workflows/milestone-audit.md +15 -3
- package/pan-wizard-core/workflows/optimize.md +14 -1
- package/pan-wizard-core/workflows/phase-tests.md +1 -1
- package/pan-wizard-core/workflows/plan-phase.md +20 -15
- package/pan-wizard-core/workflows/progress.md +1 -1
- package/pan-wizard-core/workflows/todo-add.md +1 -1
- package/pan-wizard-core/workflows/todo-check.md +7 -6
- package/pan-wizard-core/workflows/verify-phase.md +3 -13
- package/pan-zcode/README.md +3 -3
- package/scripts/build-agent-plugin.js +4 -0
- package/scripts/build-hooks.js +2 -1
- package/scripts/build-plugin.js +10 -0
- package/scripts/git-hooks/pre-commit +2 -1
- package/scripts/npm-dist-tag.js +47 -0
- package/scripts/plugin-path.js +6 -1
- package/scripts/test-surface.cjs +1 -0
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const { execFileSync } = require('child_process');
|
|
8
|
-
const { safeReadFile, normalizePhaseName, comparePhaseNum, execGit, findPhaseInternal, getMilestoneInfo, toPosix, output, EXIT_OK, error, escapeRegex } = require('./core.cjs');
|
|
8
|
+
const { safeReadFile, normalizePhaseName, comparePhaseNum, execGit, findPhaseInternal, getMilestoneInfo, toPosix, output, EXIT_OK, error, escapeRegex, loadConfig, isGitIgnored, isGitRepo } = require('./core.cjs');
|
|
9
9
|
const { extractFrontmatter, parseMustHavesBlock } = require('./frontmatter.cjs');
|
|
10
10
|
const { writeStateMd, readStateSafe } = require('./state.cjs');
|
|
11
11
|
const {
|
|
@@ -22,6 +22,7 @@ const { runDriftCheck, parseConventionRules, checkFileConventions, calculateDrif
|
|
|
22
22
|
const { collectVerificationStats, countRoadmapPhases, groupGapPatterns, cmdRetro } = require('./verify-retro.cjs');
|
|
23
23
|
const { detectInstalledRuntimes, validateRuntimeInstall, cmdValidateDeployment } = require('./verify-deploy.cjs');
|
|
24
24
|
const { cmdPreflight, cmdDepsValidate } = require('./verify-preflight.cjs');
|
|
25
|
+
const { scopePhase, cmdVerifyScope } = require('./verify-scope.cjs');
|
|
25
26
|
const { planningRootRel } = require('./planning-root.cjs');
|
|
26
27
|
|
|
27
28
|
/**
|
|
@@ -821,6 +822,23 @@ function checkStateFile(cwd, addIssue, repairs) {
|
|
|
821
822
|
* @param {Function} addIssue - Issue recording callback
|
|
822
823
|
* @param {string[]} repairs - Mutable array of repair actions to schedule
|
|
823
824
|
*/
|
|
825
|
+
/**
|
|
826
|
+
* I005: the planning tree is ignored by git while `commit_docs` is on, so every
|
|
827
|
+
* `pan-tools commit` of planning docs commits nothing, silently. planning-with-files
|
|
828
|
+
* adds `.planning/` to .gitignore by default (its README, read 2026-09-28), which is
|
|
829
|
+
* how a PAN project ends up like this (market item M3). Info, not a warning: keeping
|
|
830
|
+
* the docs out of git is a legitimate choice, and it is one config key away.
|
|
831
|
+
*/
|
|
832
|
+
function checkPlanningIgnored(cwd, addIssue) {
|
|
833
|
+
try {
|
|
834
|
+
if (loadConfig(cwd).commit_docs === false || !isGitRepo(cwd)) return;
|
|
835
|
+
const rel = planningRootRel();
|
|
836
|
+
if (!isGitIgnored(cwd, `${rel}/`)) return;
|
|
837
|
+
addIssue('info', 'I005', `${rel}/ is ignored by git while commit_docs is true, so PAN's planning commits commit nothing`,
|
|
838
|
+
`Remove ${rel}/ from .gitignore (planning-with-files adds it by default), or keep the docs out of git on purpose: pan-tools config-set commit_docs false`);
|
|
839
|
+
} catch { /* best effort: a git failure is not a finding */ }
|
|
840
|
+
}
|
|
841
|
+
|
|
824
842
|
function checkConfigFile(cwd, addIssue, repairs) {
|
|
825
843
|
const configFullPath = path.join(planningPath(cwd), CONFIG_FILE);
|
|
826
844
|
let rawContent;
|
|
@@ -1314,7 +1332,9 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
1314
1332
|
// error and stop: E002-E005 would describe a foreign layout as a broken PAN one,
|
|
1315
1333
|
// and --repair must never write into it. Reality check R15.
|
|
1316
1334
|
const foreign = detectForeignPlanningTree(planningPath(cwd));
|
|
1317
|
-
if (foreign) {
|
|
1335
|
+
if (foreign && foreign.coexists) {
|
|
1336
|
+
addIssue('info', 'I004', `${foreign.tool} also writes into this planning tree: ${foreign.evidence.join(', ')}`, 'None needed: PAN leaves its files alone. Give PAN its own tree with --planning-dir if you prefer them apart (ADR-0043)');
|
|
1337
|
+
} else if (foreign) {
|
|
1318
1338
|
addIssue('error', 'E006', `planning tree belongs to ${foreign.tool}: ${foreign.evidence.join(', ')}`, 'Run PAN with --planning-dir <dir> to use a separate tree (ADR-0043)');
|
|
1319
1339
|
output({ status: HEALTH_STATUS.BROKEN, errors, warnings, info, repairable_count: 0 }, raw, undefined, 1);
|
|
1320
1340
|
return;
|
|
@@ -1337,6 +1357,7 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
1337
1357
|
addIssue('info', 'I003', `${shape.model}-model project (${shape.evidence.join(', ')}) — the phase-model checks (project.md, roadmap.md, state.md, phases/) do not apply`, null);
|
|
1338
1358
|
}
|
|
1339
1359
|
checkConfigFile(cwd, addIssue, repairs);
|
|
1360
|
+
checkPlanningIgnored(cwd, addIssue);
|
|
1340
1361
|
if (phaseModel) {
|
|
1341
1362
|
checkPhaseDirectories(cwd, addIssue);
|
|
1342
1363
|
checkPhaseContents(cwd, addIssue);
|
|
@@ -1535,6 +1556,8 @@ module.exports = {
|
|
|
1535
1556
|
cmdVerifyReconcile,
|
|
1536
1557
|
scanStubs,
|
|
1537
1558
|
cmdVerifyStubs,
|
|
1559
|
+
scopePhase,
|
|
1560
|
+
cmdVerifyScope,
|
|
1538
1561
|
cmdValidateConsistency,
|
|
1539
1562
|
cmdValidateHealth,
|
|
1540
1563
|
cmdPreflight,
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
* history-digest Aggregate all summary.md data
|
|
29
29
|
* summary-extract <path> [--fields] Extract structured data from summary.md
|
|
30
30
|
* state-snapshot Structured parse of state.md (alias: state snapshot)
|
|
31
|
+
* findings record|list|dispose|debt Judges' verdicts and their findings ledger (evidence loop)
|
|
31
32
|
* phase-plan-index <phase> Index plans with waves and status
|
|
32
33
|
* websearch <query> Search web via Brave API (if configured)
|
|
33
34
|
* [--limit N] [--freshness day|week|month]
|
|
@@ -206,6 +207,7 @@ const cost = require('./lib/cost.cjs');
|
|
|
206
207
|
const costRebuild = require('./lib/cost-rebuild.cjs');
|
|
207
208
|
const preview = require('./lib/preview.cjs');
|
|
208
209
|
const reviewDeep = require('./lib/review-deep.cjs');
|
|
210
|
+
const findings = require('./lib/findings.cjs');
|
|
209
211
|
const knowledge = require('./lib/knowledge.cjs');
|
|
210
212
|
const skillAlign = require('./lib/skill-align.cjs');
|
|
211
213
|
const hygiene = require('./lib/hygiene.cjs');
|
|
@@ -331,7 +333,7 @@ async function main() {
|
|
|
331
333
|
+ ' --planning-dir <path> act on an arbitrary project-relative planning tree\n'
|
|
332
334
|
+ ' --all-tracks (hygiene) act on the root tree AND every discovered track\n'
|
|
333
335
|
+ ' env: PAN_TRACK, PAN_PLANNING_DIR (flags win)\n'
|
|
334
|
-
+ '\nCommands: state, resolve-model, estimate-cost, find-phase, git, distill, experiment, commit, verify-summary, template, frontmatter, verify, generate-slug, current-timestamp, list-todos, verify-path-exists, config-ensure-section, config-set, config-get, history-digest, phases, roadmap, requirements, phase, milestone, validate, progress, context-budget, todo, scaffold, init, phase-plan-index, state-snapshot, summary-extract, rollback-snapshot, batch-commit, websearch, focus, preflight, dashboard, hud, report, learnings, deps, drift-check, memory, bridge, whatif, knowledge, skills, hygiene, review-deep, preview, cost, models, squad, worktree, campaign, bus, cache, retro, codebase, standards, optimize, doc-lint, learn, links';
|
|
336
|
+
+ '\nCommands: state, resolve-model, estimate-cost, find-phase, git, distill, experiment, commit, verify-summary, template, frontmatter, verify, generate-slug, current-timestamp, list-todos, verify-path-exists, config-ensure-section, config-set, config-get, history-digest, phases, roadmap, requirements, phase, milestone, validate, progress, context-budget, todo, scaffold, init, phase-plan-index, state-snapshot, summary-extract, rollback-snapshot, batch-commit, websearch, focus, preflight, dashboard, hud, report, learnings, deps, drift-check, memory, bridge, whatif, knowledge, skills, hygiene, review-deep, findings, preview, cost, models, squad, worktree, campaign, bus, cache, retro, codebase, standards, optimize, doc-lint, learn, links';
|
|
335
337
|
|
|
336
338
|
if (!command) {
|
|
337
339
|
error(USAGE);
|
|
@@ -412,7 +414,7 @@ async function main() {
|
|
|
412
414
|
} else if (subcommand === 'load' || !subcommand) {
|
|
413
415
|
state.cmdStateLoad(cwd, raw);
|
|
414
416
|
} else {
|
|
415
|
-
error(`Unknown state subcommand: ${subcommand}. Available: json, update, get, patch, advance-plan, record-metric, update-progress, add-decision, add-blocker, resolve-blocker, record-session, load, snapshot`);
|
|
417
|
+
error(`Unknown state subcommand: ${subcommand}. Available: json, update, get, patch, compact, advance-plan, record-metric, update-progress, add-decision, add-blocker, resolve-blocker, record-session, load, snapshot`);
|
|
416
418
|
}
|
|
417
419
|
break;
|
|
418
420
|
}
|
|
@@ -420,7 +422,13 @@ async function main() {
|
|
|
420
422
|
case 'resolve-model': {
|
|
421
423
|
const metadataIdx = args.indexOf('--metadata');
|
|
422
424
|
const metadataJson = metadataIdx !== -1 ? args[metadataIdx + 1] : undefined;
|
|
423
|
-
|
|
425
|
+
const attemptRaw = getArgValue(args, '--attempt');
|
|
426
|
+
let attempt;
|
|
427
|
+
if (attemptRaw !== null && attemptRaw !== undefined) {
|
|
428
|
+
if (!/^[1-9]\d*$/.test(String(attemptRaw))) error('--attempt must be a positive integer (1 for a first try)');
|
|
429
|
+
attempt = parseInt(attemptRaw, 10);
|
|
430
|
+
}
|
|
431
|
+
commands.cmdResolveModel(cwd, args[1], raw, metadataJson, attempt);
|
|
424
432
|
break;
|
|
425
433
|
}
|
|
426
434
|
|
|
@@ -601,8 +609,10 @@ async function main() {
|
|
|
601
609
|
verify.cmdVerifyReconcile(cwd, args[2], raw);
|
|
602
610
|
} else if (subcommand === 'stubs') {
|
|
603
611
|
verify.cmdVerifyStubs(cwd, { gate: args.includes('--gate') }, raw);
|
|
612
|
+
} else if (subcommand === 'scope') {
|
|
613
|
+
verify.cmdVerifyScope(cwd, args[2], raw);
|
|
604
614
|
} else {
|
|
605
|
-
error('Unknown verify subcommand. Available: plan-structure, phase-completeness, references, commits, artifacts, key-links, reconcile, stubs');
|
|
615
|
+
error('Unknown verify subcommand. Available: plan-structure, phase-completeness, references, commits, artifacts, key-links, reconcile, stubs, scope');
|
|
606
616
|
}
|
|
607
617
|
break;
|
|
608
618
|
}
|
|
@@ -908,7 +918,13 @@ async function main() {
|
|
|
908
918
|
output({ error: 'No batch file found. Run focus plan first.' }, raw);
|
|
909
919
|
break;
|
|
910
920
|
}
|
|
911
|
-
|
|
921
|
+
if (batch.error) {
|
|
922
|
+
// The newest batch is the one /pan:focus-exec runs; classifying another would
|
|
923
|
+
// hand it waves for the wrong items, so an unusable newest batch is an error.
|
|
924
|
+
output({ error: batch.error }, raw);
|
|
925
|
+
break;
|
|
926
|
+
}
|
|
927
|
+
items = batch.batch;
|
|
912
928
|
}
|
|
913
929
|
output(focus.classifyStageDependencies(items), raw);
|
|
914
930
|
} else if (subcommand === 'reflection') {
|
|
@@ -1171,6 +1187,44 @@ async function main() {
|
|
|
1171
1187
|
break;
|
|
1172
1188
|
}
|
|
1173
1189
|
|
|
1190
|
+
case 'findings': {
|
|
1191
|
+
// Evidence loop (ADR-0049): judges' verdicts recorded from their reports, and
|
|
1192
|
+
// the dispositions workflows give the findings they continue past.
|
|
1193
|
+
const subcommand = args[1];
|
|
1194
|
+
const filters = {
|
|
1195
|
+
phase: getArgValue(args, '--phase'),
|
|
1196
|
+
agent: getArgValue(args, '--agent'),
|
|
1197
|
+
status: getArgValue(args, '--status'),
|
|
1198
|
+
class: getArgValue(args, '--class'),
|
|
1199
|
+
milestone: getArgValue(args, '--milestone'),
|
|
1200
|
+
};
|
|
1201
|
+
if (subcommand === 'record') {
|
|
1202
|
+
findings.cmdFindingsRecord(cwd, {
|
|
1203
|
+
phase: filters.phase,
|
|
1204
|
+
agent: filters.agent,
|
|
1205
|
+
file: getArgValue(args, '--file'),
|
|
1206
|
+
text: getArgValue(args, '--text'),
|
|
1207
|
+
stdin: args.includes('--stdin'),
|
|
1208
|
+
}, raw);
|
|
1209
|
+
} else if (subcommand === 'list') {
|
|
1210
|
+
findings.cmdFindingsList(cwd, filters, raw);
|
|
1211
|
+
} else if (subcommand === 'dispose') {
|
|
1212
|
+
findings.cmdFindingsDispose(cwd, {
|
|
1213
|
+
ids: findings.findingIdsIn(args.slice(2)),
|
|
1214
|
+
phase: filters.phase,
|
|
1215
|
+
agent: filters.agent,
|
|
1216
|
+
open: args.includes('--open'),
|
|
1217
|
+
as: getArgValue(args, '--as'),
|
|
1218
|
+
reason: getArgValue(args, '--reason'),
|
|
1219
|
+
}, raw);
|
|
1220
|
+
} else if (subcommand === 'debt') {
|
|
1221
|
+
findings.cmdFindingsDebt(cwd, { milestone: filters.milestone }, raw);
|
|
1222
|
+
} else {
|
|
1223
|
+
error('Unknown findings subcommand. Available: record, list, dispose, debt');
|
|
1224
|
+
}
|
|
1225
|
+
break;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1174
1228
|
case 'preview': {
|
|
1175
1229
|
const subcommand = args[1];
|
|
1176
1230
|
if (subcommand === 'phase') {
|
|
@@ -1272,6 +1326,9 @@ async function main() {
|
|
|
1272
1326
|
daily_budget: budget != null ? Number(budget) : undefined,
|
|
1273
1327
|
enabled: args.includes('--disable') ? false : undefined,
|
|
1274
1328
|
paused: args.includes('--pause') ? true : (args.includes('--resume') ? false : undefined),
|
|
1329
|
+
// campaign.cjs has always honoured enforce_budget; no flag reached it, so
|
|
1330
|
+
// making the daily budget a hard stop meant editing schedule.json by hand.
|
|
1331
|
+
enforce_budget: args.includes('--enforce-budget') ? true : (args.includes('--advisory-budget') ? false : undefined),
|
|
1275
1332
|
}, raw);
|
|
1276
1333
|
} else if (subcommand === 'status' || !subcommand) {
|
|
1277
1334
|
campaign.cmdCampaignStatus(cwd, raw);
|
|
@@ -1399,17 +1456,23 @@ async function main() {
|
|
|
1399
1456
|
} else if (subcommand === 'learn') {
|
|
1400
1457
|
optimize.cmdOptimizeLearn(cwd, {
|
|
1401
1458
|
sessionId: getArgValue(args, '--session'),
|
|
1459
|
+
sessions: getArgValue(args, '--sessions'),
|
|
1402
1460
|
}, raw);
|
|
1403
1461
|
} else if (subcommand === 'apply') {
|
|
1404
1462
|
optimize.cmdOptimizeApply(cwd, {
|
|
1405
1463
|
reportPath: getArgValue(args, '--report'),
|
|
1406
1464
|
}, raw);
|
|
1465
|
+
} else if (subcommand === 'revert') {
|
|
1466
|
+
optimize.cmdOptimizeRevert(cwd, {
|
|
1467
|
+
applyId: args[2] && !args[2].startsWith('--') ? args[2] : null,
|
|
1468
|
+
last: args.includes('--last'),
|
|
1469
|
+
}, raw);
|
|
1407
1470
|
} else if (subcommand === 'list') {
|
|
1408
1471
|
optimize.cmdOptimizeList(cwd, raw);
|
|
1409
1472
|
} else if (subcommand === 'stats') {
|
|
1410
1473
|
optimize.cmdOptimizeStats(cwd, raw);
|
|
1411
1474
|
} else {
|
|
1412
|
-
error('Unknown optimize subcommand. Available: trace, learn, apply, list, stats');
|
|
1475
|
+
error('Unknown optimize subcommand. Available: trace, learn, apply, revert, list, stats');
|
|
1413
1476
|
}
|
|
1414
1477
|
break;
|
|
1415
1478
|
}
|
|
@@ -4,7 +4,7 @@ This directory holds AI-derived behavioral patterns extracted from real PAN
|
|
|
4
4
|
Wizard sessions via the **self-improvement loop** (v3.7.0+, see
|
|
5
5
|
[ADR-0026](../../docs/decisions/ADR-0026-self-improvement-loop.md)).
|
|
6
6
|
|
|
7
|
-
Patterns are
|
|
7
|
+
Patterns are promoted by hand with `pan-tools learn promote` (see Lifecycle) from
|
|
8
8
|
harvested experiment data. They are **advisory** — orchestrators weight them
|
|
9
9
|
against current context, not as hard rules.
|
|
10
10
|
|
|
@@ -46,9 +46,10 @@ patterns:
|
|
|
46
46
|
|
|
47
47
|
## Lifecycle
|
|
48
48
|
|
|
49
|
-
1. **Promote** — `pan-tools learn promote --pattern <id> --scope universal --topic <name>` appends a pattern to the topic file (creates the file if absent).
|
|
50
|
-
2. **Unpromote** — `pan-tools learn unpromote --pattern <id> --topic <name>` removes a pattern (for rollback).
|
|
49
|
+
1. **Promote** — `pan-tools learn promote --pattern <id> --scope universal --topic <name> --summary <text> --rule <text>` appends a pattern to the topic file (creates the file if absent); `--evidence`, `--applies-in` and `--source-experiments` fill in the rest of the entry.
|
|
50
|
+
2. **Unpromote** — `pan-tools learn unpromote --pattern <id> --scope <universal|internal> --topic <name>` removes a pattern (for rollback) and deletes the topic file once it holds none.
|
|
51
51
|
3. **List** — `pan-tools learn list-promoted` shows the inventory across both tiers.
|
|
52
|
+
4. **Index** — `pan-tools learn build-index` regenerates `index.json`, the topic index `pan-tools learn topics-for --agent <name>` reads; promote and unpromote do not update it.
|
|
52
53
|
|
|
53
54
|
## Why two tiers
|
|
54
55
|
|
|
@@ -58,13 +59,15 @@ apply when the project *is* PAN. Examples:
|
|
|
58
59
|
- **PAN-internal**: "Always commit individually, never `git add -A`" (because of source repo's pre-commit hooks)
|
|
59
60
|
- **Universal**: "Run the full test suite before marking a phase complete"
|
|
60
61
|
|
|
61
|
-
The promote step
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
The promote step warns when a universal-scope pattern reads like a prompt
|
|
63
|
+
fragment rather than a structural pattern (P-RES-007), and `pan-tools learn lint`
|
|
64
|
+
warns when a universal pattern's heading or Rule names PAN-internal terms such as
|
|
65
|
+
`pan-wizard-core` or `pan-tools`, a candidate for `internal` scope. The human
|
|
66
|
+
running `promote` makes the final call.
|
|
64
67
|
|
|
65
68
|
## Maintenance
|
|
66
69
|
|
|
67
70
|
These files are **AI-managed**. Direct human edits create drift between
|
|
68
|
-
the frontmatter `
|
|
71
|
+
the frontmatter `patterns` list and the body content. For human-authored
|
|
69
72
|
behavioral content, use `references/` instead — that's the canonical
|
|
70
73
|
hand-authored channel (e.g., `references/guardrails.md` shipped in v3.6.0).
|
|
@@ -69,19 +69,31 @@ const RESOURCES = [
|
|
|
69
69
|
description: 'Doc↔code link graph verdict: forward links, backlink contracts, and anchor targets, with finding codes.' },
|
|
70
70
|
{ uri: 'pan://cost', name: 'Token cost', verb: 'cost', args: ['report'],
|
|
71
71
|
description: 'Aggregated token spend from the .planning/metrics ledger. Reads as zeros on a project with no recorded calls.' },
|
|
72
|
+
{ uri: 'pan://findings', name: 'Findings', verb: 'findings', args: ['list'],
|
|
73
|
+
description: 'Every finding PAN\'s judges recorded (verifier, plan checker, reviewer, design checker), with its folded status — open, fixed, deferred, dismissed or decision — and the reason given. Reads as an empty list on a project with no recorded verdicts.' },
|
|
72
74
|
];
|
|
73
75
|
|
|
74
76
|
/** Actionable pan-tools verbs → MCP tools (each spawns `node pan-tools.cjs <verb>`). */
|
|
75
77
|
const SPAWN_TOOLS = [
|
|
76
78
|
{
|
|
77
79
|
name: 'pan_resolve_model', title: 'Resolve model for an agent', verb: 'resolve-model',
|
|
78
|
-
description: 'Resolve the model tier/id PAN would use for an agent under the active profile.',
|
|
80
|
+
description: 'Resolve the model tier/id PAN would use for an agent under the active profile. Pass attempt > 1 for a retry after a failure: the tier climbs toward the agent\'s quality tier (routing.max_escalations caps it).',
|
|
79
81
|
readOnly: true, destructive: false,
|
|
80
82
|
inputSchema: {
|
|
81
83
|
type: 'object', additionalProperties: false, required: ['agent'],
|
|
82
|
-
properties: {
|
|
84
|
+
properties: {
|
|
85
|
+
agent: { type: 'string', description: 'Agent type, e.g. pan-planner' },
|
|
86
|
+
attempt: { type: 'integer', minimum: 1, maximum: 99, description: '1 for a first try; 2 for the first retry after a failure' },
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
args: (i) => {
|
|
90
|
+
const out = [str('agent', i && i.agent, AGENT_RE, 64)];
|
|
91
|
+
if (i && i.attempt !== undefined) {
|
|
92
|
+
if (!Number.isInteger(i.attempt) || i.attempt < 1 || i.attempt > 99) throw new Error('Invalid "attempt": must be an integer from 1 to 99');
|
|
93
|
+
out.push('--attempt', String(i.attempt));
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
83
96
|
},
|
|
84
|
-
args: (i) => [str('agent', i && i.agent, AGENT_RE, 64)],
|
|
85
97
|
},
|
|
86
98
|
{
|
|
87
99
|
name: 'pan_find_phase', title: 'Find a phase', verb: 'find-phase',
|
|
@@ -155,7 +167,7 @@ const { NATIVE_TOOLS } = require('./native-tools.cjs');
|
|
|
155
167
|
// safety argument of ADR-0041 is that no client input reaches it.
|
|
156
168
|
const PROJECT_CWD_PROPERTY = Object.freeze({
|
|
157
169
|
type: 'string',
|
|
158
|
-
description: 'Absolute path of the PAN project to operate on. Optional: defaults to the directory the server was started in. Pass it when the server was launched from a plugin directory (Agent Plugins clients do this by default), or to address another project.',
|
|
170
|
+
description: 'Absolute path of the PAN project to operate on. Optional: defaults to the directory the server was started in. Pass it when the server was launched from a plugin directory (Agent Plugins clients do this by default), or to address another project. The server acts on any existing directory named here with the permissions of the user who runs it — it trusts its caller as it trusts the session that started it.',
|
|
159
171
|
});
|
|
160
172
|
|
|
161
173
|
const PROJECT_CWD_MAX = 1024;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# The `pan-verdict` block
|
|
2
|
+
|
|
3
|
+
A judging agent ends its report with one fenced `pan-verdict` block. The block is the machine-readable form of the verdict the report already gives in prose. The orchestrator records it with `pan-tools findings record`, and that record is what the workflow branches on. It also feeds the findings ledger that milestone audits read for tech debt. The prose stays for people, and the block states the same verdict for code.
|
|
4
|
+
|
|
5
|
+
## Rules
|
|
6
|
+
|
|
7
|
+
1. **Place it last.** The block is the final element of your return. When a report holds more than one block, the recorder reads the last one.
|
|
8
|
+
2. **Valid JSON only.** No comments and no trailing commas. One line or pretty-printed are both fine.
|
|
9
|
+
3. **Same verdict as the prose.** `verdict` is the word your report already uses, and `outcome` is what that word means (see the table below). The block never disagrees with the report.
|
|
10
|
+
4. **One finding per issue.** List the findings the report lists, each as its own entry, most severe first. A clean pass has `"findings": []`.
|
|
11
|
+
5. **Plain summaries.** State each finding in one sentence of 300 characters or fewer. Put the location in `where`, not in `summary`.
|
|
12
|
+
|
|
13
|
+
````markdown
|
|
14
|
+
```pan-verdict
|
|
15
|
+
{"contract":"1.0","agent":"pan-reviewer","phase":"03","verdict":"NEEDS_FIXES","outcome":"fail","findings":[{"class":"defect","severity":"high","where":"src/utils/parser.ts:42","summary":"parse() drops the final token of every line"}]}
|
|
16
|
+
```
|
|
17
|
+
````
|
|
18
|
+
|
|
19
|
+
## Fields
|
|
20
|
+
|
|
21
|
+
| Field | Required | Value |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `contract` | yes | `"1.0"` |
|
|
24
|
+
| `agent` | yes | your agent name, e.g. `pan-reviewer` |
|
|
25
|
+
| `phase` | when you know it | the phase number you were asked about, e.g. `"03"` |
|
|
26
|
+
| `verdict` | yes | your own verdict word (table below) |
|
|
27
|
+
| `outcome` | yes | `pass`, `fail` or `needs_human` |
|
|
28
|
+
| `findings` | yes (may be empty) | a list of `{class, severity, where, summary}` |
|
|
29
|
+
|
|
30
|
+
| Agent | `verdict` → `outcome` |
|
|
31
|
+
|---|---|
|
|
32
|
+
| pan-plan-checker | `passed` → `pass` · `issues_found` → `fail` |
|
|
33
|
+
| pan-reviewer | `PASS` → `pass` · `PASS_WITH_WARNINGS` → `pass` · `NEEDS_FIXES` → `fail` |
|
|
34
|
+
| pan-design-checker | `PASS` → `pass` · `GAPS` → `fail` |
|
|
35
|
+
|
|
36
|
+
The verifier does not emit this block. Its verification.md frontmatter (`status`, `gaps`, `human_verification`, `unrequested`) is its machine contract, and the recorder reads that directly.
|
|
37
|
+
|
|
38
|
+
## `class`: what kind of finding
|
|
39
|
+
|
|
40
|
+
| Class | Use when |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `missing` | Something required is absent: a requirement with no task, a must-have not built, an unplanned key link |
|
|
43
|
+
| `partial` | Present but incomplete: a task missing its verify/done fields, a stub, a half-derived criterion |
|
|
44
|
+
| `contradicts` | It conflicts with a requirement, a locked decision (context.md) or the codebase's established architecture |
|
|
45
|
+
| `unrequested` | Work, a file or a behaviour that no plan or requirement asked for (scope creep) |
|
|
46
|
+
| `defect` | Incorrect behaviour or a code error; a broken dependency order in a plan |
|
|
47
|
+
| `risk` | A security, reliability or scale exposure; a plan whose scope will not fit its budget |
|
|
48
|
+
| `quality` | Convention, naming, style or maintainability, with no correctness impact |
|
|
49
|
+
| `human` | Cannot be settled by a check, so a person must look |
|
|
50
|
+
|
|
51
|
+
## `severity`: how much it matters
|
|
52
|
+
|
|
53
|
+
`critical` · `high` · `medium` · `low` · `info`. This is the same ladder `/pan:review-deep` uses.
|
|
54
|
+
|
|
55
|
+
## Mapping for each judge
|
|
56
|
+
|
|
57
|
+
**pan-plan-checker.**
|
|
58
|
+
- Classes by dimension:
|
|
59
|
+
- Requirement coverage, key links, test coverage, Nyquist → `missing`
|
|
60
|
+
- Task completeness, verification derivation, spec sufficiency, decision trace → `partial`
|
|
61
|
+
- Dependency correctness → `defect`
|
|
62
|
+
- Scope sanity → `risk`
|
|
63
|
+
- Context compliance → `contradicts`
|
|
64
|
+
- Standards → `quality`
|
|
65
|
+
- Severity: blocker → `high`, warning → `medium`, info → `info`.
|
|
66
|
+
- `where`: `NN-MM-plan.md` or `NN-MM-plan.md#task-N`.
|
|
67
|
+
|
|
68
|
+
**pan-reviewer.**
|
|
69
|
+
- Classes by category: Convention → `quality`, Security → `risk`, Code Quality → `defect`, work no plan asked for → `unrequested`.
|
|
70
|
+
- Severity: ERROR → `high`, WARNING → `medium`, INFO → `info`.
|
|
71
|
+
- `where`: `path:line`.
|
|
72
|
+
|
|
73
|
+
**pan-design-checker.**
|
|
74
|
+
- Classes by dimension:
|
|
75
|
+
- Requirement coverage → `missing`
|
|
76
|
+
- Architecture conformance → `contradicts`
|
|
77
|
+
- Threat coverage → `risk`
|
|
78
|
+
- Scope discipline → `unrequested`
|
|
79
|
+
- Every other dimension → `partial`
|
|
80
|
+
- Severity: each gap is `high`. A gap you report as a caveat on the final iteration is `medium`.
|
|
81
|
+
- `where`: the design section, e.g. `03-design.md#interfaces`.
|
|
82
|
+
|
|
83
|
+
## Examples
|
|
84
|
+
|
|
85
|
+
A plan check that passes:
|
|
86
|
+
|
|
87
|
+
````markdown
|
|
88
|
+
```pan-verdict
|
|
89
|
+
{"contract":"1.0","agent":"pan-plan-checker","phase":"05","verdict":"passed","outcome":"pass","findings":[]}
|
|
90
|
+
```
|
|
91
|
+
````
|
|
92
|
+
|
|
93
|
+
A design check with two gaps:
|
|
94
|
+
|
|
95
|
+
````markdown
|
|
96
|
+
```pan-verdict
|
|
97
|
+
{"contract":"1.0","agent":"pan-design-checker","phase":"05","verdict":"GAPS","outcome":"fail","findings":[
|
|
98
|
+
{"class":"missing","severity":"high","where":"05-design.md#requirements","summary":"REQ-12 (export to CSV) maps to no design element"},
|
|
99
|
+
{"class":"risk","severity":"high","where":"05-design.md#threats","summary":"the upload endpoint accepts any file type and no threat entry covers it"}]}
|
|
100
|
+
```
|
|
101
|
+
````
|
|
@@ -12,6 +12,9 @@ phase: XX-name
|
|
|
12
12
|
verified: YYYY-MM-DDTHH:MM:SSZ
|
|
13
13
|
status: passed | gaps_found | human_needed
|
|
14
14
|
score: N/M must-haves verified
|
|
15
|
+
unrequested: # Only when the scope check (`pan-tools verify scope <phase>`) found work no plan asked for
|
|
16
|
+
- path: "src/admin/panel.tsx"
|
|
17
|
+
what: "An admin panel no plan or requirement asked for"
|
|
15
18
|
---
|
|
16
19
|
|
|
17
20
|
# Phase {X}: {Name} Verification Report
|
|
@@ -89,6 +92,19 @@ None — all verifiable items checked programmatically.
|
|
|
89
92
|
**Expected:** {What should happen}
|
|
90
93
|
**Why human:** {Why can't verify programmatically}
|
|
91
94
|
|
|
95
|
+
## Unrequested Work
|
|
96
|
+
|
|
97
|
+
{If the scope check found none:}
|
|
98
|
+
None: every change traces to a plan.
|
|
99
|
+
|
|
100
|
+
{Otherwise, one row per `unrequested:` entry:}
|
|
101
|
+
|
|
102
|
+
| File | What it adds | Why no plan covers it |
|
|
103
|
+
|------|--------------|-----------------------|
|
|
104
|
+
| src/admin/panel.tsx | An admin panel | No requirement mentions admin tooling |
|
|
105
|
+
|
|
106
|
+
Unrequested work is recorded, not blocking: the status does not change because of it.
|
|
107
|
+
|
|
92
108
|
## Gaps Summary
|
|
93
109
|
|
|
94
110
|
{If no gaps:}
|
|
@@ -117,6 +117,14 @@ Parse JSON for: `phase`, `plans[]` (each with `id`, `wave`, `autonomous`, `objec
|
|
|
117
117
|
|
|
118
118
|
**Filtering:** Skip plans where `has_summary: true`. If `--gaps-only`: also skip non-gap_closure plans. If all filtered: "No matching incomplete plans" → exit.
|
|
119
119
|
|
|
120
|
+
**If `--gaps-only`:** this run is the fix round after a verification found gaps — a second attempt at work that failed once. Resolve the executor for that attempt and use it in place of `executor_model` for every spawn in this run:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
EXECUTOR_MODEL=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs resolve-model pan-executor --attempt 2 --raw)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
It equals `executor_model` unless the `budget` profile runs the executor below its quality tier; then it is one tier higher (capped by `routing.max_escalations`), so the gaps are not retried on the tier that left them.
|
|
127
|
+
|
|
120
128
|
Report:
|
|
121
129
|
```
|
|
122
130
|
## Execution Plan
|
|
@@ -417,13 +425,21 @@ Task(
|
|
|
417
425
|
)
|
|
418
426
|
```
|
|
419
427
|
|
|
420
|
-
3.
|
|
428
|
+
3. **Save the report.** Use the Write tool to write the reviewer's returned text, verbatim and in full (including its closing `pan-verdict` block), to `{phase_dir}/{phase_number}-review.md`. The reviewer is read-only by design, so the orchestrator saves the report. `/pan:review-deep` and the findings ledger read this file.
|
|
429
|
+
|
|
430
|
+
4. **Record the verdict, then act on it.** The record is what this step branches on. It also adds the findings to the ledger (`.planning/findings.jsonl`) and logs the verdict to the trace, so no separate trace call is needed:
|
|
431
|
+
```bash
|
|
432
|
+
REVIEW_FILE="{phase_dir}/{phase_number}-review.md"
|
|
433
|
+
REVIEW_VERDICT=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs findings record --phase "${PHASE_NUMBER}" --agent pan-reviewer --file "$REVIEW_FILE" --raw 2>/dev/null) \
|
|
434
|
+
|| REVIEW_VERDICT=$(grep -A1 '^### Verdict' "$REVIEW_FILE" | tail -1 | tr -d ' ')
|
|
435
|
+
```
|
|
436
|
+
The fallback reads the word under `### Verdict` when the report carries no valid `pan-verdict` block.
|
|
421
437
|
|
|
422
438
|
| Verdict | Action |
|
|
423
439
|
|---------|--------|
|
|
424
440
|
| `PASS` | Continue to verification |
|
|
425
|
-
| `PASS_WITH_WARNINGS` | Report warnings, continue to verification |
|
|
426
|
-
| `NEEDS_FIXES` | Present ERROR findings to user: "Fix before verification?" or "Continue anyway?" |
|
|
441
|
+
| `PASS_WITH_WARNINGS` | Report the warnings, then record that the phase continues past them (below), and continue to verification |
|
|
442
|
+
| `NEEDS_FIXES` | Present the ERROR findings to the user: "Fix before verification?" or "Continue anyway?" |
|
|
427
443
|
|
|
428
444
|
```
|
|
429
445
|
## Code Review Results
|
|
@@ -434,34 +450,60 @@ Task(
|
|
|
434
450
|
{If errors: list top 5 with file:line}
|
|
435
451
|
```
|
|
436
452
|
|
|
437
|
-
**
|
|
453
|
+
**Never continue past findings silently.** Whenever the phase moves on with review findings still open, record why. The reason is what a milestone audit later reports as tech debt:
|
|
454
|
+
- `PASS_WITH_WARNINGS`:
|
|
455
|
+
```bash
|
|
456
|
+
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"
|
|
457
|
+
```
|
|
458
|
+
- **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.
|
|
459
|
+
- **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.
|
|
438
460
|
|
|
439
|
-
|
|
461
|
+
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.
|
|
440
462
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
463
|
+
6. **Deep review — only when `--deep-review` is in $ARGUMENTS.** The security pass and cross-check that `/pan:review-deep` runs, done inline right after the normal review. If the normal review was skipped (`--skip-review` or `--fast`), say that `--deep-review` needs the review it builds on, and continue without it.
|
|
464
|
+
|
|
465
|
+
a. Spawn the hardener. Its output path is `.planning/reviews/${PHASE_NUMBER}/hardener.md`:
|
|
466
|
+
```
|
|
467
|
+
Task(
|
|
468
|
+
subagent_type="pan-hardener",
|
|
469
|
+
model="$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs resolve-model pan-hardener --raw)",
|
|
470
|
+
prompt="
|
|
471
|
+
<files_to_read>
|
|
472
|
+
- {phase_dir}/{phase_number}-review.md (the first-pass review)
|
|
473
|
+
- the phase plans: {phase_dir}/*-plan.md
|
|
474
|
+
Changed files to audit:
|
|
475
|
+
${CHANGED_FILES_LIST}
|
|
476
|
+
</files_to_read>
|
|
477
|
+
<output_path>.planning/reviews/${PHASE_NUMBER}/hardener.md</output_path>
|
|
478
|
+
<framework_scope>OWASP Top 10 (2025) and STRIDE, across every changed file.</framework_scope>
|
|
479
|
+
"
|
|
480
|
+
)
|
|
452
481
|
```
|
|
453
482
|
|
|
454
|
-
|
|
455
|
-
```
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
483
|
+
b. Spawn the meta-reviewer on both first-pass reports. Its output path is `.planning/reviews/${PHASE_NUMBER}/meta.md`:
|
|
484
|
+
```
|
|
485
|
+
Task(
|
|
486
|
+
subagent_type="pan-meta-reviewer",
|
|
487
|
+
model="$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs resolve-model pan-meta-reviewer --raw)",
|
|
488
|
+
prompt="
|
|
489
|
+
<files_to_read>
|
|
490
|
+
- {phase_dir}/{phase_number}-review.md
|
|
491
|
+
- .planning/reviews/${PHASE_NUMBER}/hardener.md
|
|
492
|
+
</files_to_read>
|
|
493
|
+
<output_path>.planning/reviews/${PHASE_NUMBER}/meta.md</output_path>
|
|
494
|
+
"
|
|
495
|
+
)
|
|
462
496
|
```
|
|
497
|
+
If either agent returns its report instead of writing the output path, save the returned text there with the Write tool before the merge.
|
|
463
498
|
|
|
464
|
-
|
|
499
|
+
c. Merge the three reports:
|
|
500
|
+
```bash
|
|
501
|
+
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs review-deep merge "${PHASE_NUMBER}" \
|
|
502
|
+
--reviewer-file "{phase_dir}/{phase_number}-review.md" \
|
|
503
|
+
--hardener-file ".planning/reviews/${PHASE_NUMBER}/hardener.md" \
|
|
504
|
+
--meta-file ".planning/reviews/${PHASE_NUMBER}/meta.md"
|
|
505
|
+
```
|
|
506
|
+
This writes `.planning/reviews/${PHASE_NUMBER}/deep-review.md` and prints its verdict (`ok` · `ok_with_minor` · `fix_before_merge` · `review_required` · `block`). Report the verdict and the finding count. On `review_required` or `block`, stop before verification and present the high and critical findings to the user, as with `NEEDS_FIXES`.
|
|
465
507
|
</step>
|
|
466
508
|
|
|
467
509
|
<step name="close_parent_artifacts">
|
|
@@ -531,31 +573,15 @@ Create verification.md.",
|
|
|
531
573
|
)
|
|
532
574
|
```
|
|
533
575
|
|
|
534
|
-
|
|
576
|
+
Record the verification and read its status:
|
|
535
577
|
```bash
|
|
536
|
-
|
|
578
|
+
VERIF_FILE=$(ls "$PHASE_DIR"/*-verification.md 2>/dev/null | head -1)
|
|
579
|
+
VERIF_STATUS=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs findings record --phase "${PHASE_NUMBER}" --file "$VERIF_FILE" --raw 2>/dev/null) \
|
|
580
|
+
|| VERIF_STATUS=$(grep "^status:" "$VERIF_FILE" | cut -d: -f2 | tr -d ' ')
|
|
537
581
|
```
|
|
582
|
+
`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.
|
|
538
583
|
|
|
539
|
-
**
|
|
540
|
-
|
|
541
|
-
```bash
|
|
542
|
-
if [ "$VERIF_STATUS" = "passed" ]; then
|
|
543
|
-
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs optimize trace log \
|
|
544
|
-
--type decision --category verification_passed \
|
|
545
|
-
--description "Phase ${PHASE_NUMBER} verification passed (logged from exec-phase, P-1806)" \
|
|
546
|
-
--agent pan-verifier --impact minor 2>/dev/null || true
|
|
547
|
-
elif [ "$VERIF_STATUS" = "gaps_found" ]; then
|
|
548
|
-
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs optimize trace log \
|
|
549
|
-
--type error --category verification_gaps \
|
|
550
|
-
--description "Phase ${PHASE_NUMBER} verification found gaps" \
|
|
551
|
-
--agent pan-verifier --impact major 2>/dev/null || true
|
|
552
|
-
elif [ "$VERIF_STATUS" = "human_needed" ]; then
|
|
553
|
-
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs optimize trace log \
|
|
554
|
-
--type decision --category verification_human_needed \
|
|
555
|
-
--description "Phase ${PHASE_NUMBER} verification awaiting human review" \
|
|
556
|
-
--agent pan-verifier --impact minor 2>/dev/null || true
|
|
557
|
-
fi
|
|
558
|
-
```
|
|
584
|
+
**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
585
|
|
|
560
586
|
| Status | Action |
|
|
561
587
|
|--------|--------|
|
|
@@ -163,6 +163,8 @@ Report final status.
|
|
|
163
163
|
| I001 | info | Plan without SUMMARY (may be in progress) | No |
|
|
164
164
|
| I002 | info | Phase in ROADMAP ahead of current phase, not planned yet | No |
|
|
165
165
|
| I003 | info | Focus-model or campaign tree — the phase-model checks do not apply | No |
|
|
166
|
+
| I004 | info | planning-with-files shares the tree — PAN leaves its files alone | No |
|
|
167
|
+
| I005 | info | The planning tree is gitignored while commit_docs is true — planning commits commit nothing | No |
|
|
166
168
|
| STATE_REQ_DRIFT | warning | state.md complete but REQUIREMENTS.md has unchecked boxes | Yes |
|
|
167
169
|
| STATE_ROADMAP_DRIFT | warning | state.md complete but roadmap.md has unchecked plan boxes | Yes |
|
|
168
170
|
| VERIFICATION_GATE_MISSING | warning | Phase has completed plans but no verification record | No |
|
|
@@ -224,7 +224,7 @@ The Focus workflow is a **scan → plan → exec → sync** pipeline. Each step
|
|
|
224
224
|
| `/pan:plan-phase <N>` | Research + plan a phase with verification |
|
|
225
225
|
| `/pan:exec-phase <N>` | Execute plans with wave-based parallelization |
|
|
226
226
|
| `/pan:research-phase <N>` | Deep ecosystem research for specialized domains |
|
|
227
|
-
| `/pan:verify-phase <N>` |
|
|
227
|
+
| `/pan:verify-phase <N>` | Re-run goal-backward verification with a test-suite gate |
|
|
228
228
|
|
|
229
229
|
### Phase Management
|
|
230
230
|
| Command | Description |
|
|
@@ -348,7 +348,7 @@ The Focus workflow is a **scan → plan → exec → sync** pipeline. Each step
|
|
|
348
348
|
|
|
349
349
|
**`/pan:exec-phase <N>`** — Execute all plans in a phase. Groups by wave, runs waves sequentially, plans within each wave in parallel.
|
|
350
350
|
|
|
351
|
-
**`/pan:verify-phase <N>`** —
|
|
351
|
+
**`/pan:verify-phase <N>`** — Re-run goal-backward verification behind a test-suite gate. Writes the phase's verification report (passed, gaps_found or human_needed); fix gaps with `/pan:plan-phase <N> --gaps`.
|
|
352
352
|
|
|
353
353
|
**`/pan:quick <desc>`** — Small tasks with PAN guarantees but shorter path. Skips researcher, checker, verifier. Lives in `.planning/quick/`.
|
|
354
354
|
|