| name | adversarial-verify |
| description | The ensemble verification harness: split a conclusion, fix, or design into checkable claims, classify each to a pre-written probe row, spawn N independent voters (N from the tier: 1/3/5), and aggregate mechanically. Trigger: a conclusion/fix/design is about to ship, a core path changed, or a pipeline step names an adversarial pass. Manual invocation: /adversarial-verify. |
adversarial-verify — the ensemble harness
This skill RUNS the harness; it performs no verification itself. Voters execute
pre-written probes — never invented ones — and a script, not a model, merges the
votes. Mechanics: docs/architecture/mechanisms/M2-ensembles.md (votes) and
M8-refute-by-probe.md (probes).
Step 1 — claims checklist
Break the subject into individually checkable claims with file/line anchors:
"the cache at foo.py:42 isn't taking effect", "this module has no callers".
A vague "it looks right overall" cannot be verified — split it until each claim
names one artifact and one expected fact.
Step 2 — classify each claim to a probe row (lookup, not judgment)
Load references/probe-tables.md — one file, the whole
catalog. Match each claim to a row by the row's match pattern. A claim matching no
row → STOP for that claim and escalate per docs/architecture/escalation-ladder.md
row 11 (probe-library gap → R2: a pinned model authors the probe once). Never
improvise a probe inline.
Step 3 — read N from the tier, spawn N voters
N = prescription.votes in .maestro/evidence/<diffhash>/sizing.json (T1=1, T2=3,
T3=5). Artifact missing → run bash ${CLAUDE_PLUGIN_ROOT}/hooks/lib/sizing.sh
first. Voting is not optional and N is never chosen by feel.
Each voter is a fresh agent (Task tool, model: haiku) that receives:
| A voter receives | A voter never receives |
|---|
| the identical rubric: claims + probe rows + the verdict schema | another vote's verdict or transcript |
| the LITERAL artifact under test — never a paraphrase | your working context (fresh eyes) |
read access to .maestro/evidence/<diffhash>/ | the aggregate of any prior round |
Voter prompt (fixed — fill only the slots):
You verify; you never fix. Default every claim to `failed`.
For EACH claim, run its probe EXACTLY as written in its row. Capture the real
command line, output excerpt, and exit code into the evidence field.
A claim resting on a runnable artifact (a query, command, config, or snippet in a
doc) is verified by running the LITERAL shipped text — extract it from the file;
a re-typed "equivalent" silently repairs the defect you were sent to find.
Flip failed → met ONLY with the probe output attached. A probe you cannot run =
failed, with the error as the output excerpt.
Write your verdict to .maestro/evidence/<DIFFHASH>/votes/vote-<I>.json and output it.
CLAIMS + PROBE ROWS: <paste>
SCHEMA: <the verdict schema from references/probe-tables.md>
Step 4 — aggregate mechanically (no model in the loop)
bash ${CLAUDE_PLUGIN_ROOT}/hooks/lib/aggregate_votes.sh <diffhash>
The aggregator computes per-criterion strict majority, applies the evidenced-failed
veto (one failed with attached probe output overrides any majority met), and
writes .maestro/evidence/<diffhash>/aggregate.json with a split field.
| Aggregate outcome | What you do |
|---|
every criterion met, no split | claims are deliverable; the verdict stays in the bundle |
| split at T2 (2–1 on any criterion) | escalate R1: re-run with 5 voters (ladder row 2) |
| split at T3 (≥2 of 5 dissent) | escalate R2: one pinned sonnet-class pass supersedes (ladder row 1) |
any evidenced failed | that claim is overturned — DROP it; never patch it up |
| more claims overturned than survived | the frame is wrong; rethink, don't patch claim by claim |
Step 5 — record
The gates read the bundle, so after aggregation record the ledger line:
bash ${CLAUDE_PLUGIN_ROOT}/hooks/lib/ledger.sh mark adversarial pass <ref> "<claims that survived>"
votes/vote-<i>.json + aggregate.json stay in the bundle; the commit gate
validates their existence, schema, and vote count against sizing.json.
What changed from the frontier version
- "Verify from multiple perspectives (if it matters)" is deleted: N always comes
from the tier. Voting is the default, not a stakes call.
- "Assume 60% wrong and go invent a counterexample" is deleted: voters execute probe
rows. Refute-first survives as the default-
failed rule plus the evidenced veto.