Files
easy-png-tools2/docs/quality-gates.md
T

16 KiB
Raw Blame History

Quality gates

Статус: active. Каноническое описание быстрых проверок репозитория. Краткие обязательные команды остаются в AGENTS.md.

Каноническая команда

Запускать из корня репозитория:

pnpm verify

verify выполняет последовательно:

  1. pnpm --dir web check — SvelteKit sync и svelte-check.
  2. pnpm --dir web test:coverage — полный Vitest-набор вместе с coverage-гейтом.
  3. pnpm --dir web test:rules — отдельный быстрый прогон тестов ESLint-правил.
  4. pnpm --dir web lint:all — ESLint, Stylelint и token audit.
  5. pnpm --dir web format:check — форматирование кода web/.
  6. pnpm check:docs — форматирование Markdown.
  7. pnpm --dir web build — production build.

Полный test уже включает тесты lint-правил; отдельный test:rules в verify оставлен как явный быстрый диагностический этап.

Coverage

pnpm --dir web test:coverage считает покрытие только по src/lib и падает ниже порога. Scope и список исключений — в web/vitest.config.ts, обоснование — в docs/testing-strategy.md.

Метрика Порог Baseline
statements 90 91.77%
branches 82 83.3%
functions 72 74.31%
lines 91 92.53%

Порог — нижняя граница от текущего baseline, а не оценка качества: он блокирует регрессию и не требует сначала закрывать весь долг. Локальный замер занимает ~30 с, поэтому отдельного прогона в verify нет — test:coverage заменяет test.

E2E

E2E не входит в verify, потому что Playwright поднимает build и статический сервер. Locator, fixture, i18n и test.fixme-политика описаны в docs/testing-strategy.md:

pnpm --dir web test:e2e

Запускать его обязательно для изменений маршрутов, загрузки файла, результата, download, темы или локализации. Изменения runtime fixtures/загрузки файла проверяются отдельным web/e2e/png-fixtures.spec.ts; ручные бинарники из tests/fixtures/ не входят в verify. В текущем CI это отдельный non-blocking baseline; после закрытия известных ошибок его можно сделать blocking.

Локально прогон идёт с workers: 1 и заметно медленнее: это осознанный размен, экономит память и оставляет компьютер отзывчивым. Playwright не умеет per-project лимит воркеров, а browser matrix упирается в память, а не CPU. Тяжёлые прогоны запускаются по команде пользователя — по одному, без фонового запуска и циклов повторов; детали в docs/agent-workflow.md.

Быстрые подмножества

Изменение Команда
Только Markdown pnpm check:docs
TypeScript/Svelte pnpm --dir web check и pnpm --dir web test
Lint-правило или lint-конфиг pnpm --dir web test:rules и pnpm --dir web lint:all
Пользовательский поток pnpm --dir web test:e2e
Fixtures/загрузка файла pnpm --dir web test:e2e
Полный локальный gate pnpm verify

Errors и warnings

  • errors завершают соответствующий инструмент ненулевым кодом.
  • После Q2 ESLint запускается с --max-warnings=0: новые ESLint warnings блокируют gate.
  • Token audit оставляет unused-token сообщение неблокирующим: после Q7a пыль вычищена, решение о fail-режиме зафиксировано в Q7d — новый токен появляется вместе с потребителем, но стиль не блокирует деплой.
  • Резолв var() в app.css — ошибка: несуществующий токен молча роняет объявление, поэтому этот check failing, в отличие от unused.
  • lint:all сейчас чист: 0 errors, 0 i18n warnings, 0 unused tokens.
  • dict-consistency использует base-locale fallback для registry metadata и pattern-based policy для временно неиспользуемых tools.*.params; это не молчаливый allowPaths-список.

Решения, принятые без автоматизации

Здесь лежат решения «что сознательно НЕ вводим», чтобы не пересматривать их заново через полгода. Для каждого — причина и то, что пересмотрело бы решение. В docs/backlog.md такие пункты не дублируются: backlog живёт задачами, а не историей решений.

Детектор дублирования разметки — не вводим

