pan-wizard 3.25.0 → 3.27.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 (61) hide show
  1. package/README.md +1 -1
  2. package/bin/install-lib.cjs +283 -1
  3. package/bin/install.js +127 -0
  4. package/commands/pan/hygiene.md +14 -8
  5. package/commands/pan/milestone-audit.md +10 -4
  6. package/hooks/dist/pan-cost-logger.js +69 -5
  7. package/hooks/dist/pan-stop-guard.js +32 -1
  8. package/hooks/dist/pan-trace-logger.js +35 -2
  9. package/package.json +3 -2
  10. package/pan-wizard-core/bin/lib/bridge.cjs +0 -1
  11. package/pan-wizard-core/bin/lib/bus.cjs +0 -1
  12. package/pan-wizard-core/bin/lib/campaign.cjs +3 -2
  13. package/pan-wizard-core/bin/lib/commands-learnings.cjs +8 -8
  14. package/pan-wizard-core/bin/lib/commands.cjs +15 -14
  15. package/pan-wizard-core/bin/lib/config.cjs +5 -5
  16. package/pan-wizard-core/bin/lib/constants.cjs +27 -0
  17. package/pan-wizard-core/bin/lib/context-budget.cjs +28 -0
  18. package/pan-wizard-core/bin/lib/core.cjs +190 -26
  19. package/pan-wizard-core/bin/lib/cost.cjs +0 -1
  20. package/pan-wizard-core/bin/lib/distill.cjs +3 -3
  21. package/pan-wizard-core/bin/lib/focus.cjs +16 -16
  22. package/pan-wizard-core/bin/lib/hud.cjs +1 -1
  23. package/pan-wizard-core/bin/lib/hygiene.cjs +397 -37
  24. package/pan-wizard-core/bin/lib/init.cjs +90 -13
  25. package/pan-wizard-core/bin/lib/knowledge.cjs +0 -1
  26. package/pan-wizard-core/bin/lib/memory.cjs +1 -1
  27. package/pan-wizard-core/bin/lib/milestone.cjs +3 -3
  28. package/pan-wizard-core/bin/lib/optimize.cjs +3 -3
  29. package/pan-wizard-core/bin/lib/phase.cjs +4 -4
  30. package/pan-wizard-core/bin/lib/planning-root.cjs +327 -0
  31. package/pan-wizard-core/bin/lib/preview.cjs +0 -1
  32. package/pan-wizard-core/bin/lib/review-deep.cjs +0 -1
  33. package/pan-wizard-core/bin/lib/roadmap.cjs +1 -1
  34. package/pan-wizard-core/bin/lib/state-compact.cjs +339 -0
  35. package/pan-wizard-core/bin/lib/state.cjs +0 -1
  36. package/pan-wizard-core/bin/lib/suggest.cjs +141 -0
  37. package/pan-wizard-core/bin/lib/template.cjs +1 -1
  38. package/pan-wizard-core/bin/lib/utils.cjs +39 -11
  39. package/pan-wizard-core/bin/lib/verify-deploy.cjs +113 -2
  40. package/pan-wizard-core/bin/lib/verify.cjs +4 -3
  41. package/pan-wizard-core/bin/lib/whatif.cjs +0 -1
  42. package/pan-wizard-core/bin/pan-tools.cjs +97 -7
  43. package/pan-wizard-core/mcp/native-tools.cjs +159 -0
  44. package/pan-wizard-core/mcp/orchestrator.cjs +179 -0
  45. package/{pan-zcode → pan-wizard-core}/mcp/server.cjs +35 -6
  46. package/{pan-zcode → pan-wizard-core}/mcp/tool-registry.cjs +60 -3
  47. package/pan-wizard-core/workflows/milestone-audit.md +35 -6
  48. package/pan-wizard-core/workflows/verify-phase.md +25 -6
  49. package/pan-zcode/README.md +17 -9
  50. package/pan-zcode/bin/install-zcode.js +4 -1
  51. package/scripts/build-plugin.js +35 -3
  52. package/scripts/deprecate-old-versions.js +225 -0
  53. package/scripts/plugin-path.js +84 -0
  54. package/pan-wizard-core/learnings/internal/.gitkeep +0 -2
  55. package/pan-wizard-core/learnings/internal/experiment-runner.md +0 -81
  56. package/pan-wizard-core/learnings/internal/external-research.md +0 -105
  57. package/pan-wizard-core/learnings/internal/loop-design.md +0 -33
  58. package/pan-wizard-core/learnings/internal/pan-dev-bugs.md +0 -181
  59. package/pan-zcode/mcp/native-tools.cjs +0 -63
  60. package/pan-zcode/mcp/orchestrator.cjs +0 -66
  61. /package/{pan-zcode → pan-wizard-core}/mcp/merge-gate.cjs +0 -0
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Deprecate published versions that have fallen far enough behind.
4
+ *
5
+ * WHY. Old releases stay installable forever, and `npm install pan-wizard@3.20.0`
6
+ * silently gives someone a build from several cycles ago with none of the fixes
7
+ * since. Deprecation is the honest signal: the version keeps working, keeps
8
+ * resolving, and anyone installing it sees a warning telling them what to move to.
9
+ *
10
+ * WHY DEPRECATE AND NEVER UNPUBLISH. Unpublishing removes a tarball other people
11
+ * may depend on and is refused by npm outside a 72-hour window anyway. Deprecation
12
+ * is additive, reversible (`npm deprecate <pkg>@<ver> ""` clears it), and breaks
13
+ * nobody. **This script must never gain an unpublish path.**
14
+ *
15
+ * THE RULE. Keep the newest N stable releases (default 3 — the one just published
16
+ * plus the two behind it) and deprecate every stable release older than those.
17
+ * Prereleases are never counted as "kept": once a stable release exists that
18
+ * supersedes them they are deprecated too, since an rc is not something anyone
19
+ * should be installing after the real release shipped.
20
+ *
21
+ * SAFETY, in the order it matters:
22
+ * - DRY RUN BY DEFAULT. `--apply` is required to change anything.
23
+ * - The version being released is never deprecated, even if the arithmetic
24
+ * somehow selects it — an explicit guard, not a consequence.
25
+ * - Already-deprecated versions are skipped, so re-running is a no-op.
26
+ * - A failure to deprecate NEVER fails the build. By the time this runs the
27
+ * publish has already succeeded; turning a housekeeping failure into a red
28
+ * release would be strictly worse than leaving an old version undeprecated.
29
+ *
30
+ * Usage:
31
+ * node scripts/deprecate-old-versions.js # dry run, keep 3
32
+ * node scripts/deprecate-old-versions.js --apply # actually deprecate
33
+ * node scripts/deprecate-old-versions.js --keep 5 --apply
34
+ */
35
+
36
+ 'use strict';
37
+
38
+ const { execFileSync } = require('child_process');
39
+
40
+ const PKG = 'pan-wizard';
41
+ const DEFAULT_KEEP = 3;
42
+
43
+ /**
44
+ * Parse a semver string into comparable parts. Returns null for anything that is
45
+ * not `major.minor.patch[-prerelease]`, so junk sorts out rather than throwing.
46
+ */
47
+ function parse(v) {
48
+ const m = /^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/.exec(String(v || '').trim());
49
+ if (!m) return null;
50
+ return {
51
+ version: v,
52
+ nums: [Number(m[1]), Number(m[2]), Number(m[3])],
53
+ pre: m[4] || null,
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Compare two parsed versions, ascending. Prerelease-aware: 3.26.0-rc.1 sorts
59
+ * BELOW 3.26.0, which the update-check hook's comparator deliberately does not do
60
+ * (it ignores the suffix). Getting this backwards would deprecate a real release
61
+ * in favour of its own release candidate, so it is implemented here rather than
62
+ * reused.
63
+ */
64
+ function compare(a, b) {
65
+ for (let i = 0; i < 3; i++) {
66
+ if (a.nums[i] !== b.nums[i]) return a.nums[i] - b.nums[i];
67
+ }
68
+ if (a.pre === b.pre) return 0;
69
+ if (a.pre === null) return 1; // release > prerelease
70
+ if (b.pre === null) return -1;
71
+ return a.pre < b.pre ? -1 : 1; // lexical is good enough for rc.1 < rc.2
72
+ }
73
+
74
+ /**
75
+ * Decide what to deprecate. PURE — no network, no process — so the rule is
76
+ * testable without touching a registry.
77
+ *
78
+ * @param {string[]} published every version on the registry
79
+ * @param {string} current the version just released (never deprecated)
80
+ * @param {number} keep how many newest STABLE releases to leave alone
81
+ * @param {string[]} [already] versions already carrying a deprecation message
82
+ * @returns {{deprecate:string[], keep:string[], reason:Object<string,string>}}
83
+ */
84
+ function selectVersionsToDeprecate(published, current, keep = DEFAULT_KEEP, already = []) {
85
+ const parsed = (published || []).map(parse).filter(Boolean).sort(compare);
86
+ const skip = new Set(already || []);
87
+ const stable = parsed.filter((p) => !p.pre);
88
+ // The newest `keep` stable releases are protected.
89
+ const kept = new Set(stable.slice(-keep).map((p) => p.version));
90
+ // The current release is protected regardless of where the arithmetic lands it.
91
+ kept.add(current);
92
+
93
+ const reason = {};
94
+ const deprecate = [];
95
+ for (const p of parsed) {
96
+ if (kept.has(p.version)) continue;
97
+ if (skip.has(p.version)) continue;
98
+ reason[p.version] = p.pre
99
+ ? `prerelease superseded by ${current}`
100
+ : `more than ${keep - 1} releases behind ${current}`;
101
+ deprecate.push(p.version);
102
+ }
103
+ return { deprecate, keep: [...kept].sort(), reason };
104
+ }
105
+
106
+ /** Message a deprecated version carries. Points at what to install instead. */
107
+ function buildMessage(current) {
108
+ return `No longer maintained — install pan-wizard@${current} or later (npm i pan-wizard@latest).`;
109
+ }
110
+
111
+ // ─── IO layer ───────────────────────────────────────────────────────────────
112
+
113
+ /**
114
+ * Run npm.
115
+ *
116
+ * WINDOWS: `npm` is a `.cmd` shim, so `execFileSync('npm', …)` fails ENOENT and
117
+ * `'npm.cmd'` fails EINVAL — the shim can only be launched through a shell. This
118
+ * is the same scar `runner.cjs` carries as its `shell: 'win32'` opt-in, and the
119
+ * first version of this script reproduced the bug: a local dry run reported
120
+ * "could not read the registry" and returned, so the fail-open path made a real
121
+ * platform bug look like a benign skip.
122
+ *
123
+ * QUOTING: with `shell: true` node CONCATENATES arguments rather than escaping
124
+ * them, so anything containing a space must be quoted or it arrives as several
125
+ * arguments — which matters here because the deprecation message is a sentence.
126
+ * Every argument is program-controlled (package name, versions read from the
127
+ * registry, our own message), so this is a correctness problem rather than an
128
+ * injection one, but it still has to be right. `assertQuotable` refuses a value
129
+ * carrying a double quote instead of emitting a broken command line.
130
+ */
131
+ function assertQuotable(a) {
132
+ if (String(a).includes('"')) {
133
+ throw new Error(`refusing to shell-quote an argument containing a double quote: ${a}`);
134
+ }
135
+ return a;
136
+ }
137
+
138
+ function runNpm(args, opts = {}) {
139
+ const win = process.platform === 'win32';
140
+ const argv = win ? args.map((a) => (/\s/.test(a) ? `"${assertQuotable(a)}"` : a)) : args;
141
+ return execFileSync('npm', argv, {
142
+ encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], shell: win, ...opts,
143
+ });
144
+ }
145
+
146
+ /**
147
+ * `npm view <pkg> <field> --json` prints NOTHING when the field is unset across
148
+ * every version — which is exactly the healthy starting state for `deprecated`
149
+ * (nothing deprecated yet). `JSON.parse('')` throws, and the fail-open handler
150
+ * then reported "could not read the registry", turning the normal case into an
151
+ * apparent failure. Empty means absent, not broken.
152
+ */
153
+ function npmJson(args, fallback = null) {
154
+ const out = runNpm(args);
155
+ if (!out || !out.trim()) return fallback;
156
+ return JSON.parse(out);
157
+ }
158
+
159
+ function main() {
160
+ const args = process.argv.slice(2);
161
+ const apply = args.includes('--apply');
162
+ const keepIdx = args.indexOf('--keep');
163
+ const keep = keepIdx > -1 ? Number(args[keepIdx + 1]) : DEFAULT_KEEP;
164
+ const current = require('../package.json').version;
165
+
166
+ if (!Number.isInteger(keep) || keep < 1) {
167
+ console.error(`deprecate: --keep must be a positive integer, got ${keep}`);
168
+ process.exit(1);
169
+ }
170
+
171
+ // A prerelease must never trigger a deprecation sweep: it is not the thing
172
+ // users are being pointed at, and treating it as "the new release" would
173
+ // deprecate the current stable one.
174
+ if (parse(current) && parse(current).pre) {
175
+ console.log(`deprecate: ${current} is a prerelease — skipping (sweeps run for stable releases only).`);
176
+ return;
177
+ }
178
+
179
+ let published = [];
180
+ let deprecatedAlready = [];
181
+ try {
182
+ published = npmJson(['view', PKG, 'versions', '--json'], []);
183
+ if (!Array.isArray(published)) published = [published];
184
+ const map = npmJson(['view', PKG, 'deprecated', '--json'], {});
185
+ // npm returns a bare string for a single version, or {version: message}.
186
+ deprecatedAlready = (map && typeof map === 'object') ? Object.keys(map) : [];
187
+ } catch (e) {
188
+ console.error(`deprecate: could not read the registry (${String(e.message).split('\n')[0]}). Nothing changed.`);
189
+ return; // never fail the build over housekeeping
190
+ }
191
+
192
+ const { deprecate, keep: kept, reason } = selectVersionsToDeprecate(published, current, keep, deprecatedAlready);
193
+ const message = buildMessage(current);
194
+
195
+ console.log(`deprecate: current=${current} keep=${keep}`);
196
+ console.log(` protected: ${kept.join(', ')}`);
197
+ if (deprecate.length === 0) {
198
+ console.log(' nothing to deprecate.');
199
+ return;
200
+ }
201
+ console.log(` ${apply ? 'deprecating' : 'WOULD deprecate (dry run — pass --apply)'}: ${deprecate.length}`);
202
+ for (const v of deprecate) console.log(` ${v} — ${reason[v]}`);
203
+
204
+ if (!apply) return;
205
+
206
+ let failed = 0;
207
+ for (const v of deprecate) {
208
+ try {
209
+ runNpm(['deprecate', `${PKG}@${v}`, message]);
210
+ console.log(` ✓ ${v}`);
211
+ } catch (e) {
212
+ failed++;
213
+ console.error(` ✗ ${v}: ${String(e.stderr || e.message).split('\n')[0]}`);
214
+ }
215
+ }
216
+ if (failed) {
217
+ // Reported, not fatal. The publish already succeeded; a red build here would
218
+ // imply the release failed, which is false and worse than the omission.
219
+ console.error(`deprecate: ${failed} of ${deprecate.length} failed — release is unaffected.`);
220
+ }
221
+ }
222
+
223
+ if (require.main === module) main();
224
+
225
+ module.exports = { selectVersionsToDeprecate, buildMessage, parse, compare, assertQuotable };
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Print the absolute path of the built PAN plugin directory — the contract a
4
+ * Claude Code plugin-marketplace `command` source requires (v2.1.229+).
5
+ *
6
+ * WHY THIS EXISTS. PAN builds a plugin (`npm run build:plugin`) and has shipped
7
+ * it nowhere, because marketplace publishing is gated on one unverified
8
+ * question: does `${CLAUDE_PLUGIN_ROOT}` expand inside *command markdown*? It is
9
+ * documented as substituted in hook and MCP configs, not in content. A `command`
10
+ * source needs no hosting, so it turns that question into a local experiment —
11
+ * install the plugin from this script's output and run `/pan-plugin-selftest`.
12
+ *
13
+ * THE CONTRACT, verbatim from code.claude.com/docs/en/plugin-marketplaces:
14
+ * - Claude Code runs the command "through the platform shell, `sh` on macOS and
15
+ * Linux or `cmd.exe` on Windows, from the user's home directory". So NOTHING
16
+ * here may depend on the working directory; every path is derived from
17
+ * __dirname.
18
+ * - "The command must print exactly one line on stdout and exit with code 0."
19
+ * The plugin build is chatty, so its stdout is relayed to STDERR and only the
20
+ * path reaches stdout. A stray console.log here breaks the install.
21
+ * - The printed directory must hold plugin content at its top level, must not
22
+ * be the directory Claude Code started in or one of its parents, and on
23
+ * Windows must not be a UNC path.
24
+ *
25
+ * Rebuilding on every run is deliberate: Claude Code re-runs the command once per
26
+ * session in the background, so a source edit is picked up without reinstalling.
27
+ * In `copy` mode the version is a hash of the directory contents, so an unchanged
28
+ * build counts as up to date.
29
+ */
30
+
31
+ 'use strict';
32
+
33
+ const path = require('path');
34
+ const fs = require('fs');
35
+ const { execFileSync } = require('child_process');
36
+
37
+ const ROOT = path.join(__dirname, '..');
38
+ const PLUGIN_DIR = path.join(ROOT, 'dist', 'pan-wizard-plugin');
39
+
40
+ // Top-level markers Claude Code accepts as proof of plugin content.
41
+ const PLUGIN_MARKERS = ['.claude-plugin', 'skills', 'commands', 'agents', 'hooks'];
42
+
43
+ function fail(message) {
44
+ // stderr only — stdout is reserved for the single path line.
45
+ process.stderr.write(`plugin-path: ${message}\n`);
46
+ process.exit(1);
47
+ }
48
+
49
+ function build() {
50
+ try {
51
+ // Relay the builder's stdout to stderr so stdout stays single-line.
52
+ const out = execFileSync(process.execPath, [path.join(ROOT, 'scripts', 'build-plugin.js')], {
53
+ cwd: ROOT, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'],
54
+ });
55
+ if (out) process.stderr.write(out);
56
+ } catch (err) {
57
+ const detail = (err.stderr || err.stdout || err.message || '').toString().trim();
58
+ fail(`plugin build failed: ${detail.split('\n').slice(-3).join(' | ')}`);
59
+ }
60
+ }
61
+
62
+ function main() {
63
+ build();
64
+
65
+ if (!fs.existsSync(PLUGIN_DIR)) fail(`build produced no directory at ${PLUGIN_DIR}`);
66
+
67
+ const top = fs.readdirSync(PLUGIN_DIR);
68
+ if (!PLUGIN_MARKERS.some((m) => top.includes(m))) {
69
+ fail(`no plugin content at the top level of ${PLUGIN_DIR} (need one of ${PLUGIN_MARKERS.join(', ')})`);
70
+ }
71
+
72
+ const resolved = path.resolve(PLUGIN_DIR);
73
+
74
+ // Windows UNC paths are refused by Claude Code; catch it here with a clear
75
+ // message rather than letting the install fail opaquely.
76
+ if (process.platform === 'win32' && /^\\\\/.test(resolved)) {
77
+ fail(`refusing a UNC path (Claude Code rejects it): ${resolved}`);
78
+ }
79
+
80
+ // Exactly one line, nothing else.
81
+ process.stdout.write(`${resolved}\n`);
82
+ }
83
+
84
+ main();
@@ -1,2 +0,0 @@
1
- # Placeholder so git tracks the empty directory.
2
- # This tier is NOT shipped to user installs — see ../README.md.
@@ -1,81 +0,0 @@
1
- ---
2
- topic: experiment-runner
3
- last_updated: 2026-05-03T03:30:13.038Z
4
- patterns:
5
- - id: P-EXP-001
6
- summary: new-project --auto can finish all artifacts but never commit if the run ends before the workflow's commit step (1 of 5 experiments hit this)
7
- promoted_at: 2026-05-02T14:35:52.700Z
8
- source_experiments: [whoocache]
9
- - id: P-EXP-002
10
- summary: claude -p exits at phase boundaries despite --auto and prose-based DO NOT exit (v3.7.6 cross-phase YOLO continuation fix), so multi-phase autonomous runs need one invocation per phase
11
- promoted_at: 2026-05-02T14:35:59.399Z
12
- source_experiments: [whoolog, whoocache, whooflow, whooschema, whoodb]
13
- - id: P-EXP-003
14
- summary: state.md YAML frontmatter is the authoritative truth; body prose may lag after phase completion
15
- promoted_at: 2026-05-02T14:36:04.863Z
16
- source_experiments: [whooschema, whoolog, whoocache]
17
- - id: P-EXP-004
18
- summary: 30-min DEFAULT_TIMEOUT_MS is too short for typical 3-plan phases; recommend 60+ min default
19
- promoted_at: 2026-05-02T14:36:15.357Z
20
- source_experiments: [whoolog]
21
- - id: P-EXP-005
22
- summary: 4 concurrent claude -p experiment sessions run cleanly on a single machine; no TTY contention or rate-limit issues
23
- promoted_at: 2026-05-02T14:36:22.170Z
24
- source_experiments: [whoolog, whoocache, whooflow, whooschema, whoodb]
25
- - id: P-NPRS-005
26
- summary: Single experiment can ship a 24-plan / 5-phase / 346-test / 1.46MB binary milestone in ~6h cumulative agent runtime when the planner emits decision-trace + the executor honors per-plan file ownership
27
- promoted_at: 2026-05-03T03:30:13.038Z
28
- source_experiments: [notepadrs]
29
- ---
30
-
31
- # Experiment Runner (AI-derived)
32
-
33
- > Auto-maintained by `pan-tools learn promote`. Each pattern was extracted from one or more experiment runs (see source_experiments). Patterns are **advisory** — orchestrators should weight them against current context.
34
-
35
- ## P-EXP-001 — Missing git identity in fresh experiment folder causes silent commit failures (whoocache root cause)
36
-
37
- **Evidence:** whoocache: 24 min of work produced project.md, requirements.md, roadmap.md, src/{cache,atomic-write,lock,...}.js — but git log empty. **Root cause** found in summary.md: "Git identity was not configured in this environment; per environment_notes the commits returned `committed: false` with `reason: 'commit_failed'`. File outputs landed on disk (the contract). Commits can be re-run later by the user once `git config user.email / user.name` are set." `pan-tools commit` returns exit-0 with `{committed: false, reason: 'commit_failed'}` — the autonomous loop sees no error and keeps going. State.md showed Phase 1 ready. Resumed phase commands committed normally from then on, after identity was set.
38
-
39
- **Rule:** experiment scaffolding (`pan-tools experiment new`) MUST `git init` the folder AND configure `user.email` / `user.name` (inherited from PAN source repo, falling back to placeholders) so the autonomous loop's commits don't silently fail. Fixed in `experiment.cjs initExperimentGit()` v3.7.9. As a defensive layer, `new-project.md` section 8.9 also adds an end-of-workflow safety-net commit. As a hardening item, consider making `pan-tools commit` exit non-zero on `commit_failed` so callers detect the failure mode.
40
-
41
- **Applies in:** experiment.cjs scaffolder, new-project workflow, any tooling that wraps `pan-tools commit` in a fresh git environment
42
-
43
- ## P-EXP-002 — claude -p exits at phase boundaries despite --auto and prose-based DO NOT exit (v3.7.6 cross-phase YOLO continuation fix), so multi-phase autonomous runs need one invocation per phase
44
-
45
- **Evidence:** All 5 experiments (whoolog, whoocache, whooflow, whooschema, whoodb) exited cleanly with exit_code=0 status=incomplete at every Phase N -> Phase N+1 boundary. Each phase needed a separate experiment run --prompt invocation. Even though state.md shows current_phase advanced and last_activity says transitioned to Phase N+1, the spawned claude session ends.
46
-
47
- **Rule:** Treat the autonomous cross-phase chain as best-effort, not guaranteed. Scripts/CI/runners should plan for one /pan:plan-phase N --auto invocation per phase. Single-invocation multi-phase runs are a stretch goal, not the contract.
48
-
49
- **Applies in:** any autonomous multi-phase run via claude -p, codex exec, gemini -p, opencode
50
-
51
- ## P-EXP-003 — state.md YAML frontmatter is the authoritative truth; body prose may lag after phase completion
52
-
53
- **Evidence:** whooschema after Phase 3 completion: frontmatter showed completed_phases=3 status=completed, but body still showed Current phase 1 - Foundation, Phase 1 Executed. Same pattern observed in whoolog and whoocache to lesser degree.
54
-
55
- **Rule:** When reading state.md programmatically (from runner.cjs, status checks, harvest scripts), parse the YAML frontmatter fields (completed_phases, current_phase, status). The body's Current Position / Phase Status sections sometimes do not re-render after phase completion. Prefer frontmatter parsers over markdown text scans.
56
-
57
- **Applies in:** runner.cjs status checks, state.md consumers, anything reading state programmatically
58
-
59
- ## P-EXP-004 — 30-min DEFAULT_TIMEOUT_MS is too short for typical 3-plan phases; recommend 60+ min default
60
-
61
- **Evidence:** whoolog Phase 1 first run: timed out at 30:00 after Phase 1 research only (9 commits). Resumed with 90-min timeout and finished Phase 1 fully in 26 minutes. Same pattern would have killed whooflow new-project (~60 min) if that timeout had been the default.
62
-
63
- **Rule:** DEFAULT_TIMEOUT_MS in runner.cjs should be raised from 30 min to 60 min, OR the experiment new command should set a per-experiment timeout based on roadmap.phase_count * 8 min after the new-project run. Phase 1 of whoolog (3 plans) took 26 min; whooflow (5 plans per phase) was at 35 min when killed by 30-min cap on first run. The default cuts off real work mid-phase.
64
-
65
- **Applies in:** runner.cjs DEFAULT_TIMEOUT_MS, experiment run --timeout default
66
-
67
- ## P-EXP-005 — 4 concurrent claude -p experiment sessions run cleanly on a single machine; no TTY contention or rate-limit issues
68
-
69
- **Evidence:** Ran whoolog Phase 2 + whoocache Phase 1 + whooflow new-project + whooschema new-project + whoodb new-project all in parallel for ~60 minutes. All 4 concurrent sessions made independent progress, no failures, no missed commits attributable to concurrency. Wall-clock time for full 5-experiment run: ~3 hours (vs ~9 hours sequential).
70
-
71
- **Rule:** The experiment runner can safely fan out to N=4 concurrent autonomous experiments on a single workstation. The runner's stdio ['inherit', 'pipe', 'pipe'] design holds up because claude -p does not actually CONSUME stdin (only probes for TTY). API rate limits at this concurrency are not hit on Anthropic Claude Opus 4.7. Beyond N=4, untested.
72
-
73
- **Applies in:** experiment runner, automated multi-experiment campaigns, CI
74
-
75
- ## P-NPRS-005 — Single experiment can ship a 24-plan / 5-phase / 346-test / 1.46MB binary milestone in ~6h cumulative agent runtime when the planner emits decision-trace + the executor honors per-plan file ownership
76
-
77
- **Evidence:** notepadrs experiment 2026-05-02→03: Phase 1 (4 plans, 18 tests) ran clean; Phase 2 (4 plans, 109 tests cumulative) ran clean; Phase 3 (5 plans, multi-tab + find/replace + worker thread + epoch cancellation) timed out at 90 min on first attempt at 77% — resumed cleanly with /pan:exec-phase 3 --auto and finished in 45 min; Phase 4 (5 plans split mid-run from 4 to handle wave-2 collision) took 50 min; Phase 5 (5 plans + dogfood + ship gate) took 55 min plan + 7 min finish wrap. Total cumulative: ~6h agent time including 1 timeout. Final binary: 1.46 MB (6.86× under the 10MB ship gate); 346 tests (11.5× the 30-test floor). Plan-checker iteration revisions caught wave-2 file collisions BEFORE execution; reasoning-trace handoff via Plan Decisions / Implementation Decisions sections kept context coherent across plan-checker → executor → verifier.
78
-
79
- **Rule:** Auto-mode multi-phase experiments DO complete v1-shippable software in roughly 1 hour per phase IF: (a) phase plan-phase produces explicit per-plan files_modified ownership AND a decisions buckets section; (b) plan-checker is allowed to iterate (split plans, revise files_modified) BEFORE execution starts; (c) timeouts are 90 min per command, not 60 min; (d) when a phase times out at >70% complete, resume with /pan:exec-phase N --auto rather than restarting plan-phase; (e) final phase wrap (write missing summary.md + verification.md, advance state) sometimes needs a separate short prompt because the auto-runner exits when state.md says 'verifying'. The 'incomplete' status with exit_code 0 means the agent left work mid-state, not that anything failed.
80
-
81
- **Applies in:** PAN experiment-runner orchestration; the experiment.cjs runner; auto-mode workflow guidance; planner/executor handoff design
@@ -1,105 +0,0 @@
1
- ---
2
- topic: external-research
3
- last_updated: 2026-07-09T14:04:40.520Z
4
- patterns:
5
- - id: P-RES-001
6
- summary: ACE (Zhang et al, arXiv:2510.04618, Oct 2025): summary-based context chains have brevity bias and context collapse. Treat memory as append-and-curate playbook, not paraphrase chain
7
- promoted_at: 2026-05-02T18:15:25.976Z
8
- source_experiments: [external]
9
- - id: P-RES-002
10
- summary: Chroma context-rot (July 2025): a single semantically-similar-but-irrelevant distractor degrades performance even at modest context sizes. Distractor density matters more than token count
11
- promoted_at: 2026-05-02T18:15:32.003Z
12
- source_experiments: [external]
13
- - id: P-RES-003
14
- summary: Cognition (June 2025) anti-multi-agent argument: parallel sub-agents fail because every action carries unstated decisions; downstream agents reconcile contradictions blindly when they only see artifacts
15
- promoted_at: 2026-05-02T18:15:39.391Z
16
- source_experiments: [external]
17
- - id: P-RES-004
18
- summary: Specification Gap paper (arXiv:2603.24284, early 2026): two-agent integration accuracy collapses 58 to 25 percent as spec detail is removed; coordination is quadratically sensitive to spec completeness
19
- promoted_at: 2026-05-02T18:15:50.213Z
20
- source_experiments: [external]
21
- - id: P-RES-005
22
- summary: GitHub PR audit (arXiv:2601.15195, Jan 2026): agent PRs fail mostly from spec/intent mismatch, design fit, and repo-norm violation — not buggy code. Code that compiles and tests still gets rejected
23
- promoted_at: 2026-05-02T18:15:58.959Z
24
- source_experiments: [external]
25
- - id: P-RES-006
26
- summary: S2R / RLVR (ACL 2025): naive self-critique is largely ineffective; verification gains come from FRESH-CONTEXT RESTART and FILE-MEDIATED STRUCTURE forcing re-reading, not from the judging itself. Verbose self-review can hurt via overthinking
27
- promoted_at: 2026-05-02T18:16:09.893Z
28
- source_experiments: [external]
29
- - id: P-RES-007
30
- summary: Sakana DGM (2025): in self-improvement loops, AGENT-DESIGN changes generalize across models and languages; PROMPT-FRAGMENT tweaks do not. Promote structural changes, not phrasing tweaks
31
- promoted_at: 2026-05-02T18:16:19.459Z
32
- source_experiments: [external]
33
- - id: P-RES-008
34
- summary: Enterprise "train on our data" asks are retrieval problems, not fine-tuning problems: schema/context LINKING is the bottleneck (BEAVER: SOTA ~10.8% on real enterprise schemas vs 80%+ on public benchmarks, ~68% of failures are schema-linking), and plain BM25 RAG beats fine-tuning alone (Tencent 160k-file study: 53.8% vs 44.2% EM; FT alone caused catastrophic forgetting; FT+RAG best at 57.4%)
35
- promoted_at: 2026-07-09T14:04:40.520Z
36
- source_experiments: [spec-factory]
37
- ---
38
-
39
- # External Research (AI-derived)
40
-
41
- > Auto-maintained by `pan-tools learn promote`. Each pattern was extracted from one or more experiment runs (see source_experiments). Patterns are **advisory** — orchestrators should weight them against current context.
42
-
43
- ## P-RES-001 — ACE (Zhang et al, arXiv:2510.04618, Oct 2025): summary-based context chains have brevity bias and context collapse. Treat memory as append-and-curate playbook, not paraphrase chain
44
-
45
- **Evidence:** https://arxiv.org/abs/2510.04618 — ACE: Agentic Context Engineering. Empirical: iterative summarization monotonically loses detail on agent and finance benchmarks; structured playbook curation outperforms across runs.
46
-
47
- **Rule:** Reframe memory/<agent>.md and per-phase summary.md as a structured DELTA-LOG (curated by an explicit reviewer step) rather than a paraphrase of the prior phase. Each entry is an addition or amendment to a structured field, not a fresh re-summarization. Curation is its own step, distinct from generation. The pan-optimizer's accrual model should be re-examined under this lens — does it append signal, or summarize away signal?
48
-
49
- **Applies in:** pan-optimizer accrual loop, memory.cjs, summary.md template design, retro --write-memory
50
-
51
- ## P-RES-002 — Chroma context-rot (July 2025): a single semantically-similar-but-irrelevant distractor degrades performance even at modest context sizes. Distractor density matters more than token count
52
-
53
- **Evidence:** https://www.trychroma.com/research/context-rot — Hong & Huber, July 2025. Single-distractor experiments showed degradation begins well before 200K, and is non-linear with arrangement and similarity.
54
-
55
- **Rule:** Per-phase context budgets currently track tokens. Add a notion of distractor density: how much of context.md / research.md is plausibly-related-but-off-topic. Codebase mapper and phase researcher should optimize for relevance ratio, not coverage. The phase-budget command should warn when the relevance ratio is low even if token count is healthy.
56
-
57
- **Applies in:** phase-budget, codebase scan filtering, research agent guidance
58
-
59
- ## P-RES-003 — Cognition (June 2025) anti-multi-agent argument: parallel sub-agents fail because every action carries unstated decisions; downstream agents reconcile contradictions blindly when they only see artifacts
60
-
61
- **Evidence:** https://cognition.ai/blog/dont-build-multi-agents — Walden Yan, Cognition. Contrast https://www.anthropic.com/engineering/multi-agent-research-system which argues breadth-first reads parallelize fine but writes/decisions need a single coherent trace.
62
-
63
- **Rule:** PAN's serial pipeline (planner -> researcher -> executor -> verifier) is what Cognition endorses, but file-mediated handoff passes only OUTPUTS, not reasoning traces. Consider: should plan.md include an explicit decisions-and-rationale section that the executor reads, beyond just the task list? Should summary.md include a deviations log that the verifier reads? The signal is: when an agent is briefed for a downstream phase, the upstream agent's reasoning trace should be available, not just the artifacts.
64
-
65
- **Applies in:** plan.md template, summary.md template, executor briefing, conductor briefing
66
-
67
- ## P-RES-004 — Specification Gap paper (arXiv:2603.24284, early 2026): two-agent integration accuracy collapses 58 to 25 percent as spec detail is removed; coordination is quadratically sensitive to spec completeness
68
-
69
- **Evidence:** https://arxiv.org/abs/2603.24284v1 — The Specification Gap. Two-agent integration: 58 percent accuracy with full spec, 25 percent with stripped spec. Single-agent baseline: 89 to 56 percent. Coordination cost of incomplete specs is quadratic.
70
-
71
- **Rule:** pan-plan-checker currently verifies plan COHERENCE across 8 dimensions. Add a 9th: spec-sufficiency-for-handoff. Question to answer: does this plan contain enough detail that the executor cannot make a divergent decision in the implicit space the plan does not constrain. The check is not is-the-plan-good but is-the-plan-complete-enough-to-survive-the-context-boundary. Specifically: every task has explicit Files, explicit Action, explicit Verify, explicit Done; every architectural choice is locked vs flexible; every assumption is named.
72
-
73
- **Applies in:** agents/pan-plan-checker.md (existing 8 verification dimensions), plan.md template (forcing locked-vs-flexible markers)
74
-
75
- ## P-RES-005 — GitHub PR audit (arXiv:2601.15195, Jan 2026): agent PRs fail mostly from spec/intent mismatch, design fit, and repo-norm violation — not buggy code. Code that compiles and tests still gets rejected
76
-
77
- **Evidence:** https://arxiv.org/abs/2601.15195 — Where Do AI Coding Agents Fail. 33K-PR audit. Primary failure modes: spec/intent mismatch (32 percent), design fit (24 percent), repo-norm violation (19 percent). Buggy code is a minority cause of rejection.
78
-
79
- **Rule:** pan-verifier currently checks code-against-plan. The dominant external-world failure is fit-against-repo-norms (style, naming, prior-PR conventions, framework idioms). Verifier should treat codebase/CONVENTIONS.md and codebase/STRUCTURE.md (when they exist from /pan:map-codebase) as first-class verification inputs, not advisory context. project.md and requirements.md may need a Norms section the verifier explicitly tests against. The verification dimensions should add: does this code follow the conventions evident in adjacent files.
80
-
81
- **Applies in:** agents/pan-verifier.md, agents/pan-reviewer.md, codebase/CONVENTIONS.md consumption, project.md template
82
-
83
- ## P-RES-006 — S2R / RLVR (ACL 2025): naive self-critique is largely ineffective; verification gains come from FRESH-CONTEXT RESTART and FILE-MEDIATED STRUCTURE forcing re-reading, not from the judging itself. Verbose self-review can hurt via overthinking
84
-
85
- **Evidence:** https://aclanthology.org/2025.acl-long.1104.pdf — S2R. https://magazine.sebastianraschka.com/p/state-of-llms-2025 — Raschka summary. Untrained self-critique provides little gain on reasoning; verification helps when verifier has training or runs against verifiable rewards.
86
-
87
- **Rule:** PAN has multiple judgment-style verification roles: pan-plan-checker (judges plan coherence), pan-meta-reviewer (judges other reviewers), pan-hardener (judges security risk by inspection). The S2R finding suggests these roles' value is mostly the FRESH-CONTEXT structural reset, not the judgment per se. Implication: lean these agents harder on VERIFIABLE signals (test cmd, lint cmd, schema check, type check, dep cycle scan, regex anti-pattern detection) and reduce prose-only verdicts. Where a verifiable check exists, use it instead of prose review. Where one doesn't, ask whether the role earns its compute.
88
-
89
- **Applies in:** agents/pan-plan-checker.md, agents/pan-verifier.md, agents/pan-reviewer.md, agents/pan-meta-reviewer.md, agents/pan-hardener.md, references/verification-patterns.md
90
-
91
- ## P-RES-007 — Sakana DGM (2025): in self-improvement loops, AGENT-DESIGN changes generalize across models and languages; PROMPT-FRAGMENT tweaks do not. Promote structural changes, not phrasing tweaks
92
-
93
- **Evidence:** https://sakana.ai/dgm/ — Darwin Godel Machine. Population-based self-improvement showed structural changes transferred across models; specific prompt tweaks did not. The same generalization curve likely holds for human-mediated promote gates.
94
-
95
- **Rule:** When pan-tools learn promote runs (manual gate today, possibly auto-promote in v3.8+), the promote criterion should distinguish: 1) STRUCTURAL pattern (a new agent role, a new file in .planning/, a new verification gate, a new tool-use idiom, an architectural decision) vs 2) PROMPT-FRAGMENT (specific phrasing, a worded instruction, a stylistic preference). Universal scope should be reserved for structural patterns. Prompt fragments belong in internal scope at most — they don't generalize across models or languages, so shipping them to all 5 runtimes is a bet that won't pay.
96
-
97
- **Applies in:** pan-tools learn promote --scope universal gate, optimize.cjs promotePattern criteria, future auto-promote rules
98
-
99
- ## P-RES-008 — Enterprise "train on our data" asks are retrieval problems, not fine-tuning problems: schema/context LINKING is the bottleneck (BEAVER: SOTA ~10.8% on real enterprise schemas vs 80%+ on public benchmarks, ~68% of failures are schema-linking), and plain BM25 RAG beats fine-tuning alone (Tencent 160k-file study: 53.8% vs 44.2% EM; FT alone caused catastrophic forgetting; FT+RAG best at 57.4%)
100
-
101
- **Evidence:** The the tech-spec factory tech-spec factory research roadmap (adversarially verified, with citations) synthesized: on BEAVER (real enterprise schemas) SOTA agents collapse to ~10.8%; roughly 68% of failures are schema-linking, not generation. The Tencent 160k-file study showed plain BM25 retrieval beating fine-tuning alone (53.8 vs 44.2 EM) with fine-tuning alone causing catastrophic forgetting. Design consequence adopted there: never dump a full schema into context — decompose into semantic units, hybrid-retrieve a small candidate set (~50), then resolve to physical names.
102
-
103
- **Rule:** When a project asks to "train the model on our data/schema": default to retrieval-first (decompose corpus into semantic units, hybrid lexical+semantic retrieval of a small candidate set, then resolve). Treat fine-tuning as an additive step at most, never the substitute. Size context by retrieved candidates, not by dumping the schema. Expect public-benchmark performance claims to overstate enterprise reality by up to an order of magnitude.
104
-
105
- **Applies in:** Research/planning phases for RAG or fine-tune decisions, enterprise schema tooling, context-budget design.
@@ -1,33 +0,0 @@
1
- ---
2
- topic: loop-design
3
- last_updated: 2026-05-03T05:00:00.000Z
4
- patterns:
5
- - id: P-1303
6
- summary: Exercising PAN's actual surfaces (autonomous run) produces orders-of-magnitude more PAN-relevant signal than building parallel tools — even when shorter
7
- promoted_at: 2026-04-27T11:21:36.814Z
8
- source_experiments: [panloop]
9
- - id: P-1403
10
- summary: Track wall-clock-per-commit and tokens-per-commit as autonomous-overhead metrics
11
- promoted_at: 2026-04-27T12:01:14.269Z
12
- source_experiments: [panloop]
13
- ---
14
-
15
- # Loop Design (PAN-internal)
16
-
17
- > Auto-maintained by `pan-tools learn promote`. Each pattern was extracted from one or more experiment runs (see source_experiments). Internal-scope patterns are PAN-specific and stay in the source repo (stripped at install). Patterns are **advisory** — orchestrators should weight them against current context.
18
-
19
- ## P-1303 — Exercising PAN's actual surfaces (autonomous run) produces orders-of-magnitude more PAN-relevant signal than building parallel tools — even when shorter
20
-
21
- **Evidence:** Single 25-second autonomous run (panloop) surfaced 2 critical real PAN bugs (P-1301 AskUserQuestion gap, P-1302 runner permissions gap). Compare: 8 prior hand-built mock experiments (whoocsv, whoojson, whooemoji, whoocron, whoohash, whoouuid, whoodag, whoofreq) totaling many hours produced 0 PAN-internal findings — only generic engineering patterns. The autonomous loop validates its own design hypothesis: hitting real surfaces > simulating them.
22
-
23
- **Rule:** When designing self-improvement loops or eval frameworks, the experiments must EXERCISE the system being optimized, not BUILD PARALLEL artifacts. A 25-second real run beats hours of mock work for surfacing system-internal bugs. For PAN specifically: future experiments should run /pan:new-project, /pan:plan-phase, /pan:exec-phase, /pan:focus-* against fresh test projects via the runner, not build standalone CLIs alongside. The mock builds have value for promoting GENERIC patterns; only autonomous runs surface PAN-INTERNAL ones.
24
-
25
- **Applies in:** self-improvement loop design (ADR-0026 update); v3.8+ planning; promote-step heuristics
26
-
27
- ## P-1403 — Track wall-clock-per-commit and tokens-per-commit as autonomous-overhead metrics
28
-
29
- **Evidence:** panloop: 25 commits in 29 min = 1.16 min/commit. Cost $12.84 / 25 commits = $0.51/commit. Useful baseline for future optimization.
30
-
31
- **Rule:** PAN's /pan:learn report should compute and surface (a) commits_per_minute, (b) cost_usd_per_commit, (c) cost_usd_per_phase, (d) cost_usd_per_test, by reading harvest.json + git log + harvested cost data. Trend over experiments shows whether autonomous overhead is improving as patterns saturate.
32
-
33
- **Applies in:** v3.8+ pan-optimizer agent prompt; harvest.json schema extension