qvib.pro
RU

~7 min read · everyone · Updated: 2 Jul 2026 · Читать по-русски

Adversarial Verification Beats a Single AI Pass

Why Prisms and Adversarial Verification Beat a Single Pass

In short

One agent that writes the code and then grades its own work is a conflict of interest. In the engine, the result of each step is judged by prisms — independent review angles with the contract "pass/warn/block verdict + findings + one improvement" — and by adversarial-verify: at least two independent "it's done" votes, one of them a skeptic looking for where it breaks. Quest has 13 prisms; five of them are vetoes with weight 2 (security, tenancy, gating, regression, data-integrity): a critical finding from any of them means BLOCK regardless of the other votes. Synthesis is deterministic, a tie is read in favor of safety, and the review→fix loop is capped by an iteration limit and fixes the class of problem rather than a single symptom. This costs more than one pass — which is why it switches on when it matters, not on every trifle.

What it is

One agent that "writes the code and grades its own work" is a conflict of interest. It generated the solution, it evaluates the solution, and it evaluates from the same angle it wrote from. Our engine is built differently: the result of each step passes through prisms (independent review angles) and through adversarial-verify (at least two independent "it's done" votes, one of them a skeptic actively LOOKING for where it breaks).

Один проходСам написал — сам одобрилПропускает целые классы ошибокНезависимые углыУглы не видят чужих вердиктовВето безопасности не растворяется
One self-satisfied pass versus independent angles

A prism isn't an executing agent and isn't a "style persona." It's an independent judge of one artifact from one angle. Its contract: a pass | warn | block verdict + findings with severity + one "here's what I would change." Several prisms hit the artifact independently (fan-out) — none of them sees the others' verdicts — and then synthesis tallies them by vote, weight, and veto.

Why this instead of a single pass

A single pass gives you a single point of view. A model that just wrote a SQL query tends to approve its own query: it's "explaining," not "attacking." Different independent angles with different roles break that blindness — exactly what outside practice with multi-agent systems shows: a panel of reviewers with orthogonal incentives (one penalizes unverifiable claims, another regressions, a third security) gives you signal precisely where they disagree, and their agreement is a strong prior.

Quest has 13 such angles (verified in prismPresets.ts): product, user, security, multi-tenant, subscription gating, accessibility, performance, maintainability, regression, i18n, data integrity, business, design craft. Five of them are veto prisms with weight 2: security, tenancy, gating, regression, data-integrity. A critical finding from any of them equals BLOCK regardless of every other vote. These are invariants promoted to the rank of judge: SQL injection, cross-tenant reads, a hole in billing, a regression in someone else's code, an irreversible operation with no backup — red lines, not topics for discussion.

The synthesis rule is hard-wired and deterministic (from engine.orchestration.synthesize): any critical from a veto prism → BLOCK; otherwise BLOCK if the summed weight of block votes is ≥ the threshold (1 in the base config); a tie → BLOCK (safety wins). Plus verifyVotes: 2 — a step isn't accepted on one "seems fine." Plus loopUntilDry (at most 2 review→fix rounds; the third degrades — per Anthropic and Cloudflare): the class of problem gets fixed rather than a single instance, with the affected angles re-judging until it runs dry; once the cap is hit, it stops and reports the open items to the owner.

13
independent review angles (prismPresets.ts)
5
veto prisms with weight 2: critical = BLOCK
2
independent "it's done" votes (verifyVotes)
2
review→fix rounds at most (loopUntilDry)
The engine's synthesis config; a tied vote → BLOCK in favor of safety

When it switches on

In the Review phase: fanOut distributes the independent chunks and angles across different roles; synthesis tallies the verdicts; reviewLoop fixes the class and re-judges. Every prism is scoped by its own trigger (for example, a11y only fires on ui, data-integrity only on migration), so a small edit doesn't drag in unnecessary angles.

Example: input → what the engine does → result

Input. An engineer added a GET /api/orders/:id route that pulls an order by the id in the URL. It technically works, tests are green.

What the engine does (fan-out across prisms, independently):

  • tenancy (veto, weight 2) asks its rubric question: "Is a resource id taken from client input without an ownership check against the org?" — yes, it is. The query SELECT ... WHERE id = $1 doesn't filter by organization_id. Verdict: BLOCK, severity critical ("cross-tenant reads are reachable").
  • security (veto, weight 2): no injection (it's a bound parameter), but it checks the auth boundary.
  • regression (veto, weight 2): "who else calls the changed code" — clean.
  • perf (weight 1): there's an index on id — the warn is withdrawn.

Synthesis. tenancy returned a critical. Under the hard-wired rule that's a BLOCK regardless of the three other angles saying pass. A single pass by a single agent lets this class of hole (cross-tenant IDOR) into production more often than any other and it costs more than any other — here it's stopped before delivery.

Fan-out across prisms: GET /api/orders/:id
tenancy (veto ×2)BLOCKcritical: no filter on organization_id
security (veto ×2)passno injection, auth boundary checked
regression (veto ×2)passcallers of the changed code — clean
perf (×1)passindex on id exists, warn withdrawn
Synthesis: a critical from a veto prism → BLOCK, even with three passes

The loopUntilDry cycle. The engine fixes not one line but the class: it greps every query of the same shape, adds the tenant filter everywhere it's missing, and has tenancy + regression re-judge. Round 2 comes back dry. The step is accepted by two votes.

Result. The route ships with a tenant filter; the neighboring instances of the same problem are closed along the way; and the report says which requirement was confirmed by which check.

Honest caveat

Today prism verdicts are ADVISORY: the engine instructs the target model to obey the verdict, but on Cursor and AGENTS.md there's no runtime that physically blocks a violation (hard blocking comes only from the Claude hook and the portable git/CI floor — see the article on ENFORCED vs ADVISORY). In a regular (non-server-bound) export the prism rubric text itself sits in the open, so you can read it and adapt it. The value is that the discipline of "independent angles + veto + two votes + a loop until dry" is already assembled, calibrated, and working out of the box — not that you get one self-satisfied pass from one agent.

Sources: