Files
wiki/tasks/multi-agent/proposal_v1/03_quality_gates.md
2026-05-15 00:50:01 +03:00

350 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 — целиком машинные.
Это и есть **«ворота, которые нельзя забыть»**.