@wazir-dev/cli 1.2.0 → 1.4.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 (161) hide show
  1. package/CHANGELOG.md +54 -44
  2. package/README.md +13 -13
  3. package/assets/demo.cast +47 -0
  4. package/assets/demo.gif +0 -0
  5. package/docs/anti-patterns/AP-23-skipping-enabled-workflows.md +28 -0
  6. package/docs/anti-patterns/AP-24-clarifier-deciding-scope.md +34 -0
  7. package/docs/concepts/architecture.md +1 -1
  8. package/docs/concepts/why-wazir.md +1 -1
  9. package/docs/readmes/INDEX.md +1 -1
  10. package/docs/readmes/features/expertise/README.md +1 -1
  11. package/docs/readmes/features/hooks/pre-compact-summary.md +1 -1
  12. package/docs/reference/hooks.md +1 -0
  13. package/docs/reference/launch-checklist.md +3 -3
  14. package/docs/reference/review-loop-pattern.md +3 -2
  15. package/docs/reference/skill-tiers.md +2 -2
  16. package/docs/research/2026-03-20-agents/a18fb002157904af5.txt +187 -0
  17. package/docs/research/2026-03-20-agents/a1d0ac79ac2f11e6f.txt +2 -0
  18. package/docs/research/2026-03-20-agents/a324079de037abd7c.txt +198 -0
  19. package/docs/research/2026-03-20-agents/a357586bccfafb0e5.txt +256 -0
  20. package/docs/research/2026-03-20-agents/a4365394e4d753105.txt +137 -0
  21. package/docs/research/2026-03-20-agents/a492af28bc52d3613.txt +136 -0
  22. package/docs/research/2026-03-20-agents/a4984db0b6a8eee07.txt +124 -0
  23. package/docs/research/2026-03-20-agents/a5b30e59d34bbb062.txt +214 -0
  24. package/docs/research/2026-03-20-agents/a5cf7829dab911586.txt +165 -0
  25. package/docs/research/2026-03-20-agents/a607157c30dd97c9e.txt +96 -0
  26. package/docs/research/2026-03-20-agents/a60b68b1e19d1e16b.txt +115 -0
  27. package/docs/research/2026-03-20-agents/a722af01c5594aba0.txt +166 -0
  28. package/docs/research/2026-03-20-agents/a787bdc516faa5829.txt +181 -0
  29. package/docs/research/2026-03-20-agents/a7c46d1bba1056ed2.txt +132 -0
  30. package/docs/research/2026-03-20-agents/a7e5abbab2b281a0d.txt +100 -0
  31. package/docs/research/2026-03-20-agents/a8dbadc66cd0d7d5a.txt +95 -0
  32. package/docs/research/2026-03-20-agents/a904d9f45d6b86a6d.txt +75 -0
  33. package/docs/research/2026-03-20-agents/a927659a942ee7f60.txt +102 -0
  34. package/docs/research/2026-03-20-agents/a962cb569191f7583.txt +125 -0
  35. package/docs/research/2026-03-20-agents/aab6decea538aac41.txt +148 -0
  36. package/docs/research/2026-03-20-agents/abd58b853dd938a1b.txt +295 -0
  37. package/docs/research/2026-03-20-agents/ac009da573eff7f65.txt +100 -0
  38. package/docs/research/2026-03-20-agents/ac1bc783364405e5f.txt +190 -0
  39. package/docs/research/2026-03-20-agents/aca5e2b57fde152a0.txt +132 -0
  40. package/docs/research/2026-03-20-agents/ad849b8c0a7e95b8b.txt +176 -0
  41. package/docs/research/2026-03-20-agents/adc2b12a4da32c962.txt +258 -0
  42. package/docs/research/2026-03-20-agents/af97caaaa9a80e4cb.txt +146 -0
  43. package/docs/research/2026-03-20-agents/afc5faceee368b3ca.txt +111 -0
  44. package/docs/research/2026-03-20-agents/afdb282d866e3c1e4.txt +164 -0
  45. package/docs/research/2026-03-20-agents/afe9d1f61c02b1e8d.txt +299 -0
  46. package/docs/research/2026-03-20-agents/b4hmkwril.txt +1856 -0
  47. package/docs/research/2026-03-20-agents/b80ptk89g.txt +1856 -0
  48. package/docs/research/2026-03-20-agents/bf54s1jss.txt +1150 -0
  49. package/docs/research/2026-03-20-agents/bhd6kq2kx.txt +1856 -0
  50. package/docs/research/2026-03-20-agents/bmb2fodyr.txt +988 -0
  51. package/docs/research/2026-03-20-agents/bmmsrij8i.txt +826 -0
  52. package/docs/research/2026-03-20-agents/bn4t2ywpu.txt +2175 -0
  53. package/docs/research/2026-03-20-agents/bu22t9f1z.txt +0 -0
  54. package/docs/research/2026-03-20-agents/bwvl98v2p.txt +738 -0
  55. package/docs/research/2026-03-20-agents/psych-a3697a7fd06eb64fd.txt +135 -0
  56. package/docs/research/2026-03-20-agents/psych-a37776fabc870feae.txt +123 -0
  57. package/docs/research/2026-03-20-agents/psych-a5b1fe05c0589efaf.txt +2 -0
  58. package/docs/research/2026-03-20-agents/psych-a95c15b1f29424435.txt +76 -0
  59. package/docs/research/2026-03-20-agents/psych-a9c26f4d9172dde7c.txt +2 -0
  60. package/docs/research/2026-03-20-agents/psych-aa19c69f0ca2c5ad3.txt +2 -0
  61. package/docs/research/2026-03-20-agents/psych-aa4e4cb70e1be5ecb.txt +95 -0
  62. package/docs/research/2026-03-20-agents/psych-ab5b302f26a554663.txt +102 -0
  63. package/docs/research/2026-03-20-deep-research-complete.md +101 -0
  64. package/docs/research/2026-03-20-deep-research-status.md +38 -0
  65. package/docs/research/2026-03-20-enforcement-research.md +107 -0
  66. package/expertise/antipatterns/process/ai-coding-antipatterns.md +117 -0
  67. package/expertise/composition-map.yaml +27 -8
  68. package/expertise/digests/reviewer/ai-coding-digest.md +83 -0
  69. package/expertise/digests/reviewer/architectural-thinking-digest.md +63 -0
  70. package/expertise/digests/reviewer/architecture-antipatterns-digest.md +49 -0
  71. package/expertise/digests/reviewer/code-smells-digest.md +53 -0
  72. package/expertise/digests/reviewer/coupling-cohesion-digest.md +54 -0
  73. package/expertise/digests/reviewer/ddd-digest.md +60 -0
  74. package/expertise/digests/reviewer/dependency-risk-digest.md +40 -0
  75. package/expertise/digests/reviewer/error-handling-digest.md +55 -0
  76. package/expertise/digests/reviewer/review-methodology-digest.md +49 -0
  77. package/exports/hosts/claude/.claude/commands/learn.md +61 -8
  78. package/exports/hosts/claude/.claude/commands/plan-review.md +3 -1
  79. package/exports/hosts/claude/.claude/commands/verify.md +30 -1
  80. package/exports/hosts/claude/.claude/settings.json +7 -6
  81. package/exports/hosts/claude/export.manifest.json +8 -5
  82. package/exports/hosts/claude/host-package.json +3 -0
  83. package/exports/hosts/codex/export.manifest.json +8 -5
  84. package/exports/hosts/codex/host-package.json +3 -0
  85. package/exports/hosts/cursor/.cursor/hooks.json +6 -6
  86. package/exports/hosts/cursor/export.manifest.json +8 -5
  87. package/exports/hosts/cursor/host-package.json +3 -0
  88. package/exports/hosts/gemini/export.manifest.json +8 -5
  89. package/exports/hosts/gemini/host-package.json +3 -0
  90. package/hooks/definitions/pretooluse_dispatcher.yaml +26 -0
  91. package/hooks/definitions/pretooluse_pipeline_guard.yaml +22 -0
  92. package/hooks/definitions/stop_pipeline_gate.yaml +22 -0
  93. package/hooks/hooks.json +7 -6
  94. package/hooks/pretooluse-dispatcher +84 -0
  95. package/hooks/pretooluse-pipeline-guard +9 -0
  96. package/hooks/stop-pipeline-gate +9 -0
  97. package/llms-full.txt +48 -18
  98. package/package.json +2 -3
  99. package/schemas/decision.schema.json +15 -0
  100. package/schemas/hook.schema.json +4 -1
  101. package/schemas/phase-report.schema.json +9 -0
  102. package/skills/TEMPLATE-3-ZONE.md +160 -0
  103. package/skills/brainstorming/SKILL.md +137 -21
  104. package/skills/clarifier/SKILL.md +364 -53
  105. package/skills/claude-cli/SKILL.md +91 -12
  106. package/skills/codex-cli/SKILL.md +91 -12
  107. package/skills/debugging/SKILL.md +133 -38
  108. package/skills/design/SKILL.md +173 -37
  109. package/skills/dispatching-parallel-agents/SKILL.md +129 -31
  110. package/skills/executing-plans/SKILL.md +113 -25
  111. package/skills/executor/SKILL.md +252 -21
  112. package/skills/finishing-a-development-branch/SKILL.md +107 -18
  113. package/skills/gemini-cli/SKILL.md +91 -12
  114. package/skills/humanize/SKILL.md +92 -13
  115. package/skills/init-pipeline/SKILL.md +90 -18
  116. package/skills/prepare-next/SKILL.md +93 -24
  117. package/skills/receiving-code-review/SKILL.md +90 -16
  118. package/skills/requesting-code-review/SKILL.md +100 -24
  119. package/skills/requesting-code-review/code-reviewer.md +29 -17
  120. package/skills/reviewer/SKILL.md +270 -57
  121. package/skills/run-audit/SKILL.md +92 -15
  122. package/skills/scan-project/SKILL.md +93 -14
  123. package/skills/self-audit/SKILL.md +133 -39
  124. package/skills/skill-research/SKILL.md +275 -0
  125. package/skills/subagent-driven-development/SKILL.md +129 -30
  126. package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +30 -2
  127. package/skills/subagent-driven-development/implementer-prompt.md +40 -27
  128. package/skills/subagent-driven-development/spec-reviewer-prompt.md +25 -12
  129. package/skills/tdd/SKILL.md +125 -20
  130. package/skills/using-git-worktrees/SKILL.md +118 -28
  131. package/skills/using-skills/SKILL.md +116 -29
  132. package/skills/verification/SKILL.md +160 -17
  133. package/skills/wazir/SKILL.md +750 -120
  134. package/skills/writing-plans/SKILL.md +134 -28
  135. package/skills/writing-skills/SKILL.md +91 -13
  136. package/skills/writing-skills/anthropic-best-practices.md +104 -64
  137. package/skills/writing-skills/persuasion-principles.md +100 -34
  138. package/tooling/src/capture/command.js +46 -2
  139. package/tooling/src/capture/decision.js +40 -0
  140. package/tooling/src/capture/store.js +33 -0
  141. package/tooling/src/capture/user-input.js +66 -0
  142. package/tooling/src/checks/security-sensitivity.js +69 -0
  143. package/tooling/src/cli.js +28 -26
  144. package/tooling/src/config/depth-table.js +60 -0
  145. package/tooling/src/export/compiler.js +7 -8
  146. package/tooling/src/guards/guardrail-functions.js +131 -0
  147. package/tooling/src/guards/phase-prerequisite-guard.js +97 -3
  148. package/tooling/src/hooks/pretooluse-dispatcher.js +300 -0
  149. package/tooling/src/hooks/pretooluse-pipeline-guard.js +141 -0
  150. package/tooling/src/hooks/stop-pipeline-gate.js +92 -0
  151. package/tooling/src/init/auto-detect.js +0 -2
  152. package/tooling/src/init/command.js +3 -95
  153. package/tooling/src/learn/pipeline.js +177 -0
  154. package/tooling/src/state/db.js +251 -2
  155. package/tooling/src/state/pipeline-state.js +262 -0
  156. package/tooling/src/status/command.js +6 -1
  157. package/tooling/src/verify/proof-collector.js +299 -0
  158. package/wazir.manifest.yaml +3 -0
  159. package/workflows/learn.md +61 -8
  160. package/workflows/plan-review.md +3 -1
  161. package/workflows/verify.md +30 -1
@@ -0,0 +1,299 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { execFileSync } from 'node:child_process';
4
+
5
+ const WEB_FRAMEWORKS = ['next', 'vite', 'react-scripts', '@angular/cli', 'nuxt', 'astro', 'gatsby'];
6
+ const API_FRAMEWORKS = ['express', 'fastify', 'hono', 'koa', '@nestjs/core', '@hapi/hapi'];
7
+
8
+ /**
9
+ * Detect whether a project produces runnable output and what type.
10
+ *
11
+ * @param {string} projectRoot
12
+ * @returns {'web' | 'api' | 'cli' | 'library'}
13
+ */
14
+ export function detectRunnableType(projectRoot) {
15
+ const pkgPath = path.join(projectRoot, 'package.json');
16
+ if (!fs.existsSync(pkgPath)) return 'library';
17
+
18
+ let pkg;
19
+ try {
20
+ pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
21
+ } catch {
22
+ return 'library';
23
+ }
24
+
25
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
26
+
27
+ if (WEB_FRAMEWORKS.some((fw) => fw in allDeps)) return 'web';
28
+ if (API_FRAMEWORKS.some((fw) => fw in allDeps)) return 'api';
29
+ if (pkg.bin) return 'cli';
30
+
31
+ return 'library';
32
+ }
33
+
34
+ /**
35
+ * Run a command safely using execFileSync (no shell injection).
36
+ *
37
+ * @param {string} cmd - The executable
38
+ * @param {string[]} args - Arguments array
39
+ * @param {string} cwd
40
+ * @returns {{ exit_code: number, stdout: string, stderr: string }}
41
+ */
42
+ function runCommand(cmd, args, cwd) {
43
+ try {
44
+ const stdout = execFileSync(cmd, args, {
45
+ cwd,
46
+ encoding: 'utf8',
47
+ timeout: 60000,
48
+ stdio: ['pipe', 'pipe', 'pipe'],
49
+ });
50
+ return { exit_code: 0, stdout: stdout.trim(), stderr: '' };
51
+ } catch (err) {
52
+ return {
53
+ exit_code: err.status ?? 1,
54
+ stdout: (err.stdout ?? '').trim(),
55
+ stderr: (err.stderr ?? '').trim(),
56
+ };
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Summarize command output to a short string.
62
+ *
63
+ * @param {string} stdout
64
+ * @param {number} maxLen
65
+ * @returns {string}
66
+ */
67
+ function summarize(stdout, maxLen = 200) {
68
+ if (!stdout) return '';
69
+ const lines = stdout.split('\n');
70
+ if (lines.length <= 5) return stdout.slice(0, maxLen);
71
+ return [...lines.slice(0, 3), `... (${lines.length} lines total)`, ...lines.slice(-2)]
72
+ .join('\n')
73
+ .slice(0, maxLen);
74
+ }
75
+
76
+ /**
77
+ * Check if a package.json has a specific script.
78
+ *
79
+ * @param {string} projectRoot
80
+ * @param {string} scriptName
81
+ * @returns {boolean}
82
+ */
83
+ function hasScript(projectRoot, scriptName) {
84
+ try {
85
+ const pkg = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
86
+ return !!(pkg.scripts && pkg.scripts[scriptName]);
87
+ } catch {
88
+ return false;
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Check if a config file exists for a tool.
94
+ *
95
+ * @param {string} projectRoot
96
+ * @param {string[]} candidates
97
+ * @returns {boolean}
98
+ */
99
+ function hasConfigFile(projectRoot, candidates) {
100
+ return candidates.some((f) => fs.existsSync(path.join(projectRoot, f)));
101
+ }
102
+
103
+ /**
104
+ * Collect library-type proof: tests, lint, format, type-check.
105
+ *
106
+ * @param {string} projectRoot
107
+ * @returns {{ tool: string, command: string, exit_code: number, stdout_summary: string, passed: boolean }[]}
108
+ */
109
+ function collectLibraryEvidence(projectRoot) {
110
+ const evidence = [];
111
+
112
+ // npm test
113
+ if (hasScript(projectRoot, 'test')) {
114
+ const result = runCommand('npm', ['test'], projectRoot);
115
+ evidence.push({
116
+ tool: 'npm test',
117
+ command: 'npm test',
118
+ exit_code: result.exit_code,
119
+ stdout_summary: summarize(result.stdout),
120
+ passed: result.exit_code === 0,
121
+ });
122
+ }
123
+
124
+ // TypeScript type check
125
+ if (
126
+ hasConfigFile(projectRoot, ['tsconfig.json']) ||
127
+ hasScript(projectRoot, 'typecheck')
128
+ ) {
129
+ const cmd = hasScript(projectRoot, 'typecheck')
130
+ ? ['npm', ['run', 'typecheck']]
131
+ : ['npx', ['tsc', '--noEmit']];
132
+ const result = runCommand(cmd[0], cmd[1], projectRoot);
133
+ evidence.push({
134
+ tool: 'tsc',
135
+ command: cmd[0] + ' ' + cmd[1].join(' '),
136
+ exit_code: result.exit_code,
137
+ stdout_summary: summarize(result.exit_code === 0 ? 'No type errors' : result.stdout || result.stderr),
138
+ passed: result.exit_code === 0,
139
+ });
140
+ }
141
+
142
+ // ESLint
143
+ if (
144
+ hasConfigFile(projectRoot, ['.eslintrc', '.eslintrc.js', '.eslintrc.json', '.eslintrc.yml', 'eslint.config.js', 'eslint.config.mjs']) ||
145
+ hasScript(projectRoot, 'lint')
146
+ ) {
147
+ const cmd = hasScript(projectRoot, 'lint')
148
+ ? ['npm', ['run', 'lint']]
149
+ : ['npx', ['eslint', '.']];
150
+ const result = runCommand(cmd[0], cmd[1], projectRoot);
151
+ evidence.push({
152
+ tool: 'eslint',
153
+ command: cmd[0] + ' ' + cmd[1].join(' '),
154
+ exit_code: result.exit_code,
155
+ stdout_summary: summarize(result.exit_code === 0 ? 'No lint errors' : result.stdout || result.stderr),
156
+ passed: result.exit_code === 0,
157
+ });
158
+ }
159
+
160
+ // Prettier
161
+ if (
162
+ hasConfigFile(projectRoot, ['.prettierrc', '.prettierrc.js', '.prettierrc.json', '.prettierrc.yml', 'prettier.config.js', 'prettier.config.mjs']) ||
163
+ hasScript(projectRoot, 'format:check')
164
+ ) {
165
+ const cmd = hasScript(projectRoot, 'format:check')
166
+ ? ['npm', ['run', 'format:check']]
167
+ : ['npx', ['prettier', '--check', '.']];
168
+ const result = runCommand(cmd[0], cmd[1], projectRoot);
169
+ evidence.push({
170
+ tool: 'prettier',
171
+ command: cmd[0] + ' ' + cmd[1].join(' '),
172
+ exit_code: result.exit_code,
173
+ stdout_summary: summarize(result.exit_code === 0 ? 'All files formatted' : result.stdout || result.stderr),
174
+ passed: result.exit_code === 0,
175
+ });
176
+ }
177
+
178
+ return evidence;
179
+ }
180
+
181
+ /**
182
+ * Collect web-type proof: build + library checks.
183
+ *
184
+ * @param {string} projectRoot
185
+ * @returns {{ tool: string, command: string, exit_code: number, stdout_summary: string, passed: boolean }[]}
186
+ */
187
+ function collectWebEvidence(projectRoot) {
188
+ const evidence = [];
189
+
190
+ // Build
191
+ if (hasScript(projectRoot, 'build')) {
192
+ const result = runCommand('npm', ['run', 'build'], projectRoot);
193
+ evidence.push({
194
+ tool: 'build',
195
+ command: 'npm run build',
196
+ exit_code: result.exit_code,
197
+ stdout_summary: summarize(result.stdout),
198
+ passed: result.exit_code === 0,
199
+ });
200
+ }
201
+
202
+ // Also run library checks (tests, lint, etc.)
203
+ evidence.push(...collectLibraryEvidence(projectRoot));
204
+
205
+ return evidence;
206
+ }
207
+
208
+ /**
209
+ * Collect API-type proof: library checks (server start/stop is complex, defer to manual).
210
+ *
211
+ * @param {string} projectRoot
212
+ * @returns {{ tool: string, command: string, exit_code: number, stdout_summary: string, passed: boolean }[]}
213
+ */
214
+ function collectApiEvidence(projectRoot) {
215
+ return collectLibraryEvidence(projectRoot);
216
+ }
217
+
218
+ /**
219
+ * Collect CLI-type proof: --help output + library checks.
220
+ *
221
+ * @param {string} projectRoot
222
+ * @returns {{ tool: string, command: string, exit_code: number, stdout_summary: string, passed: boolean }[]}
223
+ */
224
+ function collectCliEvidence(projectRoot) {
225
+ const evidence = [];
226
+
227
+ try {
228
+ const pkg = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
229
+ const binEntry = typeof pkg.bin === 'string' ? pkg.bin : Object.values(pkg.bin || {})[0];
230
+ if (binEntry) {
231
+ const binPath = path.join(projectRoot, binEntry);
232
+ if (fs.existsSync(binPath)) {
233
+ const result = runCommand('node', [binPath, '--help'], projectRoot);
234
+ evidence.push({
235
+ tool: 'cli --help',
236
+ command: `node ${binEntry} --help`,
237
+ exit_code: result.exit_code,
238
+ stdout_summary: summarize(result.stdout),
239
+ passed: result.exit_code === 0,
240
+ });
241
+ }
242
+ }
243
+ } catch { /* ignore */ }
244
+
245
+ evidence.push(...collectLibraryEvidence(projectRoot));
246
+
247
+ return evidence;
248
+ }
249
+
250
+ /**
251
+ * Collect proof of implementation for a task.
252
+ *
253
+ * @param {{ id: string, title: string }} taskSpec
254
+ * @param {{ projectRoot: string, runId?: string, stateRoot?: string }} runConfig
255
+ * @returns {Promise<{ task_id: string, type: string, timestamp: string, evidence: object[], status: string, all_passed: boolean }>}
256
+ */
257
+ export async function collectProof(taskSpec, runConfig) {
258
+ const { projectRoot } = runConfig;
259
+ const type = detectRunnableType(projectRoot);
260
+
261
+ let evidence;
262
+ switch (type) {
263
+ case 'web':
264
+ evidence = collectWebEvidence(projectRoot);
265
+ break;
266
+ case 'api':
267
+ evidence = collectApiEvidence(projectRoot);
268
+ break;
269
+ case 'cli':
270
+ evidence = collectCliEvidence(projectRoot);
271
+ break;
272
+ default:
273
+ evidence = collectLibraryEvidence(projectRoot);
274
+ }
275
+
276
+ const allPassed = evidence.length === 0 || evidence.every((e) => e.passed);
277
+
278
+ const result = {
279
+ task_id: taskSpec.id,
280
+ type,
281
+ timestamp: new Date().toISOString(),
282
+ evidence,
283
+ status: allPassed ? 'pass' : 'fail',
284
+ all_passed: allPassed,
285
+ };
286
+
287
+ // Save to artifacts if runId provided
288
+ if (runConfig.runId && runConfig.stateRoot) {
289
+ const artifactDir = path.join(runConfig.stateRoot, 'runs', runConfig.runId, 'artifacts');
290
+ if (fs.existsSync(artifactDir)) {
291
+ fs.writeFileSync(
292
+ path.join(artifactDir, `proof-${taskSpec.id}.json`),
293
+ JSON.stringify(result, null, 2) + '\n',
294
+ );
295
+ }
296
+ }
297
+
298
+ return result;
299
+ }
@@ -97,6 +97,9 @@ required_hooks:
97
97
  - protected_path_write_guard
98
98
  - loop_cap_guard
99
99
  - context_mode_router
100
+ - stop_pipeline_gate
101
+ - pretooluse_pipeline_guard
102
+ - pretooluse_dispatcher
100
103
  protected_paths:
101
104
  - input
102
105
  - roles
@@ -2,37 +2,90 @@
2
2
 
3
3
  ## Purpose
4
4
 
5
- Extract durable scoped learnings and experiments from the completed run.
5
+ Extract durable scoped learnings from the completed run using the 4-stage promotion pipeline.
6
6
 
7
7
  ## Phase entry
8
8
 
9
9
  On entering this phase, run:
10
- `wazir capture event --run <run-id> --event phase_enter --phase <phase-name> --status in_progress`
10
+ `wazir capture event --run <run-id> --event phase_enter --phase learn --status in_progress`
11
11
 
12
12
  ## Inputs
13
13
 
14
14
  - run artifacts
15
- - review findings
15
+ - review findings (all passes, all tiers)
16
16
  - verification proof
17
17
 
18
18
  ## Primary Role
19
19
 
20
20
  - `learner`
21
21
 
22
+ ## Pipeline Stages
23
+
24
+ The learning pipeline follows a 4-stage promotion model (Tally → Candidate → Promote → Active):
25
+
26
+ ### Stage 1: TALLY (Automatic)
27
+
28
+ Every finding from the run is:
29
+ 1. Canonicalized (file paths, line numbers, identifiers stripped)
30
+ 2. Hashed for dedup
31
+ 3. Clustered by semantic similarity in `finding_clusters` table
32
+ 4. Category-tagged (from the reviewer's finding category)
33
+
34
+ Also:
35
+ - Read `.wazir/runs/<id>/decisions.ndjson` for recurring patterns
36
+ - Append summary to `memory/findings/cumulative-findings.md`
37
+
38
+ Implementation: `tooling/src/learn/pipeline.js` → `tallyFinding()`
39
+
40
+ ### Stage 2: CANDIDATE (Automatic)
41
+
42
+ Clusters meeting the promotion threshold are flagged:
43
+ - **Occurrence threshold:** 3+ findings with the same canonical pattern
44
+ - **Run threshold:** Pattern must appear across 2+ distinct runs
45
+ - **Drift cap:** No promotion if active antipatterns count >= 30
46
+
47
+ Implementation: `tooling/src/learn/pipeline.js` → `identifyCandidates()` + `promoteToCandidates()`
48
+
49
+ ### Stage 3: PROMOTE (Human Gate)
50
+
51
+ Candidates are proposed for user review:
52
+ - Written to `memory/learnings/proposed/<run-id>-<NNN>.md`
53
+ - User reviews and accepts/rejects via `/wazir audit learnings`
54
+ - Accepted candidates move to `status: accepted` in `antipattern_candidates` table
55
+
56
+ ### Stage 4: ACTIVE (Automatic)
57
+
58
+ Accepted antipatterns are loaded into reviewer context for future runs:
59
+ - Injected as project-level learnings alongside expertise modules
60
+ - Hit-rate tracked: if an antipattern triggers in <5% of runs over 90 days, it's demoted
61
+ - Max 30 active project-level antipatterns (drift prevention)
62
+
63
+ ## Drift Prevention
64
+
65
+ - **Cap:** 30 active project antipatterns maximum
66
+ - **TTL:** 90-day expiry on unreviewed candidates
67
+ - **Demotion:** Antipatterns with <5% hit rate over 90 days are auto-demoted
68
+ - **Consolidation:** When count exceeds 25, similar antipatterns are merged
69
+
22
70
  ## Outputs
23
71
 
24
- - proposed learning artifacts
25
- - experiment summaries
72
+ - Tallied findings in `finding_clusters` table
73
+ - Promoted candidates in `antipattern_candidates` table
74
+ - Proposed learning artifacts in `memory/learnings/proposed/`
75
+ - Cumulative findings appended to `memory/findings/cumulative-findings.md`
26
76
 
27
77
  ## Approval Gate
28
78
 
29
- - accepted learnings require explicit review and scope tags
79
+ - Accepted learnings require explicit user review and scope tags
80
+ - Learnings are NEVER auto-applied to future runs without user acceptance
30
81
 
31
82
  ## Phase exit
32
83
 
33
84
  On completing this phase, run:
34
- `wazir capture event --run <run-id> --event phase_exit --phase <phase-name> --status completed`
85
+ `wazir capture event --run <run-id> --event phase_exit --phase learn --status completed`
35
86
 
36
87
  ## Failure Conditions
37
88
 
38
- - auto-applied learning drift
89
+ - auto-applied learning drift (bypassing human gate)
90
+ - candidate count exceeds cap without consolidation
91
+ - stale candidates not expired
@@ -39,7 +39,9 @@ On completing this phase, run:
39
39
 
40
40
  ## Loop Structure
41
41
 
42
- Follows the review loop pattern in `docs/reference/review-loop-pattern.md` with plan dimensions. The planner role resolves findings. Pass count determined by depth. No extension.
42
+ Follows the review loop pattern in `docs/reference/review-loop-pattern.md` with 8 plan dimensions (including Input Coverage). The planner role resolves findings. Pass count determined by depth. No extension.
43
+
44
+ **Input Coverage dimension:** The reviewer reads the original input/briefing, counts distinct items, and compares against tasks in the plan. If `tasks_in_plan < items_in_input`, this is a HIGH finding listing the missing items. This prevents silent scope reduction where 21 input items become 5 tasks.
43
45
 
44
46
  ## Failure Conditions
45
47
 
@@ -14,6 +14,16 @@ On entering this phase, run:
14
14
  - changed files
15
15
  - claimed outcomes
16
16
  - acceptance criteria
17
+ - project type (detected via `detectRunnableType(projectRoot)` → web | api | cli | library, from `tooling/src/verify/proof-collector.js`)
18
+
19
+ ## Process
20
+
21
+ 1. **Detect project type:** Run `detectRunnableType(projectRoot)` to determine verification strategy
22
+ 2. **Collect evidence:** Run `collectProof(taskSpec, runConfig)` with the detected type
23
+ 3. **For runnable output (web/api/cli):** Run the application and capture runtime evidence (build output, screenshots, curl responses, CLI output)
24
+ 4. **For non-runnable output (library/config/skills):** Run lint, format check, type check, and tests — all must pass
25
+ 5. **Save evidence:** Write to `.wazir/runs/<id>/artifacts/proof-<task>.json`
26
+ 6. **Validate:** Ensure every acceptance criterion has at least one evidence item mapped to it
17
27
 
18
28
  ## Primary Role
19
29
 
@@ -21,7 +31,11 @@ On entering this phase, run:
21
31
 
22
32
  ## Outputs
23
33
 
24
- - verification proof artifact
34
+ - verification proof artifact (produced by `collectProof` from `tooling/src/verify/proof-collector.js`)
35
+
36
+ ## Proof Collection
37
+
38
+ Use `detectRunnableType` to classify the project, then `collectProof` to gather evidence. The proof-collector runs type-appropriate commands (build, test, lint, type-check) using `execFileSync` and returns structured `{ type, evidence }`.
25
39
 
26
40
  ## Approval Gate
27
41
 
@@ -32,6 +46,19 @@ On entering this phase, run:
32
46
  On completing this phase, run:
33
47
  `wazir capture event --run <run-id> --event phase_exit --phase <phase-name> --status completed`
34
48
 
49
+ ## Proof of Implementation
50
+
51
+ The verifier detects whether the project output is runnable and collects appropriate evidence:
52
+
53
+ | Project Type | Detection | Evidence Collected |
54
+ |-------------|-----------|-------------------|
55
+ | `web` | next/vite/react-scripts in deps | Build output, Playwright screenshot (if available), curl response |
56
+ | `api` | express/fastify/hono in deps | curl endpoint responses with status codes |
57
+ | `cli` | `bin` field in package.json | `--help` output, test run with sample args |
58
+ | `library` | default (no runnable markers) | npm test, tsc, eslint, prettier — all must pass |
59
+
60
+ Evidence is saved to `.wazir/runs/<id>/artifacts/proof-<task>.json` using `collectProof()` from `tooling/src/verify/proof-collector.js`.
61
+
35
62
  ## Relationship to Review Loops
36
63
 
37
64
  Verification is invoked per-task during execution, not as a review loop. It produces deterministic proof, not adversarial findings.
@@ -39,3 +66,5 @@ Verification is invoked per-task during execution, not as a review loop. It prod
39
66
  ## Failure Conditions
40
67
 
41
68
  - stale or partial verification
69
+ - proof-collector reports `status: "fail"` for any evidence item
70
+ - runnable type detected but no evidence collected