# 03. Quality Gates (QG) **Назначение:** превратить «согласовать у Иванова» в машинно-проверяемые ворота между этапами. Без зелёного QG задача физически не может уйти на следующий этап — git hook и CI этого не позволят. --- ## Простым языком Quality Gate — это шлагбаум на выходе с каждого этапа. Шлагбаум открывает не человек, а робот, который проверяет: - лежат ли все нужные файлы там, где они должны лежать; - проходят ли они формальную проверку (валидный YAML, заполненные секции, ссылки на оригиналы); - зелёный ли CI; - поставил ли кто-то нужный «штамп» (reaction `:approved:` в Plane от пользователя с правом утверждения). Если что-то не так — робот не пускает дальше и возвращает задачу с конкретным списком замечаний. Никакого «договорились в чате», никакого «потом доделаем». Это и есть главная защита от того, что агент **сам себе** поставит галочку «готово». --- ## Принципы QG 1. **Всё машинно-проверяемо.** Если критерий нельзя проверить скриптом или линтером — это не QG, а пожелание. 2. **Каждое QG имеет владельца.** «Кто чинит, если QG красный» — однозначно (см. таблицу ниже). 3. **QG не пропускается.** Нет режима «давайте этот раз без проверки». Если действительно есть исключительный случай — заводится отдельная процедура `qg-override` с явным человеческим approve и записью в audit-лог. 4. **Reactions — это допустимая форма подписи.** `:approved:` от пользователя с ролью `Stakeholder` в комментарии Plane или PR — валидный «штамп». Их собирает CI через API. 5. **Обратная совместимость не оправдание.** Если изменение требует апдейта `CLAUDE.md`, миграции, новой переменной окружения — она часть QG, не «потом». 6. **Время на 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//01-brd.md` - `docs/work-items//02-trz.md` - `docs/work-items//03-acceptance-criteria.md` - `docs/work-items//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/-*` ИЛИ комментарий в Plane с подписью. **Что делать если красный:** агент-Analyst исправляет, делает новый коммит. CI пере-проверяет. --- ## QG-2: Архитектура → (Дизайн или Разработка) **Что проверяет:** архитектурные решения зафиксированы и покрывают требования. **Машинные проверки (`scripts/lint-adr.sh` + `scripts/req-coverage.py`):** ADR-проверки: - В `docs/work-items//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//11-design/wireframes.md` - `docs/work-items//11-design/mockups.md` - `docs/work-items//11-design/states.md` - `docs/work-items//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` (контейнер): нет критичных CVE - `bandit` (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//12-review.md` есть запись с вердиктом `approved` - Frontmatter `12-review.md` содержит: - `reviewer_findings`: список (P0/P1 = blocker; P2/P3 — допустимы и описаны) - `compliance_with_trz: true` - `compliance_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//13-test-report.md` создан, frontmatter `verdict: 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` создан (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. Для этого: 1. В Plane создаётся отдельный Work Item типа `qg-override` с: - `parent` = Work Item с проблемой - `description` = причина override и список пропускаемых QG - reaction `:approved:` от пользователя с ролью `Owner` workspace 2. Override логируется в `docs/operations/qg-overrides.log` (CI-скрипт пишет автоматически) 3. После инцидента — обязательная ретроспектива и закрытие 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 — целиком машинные. Это и есть **«ворота, которые нельзя забыть»**.