20 KiB
03. Quality Gates (QG)
Назначение: превратить «согласовать у Иванова» в машинно-проверяемые ворота между этапами. Без зелёного QG задача физически не может уйти на следующий этап — git hook и CI этого не позволят.
Простым языком
Quality Gate — это шлагбаум на выходе с каждого этапа. Шлагбаум открывает не человек, а робот, который проверяет:
- лежат ли все нужные файлы там, где они должны лежать;
- проходят ли они формальную проверку (валидный YAML, заполненные секции, ссылки на оригиналы);
- зелёный ли CI;
- поставил ли кто-то нужный «штамп» (reaction
:approved:в Plane от пользователя с правом утверждения).
Если что-то не так — робот не пускает дальше и возвращает задачу с конкретным списком замечаний. Никакого «договорились в чате», никакого «потом доделаем».
Это и есть главная защита от того, что агент сам себе поставит галочку «готово».
Принципы QG
- Всё машинно-проверяемо. Если критерий нельзя проверить скриптом или линтером — это не QG, а пожелание.
- Каждое QG имеет владельца. «Кто чинит, если QG красный» — однозначно (см. таблицу ниже).
- QG не пропускается. Нет режима «давайте этот раз без проверки». Если действительно есть исключительный случай — заводится отдельная процедура
qg-overrideс явным человеческим approve и записью в audit-лог. - Reactions — это допустимая форма подписи.
:approved:от пользователя с рольюStakeholderв комментарии Plane или PR — валидный «штамп». Их собирает CI через API. - Обратная совместимость не оправдание. Если изменение требует апдейта
CLAUDE.md, миграции, новой переменной окружения — она часть QG, не «потом». - Время на QG ограничено. Если QG висит красный больше SLA — эскалация в Plane.
Сводная таблица всех QG
| QG | Между этапами | Чья ответственность | Чем проверяется | SLA до устранения |
|---|---|---|---|---|
| QG-0 | Inception → Analysis | Webhook handler | plane-webhook-validator |
n/a (синхронно) |
| QG-1 | Analysis → Architecture | Analyst | lint-spec.sh + reaction-checker |
24h |
| QG-2 | Architecture → Design/Dev | Architect | lint-adr.sh + req-coverage |
24h |
| QG-3 | Design → Development | Designer | lint-design.sh + token-check |
24h |
| QG-4 | Development → Review | Developer | CI: lint+type+unit+integration+build | 8h |
| QG-5 | Review → Test | Reviewer | GitHub/Gitea API: approve + 0 unresolved | 4h |
| QG-6 | Test → Deploy | Tester | CI на preview: e2e + visual + a11y + perf | 8h |
| QG-7 | Deploy (test) → Deploy (prom) | Deployer/CI | smoke + healthcheck + user approval | 4h |
| QG-final | Done | Deployer/CI | uptime 10min + user :approved: финала |
1h |
QG-0: Постановка → Анализ
Что проверяет: валидность Work Item в Plane.
Технически:
titleсуществует, длина 5–80 символовdescriptionсуществует, ≥3 предложений (≥150 символов)projectвалиден (есть в Plane)priority∈ {low, medium, high, urgent}- (опционально)
labelsсоответствуют известному словарю (area:*,type:*)
Реализация: Plane webhook → scripts/plane-webhook-validator.py. При успехе — создаются ветка и подзадачи. При неуспехе — Work Item получает комментарий «не хватает X», статус blocked.
Кто чинит: заказчик (человек) дополняет Work Item.
QG-1: Анализ → Архитектура
Что проверяет: артефакты этапа Анализа полны и согласованы.
Машинные проверки (scripts/lint-spec.sh + scripts/lint-test-plan.sh):
Обязательные файлы существуют:
docs/work-items/<id>/01-brd.mddocs/work-items/<id>/02-trz.mddocs/work-items/<id>/03-acceptance-criteria.mddocs/work-items/<id>/04-test-plan.yaml
Frontmatter валиден:
typeсоответствует имени файла (type: brdдля01-brd.mdи т.д.)plane_idсовпадает с папкойstatus: approvedдля всех
Семантические проверки:
- В
02-trz.mdкаждоеREQ-встречается ≥1 раз - В
03-acceptance-criteria.mdдля каждогоREQ-F-*есть хотя бы одинAC-со ссылкой[REQ-F-N] - В
04-test-plan.yamlдля каждогоAC-есть хотя бы одинTC-(полеcoverage) - Все ссылки из frontmatter
related:указывают на существующие файлы
Бизнес-проверки (от человека):
- На подзадаче «Анализ» в Plane стоит reaction
:approved:от пользователя с рольюStakeholder
Реализация: GitHub Action job qg-analysis, триггер — push в ветку feature/<id>-* ИЛИ комментарий в Plane с подписью.
Что делать если красный: агент-Analyst исправляет, делает новый коммит. CI пере-проверяет.
QG-2: Архитектура → (Дизайн или Разработка)
Что проверяет: архитектурные решения зафиксированы и покрывают требования.
Машинные проверки (scripts/lint-adr.sh + scripts/req-coverage.py):
ADR-проверки:
- В
docs/work-items/<id>/06-adr/есть хотя бы один файлadr-NNNN-*.md - Каждый ADR имеет валидный frontmatter (
adr_id,status,date,authors) - Каждый ADR имеет секции:
## Context,## Decision,## Alternatives considered,## Consequences superseded_by(если есть) указывает на существующий ADR
Покрытие требований:
- Скрипт
req-coverage.pyсобирает всеREQ-из ТЗ и проверяет, что для каждого:- либо есть упоминание в ADR данной задачи,
- либо есть явная пометка в
06-adr/no-decision-needed.mdсо списком таких REQ.
- Если есть «голые» REQ — QG красный.
Диаграммы:
- Все
.mmdвdocs/architecture/рендерятся без ошибок (Mermaid CLI).
UI-флаг:
- Если в ТЗ
ui_affected: true, обязателен файл09-ui-requirements.md. Еслиfalse— Designer-этап автозакрывается с лейбломskip:not-applicable.
Инфраструктура:
- Если
07-infra-requirements.mdупоминает новые сервисы/переменные —.env.exampleиdocker-compose.ymlуже обновлены (CI проверяет diff).
Реализация: GitHub Action job qg-architecture. При зелёном — лейбл PR меняется на stage:design или stage:dev (в зависимости от UI-флага).
Что делать если красный: Architect добавляет недостающие ADR / уточнения.
QG-3: Дизайн → Разработка (опциональный)
Что проверяет: дизайн полный и соответствует UI-требованиям.
Машинные проверки (scripts/lint-design.sh):
Файлы:
docs/work-items/<id>/11-design/wireframes.mddocs/work-items/<id>/11-design/mockups.mddocs/work-items/<id>/11-design/states.mddocs/work-items/<id>/11-design/a11y.md
Покрытие:
- Каждое UI-требование из
09-ui-requirements.mdупомянуто вmockups.md(по ID).
Состояния:
- В
states.mdдля каждого экрана описаны минимум:loading,empty,error,success. Если какое-то состояние неприменимо — явная пометкаnot-applicable: <причина>.
Дизайн-токены:
- Линтер парсит
mockups.md(если есть встроенные стили) и проверяет, что цвета/шрифты — только изdocs/design/design-tokens.json. Любой произвольный hex/font — fail.
A11y чек-лист:
- В
a11y.mdвсе обязательные пункты отмечены (контраст, ARIA, клавиатурная навигация, focus order).
Бизнес-approve:
- Reaction
:approved:от стейкхолдера на подзадаче «Дизайн» в Plane.
Реализация: GitHub Action job qg-design. Запускается, только если этап не skip:not-applicable.
Что делать если красный: Designer дорабатывает.
QG-4: Разработка → Code Review
Что проверяет: код, собирается, тесты зелёные, документация обновлена.
Машинные проверки (CI pipeline ci.yml):
Сборка и линт:
make lint— все линтеры (eslint, ruff, mypy, тип-чекеры) — без ошибокmake build— успешная сборка- Никаких новых TODO/FIXME в diff (linter
no-new-todos.sh)
Тесты:
make test— все тесты зелёные- Покрытие: новый код имеет coverage ≥ 80% (
check-coverage.sh) - Coverage delta всего проекта ≥ 0% (
coverage-delta.shсравнивает с main)
Безопасность:
trivy(контейнер): нет критичных CVEbandit(Python) илиnpm audit(JS): нет критичных- secret-scan (gitleaks): нет утечек
Документация:
CHANGELOG.mdобновлён (есть запись для этой задачи)- Если есть API-изменения —
docs/api/openapi.yamlобновлён CLAUDE.mdактуален (если изменился стек или команды)
PR-правила:
- Заполнен PR template (
.github/PULL_REQUEST_TEMPLATE.md):- ссылка на ТЗ ✓
- чек-лист DoD заполнен ✓
- заметка о breaking changes (даже если их нет — явное «нет») ✓
- Лейбл
stage:devстоит - Размер PR ≤ 1500 строк diff (если больше — предупреждение, но не блокировка)
Реализация: GitHub Action ci.yml — обязательная проверка на PR.
Что делать если красный: Developer чинит.
QG-5: Code Review → Test
Что проверяет: ревью прошло, нет открытых вопросов.
Машинные проверки (Forge API через scripts/check-review.sh):
- В PR хотя бы 1 review со статусом
APPROVED - Reviewer ≠ Developer (проверка через автора коммитов и автора review)
- 0 review-комментариев в статусе
unresolved - В
docs/work-items/<id>/12-review.mdесть запись с вердиктомapproved - Frontmatter
12-review.mdсодержит:reviewer_findings: список (P0/P1 = blocker; P2/P3 — допустимы и описаны)compliance_with_trz: truecompliance_with_adr: true
Если Reviewer-агент даёт request-changes — PR возвращается в stage:dev.
Реализация: GitHub Action qg-review запускается на event pull_request_review.
Что делать если красный: Developer вносит правки.
QG-6: Тестирование → Внедрение
Что проверяет: полный регресс на preview-окружении, включая UI.
Машинные проверки (CI workflow preview.yml + qg-test.yml):
Окружение:
- Preview-окружение поднялось из текущей ветки (Docker Compose в CI)
- Healthcheck preview-сервиса зелёный
Функциональные тесты:
- Все unit/integration ещё раз зелёные
- Все e2e (Playwright) зелёные
- Все TC из
04-test-plan.yamlзапущены (поautomation.toolиautomation.file)
UI-тесты:
- Visual regression: 0 нерассмотренных diff'ов (либо явное обновление baseline в коммите)
- a11y (axe-core): 0 нарушений уровня A и AA
- Cross-browser: e2e прошли в Chromium, Firefox, WebKit
Производительность (если есть NFR в ТЗ):
- p95 latency не превышает порог из ТЗ
- Lighthouse score (для UI) ≥ согласованного
Безопасность:
- Trivy / npm audit на собранном образе — нет критичных
- Базовая OWASP-проверка через ZAP baseline (если применимо)
Артефакты:
docs/work-items/<id>/13-test-report.mdсоздан, frontmatterverdict: pass- Скриншоты сохранены в
13-test-report/screenshots/ - Логи CI прикреплены к PR
Баги:
- Если найдены — заведены в Plane с лейблом
bug:found-by-qa, привязаны к Work Item parent
Реализация: GitHub Action qg-test.yml, триггер — лейбл stage:test.
Что делать если красный: Tester заводит баги, PR возвращается в stage:dev. После фикса — снова QG-4 → QG-5 → QG-6.
QG-7: Внедрение в test → Внедрение в prom
Что проверяет: деплой в test прошёл корректно, smoke на test зелёный, есть человеческий approve.
Машинные проверки (deploy-test.yml + qg-deploy-test.sh):
Деплой:
- merge в
mainвыполнен (squash или rebase согласно проекту) - tag
v<X.Y.Z>создан (semver на основе типа commit'а) - CI задеплоил в test-окружение без ошибок
- Healthcheck test-окружения зелёный 5 минут после деплоя
- Smoke-тесты на test зелёные (минимальный набор из
tests/smoke/)
Approve:
- В Plane на подзадаче «Внедрение» стоит reaction
:approved:от пользователя с рольюStakeholder(deployment approval)
Реализация: GitHub Action deploy-test.yml, далее ждёт approval-event из Plane.
Что делать если красный: Deployer-агент анализирует deploy log, при тривиальной проблеме — фикс и retry. При нетривиальной — эскалация (issue в Plane, лейбл incident).
QG-final: prom → Done
Что проверяет: prom стабилен после деплоя.
Машинные проверки (deploy-prom.yml + qg-final.sh):
Деплой:
- CI задеплоил в prom без ошибок
- Healthcheck prom-окружения зелёный 10 минут после деплоя
- Smoke-тесты на prom зелёные
- Метрики: error rate, latency не выросли больше чем на согласованный порог за 10-минутное окно
- Нет открытых алёртов в Prometheus/Grafana (новых, привязанных по времени к деплою)
Финальный approve:
- В Plane на Work Item стоит reaction
:approved:от стейкхолдера (financial close)
При выполнении — Work Item автоматически закрывается, статус Done.
Override-процедура (исключения)
В исключительных случаях (например, hotfix во время инцидента) можно пропустить QG. Для этого:
- В Plane создаётся отдельный Work Item типа
qg-overrideс:parent= Work Item с проблемойdescription= причина override и список пропускаемых QG- reaction
:approved:от пользователя с рольюOwnerworkspace
- Override логируется в
docs/operations/qg-overrides.log(CI-скрипт пишет автоматически) - После инцидента — обязательная ретроспектива и закрытие override-Work Item с заполненным
13-test-report.md(т.е. техдолг учтён)
Override — не способ работать «быстрее». Это аварийный выход. Использование override чаще, чем 1 раз в месяц, — сигнал, что процесс сломан.
Метрики QG (для дашборда)
Снимаются автоматически из CI и Plane:
- QG pass-rate first try — % случаев, когда QG прошёл с первой попытки. Цель: ≥80%.
- Время простоя в красном QG — медиана и p95. Цель: p95 ≤ SLA.
- QG retry count — сколько раз задача возвращалась на тот же этап. Цель: ≤2 для P1+ задач.
- Override count — количество QG-override в месяц. Цель: ≤1.
- Время от Inception до Done (lead time) — DORA метрика.
Эти метрики пишутся CI в Prometheus и визуализируются в Grafana (или отдельный простой дашборд на Plotly/Streamlit).
Чем эта схема отличается от «обычного DoD-чек-листа»
В типичной команде «Definition of Done» — это галочки в Confluence, которые ставит человек: «тесты написал ✓», «доку обновил ✓». Проблема: галочки ставит сам исполнитель, перед лицом дедлайна.
Здесь:
- Галочка = результат автоматической проверки.
- Кто ставит галочку — не имеет права изменить условия проверки в текущей задаче.
- Reactions от человека — лимитированы только бизнес-approve (когда машина не может проверить); технические QG — целиком машинные.
Это и есть «ворота, которые нельзя забыть».