qvib.pro
EN

~5 мин чтения · профи

Ревью и тесты: как движок сам себя проверяет

Что это

Движок не доверяет собственному «вроде ок». Он проверяет себя двумя независимыми механизмами: призмы (многоугловое ревью артефакта) и тестирование (QA с доказуемыми тестами). Оба экспортируются буквальным рецептом в пакет, чтобы работали даже на слабой модели.

Реализацияшаг плана2 голоса «готово»второй — скептикПризмывето-углыТестыred-firstСдачас пруфами
Самопроверка: два голоса, призмы с вето, тесты red-first — потом сдача

Призмы — независимые критики

Призма — это угол независимой оценки от лица роли, а НЕ агент-исполнитель. Контракт: независимый вердикт pass | warn | block + находки с severity. Рецепт в пакете прямо требует:

Прогони артефакт через углы НЕЗАВИСИМО: каждый угол судит сам и не видит чужих вердиктов.

В каталоге 13 призм. Пять из них — вето-призмы (инварианты, поднятые в ранг судей): security (вето, вес 2), tenancy (вето, вес 2), gating (вето, вес 2), regression (вето, вес 2), data-integrity (вето, вес 2). У каждой призмы есть blockIf — красные линии, и trigger — по каким фазам/артефактам/стеку она включается (a11y — только когда есть UI, data-integrity — только на миграциях).

Синтез вердиктов (детерминированное правило из orchestration.synthesize):

Любой critical у вето-призмы → BLOCK; иначе BLOCK, если сумма весов block-голосов ≥ порога; ничья → BLOCK (в пользу безопасности).

То есть одна security-призма с critical перевешивает любое число «всё хорошо» от остальных.

Оркестрация: adversarial-verify ≥2 голоса

Поверх призм — правило голосов (verifyVotes, в Quest = 2):

ПЕРЕД сдачей шага собери минимум 2 независимых голоса «готово»: первый — твоя реализация; остальные — скептики-ревьюеры, которые ИЩУТ, что сломается и где приукрашено. Один голос «вроде ок» — НЕ готово.

Плюс fan-out: «один пишет — ДРУГОЙ проверяет», и ЗАКОН РЕСУРСА: «лучше сжечь токены на второй угол, чем сдать непроверенное и переделывать».

Ревью до идеала (слой конструктора)

Статус. engine.reviewслой конструктора: поддержан схемой и экспортёром, но в базовый флагманский сид Quest пока не входит (в разработке для флагмана). Призмы и verifyVotes выше — часть базового Quest; описанный здесь цикл полировки вы добавляете сами.

engine.review добавляет планку выше pass/fail: цикл «улучшай → пере-суди призмами», пока нет находки ≥ порога severity (minSeverity) ИЛИ достигнут кап полировки (maxPolish, дефолт 4). Рецепт разделяет DONE (годно к сдаче) и IDEAL (полировать нечего) — «не путай сдал и идеально».

Тестирование — доказуемые тесты (слой конструктора)

Статус. engine.testing (RED-FIRST + мутационный гейт) — слой конструктора: поддержан схемой и экспортёром, но в базовый флагманский сид Quest пока не входит (в разработке для флагмана). Купленный Quest не приносит этот QA-рецепт из коробки; это то, что вы включаете, описывая свой движок в конфигураторе.

engine.testing включает QA-рецепт с четырьмя жёсткими правилами:

  • Тест-план и кейсы выводятся ИЗ критериев готовности (каждый required → минимум один кейс).
  • RED-FIRST: сначала падающий тест, потом код. «Тест, который никогда не падал, не проверил НИЧЕГО.»
  • BANNED — тавтология: тест ОБЯЗАН уметь падать; expect(true).toBe(true) запрещён.
  • Мутационный гейт: прогнать реальный инструмент (StrykerJS для JS/TS, mutmut для Python). Выживший мутант = дыра в тестах. Нет инструмента → FAIL-CLOSED-SKIP (честно: гейт пропущен, а не пройден).
  • Покрытие — только поиск дыр, НЕ цель само по себе.

Артефакты: TEST-PLAN.md и BUG-LOG.md.

Worked-пример

Вход: движок дописал SQL-выборку заказов в multi-tenant backend и говорит «готово». В этом примере движок собран с включённым слоем engine.testing (шаг 5) поверх базового Quest (шаги 1–4, 6).

Что делает движок:

  1. Fan-out (Quest): реализация — одна роль; ревью — другая (скептик).
  2. Призмы независимо (Quest): tenancy смотрит запрос и находит SELECT * FROM orders WHERE id = $1 без organization_id → вердикт block, critical («cross-tenant чтение достижимо»). security проверяет параметризацию — ok. perf отмечает отсутствие индекса — minor.
  3. Синтез (Quest): critical у вето-призмы tenancy → общий BLOCK, несмотря на то что security и perf почти зелёные.
  4. loop-until-dry (Quest): движок чинит КЛАСС — грепает весь модуль на запросы без тенант-фильтра (не только этот), добавляет AND organization_id = $2 везде, пере-судит только tenancy → теперь pass.
  5. Тесты (слой конструктора engine.testing): выводит кейс «запрос юзера B не видит заказы юзера A», пишет его RED-FIRST (сначала падает на старом коде), затем зелёный на новом. Мутационный гейт StrykerJS убивает мутанта, который удалял тенант-условие. Этот шаг доступен, только если вы добавили слой testing.
  6. Второй голос (Quest): скептик-ревьюер подтверждает — 2 независимых «готово».

Результат: артефакт сдан только после того, как вето-призма стала зелёной; при включённом слое testing регрессия ещё и закрыта тестом, способным падать, а мутант убит. Одна такая проверка ловит целый класс cross-tenant утечек, а не один инстанс.

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

Сначала о статусе: призмы, синтез вердиктов и правило голосов verifyVotes — часть базового Quest. Слой полировки engine.review и QA-рецепт engine.testing (RED-FIRST + мутационный гейт) — слои конструктора, во флагманский сид пока не входят (в разработке). Мутационный гейт из worked-примера работает, только если вы этот слой добавили.

Дальше о границе гарантии. Мутационный гейт — ENFORCED только там, где реальный инструмент запущен (есть код выхода); иначе честный FAIL-CLOSED-SKIP. Синтез призм и правило голосов — детерминированное правило, но их исполнение на Cursor/AGENTS без рантайма остаётся ADVISORY (модель следует рецепту, код выхода не блокирует). На Claude Code и в Cursor часть этого можно закрепить hook'ом; git-pre-commit/CI дают ENFORCED-пол на любом таргете. Конфигуратор помечает эту границу честно.