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).
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.
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 querySELECT ... WHERE id = $1doesn't filter byorganization_id. Verdict: BLOCK, severitycritical("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 — thewarnis 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.
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: