qvib.pro
EN

~4 мин чтения · всем

Почему призмы и adversarial-verify лучше одного прохода

Что это

Один агент, который «пишет и сам себе ставит зачёт», — это конфликт интересов. Он сгенерировал решение, он же его оценивает, и оценивает под тем же углом, под которым писал. Наш движок устроен иначе: результат каждого шага проходит через призмы (независимые углы ревью) и через adversarial-verify (минимум два независимых голоса «готово», один из которых — скептик, который ИЩЕТ, где сломается).

Один проходСам написал — сам одобрилПропускает целые классы ошибокНезависимые углыУглы не видят чужих вердиктовВето безопасности не растворяется
Один самодовольный проход против независимых углов

Призма — это не агент-исполнитель и не «персона-стиль». Это независимый судья одного артефакта под одним углом. Контракт призмы: вердикт pass | warn | block + находки с severity + одно «что бы я изменил». Несколько призм бьют по артефакту независимо (fan-out) — каждая не видит вердиктов других, — а потом синтез сводит их по голосам, весу и вето.

Почему так, а не одним проходом

Один проход даёт один угол зрения. Модель, которая только что написала SQL-запрос, склонна одобрить свой же запрос: она «объясняет», а не «атакует». Разные независимые углы с разными ролями ломают эту слепоту — ровно то, что показывает и внешняя практика мульти-агентных систем: панель ревьюеров с ортогональными стимулами (один штрафует за непроверяемые заявления, другой — за регрессии, третий — за безопасность) даёт сигнал именно там, где они расходятся, а их согласие — сильный приор.

В Quest таких углов 13 (проверено в prismPresets.ts): продукт, пользователь, безопасность, multi-tenant, гейт подписки, доступность, перф, сопровождаемость, регрессия, i18n, целостность данных, бизнес, дизайн-ремесло. Пять из них — вето-призмы весом 2: security, tenancy, gating, regression, data-integrity. Их critical-находка = BLOCK независимо от всех остальных голосов. Это инварианты, поднятые в ранг судей: SQL-инъекция, чтение между арендаторами, дыра в биллинге, регрессия у соседа, необратимая операция без бэкапа — красные линии, а не «обсудим».

Правило синтеза зашито детерминированно (из engine.orchestration.synthesize): любой critical у вето-призмы → BLOCK; иначе BLOCK, если сумма весов block-голосов ≥ порога (в базе = 1); ничья → BLOCK (в пользу безопасности). Плюс verifyVotes: 2 — шаг не принимается по одному «вроде ок». Плюс loopUntilDry (максимум 2 круга «ревью→фикс»; 3-й деградирует — Anthropic/Cloudflare): чинится класс проблемы, а не один инстанс, с пере-судом затронутых углов, пока не «сухо»; после капа — стоп и отчёт владельцу с открытыми пунктами.

Когда это включается

В фазе Review: fanOut раскладывает независимые куски и углы по разным ролям; синтез сводит вердикты; reviewLoop фиксит класс и пересуживает. Каждая призма скоупится своим trigger (например, a11y бьёт только по ui, data-integrity — только по migration) — так на маленькой правке не гоняются лишние углы.

Пример: вход → что делает движок → результат

Вход. Инженер добавил роут GET /api/orders/:id, тянущий заказ по id из URL. Формально работает, тесты «зелёные».

Что делает движок (fan-out по призмам, независимо):

  • tenancy (вето, вес 2) задаёт свой вопрос из рубрики: «Берётся ли id ресурса из ввода клиента без проверки принадлежности к org?» — да, берётся. Запрос SELECT ... WHERE id = $1 не фильтрует по organization_id. Вердикт: BLOCK, severity critical («cross-tenant чтение достижимо»).
  • security (вето, вес 2): инъекции нет (параметр), но проверяет auth-границу.
  • regression (вето, вес 2): «кто ещё зовёт изменённый код» — чисто.
  • perf (вес 1): индекс по id есть — warn снят.

Синтез. У tenancycritical. По зашитому правилу это BLOCK независимо от того, что три остальных угла сказали pass. Один проход одного агента этот класс дыр (IDOR между арендаторами) пропускает в проде чаще всего и стоит дороже всего — здесь он остановлен до сдачи.

Цикл loopUntilDry. Движок чинит не одну строку, а класс: грепает все запросы того же вида, добавляет тенант-фильтр везде, где его нет, и пере-суживает tenancy + regression. Круг 2 — сухо. Шаг принят двумя голосами.

Результат. Роут уходит с фильтром по арендатору; попутно закрыты соседние такие же места; в отчёте — какое требование какой проверкой подтверждено.

Честная оговорка

Сегодня вердикты призм — ADVISORY: движок инструктирует целевую модель подчиниться вердикту, но на Cursor/AGENTS нет рантайма, который физически заблокирует нарушение (жёстко блокирует только Claude-хук и переносимый git/CI-floor — см. статью про ENFORCED vs ADVISORY). И сам текст рубрик призм в обычном (не server-bound) экспорте — plaintext, копируемый. Ценность здесь не в секретности текста, а в том, что дисциплина «независимые углы + вето + два голоса + цикл до сухого» уже собрана, откалибрована и работает из коробки — а не в том, что вы получаете один самодовольный проход одного агента.

Sources: