feat(review): multi-lens orchestration — 5 parallel opencode subprocesses (security/docs/code-quality/tests/perf)

On by default, opt-out via "reviewers": []. 290 tests pass.

- pilot/opencode_review.py: ReviewerSpec dataclass, default_reviewers(),
  parse_reviewers_config(), parse_triage_config(), resolve_reviewers(),
  _normalize_lens_finding(), posthash() (matches feedback.py scheme),
  _agreement_hash() (severity-free for cross-lens promotion), _tone_strip(),
  synthesize() 7-stage (severity_floor → tone-strip → length cap → per-lens
  max → per-file cap → dedup by _posthash → cross-lens severity promote →
  per-PR cap), run_lenses() (ThreadPoolExecutor pool=4), triage(),
  _intersect_with_triage(), _filter_by_skip_if(), run_lenses_review().
  run() routes to fan-out when config.reviewers[] present or PRAGENT_REVIEWERS=1.
- pilot/ai_review.py: parse_repo_config learns reviewers[] and triage objects
  (id regex /^[a-z0-9][a-z0-9-]{0,31}$/, 8-entry cap, agent_file/model/
  severity_floor/max_findings/activation/skip_if_all_changed_paths/hotpath_globs).
  review_pr branches to opencode_review.run_lenses_review when configured.
  _render_collapsible_usage shows lenses: ... line when present.
- .opencode/agents/{docs,code-quality,triage}.md: 3 new lens subagents.
- .opencode/skills/lens-orchestration/SKILL.md: strict-JSON contract every
  lens subagent MUST honor.
- .opencode/agents/pragent.md: slim to coordinator; no more hardcoded
  @security/@tests/@perf delegation; loads lens-orchestration skill.
- .opencode/README.md: rewrite 'Add a review lens' recipe for multi-lens.
- pilot/README-webhook.md: new 'Multi-lens pipeline' section (diagram +
  default roster + config schema + env vars + cross-lens dedup contract).
- tests: 36 new tests (test_ai_review.py +12 reviewers/triage/usage,
  test_opencode_review.py +24 orchestration). posthash golden-vector matches
  feedback.py exactly across 5 severity × 2 line cases.
This commit is contained in:
pragent-bot
2026-08-20 22:16:21 +00:00
parent e8ebc54362
commit 78bcf6a9a0
11 changed files with 1847 additions and 51 deletions
+35 -15
View File
@@ -71,22 +71,42 @@ host-local runs deterministic.
### Add a review lens (subagent)
1. Create `.opencode/agents/<name>.md` with `mode: subagent`, `hidden: true`, a
`description`, and a read-only `permission` (deny edit/write, allow bash/webfetch,
`task: deny` so it can't recurse). The body is its system prompt; end it by
requiring the same findings-JSON shape.
2. Allow it in the primary's `permission.task` list in `pragent.md`:
```yaml
task:
"*": "deny"
"security": "allow"
"tests": "allow"
"<name>": "allow" # add this
```
3. Mention in `pragent.md`'s "Delegate on heavy diffs" step when to invoke it.
Multi-lens orchestration is now Python-side (`pilot/opencode_review.py`).
Each lens is just a `.md` file; the Python side spawns one subprocess per
lens in parallel and synthesises the merged findings.
That's it — the primary can now `@<name>` it via the Task tool. It stays dormant
(the primary decides when), so adding it costs nothing for small PRs.
1. Create `.opencode/agents/<id>.md` with frontmatter:
```yaml
---
description: One line that names what this lens catches.
mode: subagent
hidden: true
model: headroom/glm-5.2:cloud
temperature: 0.1
permission:
edit: deny
write: deny
bash: "allow" # or narrow: "<cmd>": "allow"
webfetch: allow
task: deny
---
```
Body = the system prompt. End it with the **strict JSON contract** in
`.opencode/skills/lens-orchestration/SKILL.md` (findings shape, `severity_floor`,
no writes outside workdir, prompt-injection reporting). A real lens has
target paths + output schema + tool budget + example findings — not just a
different system prompt.
2. Add one entry to the repo's `.pr-review.json:reviewers[]`:
```jsonc
{ "id": "<id>", "severity_floor": "low", "max_findings": 8 }
```
No Python change. No image rebuild. The orchestrator picks it up next run.
3. (Optional) Tighter defaults: `activation: "off"` to ship-disabled,
`skip_if_all_changed_paths: "docs/**"` to skip when only docs changed,
`hotpath_globs: ["**/queries/**"]` to help triage recognise the lens.
**Built-in lenses** (you can override any of them): `security`, `docs`,
`code-quality`, `tests`, `perf`. Set `reviewers: []` to opt out.
### Add a skill