agent-bober 0.15.0 → 0.17.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 (301) hide show
  1. package/.claude-plugin/marketplace.json +20 -0
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/CHANGELOG.md +30 -0
  4. package/README.md +127 -3
  5. package/agents/bober-architect.md +34 -0
  6. package/agents/bober-code-reviewer.md +2 -0
  7. package/agents/bober-curator.md +12 -0
  8. package/agents/bober-documenter.md +129 -0
  9. package/agents/bober-evaluator.md +46 -0
  10. package/agents/bober-generator.md +12 -0
  11. package/agents/bober-planner.md +8 -1
  12. package/dist/cli/commands/graph.js +3 -3
  13. package/dist/cli/commands/graph.js.map +1 -1
  14. package/dist/cli/commands/init.js +4 -0
  15. package/dist/cli/commands/init.js.map +1 -1
  16. package/dist/cli/commands/memory.d.ts +14 -0
  17. package/dist/cli/commands/memory.d.ts.map +1 -0
  18. package/dist/cli/commands/memory.js +132 -0
  19. package/dist/cli/commands/memory.js.map +1 -0
  20. package/dist/cli/index.js +6 -0
  21. package/dist/cli/index.js.map +1 -1
  22. package/dist/config/defaults.d.ts.map +1 -1
  23. package/dist/config/defaults.js +14 -3
  24. package/dist/config/defaults.js.map +1 -1
  25. package/dist/config/loader.d.ts.map +1 -1
  26. package/dist/config/loader.js +7 -0
  27. package/dist/config/loader.js.map +1 -1
  28. package/dist/config/role-providers.d.ts +29 -0
  29. package/dist/config/role-providers.d.ts.map +1 -0
  30. package/dist/config/role-providers.js +115 -0
  31. package/dist/config/role-providers.js.map +1 -0
  32. package/dist/config/schema.d.ts +383 -14
  33. package/dist/config/schema.d.ts.map +1 -1
  34. package/dist/config/schema.js +42 -0
  35. package/dist/config/schema.js.map +1 -1
  36. package/dist/contracts/eval-result.d.ts +112 -56
  37. package/dist/contracts/eval-result.d.ts.map +1 -1
  38. package/dist/contracts/eval-result.js +3 -0
  39. package/dist/contracts/eval-result.js.map +1 -1
  40. package/dist/contracts/sprint-contract.d.ts +30 -30
  41. package/dist/fleet/aggregator.d.ts +5 -0
  42. package/dist/fleet/aggregator.d.ts.map +1 -0
  43. package/dist/fleet/aggregator.js +39 -0
  44. package/dist/fleet/aggregator.js.map +1 -0
  45. package/dist/fleet/child-config.d.ts +12 -0
  46. package/dist/fleet/child-config.d.ts.map +1 -0
  47. package/dist/fleet/child-config.js +38 -0
  48. package/dist/fleet/child-config.js.map +1 -0
  49. package/dist/fleet/coordinator.d.ts +25 -0
  50. package/dist/fleet/coordinator.d.ts.map +1 -0
  51. package/dist/fleet/coordinator.js +40 -0
  52. package/dist/fleet/coordinator.js.map +1 -0
  53. package/dist/fleet/index.d.ts +40 -0
  54. package/dist/fleet/index.d.ts.map +1 -0
  55. package/dist/fleet/index.js +117 -0
  56. package/dist/fleet/index.js.map +1 -0
  57. package/dist/fleet/manifest.d.ts +51 -0
  58. package/dist/fleet/manifest.d.ts.map +1 -0
  59. package/dist/fleet/manifest.js +32 -0
  60. package/dist/fleet/manifest.js.map +1 -0
  61. package/dist/fleet/reporter.d.ts +32 -0
  62. package/dist/fleet/reporter.d.ts.map +1 -0
  63. package/dist/fleet/reporter.js +71 -0
  64. package/dist/fleet/reporter.js.map +1 -0
  65. package/dist/fleet/runner.d.ts +48 -0
  66. package/dist/fleet/runner.d.ts.map +1 -0
  67. package/dist/fleet/runner.js +104 -0
  68. package/dist/fleet/runner.js.map +1 -0
  69. package/dist/fleet/scaffolder.d.ts +12 -0
  70. package/dist/fleet/scaffolder.d.ts.map +1 -0
  71. package/dist/fleet/scaffolder.js +82 -0
  72. package/dist/fleet/scaffolder.js.map +1 -0
  73. package/dist/fleet/types.d.ts +21 -0
  74. package/dist/fleet/types.d.ts.map +1 -0
  75. package/dist/fleet/types.js +2 -0
  76. package/dist/fleet/types.js.map +1 -0
  77. package/dist/graph/cli.d.ts +6 -2
  78. package/dist/graph/cli.d.ts.map +1 -1
  79. package/dist/graph/cli.js +53 -12
  80. package/dist/graph/cli.js.map +1 -1
  81. package/dist/graph/pipeline-lifecycle.d.ts +9 -0
  82. package/dist/graph/pipeline-lifecycle.d.ts.map +1 -1
  83. package/dist/graph/pipeline-lifecycle.js +12 -0
  84. package/dist/graph/pipeline-lifecycle.js.map +1 -1
  85. package/dist/graph/preflight-injector.d.ts +14 -0
  86. package/dist/graph/preflight-injector.d.ts.map +1 -1
  87. package/dist/graph/preflight-injector.js +84 -4
  88. package/dist/graph/preflight-injector.js.map +1 -1
  89. package/dist/incident/types.d.ts +24 -24
  90. package/dist/mcp/tools/graph-schemas.d.ts +7 -7
  91. package/dist/mcp/tools/init.d.ts.map +1 -1
  92. package/dist/mcp/tools/init.js +2 -0
  93. package/dist/mcp/tools/init.js.map +1 -1
  94. package/dist/orchestrator/agent-loader.d.ts.map +1 -1
  95. package/dist/orchestrator/agent-loader.js +15 -1
  96. package/dist/orchestrator/agent-loader.js.map +1 -1
  97. package/dist/orchestrator/agentic-loop.d.ts +51 -0
  98. package/dist/orchestrator/agentic-loop.d.ts.map +1 -1
  99. package/dist/orchestrator/agentic-loop.js +123 -4
  100. package/dist/orchestrator/agentic-loop.js.map +1 -1
  101. package/dist/orchestrator/arch-lenses.d.ts +7 -0
  102. package/dist/orchestrator/arch-lenses.d.ts.map +1 -0
  103. package/dist/orchestrator/arch-lenses.js +22 -0
  104. package/dist/orchestrator/arch-lenses.js.map +1 -0
  105. package/dist/orchestrator/architect-agent.d.ts +16 -0
  106. package/dist/orchestrator/architect-agent.d.ts.map +1 -1
  107. package/dist/orchestrator/architect-agent.js +509 -1
  108. package/dist/orchestrator/architect-agent.js.map +1 -1
  109. package/dist/orchestrator/curator-agent.js +1 -1
  110. package/dist/orchestrator/curator-agent.js.map +1 -1
  111. package/dist/orchestrator/deploy/types.d.ts +2 -2
  112. package/dist/orchestrator/documenter-agent.d.ts +57 -0
  113. package/dist/orchestrator/documenter-agent.d.ts.map +1 -0
  114. package/dist/orchestrator/documenter-agent.js +195 -0
  115. package/dist/orchestrator/documenter-agent.js.map +1 -0
  116. package/dist/orchestrator/environment.d.ts +45 -0
  117. package/dist/orchestrator/environment.d.ts.map +1 -0
  118. package/dist/orchestrator/environment.js +151 -0
  119. package/dist/orchestrator/environment.js.map +1 -0
  120. package/dist/orchestrator/eval-lenses.d.ts +7 -0
  121. package/dist/orchestrator/eval-lenses.d.ts.map +1 -0
  122. package/dist/orchestrator/eval-lenses.js +19 -0
  123. package/dist/orchestrator/eval-lenses.js.map +1 -0
  124. package/dist/orchestrator/eval-persist.d.ts +25 -0
  125. package/dist/orchestrator/eval-persist.d.ts.map +1 -0
  126. package/dist/orchestrator/eval-persist.js +74 -0
  127. package/dist/orchestrator/eval-persist.js.map +1 -0
  128. package/dist/orchestrator/evaluator-agent.d.ts +23 -0
  129. package/dist/orchestrator/evaluator-agent.d.ts.map +1 -1
  130. package/dist/orchestrator/evaluator-agent.js +60 -3
  131. package/dist/orchestrator/evaluator-agent.js.map +1 -1
  132. package/dist/orchestrator/generator-agent.d.ts.map +1 -1
  133. package/dist/orchestrator/generator-agent.js +32 -0
  134. package/dist/orchestrator/generator-agent.js.map +1 -1
  135. package/dist/orchestrator/memory/distill.d.ts +60 -0
  136. package/dist/orchestrator/memory/distill.d.ts.map +1 -0
  137. package/dist/orchestrator/memory/distill.js +177 -0
  138. package/dist/orchestrator/memory/distill.js.map +1 -0
  139. package/dist/orchestrator/memory/eval-source.d.ts +20 -0
  140. package/dist/orchestrator/memory/eval-source.d.ts.map +1 -0
  141. package/dist/orchestrator/memory/eval-source.js +88 -0
  142. package/dist/orchestrator/memory/eval-source.js.map +1 -0
  143. package/dist/orchestrator/memory/retrieve.d.ts +45 -0
  144. package/dist/orchestrator/memory/retrieve.d.ts.map +1 -0
  145. package/dist/orchestrator/memory/retrieve.js +102 -0
  146. package/dist/orchestrator/memory/retrieve.js.map +1 -0
  147. package/dist/orchestrator/model-resolver.d.ts.map +1 -1
  148. package/dist/orchestrator/model-resolver.js +12 -0
  149. package/dist/orchestrator/model-resolver.js.map +1 -1
  150. package/dist/orchestrator/pipeline.d.ts +10 -0
  151. package/dist/orchestrator/pipeline.d.ts.map +1 -1
  152. package/dist/orchestrator/pipeline.js +111 -3
  153. package/dist/orchestrator/pipeline.js.map +1 -1
  154. package/dist/orchestrator/planner-agent.d.ts +22 -1
  155. package/dist/orchestrator/planner-agent.d.ts.map +1 -1
  156. package/dist/orchestrator/planner-agent.js +160 -4
  157. package/dist/orchestrator/planner-agent.js.map +1 -1
  158. package/dist/orchestrator/research-agent.js +2 -2
  159. package/dist/orchestrator/research-agent.js.map +1 -1
  160. package/dist/orchestrator/tools/handlers.d.ts +14 -0
  161. package/dist/orchestrator/tools/handlers.d.ts.map +1 -1
  162. package/dist/orchestrator/tools/handlers.js +29 -4
  163. package/dist/orchestrator/tools/handlers.js.map +1 -1
  164. package/dist/orchestrator/tools/schemas.js +5 -5
  165. package/dist/orchestrator/tools/schemas.js.map +1 -1
  166. package/dist/orchestrator/workflow/args-builder.d.ts +35 -0
  167. package/dist/orchestrator/workflow/args-builder.d.ts.map +1 -0
  168. package/dist/orchestrator/workflow/args-builder.js +142 -0
  169. package/dist/orchestrator/workflow/args-builder.js.map +1 -0
  170. package/dist/orchestrator/workflow/budget.d.ts +57 -0
  171. package/dist/orchestrator/workflow/budget.d.ts.map +1 -0
  172. package/dist/orchestrator/workflow/budget.js +80 -0
  173. package/dist/orchestrator/workflow/budget.js.map +1 -0
  174. package/dist/orchestrator/workflow/conformance.d.ts +27 -0
  175. package/dist/orchestrator/workflow/conformance.d.ts.map +1 -0
  176. package/dist/orchestrator/workflow/conformance.js +111 -0
  177. package/dist/orchestrator/workflow/conformance.js.map +1 -0
  178. package/dist/orchestrator/workflow/eligibility.d.ts +8 -0
  179. package/dist/orchestrator/workflow/eligibility.d.ts.map +1 -0
  180. package/dist/orchestrator/workflow/eligibility.js +10 -0
  181. package/dist/orchestrator/workflow/eligibility.js.map +1 -0
  182. package/dist/orchestrator/workflow/engine.d.ts +10 -0
  183. package/dist/orchestrator/workflow/engine.d.ts.map +1 -0
  184. package/dist/orchestrator/workflow/engine.js +2 -0
  185. package/dist/orchestrator/workflow/engine.js.map +1 -0
  186. package/dist/orchestrator/workflow/errors.d.ts +13 -0
  187. package/dist/orchestrator/workflow/errors.d.ts.map +1 -0
  188. package/dist/orchestrator/workflow/errors.js +26 -0
  189. package/dist/orchestrator/workflow/errors.js.map +1 -0
  190. package/dist/orchestrator/workflow/flusher.d.ts +19 -0
  191. package/dist/orchestrator/workflow/flusher.d.ts.map +1 -0
  192. package/dist/orchestrator/workflow/flusher.js +81 -0
  193. package/dist/orchestrator/workflow/flusher.js.map +1 -0
  194. package/dist/orchestrator/workflow/interpreter.d.ts +48 -0
  195. package/dist/orchestrator/workflow/interpreter.d.ts.map +1 -0
  196. package/dist/orchestrator/workflow/interpreter.js +92 -0
  197. package/dist/orchestrator/workflow/interpreter.js.map +1 -0
  198. package/dist/orchestrator/workflow/pure-sprint.d.ts +65 -0
  199. package/dist/orchestrator/workflow/pure-sprint.d.ts.map +1 -0
  200. package/dist/orchestrator/workflow/pure-sprint.js +82 -0
  201. package/dist/orchestrator/workflow/pure-sprint.js.map +1 -0
  202. package/dist/orchestrator/workflow/reconciler.d.ts +15 -0
  203. package/dist/orchestrator/workflow/reconciler.d.ts.map +1 -0
  204. package/dist/orchestrator/workflow/reconciler.js +65 -0
  205. package/dist/orchestrator/workflow/reconciler.js.map +1 -0
  206. package/dist/orchestrator/workflow/resume-cursor.d.ts +10 -0
  207. package/dist/orchestrator/workflow/resume-cursor.d.ts.map +1 -0
  208. package/dist/orchestrator/workflow/resume-cursor.js +25 -0
  209. package/dist/orchestrator/workflow/resume-cursor.js.map +1 -0
  210. package/dist/orchestrator/workflow/retry.d.ts +50 -0
  211. package/dist/orchestrator/workflow/retry.d.ts.map +1 -0
  212. package/dist/orchestrator/workflow/retry.js +100 -0
  213. package/dist/orchestrator/workflow/retry.js.map +1 -0
  214. package/dist/orchestrator/workflow/scheduler.d.ts +87 -0
  215. package/dist/orchestrator/workflow/scheduler.d.ts.map +1 -0
  216. package/dist/orchestrator/workflow/scheduler.js +158 -0
  217. package/dist/orchestrator/workflow/scheduler.js.map +1 -0
  218. package/dist/orchestrator/workflow/selector.d.ts +26 -0
  219. package/dist/orchestrator/workflow/selector.d.ts.map +1 -0
  220. package/dist/orchestrator/workflow/selector.js +54 -0
  221. package/dist/orchestrator/workflow/selector.js.map +1 -0
  222. package/dist/orchestrator/workflow/synthesizer.d.ts +52 -0
  223. package/dist/orchestrator/workflow/synthesizer.d.ts.map +1 -0
  224. package/dist/orchestrator/workflow/synthesizer.js +75 -0
  225. package/dist/orchestrator/workflow/synthesizer.js.map +1 -0
  226. package/dist/orchestrator/workflow/ts-engine.d.ts +13 -0
  227. package/dist/orchestrator/workflow/ts-engine.d.ts.map +1 -0
  228. package/dist/orchestrator/workflow/ts-engine.js +14 -0
  229. package/dist/orchestrator/workflow/ts-engine.js.map +1 -0
  230. package/dist/orchestrator/workflow/types.d.ts +55 -0
  231. package/dist/orchestrator/workflow/types.d.ts.map +1 -0
  232. package/dist/orchestrator/workflow/types.js +3 -0
  233. package/dist/orchestrator/workflow/types.js.map +1 -0
  234. package/dist/orchestrator/workflow/workflow-engine.d.ts +31 -0
  235. package/dist/orchestrator/workflow/workflow-engine.d.ts.map +1 -0
  236. package/dist/orchestrator/workflow/workflow-engine.js +70 -0
  237. package/dist/orchestrator/workflow/workflow-engine.js.map +1 -0
  238. package/dist/providers/anthropic.d.ts.map +1 -1
  239. package/dist/providers/anthropic.js +49 -6
  240. package/dist/providers/anthropic.js.map +1 -1
  241. package/dist/providers/claude-code.d.ts +44 -0
  242. package/dist/providers/claude-code.d.ts.map +1 -0
  243. package/dist/providers/claude-code.js +143 -0
  244. package/dist/providers/claude-code.js.map +1 -0
  245. package/dist/providers/factory.d.ts +16 -2
  246. package/dist/providers/factory.d.ts.map +1 -1
  247. package/dist/providers/factory.js +66 -12
  248. package/dist/providers/factory.js.map +1 -1
  249. package/dist/providers/google.d.ts.map +1 -1
  250. package/dist/providers/google.js +27 -3
  251. package/dist/providers/google.js.map +1 -1
  252. package/dist/providers/index.d.ts +3 -1
  253. package/dist/providers/index.d.ts.map +1 -1
  254. package/dist/providers/index.js +3 -1
  255. package/dist/providers/index.js.map +1 -1
  256. package/dist/providers/openai.d.ts.map +1 -1
  257. package/dist/providers/openai.js +24 -3
  258. package/dist/providers/openai.js.map +1 -1
  259. package/dist/providers/preflight.d.ts +22 -0
  260. package/dist/providers/preflight.d.ts.map +1 -0
  261. package/dist/providers/preflight.js +54 -0
  262. package/dist/providers/preflight.js.map +1 -0
  263. package/dist/providers/structured.d.ts +130 -0
  264. package/dist/providers/structured.d.ts.map +1 -0
  265. package/dist/providers/structured.js +205 -0
  266. package/dist/providers/structured.js.map +1 -0
  267. package/dist/providers/types.d.ts +28 -0
  268. package/dist/providers/types.d.ts.map +1 -1
  269. package/dist/state/history-rotation.d.ts +17 -0
  270. package/dist/state/history-rotation.d.ts.map +1 -0
  271. package/dist/state/history-rotation.js +84 -0
  272. package/dist/state/history-rotation.js.map +1 -0
  273. package/dist/state/history.d.ts +16 -4
  274. package/dist/state/history.d.ts.map +1 -1
  275. package/dist/state/history.js +62 -20
  276. package/dist/state/history.js.map +1 -1
  277. package/dist/state/index.d.ts +1 -1
  278. package/dist/state/index.d.ts.map +1 -1
  279. package/dist/state/index.js +1 -1
  280. package/dist/state/index.js.map +1 -1
  281. package/dist/state/memory.d.ts +60 -0
  282. package/dist/state/memory.d.ts.map +1 -0
  283. package/dist/state/memory.js +242 -0
  284. package/dist/state/memory.js.map +1 -0
  285. package/hooks/hooks.json +12 -2
  286. package/package.json +9 -5
  287. package/scripts/spike-claude-code-provider.mjs +66 -0
  288. package/scripts/spike-deepseek.mjs +63 -0
  289. package/scripts/sync-targets.json +12 -0
  290. package/scripts/update-all.mjs +255 -0
  291. package/skills/bober.architect/SKILL.md +13 -0
  292. package/skills/bober.architect/references/arch-lens-panel.md +126 -0
  293. package/skills/bober.eval/SKILL.md +9 -0
  294. package/skills/bober.eval/references/lens-panel.md +115 -0
  295. package/skills/bober.plan/SKILL.md +6 -0
  296. package/skills/bober.run/SKILL.md +23 -4
  297. package/skills/bober.run/references/lens-panel.md +115 -0
  298. package/skills/bober.sprint/SKILL.md +44 -2
  299. package/skills/bober.sprint/references/lens-panel.md +115 -0
  300. package/skills/shared/arch-lens-panel.md +126 -0
  301. package/skills/shared/lens-panel.md +115 -0
@@ -0,0 +1,115 @@
1
+ # Lens Panel — Canonical Protocol Reference
2
+
3
+ This document is the single source of truth for native panel orchestration in agent-bober.
4
+ It embeds the five canonical lens focus fragments verbatim from
5
+ `src/orchestrator/eval-lenses.ts` (the `LENS_CATALOG` literal) and documents the
6
+ split fan-out, majority-vote/fail-closed reconciliation, and the `lensVerdicts` output shape.
7
+
8
+ ---
9
+
10
+ ## Lens Focus Fragments
11
+
12
+ The following fragments are the exact strings returned by `resolveLensFocus(lens)` for each
13
+ built-in lens. They MUST remain byte-for-byte identical to the corresponding entries in
14
+ `LENS_CATALOG` — the drift gate (`src/orchestrator/lens-panel-parity.test.ts`) enforces this.
15
+
16
+ ### correctness
17
+
18
+ ```
19
+ Focus on whether the implementation actually satisfies each success criterion verbatim. Check that all required behaviours exist, all edge cases are handled, and the contract's definitionOfDone is met.
20
+ ```
21
+
22
+ ### security
23
+
24
+ ```
25
+ Focus on injection vulnerabilities, authentication and authorisation gaps, secret handling, unsafe input validation, and any path traversal or privilege escalation risks.
26
+ ```
27
+
28
+ ### regression
29
+
30
+ ```
31
+ Focus on whether previously working behaviour still works after the changes. Verify that pre-existing tests pass, that no public API or config interface was broken, and that the sprint diff does not silently remove functionality.
32
+ ```
33
+
34
+ ### quality
35
+
36
+ ```
37
+ Focus on principles violations, dead code, misleading naming, smells, duplicated logic, and whether the implementation follows the project's established patterns and conventions.
38
+ ```
39
+
40
+ ### simplicity
41
+
42
+ ```
43
+ Focus exclusively on over-engineering in the production code: logic that reinvents the standard library, dependencies or hand-rolled code doing what a native platform feature already provides, abstractions with a single implementation, configuration nobody reads, dead flexibility, and code expressible in materially fewer lines. For each, name the location, what to cut, and what replaces it. Never flag tests, assertion-based self-checks, input validation at trust boundaries, error handling, security measures, or accessibility as deletable — minimalism governs production code, never the verification or safety discipline.
44
+ ```
45
+
46
+ > The `simplicity` lens is the complexity-only counterpart to `quality`. `quality` asks
47
+ > "does this follow our patterns and is it free of smells?"; `simplicity` asks "what can be
48
+ > deleted, replaced by stdlib/native, or shrunk?" — and is forbidden from ever recommending the
49
+ > removal of a test, a validation, or a safety measure. It pairs cleanly with the evaluator's
50
+ > test/verification Iron Law: minimalism governs what is built, never what is verified.
51
+
52
+ ---
53
+
54
+ ## Native Panel Protocol
55
+
56
+ ### Split Fan-out
57
+
58
+ When the native panel is active, the orchestrator spawns evaluators in two passes:
59
+
60
+ 1. **Deterministic evaluator (one instance):** runs the configured strategy suite exactly once
61
+ (build, typecheck, lint, unit-test, playwright, api-check, etc.). This produces the
62
+ deterministic verdict — objective, tool-based checks that do not depend on lens focus.
63
+
64
+ 2. **Qualitative evaluators (one per configured lens):** each evaluator receives the same
65
+ sprint diff and context but is instructed to judge the contract's success criteria
66
+ exclusively through its lens focus fragment. The strategy suite is **not** re-run for
67
+ these evaluators — they perform qualitative assessment only, using the results already
68
+ collected by the deterministic evaluator as supporting context.
69
+
70
+ This split ensures strategies execute once (no duplicate CI cost) while each lens evaluates
71
+ the diff independently.
72
+
73
+ ### Reconciliation — Majority Vote, Fail-Closed
74
+
75
+ The lens verdicts are reconciled by `reconcile()` in
76
+ `src/orchestrator/workflow/reconciler.ts` using the following semantics:
77
+
78
+ - **Inputs:** the array of per-lens `EvalResult` objects (`lensVerdicts`).
79
+ - **Require non-empty:** an empty array throws `"reconcile: lensVerdicts must be non-empty"`.
80
+ - **Vote count:** `passCount` = number of lenses where `passed === true`;
81
+ `failCount` = total − passCount.
82
+ - **Verdict:** `passed = passCount > failCount` (strict majority).
83
+ - **Fail-closed on tie:** when `passCount === failCount` the panel verdict is `false`.
84
+ - **Details:** union of all failing lens details, de-duplicated by `(criterion, message)` key.
85
+ - **Feedback:** failing lenses' feedback joined with `\n`; `"All lenses passed."` when all pass.
86
+ - **Summary:** `"Panel verdict: ${passCount}/${n} lenses passed"`.
87
+ - **Score:** `Math.round((100 * passCount) / n)`.
88
+ - **Evaluator tag:** `evaluator = "panel"`.
89
+ - **Timestamp:** echoed verbatim from the input argument (pure function, ADR-4).
90
+
91
+ ### Combine
92
+
93
+ The final sprint verdict combines both passes:
94
+
95
+ ```
96
+ final.passed = deterministic.passed && reconciled.passed
97
+ ```
98
+
99
+ Both must pass for the sprint to be accepted.
100
+
101
+ ### lensVerdicts Output Shape
102
+
103
+ After reconciliation the orchestrator writes a `lensVerdicts` array into the saved
104
+ `EvalResult` JSON and sets `evaluator = "panel"`. The array shape is:
105
+
106
+ ```ts
107
+ lensVerdicts: Array<{
108
+ lens: string; // e.g. "correctness", "security", "regression", "quality", "simplicity"
109
+ passed: boolean; // individual lens verdict
110
+ summary: string; // per-lens summary from the qualitative evaluator
111
+ }>
112
+ ```
113
+
114
+ This field is optional and backward-compatible: eval results produced before the panel
115
+ feature (or by non-panel evaluators) simply omit it.
@@ -283,6 +283,15 @@ When done, respond with EXACTLY this JSON structure (no other text):
283
283
 
284
284
  ## Step 6: Spawn the Evaluator Subagent
285
285
 
286
+ **Panel mode (gated, off by default):** Read `config.evaluator.panel`. If `panel.enabled` is `true` AND `panel.lenses.length >= 2`, run the PANEL flow described in the inlined Lens Panel reference below (`<!-- Reference: lens-panel.md -->`):
287
+ - Spawn ONE bober-evaluator with **MODE:deterministic** — runs the configured strategy suite exactly once.
288
+ - Then spawn one bober-evaluator per lens with **MODE:lens:<name>** for each name in `panel.lenses`, bounded by `panel.maxConcurrent` concurrent spawns.
289
+ - Collect each lens verdict; majority-vote: `passed = passCount > failCount`, **FAIL-CLOSED on tie** (tie → false).
290
+ - Set `final.passed = deterministic.passed && reconciled.passed`.
291
+ - Save the eval-result with `evaluator: "panel"` and a `lensVerdicts: [{ lens, passed, summary }]` array.
292
+
293
+ OTHERWISE (panel disabled, or fewer than 2 lenses), spawn exactly ONE bober-evaluator with **MODE:full** exactly as described below — byte-identical to today's behaviour.
294
+
286
295
  **Use the Agent tool to spawn the evaluator:**
287
296
 
288
297
  ```
@@ -368,12 +377,44 @@ Respond with EXACTLY this JSON structure (no other text):
368
377
  {"event":"sprint-completed","contractId":"...","specId":"...","iteration":N,"timestamp":"..."}
369
378
  ```
370
379
 
371
- 4. **Check if the plan is now fully complete.** Read the PlanSpec's `sprints` array to get the total count. Count how many of those contracts now have `status: "completed"`. If ALL sprints are completed (N/N):
380
+ 4. **Spawn the Documenter subagent write docs now, while the change is fresh.** The sprint is committed and marked complete; document it per-sprint instead of batching all docs into a final sprint (which goes stale and error-prone). Use the Agent tool:
381
+
382
+ ```
383
+ Agent tool call:
384
+ description: "Docs for sprint <N>: <sprint title>"
385
+ subagent_type: bober-documenter
386
+ mode: auto
387
+ prompt: <the prompt below>
388
+ ```
389
+
390
+ IMPORTANT: Use `mode: auto` or `mode: bypassPermissions` — the documenter needs write access to create/edit docs and commit them.
391
+
392
+ **Documenter prompt:**
393
+ ```
394
+ You are the Bober Documenter subagent. Sprint <N> just PASSED evaluation and was marked complete. Write its documentation and update related docs while the change is fresh.
395
+
396
+ Read these from disk:
397
+ - SprintContract: .bober/contracts/<contractId>.json
398
+ - Generator report: .bober/handoffs/gen-report-<contractId>-<iteration>.json
399
+ - Eval result: .bober/eval-results/eval-<contractId>-<iteration>.json
400
+ - .bober/principles.md if it exists
401
+
402
+ Then follow your agent instructions: determine what was built from the committed diff, write the sprint record to docs/sprints/<contractId>.md, find & update related existing docs (README, ADRs, CLAUDE.md, module docs) that the change made stale, and commit ONLY the doc files separately. Do NOT modify application code or tests.
403
+
404
+ Respond with the JSON structure defined in your agent spec.
405
+ ```
406
+
407
+ **After the Documenter returns:**
408
+ - Parse its JSON response. Note `sprintDocPath`, `relatedDocsUpdated`, and any `concerns`.
409
+ - If the documenter crashed or returned an error, do NOT fail the sprint — it already passed. Log `{"event":"sprint-docs-failed","contractId":"...","timestamp":"..."}` and continue. Docs can be regenerated later.
410
+ - If `concerns` is non-empty, surface them in the success report so the user can decide whether to act.
411
+
412
+ 5. **Check if the plan is now fully complete.** Read the PlanSpec's `sprints` array to get the total count. Count how many of those contracts now have `status: "completed"`. If ALL sprints are completed (N/N):
372
413
  - Update the PlanSpec: set `status` to `"completed"` and `completedAt` to current ISO-8601 timestamp. Save to `.bober/specs/<specId>.json`. **The `status` field MUST remain in the first 10 lines of the JSON** so future runs can skip it with a partial read.
373
414
  - Update `.bober/progress.md` — change the plan's status line to `completed (N/N sprints)`.
374
415
  - Log event: `{"event":"plan-completed","specId":"...","sprintsCompleted":N,"timestamp":"..."}`
375
416
 
376
- 5. **Report success to the user:**
417
+ 6. **Report success to the user:**
377
418
  ```
378
419
  === Sprint <N> PASSED on iteration <M> ===
379
420
 
@@ -383,6 +424,7 @@ Respond with EXACTLY this JSON structure (no other text):
383
424
  - <criterion 2>: PASS
384
425
  ...
385
426
 
427
+ Docs: <sprintDocPath> (+ <count> related docs updated)
386
428
  Next sprint: <next sprint title> (run /bober-sprint to continue)
387
429
  ```
388
430
  If all sprints are done, report `=== PLAN COMPLETE (N/N sprints) ===` instead of "Next sprint".
@@ -0,0 +1,115 @@
1
+ # Lens Panel — Canonical Protocol Reference
2
+
3
+ This document is the single source of truth for native panel orchestration in agent-bober.
4
+ It embeds the five canonical lens focus fragments verbatim from
5
+ `src/orchestrator/eval-lenses.ts` (the `LENS_CATALOG` literal) and documents the
6
+ split fan-out, majority-vote/fail-closed reconciliation, and the `lensVerdicts` output shape.
7
+
8
+ ---
9
+
10
+ ## Lens Focus Fragments
11
+
12
+ The following fragments are the exact strings returned by `resolveLensFocus(lens)` for each
13
+ built-in lens. They MUST remain byte-for-byte identical to the corresponding entries in
14
+ `LENS_CATALOG` — the drift gate (`src/orchestrator/lens-panel-parity.test.ts`) enforces this.
15
+
16
+ ### correctness
17
+
18
+ ```
19
+ Focus on whether the implementation actually satisfies each success criterion verbatim. Check that all required behaviours exist, all edge cases are handled, and the contract's definitionOfDone is met.
20
+ ```
21
+
22
+ ### security
23
+
24
+ ```
25
+ Focus on injection vulnerabilities, authentication and authorisation gaps, secret handling, unsafe input validation, and any path traversal or privilege escalation risks.
26
+ ```
27
+
28
+ ### regression
29
+
30
+ ```
31
+ Focus on whether previously working behaviour still works after the changes. Verify that pre-existing tests pass, that no public API or config interface was broken, and that the sprint diff does not silently remove functionality.
32
+ ```
33
+
34
+ ### quality
35
+
36
+ ```
37
+ Focus on principles violations, dead code, misleading naming, smells, duplicated logic, and whether the implementation follows the project's established patterns and conventions.
38
+ ```
39
+
40
+ ### simplicity
41
+
42
+ ```
43
+ Focus exclusively on over-engineering in the production code: logic that reinvents the standard library, dependencies or hand-rolled code doing what a native platform feature already provides, abstractions with a single implementation, configuration nobody reads, dead flexibility, and code expressible in materially fewer lines. For each, name the location, what to cut, and what replaces it. Never flag tests, assertion-based self-checks, input validation at trust boundaries, error handling, security measures, or accessibility as deletable — minimalism governs production code, never the verification or safety discipline.
44
+ ```
45
+
46
+ > The `simplicity` lens is the complexity-only counterpart to `quality`. `quality` asks
47
+ > "does this follow our patterns and is it free of smells?"; `simplicity` asks "what can be
48
+ > deleted, replaced by stdlib/native, or shrunk?" — and is forbidden from ever recommending the
49
+ > removal of a test, a validation, or a safety measure. It pairs cleanly with the evaluator's
50
+ > test/verification Iron Law: minimalism governs what is built, never what is verified.
51
+
52
+ ---
53
+
54
+ ## Native Panel Protocol
55
+
56
+ ### Split Fan-out
57
+
58
+ When the native panel is active, the orchestrator spawns evaluators in two passes:
59
+
60
+ 1. **Deterministic evaluator (one instance):** runs the configured strategy suite exactly once
61
+ (build, typecheck, lint, unit-test, playwright, api-check, etc.). This produces the
62
+ deterministic verdict — objective, tool-based checks that do not depend on lens focus.
63
+
64
+ 2. **Qualitative evaluators (one per configured lens):** each evaluator receives the same
65
+ sprint diff and context but is instructed to judge the contract's success criteria
66
+ exclusively through its lens focus fragment. The strategy suite is **not** re-run for
67
+ these evaluators — they perform qualitative assessment only, using the results already
68
+ collected by the deterministic evaluator as supporting context.
69
+
70
+ This split ensures strategies execute once (no duplicate CI cost) while each lens evaluates
71
+ the diff independently.
72
+
73
+ ### Reconciliation — Majority Vote, Fail-Closed
74
+
75
+ The lens verdicts are reconciled by `reconcile()` in
76
+ `src/orchestrator/workflow/reconciler.ts` using the following semantics:
77
+
78
+ - **Inputs:** the array of per-lens `EvalResult` objects (`lensVerdicts`).
79
+ - **Require non-empty:** an empty array throws `"reconcile: lensVerdicts must be non-empty"`.
80
+ - **Vote count:** `passCount` = number of lenses where `passed === true`;
81
+ `failCount` = total − passCount.
82
+ - **Verdict:** `passed = passCount > failCount` (strict majority).
83
+ - **Fail-closed on tie:** when `passCount === failCount` the panel verdict is `false`.
84
+ - **Details:** union of all failing lens details, de-duplicated by `(criterion, message)` key.
85
+ - **Feedback:** failing lenses' feedback joined with `\n`; `"All lenses passed."` when all pass.
86
+ - **Summary:** `"Panel verdict: ${passCount}/${n} lenses passed"`.
87
+ - **Score:** `Math.round((100 * passCount) / n)`.
88
+ - **Evaluator tag:** `evaluator = "panel"`.
89
+ - **Timestamp:** echoed verbatim from the input argument (pure function, ADR-4).
90
+
91
+ ### Combine
92
+
93
+ The final sprint verdict combines both passes:
94
+
95
+ ```
96
+ final.passed = deterministic.passed && reconciled.passed
97
+ ```
98
+
99
+ Both must pass for the sprint to be accepted.
100
+
101
+ ### lensVerdicts Output Shape
102
+
103
+ After reconciliation the orchestrator writes a `lensVerdicts` array into the saved
104
+ `EvalResult` JSON and sets `evaluator = "panel"`. The array shape is:
105
+
106
+ ```ts
107
+ lensVerdicts: Array<{
108
+ lens: string; // e.g. "correctness", "security", "regression", "quality", "simplicity"
109
+ passed: boolean; // individual lens verdict
110
+ summary: string; // per-lens summary from the qualitative evaluator
111
+ }>
112
+ ```
113
+
114
+ This field is optional and backward-compatible: eval results produced before the panel
115
+ feature (or by non-panel evaluators) simply omit it.
@@ -0,0 +1,126 @@
1
+ # Arch Lens Panel — Canonical Protocol Reference
2
+
3
+ This document is the single source of truth for native architect panel orchestration in agent-bober.
4
+ It embeds the seven canonical arch lens focus fragments verbatim from
5
+ `src/orchestrator/arch-lenses.ts` (the `ARCH_LENS_CATALOG` literal) and documents the
6
+ CP2 synthesis panel and CP5 reconcile panel protocols.
7
+ The drift gate (`src/orchestrator/arch-lens-panel-parity.test.ts`) enforces byte-exact parity.
8
+
9
+ ---
10
+
11
+ ## Lens Focus Fragments
12
+
13
+ The following fragments are the exact strings returned by `resolveArchLensFocus(lens)` for each
14
+ built-in arch lens. They MUST remain byte-for-byte identical to the corresponding entries in
15
+ `ARCH_LENS_CATALOG` — the drift gate (`src/orchestrator/arch-lens-panel-parity.test.ts`) enforces this.
16
+
17
+ ### scalability
18
+
19
+ ```
20
+ Focus on whether the proposed architecture can handle projected load growth. Evaluate horizontal and vertical scaling paths, bottlenecks, stateful vs stateless components, and whether partitioning or sharding strategies are available when needed.
21
+ ```
22
+
23
+ ### security
24
+
25
+ ```
26
+ Focus on the threat surface introduced by this architecture. Evaluate trust boundaries, data flows across zones, authentication and authorisation enforcement points, secrets management, and exposure of internal services.
27
+ ```
28
+
29
+ ### cost
30
+
31
+ ```
32
+ Focus on the total cost of ownership implied by this architecture. Evaluate compute, storage, and egress costs at projected scale, licensing or SaaS subscription expenses, and the operational overhead of running, monitoring, and scaling the system.
33
+ ```
34
+
35
+ ### operability
36
+
37
+ ```
38
+ Focus on how easy it will be to operate this architecture in production. Evaluate observability (metrics, logs, traces), deployment complexity, rollout and rollback procedures, on-call burden, and the blast radius of common failure modes.
39
+ ```
40
+
41
+ ### maintainability
42
+
43
+ ```
44
+ Focus on how easy it will be to change and extend this architecture over time. Evaluate coupling between components, clarity of boundaries, documentation needs, onboarding friction for new contributors, and the risk of accruing technical debt.
45
+ ```
46
+
47
+ ### reversibility
48
+
49
+ ```
50
+ Focus on how difficult or costly it would be to undo or replace this architectural decision. Evaluate lock-in to vendors or proprietary technologies, data migration complexity, and whether a strangler-fig or incremental migration path exists if the approach needs to change.
51
+ ```
52
+
53
+ ### simplicity
54
+
55
+ ```
56
+ Focus on whether this is the simplest architecture that satisfies the Checkpoint 1 constraints. Challenge whether each component needs to exist, whether a native platform feature or an already-present dependency removes a proposed custom layer, whether two components should collapse into one, and whether any abstraction is speculative — added for a use case absent from the problem statement. Reward the smallest design that honours every hard constraint; penalise layers introduced for unproven future flexibility, but never at the expense of a stated constraint.
57
+ ```
58
+
59
+ > The `simplicity` lens enforces the top rung of the YAGNI ladder at design time: "does this
60
+ > component need to exist at all?". It is constraint-bounded by construction — it may never
61
+ > recommend dropping a layer that a Checkpoint 1 hard constraint requires. This keeps it
62
+ > consistent with the architect's IRON LAW (every decision must cite the constraint that
63
+ > eliminates the rejected alternative): a simplification that violates a constraint is not simpler,
64
+ > it is wrong.
65
+
66
+ ---
67
+
68
+ ## Native Architect Panel Protocol
69
+
70
+ ### CP2 Synthesis Panel
71
+
72
+ At Checkpoint 2 (candidate generation + scoring), the orchestrator runs the synthesis panel:
73
+
74
+ 1. **Generate candidates:** The architect produces 2–3 candidate approaches that satisfy the
75
+ Checkpoint 1 constraints.
76
+
77
+ 2. **Lens scorer fan-out (one per lens):** The orchestrator spawns one scorer subagent per
78
+ configured arch lens (scalability, security, cost, operability, maintainability, reversibility,
79
+ simplicity), bounded by `maxConcurrent`. Each scorer receives the same candidate set and is instructed to
80
+ score the candidates exclusively through its lens focus fragment (the exact string returned by
81
+ `resolveArchLensFocus(lens)` from `src/orchestrator/arch-lenses.ts`).
82
+
83
+ 3. **Synthesis:** `synthesize()` in `src/orchestrator/synthesizer.ts` aggregates the per-lens
84
+ scores and produces a ranked winner with dissent. The highest-scoring approach across lenses
85
+ becomes the recommended architecture; any lens that preferred a different candidate is recorded
86
+ as a dissenting voice in the synthesis output.
87
+
88
+ ### CP5 Reconcile Panel
89
+
90
+ At Checkpoint 5 (review pass), the orchestrator runs the reconcile panel:
91
+
92
+ 1. **Lens reviewer fan-out (one per lens):** The orchestrator spawns one reviewer subagent per
93
+ configured arch lens. Each reviewer receives the assembled architecture document and ADRs, and
94
+ is instructed to produce a PASS/FAIL verdict exclusively through its lens focus fragment.
95
+
96
+ 2. **Reconciliation — fail-closed on tie:** `reconcile()` in
97
+ `src/orchestrator/workflow/reconciler.ts` aggregates the per-lens verdicts using the following
98
+ semantics:
99
+
100
+ - **Inputs:** the array of per-lens `EvalResult` objects (`lensVerdicts`).
101
+ - **Require non-empty:** an empty array throws `"reconcile: lensVerdicts must be non-empty"`.
102
+ - **Vote count:** `passCount` = number of lenses where `passed === true`;
103
+ `failCount` = total − passCount.
104
+ - **Verdict:** `passed = passCount > failCount` (strict majority).
105
+ - **Fail-closed on tie:** when `passCount === failCount` the panel verdict is `false`.
106
+ - **Details:** union of all failing lens details, de-duplicated by `(criterion, message)` key.
107
+ - **Feedback:** failing lenses' feedback joined with `\n`; `"All lenses passed."` when all pass.
108
+ - **Summary:** `"Panel verdict: ${passCount}/${n} lenses passed"`.
109
+ - **Score:** `Math.round((100 * passCount) / n)`.
110
+ - **Evaluator tag:** `evaluator = "panel"`.
111
+
112
+ ### lensVerdicts Output Shape
113
+
114
+ After reconciliation the orchestrator writes a `lensVerdicts` array into the saved result.
115
+ The array shape is:
116
+
117
+ ```ts
118
+ lensVerdicts: Array<{
119
+ lens: string; // e.g. "scalability", "security", "cost", "operability", "maintainability", "reversibility", "simplicity"
120
+ passed: boolean; // individual lens verdict
121
+ summary: string; // per-lens summary from the scorer or reviewer subagent
122
+ }>
123
+ ```
124
+
125
+ This field is optional and backward-compatible: results produced before the panel feature
126
+ (or by non-panel architect runs) simply omit it.
@@ -0,0 +1,115 @@
1
+ # Lens Panel — Canonical Protocol Reference
2
+
3
+ This document is the single source of truth for native panel orchestration in agent-bober.
4
+ It embeds the five canonical lens focus fragments verbatim from
5
+ `src/orchestrator/eval-lenses.ts` (the `LENS_CATALOG` literal) and documents the
6
+ split fan-out, majority-vote/fail-closed reconciliation, and the `lensVerdicts` output shape.
7
+
8
+ ---
9
+
10
+ ## Lens Focus Fragments
11
+
12
+ The following fragments are the exact strings returned by `resolveLensFocus(lens)` for each
13
+ built-in lens. They MUST remain byte-for-byte identical to the corresponding entries in
14
+ `LENS_CATALOG` — the drift gate (`src/orchestrator/lens-panel-parity.test.ts`) enforces this.
15
+
16
+ ### correctness
17
+
18
+ ```
19
+ Focus on whether the implementation actually satisfies each success criterion verbatim. Check that all required behaviours exist, all edge cases are handled, and the contract's definitionOfDone is met.
20
+ ```
21
+
22
+ ### security
23
+
24
+ ```
25
+ Focus on injection vulnerabilities, authentication and authorisation gaps, secret handling, unsafe input validation, and any path traversal or privilege escalation risks.
26
+ ```
27
+
28
+ ### regression
29
+
30
+ ```
31
+ Focus on whether previously working behaviour still works after the changes. Verify that pre-existing tests pass, that no public API or config interface was broken, and that the sprint diff does not silently remove functionality.
32
+ ```
33
+
34
+ ### quality
35
+
36
+ ```
37
+ Focus on principles violations, dead code, misleading naming, smells, duplicated logic, and whether the implementation follows the project's established patterns and conventions.
38
+ ```
39
+
40
+ ### simplicity
41
+
42
+ ```
43
+ Focus exclusively on over-engineering in the production code: logic that reinvents the standard library, dependencies or hand-rolled code doing what a native platform feature already provides, abstractions with a single implementation, configuration nobody reads, dead flexibility, and code expressible in materially fewer lines. For each, name the location, what to cut, and what replaces it. Never flag tests, assertion-based self-checks, input validation at trust boundaries, error handling, security measures, or accessibility as deletable — minimalism governs production code, never the verification or safety discipline.
44
+ ```
45
+
46
+ > The `simplicity` lens is the complexity-only counterpart to `quality`. `quality` asks
47
+ > "does this follow our patterns and is it free of smells?"; `simplicity` asks "what can be
48
+ > deleted, replaced by stdlib/native, or shrunk?" — and is forbidden from ever recommending the
49
+ > removal of a test, a validation, or a safety measure. It pairs cleanly with the evaluator's
50
+ > test/verification Iron Law: minimalism governs what is built, never what is verified.
51
+
52
+ ---
53
+
54
+ ## Native Panel Protocol
55
+
56
+ ### Split Fan-out
57
+
58
+ When the native panel is active, the orchestrator spawns evaluators in two passes:
59
+
60
+ 1. **Deterministic evaluator (one instance):** runs the configured strategy suite exactly once
61
+ (build, typecheck, lint, unit-test, playwright, api-check, etc.). This produces the
62
+ deterministic verdict — objective, tool-based checks that do not depend on lens focus.
63
+
64
+ 2. **Qualitative evaluators (one per configured lens):** each evaluator receives the same
65
+ sprint diff and context but is instructed to judge the contract's success criteria
66
+ exclusively through its lens focus fragment. The strategy suite is **not** re-run for
67
+ these evaluators — they perform qualitative assessment only, using the results already
68
+ collected by the deterministic evaluator as supporting context.
69
+
70
+ This split ensures strategies execute once (no duplicate CI cost) while each lens evaluates
71
+ the diff independently.
72
+
73
+ ### Reconciliation — Majority Vote, Fail-Closed
74
+
75
+ The lens verdicts are reconciled by `reconcile()` in
76
+ `src/orchestrator/workflow/reconciler.ts` using the following semantics:
77
+
78
+ - **Inputs:** the array of per-lens `EvalResult` objects (`lensVerdicts`).
79
+ - **Require non-empty:** an empty array throws `"reconcile: lensVerdicts must be non-empty"`.
80
+ - **Vote count:** `passCount` = number of lenses where `passed === true`;
81
+ `failCount` = total − passCount.
82
+ - **Verdict:** `passed = passCount > failCount` (strict majority).
83
+ - **Fail-closed on tie:** when `passCount === failCount` the panel verdict is `false`.
84
+ - **Details:** union of all failing lens details, de-duplicated by `(criterion, message)` key.
85
+ - **Feedback:** failing lenses' feedback joined with `\n`; `"All lenses passed."` when all pass.
86
+ - **Summary:** `"Panel verdict: ${passCount}/${n} lenses passed"`.
87
+ - **Score:** `Math.round((100 * passCount) / n)`.
88
+ - **Evaluator tag:** `evaluator = "panel"`.
89
+ - **Timestamp:** echoed verbatim from the input argument (pure function, ADR-4).
90
+
91
+ ### Combine
92
+
93
+ The final sprint verdict combines both passes:
94
+
95
+ ```
96
+ final.passed = deterministic.passed && reconciled.passed
97
+ ```
98
+
99
+ Both must pass for the sprint to be accepted.
100
+
101
+ ### lensVerdicts Output Shape
102
+
103
+ After reconciliation the orchestrator writes a `lensVerdicts` array into the saved
104
+ `EvalResult` JSON and sets `evaluator = "panel"`. The array shape is:
105
+
106
+ ```ts
107
+ lensVerdicts: Array<{
108
+ lens: string; // e.g. "correctness", "security", "regression", "quality", "simplicity"
109
+ passed: boolean; // individual lens verdict
110
+ summary: string; // per-lens summary from the qualitative evaluator
111
+ }>
112
+ ```
113
+
114
+ This field is optional and backward-compatible: eval results produced before the panel
115
+ feature (or by non-panel evaluators) simply omit it.