Ни свой AST-правило, ни готовая зависимость (jscpd, eslint-plugin-sonarjs).

  • Измерение по 65 .svelte в components/** и routes/**: при пороге 5 нормализованных строк — одна осмысленная пара, при пороге 3 строки — 17 пар и все они шум (</label>, {/each}, {#if children}). Семейство schema-контролов делит максимум 4 строки — это законное сходство by design.
  • Причина: построчное сравнение Svelte-разметки принципиально ненадёжно — одинаковый контейнер с разным содержимым даёт ложное срабатывание, а намеренно общий класс — ложную тишину. Чтобы не ловить шум, порог пришлось бы поднять до 12+ строк, и тогда правило срабатывает ровно один раз.
  • Контроль остаётся на ревью (расхождение видно в диффе) и на поведенческих e2e-проверках; извлечение общей разметки закреплено конвенцией в AGENTS.md.
  • Пересмотреть, если появится реально «уехавшая» копипаста в компонентах или библиотека разрастётся на уровень композиций страниц.

Линтер согласованности комментариев — не вводим

Описания инструментов различаются осознанно, и ловить это текстовым правилом дороже, чем смотреть на ревью. Действенная часть выполнена вручную: все TODO/FIXME перенесены в backlog, незарегистрированных пометок в коде нет; новые запрещены правилом в AGENTS.md.

Visual snapshots — не вводим

toHaveScreenshot сравнивает страницу с PNG-baseline из прошлого коммита. При активно меняющемся визуальном языке это превращает каждый дизайн-PR в перегенерацию и ревью картинок, а baseline платформенные (снимок с Windows не совпадёт на ubuntu-latest). Потребность закрывают e2e-поведение, lint:tokens с token audit, i18n-гейт и ручной чеклист. Вернуться стоит, когда визуальный язык стабилизируется; тогда первым идёт /kit в двух темах, а baseline рождаются на Linux.

Fail-режим для unused-token аудита — не вводим

Остаётся предупреждением: verify входит в deploy-workflow, поэтому стилевой долг блокировал бы деплой сайта. Кроме того, аудит видит только ссылки var(--x), и чтение токена из JS дало бы ложное срабатывание. Правило «новый токен — вместе с потребителем» живёт в AGENTS.md.

Per-project expect.timeout — не задаём

Firefox и WebKit отдают результат так же быстро, как Chromium: расхождения объясняются памятью, а не скоростью движка. Таймаут под конкретную машину — магическое число, которое придётся подстраивать на каждом раннере, поэтому lint/Playwright-конфиг остаётся с дефолтами, а проблема решается лимитом воркеров.

Coverage: браузерные модули вне scope

src/lib/core/domText.ts и src/lib/core/io.ts (canvas, createImageBitmap) исключены из coverage-гейта: в node-Vitest они не исполнимы, и их включение превращало бы метрику в шум. registry/* из scope НЕ исключены — низкое покрытие там означает непокрытую логику, а не ограничение окружения. Список исключений с причинами — в docs/testing-strategy.md.

CI

.github/workflows/quality.yml:

  • verify блокирует PR при typecheck, unit, rule-test, lint, format, docs или build ошибке;
  • e2e запускается отдельным job после verify и пока не блокирует PR.

.github/workflows/deploy.yml перед production build запускает тот же pnpm verify, поэтому deploy не должен проходить при ошибке быстрых проверок.

Что и когда запускается

Workflow Триггер Jobs
Deploy to GitHub Pages push в main, dispatch verify, build, deploy
Quality push в main, pull_request, dispatch verify, e2e

Пуш в main запускает оба workflow: deploy проверяет быстрый gate и собирает сайт, Quality прогоняет тот же verify и browser matrix. Дублирование verify (~1 мин) сознательное: matrix на каждый пуш стоит ~3 мин, и условные job-и ради минуты не окупаются. Browser matrix проверяется на каждом пуше, а ручной gh workflow run quality.yml нужен только для перепрогона старого коммита.

Проверка результатов CI после пуша

Первый реальный прогон browser matrix происходит на runner, а не на локальной машине: локально Firefox и WebKit проходят на 1 воркере, но состав, скорость и память Linux-раннера отличаются. Поэтому после пуша разработчика:

  1. дождаться завершения workflow и посмотреть, какие job вообще запустились;
  2. смотреть статусы отдельных job, а не общий conclusion прогона: у e2e стоит continue-on-error: true, поэтому прогон с упавшим e2e целиком помечается как success — проверено на run 36225579363 (E2E: failure при conclusion: success);
  3. если e2e запускался и зелёный — сообщить фактические числа passed, failed, skipped;
  4. если e2e не запускался, сказать это прямо: matrix на раннере не проверена, и её можно прогнать через gh workflow run quality.yml;
  5. красный e2e только из-за ресурсов раннера фиксируется как ограничение окружения: сначала проверяется один проект и один spec, а не увеличиваются таймауты под конкретную машину.

Измеренная стоимость прогона

Замер на ручном запуске quality.yml (276 e2e-тестов, 4 проекта, ubuntu-latest):

Этап Время
verify job ~1 мин
e2e job целиком ~3.1 мин
из них сами тесты ~2.2 мин
весь run ~4.2 мин

Browser matrix стоит около трёх минут, поэтому её дешёво держать на каждом PR. Полный прогон локально на 1 воркере — заметно дольше (~7 мин), и именно поэтому локальные правила нагрузки описаны в docs/agent-workflow.md.

Политика e2e в CI

Текущее состояние: e2e — non-blocking baseline, запускается на каждом пуше в main и на каждом PR целиком (все четыре проекта matrix). Ночного разделения нет: при стоимости job около трёх минут оно не окупается, поэтому новые browser-critical спецификации просто добавляются в browserContractTests.

e2e станет blocking, когда выполнятся три условия:

  1. Условия matrix пересмотрены: решено, какие спецификации обязаны идти в browserContractTests и mobileTests, нужен ли png-fixtures вне Chromium и что делать с engine-специфичными расхождениями декодеров.
  2. Накопились стабильные прогоны на раннере без падений по таймингу.
  3. Вместе с continue-on-error снимается и сам trick с общим conclusion: иначе зелёный прогон при красном e2e останется возможен.

Пока условия не выполнены, e2e остаётся non-blocking, а его статус читается по отдельному job.

Локальная диагностика

При медленном полном прогоне сначала запускай минимальную команду из таблицы, а перед ревью или merge — pnpm verify. После каждого шага плана результат команд и текущий baseline фиксируются в отчёте агента.