diff --git a/.changes/review/host-run-12505-round5-sweep-wait-4e81c0d2.md b/.changes/review/host-run-12505-round5-sweep-wait-4e81c0d2.md new file mode 100644 index 00000000000..f1feba1517d --- /dev/null +++ b/.changes/review/host-run-12505-round5-sweep-wait-4e81c0d2.md @@ -0,0 +1,7 @@ +--- +bump: patch +--- + +### Fixed + +- The run-everything sweep waits for the `review:fanout-sweep` workflow's completion notification and takes each leaf's text from the returned `raw` array or its findings file, instead of listing or reading the workflow's run directory. Those run-directory reads were denied in eval runs, which made the reviewer-diversity suites invalid. diff --git a/plugins/review/skills/fanout/context/run-everything-mode.md b/plugins/review/skills/fanout/context/run-everything-mode.md index dd93aad862d..ebe069c286e 100644 --- a/plugins/review/skills/fanout/context/run-everything-mode.md +++ b/plugins/review/skills/fanout/context/run-everything-mode.md @@ -15,13 +15,14 @@ Trigger: `$ARGUMENTS` is `run-everything` / `everything` / `all`. Distinct from - **Pilot.** The workflow launches its whole roster in one call, so when `slices` is non-empty, pilot outside it (SKILL.md "Pilot a wide fan-out"): dispatch one slice alone on the main thread as `review:brief-reviewer`, with the slice prompt the workflow would send, and confirm usage remains. Then launch with that slice removed from `slices`, add its output to the orchestrator outputs for step 6's Stage 0, and list it in the `## Surfaces` `Ran` entry. - **Launch** `Workflow({ name: "review:fanout-sweep", args: { diffBase, slices, roles, maxConcurrent, diversity, session, findingsPaths } })`: `findingsPaths` maps `code-reviewer` and `security-reviewer` to the findings paths resolved per [`reviewer-handback.md`](../../../reference/reviewer-handback.md) (omitted, those leaves reply by value), `diffBase` is the step-2 base, `slices` the step-4 slice names, `roles` the map above, `maxConcurrent` an optional integer wave size (clamped to 1-16, default 4), `diversity` the resolved `fanout_diversity` (SKILL.md "Arguments"), except `lens` when it resolved `codex`, and `session` the same alias passed to `/multi-agent:route`, omitted when unknown. - **Bundled files.** The workflow's script is `/workflows/fanout-sweep.js`: `Read` it by that path when its args or returns are in question, never search the plugin directory with `Glob`, `Grep` or `ls`, since it sits outside the repository under review. + - **Wait.** Wait for the sweep's completion notification, without listing or reading its run directory (`journal.jsonl` and the files beside it). - **`codex` diversity.** The panel is the Codex reviewer, not the model tiers: launch with `args.diversity` set to `lens`, since the workflow takes only `lens` or `model` and Codex runs on the main thread. Step 3's two `codex-review.sh` runs, plain and `--adversarial`, are the panel. The surfaces that run are the ones `lens` runs; what `codex` adds is the panel report. Report one line under the `fanout_diversity:` line: `panel: codex ran` when either run printed `codex: ran`, else `panel: codex skipped ()` or `panel: codex failed ()` from the first run's status line, `panel: codex failed (timed out)` when a run timed out or printed no status line, and `panel: codex skipped (permission denied)` when the Bash call was denied. A skipped or failed panel does not stop the sweep: the lens roster still runs, and the `## Surfaces` line names Codex as step 3 says. - **`model` diversity.** The workflow collects the distinct fan-out models in `roles` (orchestrator, worker, verifier, retrieval, first seen first), deduped by the model each resolves to: `inherit` is the `session` alias, and with no `session` it counts as frontier; `fable` and `best` are left out. With two or more it sends the one review prompt to each as `review:lane-verifier`, at the verifier fan-out effort, in place of the per-concern agents and slices. With fewer than two, or no `roles`, it runs `lens` and returns `diversity: "lens"`; report that in `## Surfaces`. When step 3's `codex` surface ran, list it in `## Surfaces` as one more model tier. - **Pointer**: for which model wins when a script's `agent()` call or an Agent dispatch names one and the agent definition says `inherit`, see [Choose a model](https://code.claude.com/docs/en/sub-agents#choose-a-model) and the model paragraph of [Cost](https://code.claude.com/docs/en/workflows#cost). - **As of**: 2026-10-11 - **Recheck trigger**: either section changes where a per-call model ranks against the definition's `model` field. - The workflow returns `diffBase`, `records`, `raw`, `findingsPaths` (the paths it passed on), `nulls`, `ran`, `roles` (the variants it used), `diversity` (the value that ran) and, under `model`, `tiers`. An `error` return (`missing-diff-base`, `bad-diff-base` or `bad-diversity`, with a `next` hint) means nothing was dispatched: fix the input and launch again. -6. **Normalize main-thread.** Gather the Workflow's extracted leaf records + the raw orchestrator outputs; run Stage 0 on the orchestrator outputs (the Workflow only extracted the leaf branch), then Stages 1–4 of `findings-normalization.md` over the combined record set. Reconcile per surface against the Workflow's `raw` array: any surface whose raw output is non-empty but yielded zero extracted records gets Stage 0 re-run main-thread on that raw text, or, for a leaf in `findingsPaths`, on the file at your own copy of its path; whatever still fails to parse goes verbatim into `## Unparsed`. Partial extraction never silently drops a surface. +6. **Normalize main-thread.** Gather the Workflow's extracted leaf records + the raw orchestrator outputs; run Stage 0 on the orchestrator outputs (the Workflow only extracted the leaf branch), then Stages 1–4 of `findings-normalization.md` over the combined record set. Reconcile per surface against the Workflow's `raw` array: any surface whose raw output is non-empty but yielded zero extracted records gets Stage 0 re-run main-thread on that raw text, or, for a leaf in `findingsPaths`, on the file at your own copy of its path; whatever still fails to parse goes verbatim into `## Unparsed`. Partial extraction never silently drops a surface. Take a leaf's text from its `raw` entry's `output` in the result its completion notification names, or from its `findingsPaths` file, never from the workflow's run directory. 7. **Persist** per `findings-file-shape.md` "Findings-writer contract"; prepend the DEGRADED block when the fallback was taken. **Pre-flight gate first:** SKILL.md's pre-flight gate applies to this mode too. The ask-shape check routes a whole-repo security-audit ask to the `leaf-roster.md` "Deep-scan escalation" before any diff resolution, and an unresolvable base ref or an empty change set (including untracked-only) reports and stops before step 1; with nothing diffable, every leaf would diff an empty tree and return nothing. Do NOT stage files.