1. Quality gate — не просто список команд
Когда разработчик впервые слышит про quality gate, у него часто возникает очень житейская мысль: «Quality gate — это же CI, который гоняет тесты и линтер». Мысль понятная, но неточная. Harness — набор инструментов обратной связи. Gate — граница решения, через которую изменение либо проходит, либо нет.
Если совсем упростить, harness — это домашний ящик с инструментами: отвёртка, мультиметр, фонарик, запасной предохранитель. Помогает понять, что происходит. Quality gate — турникет на входе в стадион: не «что у меня под рукой», а «пускаем дальше или нет». Отвёртка полезная, но турникет из неё так себе.
| Вопрос | Verification harness | Quality gate |
|---|---|---|
| Главный смысл | Дать обратную связь во время работы | Принять решение, можно ли двигать change дальше |
| Когда используется | Локально, по ходу разработки | На границе PR, merge, release, demo |
| Что включает | Любые полезные сенсоры: tests, lint, type-check, build, static analysis | Только те проверки и условия, которые реально влияют на проход |
| Последствие падения | Разработчик видит проблему и чинит | Изменение останавливается на gate |
| Тон разговора | «Вот что мы заметили» | «Пока это не пройдёт, дальше нельзя» |
Для Commerce OS это различие особенно хорошо видно на реальном сценарии. Представьте PR, который меняет сортировку refund-запросов в support inbox. Локально вы прогоняете unit-тесты, integration-тест, линтер, compile, быстрый smoke check интерфейса — всё это harness. Gate отвечает на другой вопрос: достаточно ли пройденного, чтобы PR имел право идти в main. Не всё локальное обязано блокировать; и наоборот — часть правил gate про коллективное доверие к change.
2. Место quality gate в модели review и verification
Здесь чаще всего путаются не потому, что идея сложная, а потому что рядом живут две разные шкалы: review-границы — кто смотрит change и решает, идёт ли он дальше, и verification — какие сенсоры дают evidence и где запускаются. Совпадение номера ничего не значит: Layer 2 review и L2 verification — разные вещи.
Quality gate относится к Layer 2 review — слою, где CI и другие gate-механизмы решают, может ли change пройти. Это не L2 verification — выбор типов тестов — и не L4 verification — когда локальные сенсоры уже автоматизированы в CI.
Ниже — короткая карта, чтобы не воевать с терминологией.
| Обозначение | Шкала | Что это значит | Пример |
|---|---|---|---|
| Layer 1 review | review | Локальный PR review | Вы сами читаете diff, запускаете reviewer-agent, смотрите тесты |
| Layer 2 review | review | CI / gate review | Quality gate решает, можно ли двигать PR дальше |
| Layer 3 review | review | Team approval gate | Команда отдельно одобряет чувствительные изменения |
| L2 verification | verification | Дизайн тестов | Решаем, нужны unit, integration, API или regression tests |
| L4 verification | verification | CI-интеграция сенсоров | Те же tests/lint/build уже гоняются автоматически |
Это можно увидеть и как схему:
flowchart LR
A[Layer 1 review
локальный PR review] --> B[Layer 2 review
quality gate]
B --> C[Layer 3 review
team approval]
D[Verification evidence
tests lint build scans] --> B
Ключевая мысль здесь очень практическая: gate — решение поверх evidence, а не сами тесты и линтеры. Поэтому «у нас есть CI, значит, есть quality gate» — не аргумент: бывает CI на десять задач, а какие из них блокируют merge, а какие просто моргают в стороне, ответить некому. Это не gate, а витрина электроники.
3. Первый слой: deterministic checks
Прежде чем добавлять умные semantic reviews, агента-рецензента и вообще всё красивое, gate должен стоять на твёрдом полу — на deterministic checks: проверках с воспроизводимым бинарным результатом, зелёный или красный. Без них всё остальное — интеллектуальный туман с ароматом «мне кажется».
Для Commerce OS типичный первый слой выглядит вполне приземлённо: build, compile или type-check, тесты, lint, базовые security/secret scans. Иногда туда же dependency audit — зависит от того, обязана ли проверка блокировать.
Удобно мыслить так.
| Проверка | Зачем она в gate | Типичный статус |
|---|---|---|
|
Показывает, что проект вообще собирается | must-pass |
| Unit / integration tests | Подтверждают ключевое поведение и отсутствие регрессии | must-pass |
| Lint / formatting | Убирают базовый шум и несогласованность | обычно must-pass |
| Secret scan | Ловит опасные утечки до merge | must-pass |
| Coverage delta | Полезный сигнал, но не всегда повод блокировать | informational |
| Тяжёлый smoke / exploratory check | Может быть дорогим и редким | чаще informational или manual |
Очень важный нюанс: не тащите в gate всё, что умеет harness. Медленный smoke-тест хорош для предрелизной уверенности, но если каждый PR будет ждать его вечность, команда возненавидит и тест, и саму идею качества. Gate строгий, но не истеричный.
Небольшой фрагмент для QUALITY_GATES.md может выглядеть так.
## Must-pass (детерминированные) - backend build: green - unit + integration tests: 100% pass - frontend lint: no violations - frontend type-check: clean - secret scan: no findings
Это скучно? Да. Но production-инциденты тоже часто очень скучные. Поэтому deterministic-слой идёт первым: он не пытается быть умным, он пытается быть надёжным.
4. Второй слой: AI-assisted semantic review
После deterministic-слоя можно поднимать второй этаж — AI-assisted semantic review. Проверяют не «собирается ли проект», а смысловые риски: scope creep, пропущенные edge cases, подозрительные изменения в API, слишком широкий diff, слабую regression-защиту, странные правки в критичном коде. Как раз та зона, где линтер бессилен, а reviewer-agent замечает проблему.
Если reviewer-agent у вас уже живёт в локальном review, логика та же — просто теперь она поднимается на gate-уровень. Причём иногда не в одиночку: на чувствительном diff параллельно запускают security reviewer, performance reviewer, reviewer по тестам и reviewer по архитектуре. Это parallel multi-agent review на уровне gate.
Пример короткого консолидированного отчёта:
### Summary AI-ревью - security reviewer: критичных находок нет - test reviewer: нет regression test для пустой refund-очереди - performance reviewer: изменение запроса выглядит безопасно - architecture reviewer: diff не выходит за согласованный scope
Здесь есть принцип, который нельзя размывать: AI-assisted review остаётся advisory, даже когда reviewer'ов несколько и они работают параллельно. Консолидированный отчёт — материал для решения, не само решение.
Почему так? Потому что semantic review по своей природе не детерминирован: один reviewer-agent даст ложноположительное замечание, другой переоценит риск. Сделайте его must-pass — pipeline станет красным по причинам уровня «агенту не понравилось имя функции». Это уже не quality gate, а литературный кружок с блокировкой merge.
Запускать такой review можно по-разному. Один путь — локальная команда reviewer-агентов, которую мы собирали раньше в курсе. Второй — облачное ревью: команда reviewer'ов в управляемой среде (условно /ultrareview или аналогичная команда; точное имя и доступность меняются от версии к версии), которая гоняет многоагентный анализ и возвращает аннотированный diff. Где оно уместно и где его границы — разбираем в следующих уровнях курса как пятый слой review-стека.
На уровне второго слоя ценность облачного ревью — в расширенном контексте: локальный reviewer-subagent видит только diff и связанные файлы, а агент с большим контекстом замечает проблемы между модулями — например, что новый endpoint в orders нарушает контракт, описанный в другом месте кодовой базы. По правам доступа это отдельная история со своей моделью разрешений, а для чувствительных PR держите в голове и местонахождение данных — этим темам в курсе посвящены отдельные уровни дальше.
5. Must-pass и informational по делу
Одна из самых вредных вещей, которые можно сделать с quality gate, — свалить блокирующие и неблокирующие сигналы в одну кучу. Дальше — знакомая корпоративная комедия: в CI всё красное, половину никто не читает, вторую «временно игнорируют», а потом не помнят, какой красный был настоящим. Если система всё время кричит, ей перестают верить.
Поэтому у каждого check должен быть явный статус: must-pass или informational — не где-то в голове у тимлида, а прямо в артефакте.
Вот типичный расклад для Commerce OS.
| Check | Статус | Почему |
|---|---|---|
| Build / compile / type-check | must-pass | Без этого change просто технически нестабилен |
| Unit / integration tests | must-pass | Это базовое доказательство корректности |
| Secret scan | must-pass | Утечки нельзя пускать «ну потом поправим» |
| Reviewer approval | must-pass | Gate не должен жить без человека |
| Coverage delta | informational | Полезный сигнал, но не каждый спад критичен |
| Reviewer-agent findings | informational | Semantic guidance, а не автоматическое вето |
| Parallel multi-agent review | informational | Расширяет обзор, но не блокирует само по себе |
Хорошее правило звучит так: must-pass — то, без чего change не идёт дальше в принципе. Informational обязано быть прочитано и понято, но не блокирует merge. Иногда informational finding приводит к ручному стопу — но это решение человека, а не наказание от AI-проверки.
Именно на этом месте команда обычно взрослеет: пока проверки не размечены, кажется, что «чем больше красного, тем больше качества», а на деле качество растёт, когда красный редкий и значит «стой, здесь проблема».
6. Explainable gate: проверка объясняет падение
Есть простой и очень болезненный анти-паттерн: pipeline падает, разработчик видит job failed — и всё. Непонятно, какая проверка упала, где лог, есть ли смысл в rerun. Такой gate как коллега, который подбегает, кричит «всё сломано!» и убегает пить кофе. Формально информация передана — практически лучше бы молчал.
Поэтому хороший gate должен быть объяснимым. Если check падает, из сообщения понятно как минимум четыре вещи: что именно упало, где evidence, в чём вероятная причина и когда rerun имеет смысл.
Мини-шаблон можно зафиксировать прямо в QUALITY_GATES.md:
## Контракт сообщения об ошибке - check: <name> - status: failed - evidence: <log path / report / artifact> - likely cause: <short explanation> - rerun condition: <when rerun makes sense>
А применённый вариант может выглядеть так:
- check: integration-tests - status: failed - evidence: build/reports/tests/integration/index.html - likely cause: refund sorting changed null-handling in inbox query - rerun condition: only after code or fixture fix
Почему это важно? Потому что gate — не только stop-сигнал, но и часть рабочего цикла. Понимаете, где ошибка, — быстро чините change и двигаетесь дальше. Не понимаете — начинается серия магических повторных запусков: люди надеются, что красный сам устанет и станет зелёным. Обычно красный, к сожалению, выносливее.
7. Собираем QUALITY_GATES.md для Commerce OS
Теперь давайте заземлим всё это в базовую версию. Команда Commerce OS чинит порядок refund-запросов в support inbox: изменение небольшое, но чувствительное — затронуты backend-логика, тесты и UI-фильтрация. Нужен gate, который не изображает строгого охранника, а формулирует правила прохода. Ниже — базовый skeleton; дальше его расширяют секциями про docs, release candidate и recovery policy.
# QUALITY_GATES.md ## PR -> main ### Must-pass (детерминированные) - backend build: green - unit + integration tests: 100% pass - frontend lint: no violations - frontend type-check: clean - secret scan: no findings ### Must-pass (человек) - 1 reviewer approval after diff review ### Информационные - coverage delta: warn if drops > 2% - reviewer-agent semantic review - parallel multi-agent review: - security reviewer - performance reviewer - test reviewer - architecture reviewer ### Контракт сообщения об ошибке - check name must be explicit - each failed check must link to evidence - rerun allowed only if condition is stated
Обратите внимание на две вещи: AI-слой здесь явно отделён от must-pass, а reviewer approval стоит в gate отдельно от deterministic-блока. Это важно: человек не заменяет тесты, тесты не заменяют человека.
Если gate подключён к CI, это может выглядеть так:
jobs:
deterministic:
steps:
- run: ./gradlew check
- run: npm run lint && npm run typecheck
ai_review:
continue-on-error: true
steps:
- run: claude -p "Проверь текущий diff и верни semantic findings"
Точные флаги non-interactive режима и интеграция с Claude Code меняются от версии к окружению — важна не магическая строка, а архитектура: blocking deterministic job отдельно, advisory AI-review отдельно.
Если теперь вернуться к нашему PR про refund inbox, логика становится очень прозрачной. Пока build и tests не зелёные, турникет закрыт. Reviewer-agent нашёл риск, test reviewer подсветил отсутствие regression test — это не «автоматический запрет», а повод человеку сказать: «Стоп, сначала добавьте проверку». А когда deterministic-слой зелёный, human review есть, AI findings поняты, change проходит не потому, что «вроде нормально», а потому, что gate это формально и объяснимо подтвердил. В этот момент delivery mechanics превращается в delivery reliability, а QUALITY_GATES.md из красивого документа становится рабочим правилом команды.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