Files
wiki/tasks/orchestrator/proposal_v1/03_quality_gates.md
2026-06-02 21:00:01 +03:00

20 KiB
Raw Blame History

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 существует, длина 580 символов
  • 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.md
  • docs/work-items/<id>/02-trz.md
  • docs/work-items/<id>/03-acceptance-criteria.md
  • docs/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.md
  • docs/work-items/<id>/11-design/mockups.md
  • docs/work-items/<id>/11-design/states.md
  • docs/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 (контейнер): нет критичных 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/<id>/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/<id>/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<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. Для этого:

  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 — целиком машинные.

Это и есть «ворота, которые нельзя забыть».