# Решения по гейтам и тестам > Статус: **active**. Журнал решений «что сознательно НЕ вводим» и «как читаем > результат CI». Только про гейты, линтеры, coverage, e2e и CI — **для обычных > правок production-кода не нужен**. Читать, когда проектируется или меняется > сам гейт, либо когда спрашивают «почему так, а не иначе». Оперативные команды > и пороги — в `docs/quality-gates.md`, правила нагрузки на машину — в > `docs/agent-workflow.md`, раздел 3. Здесь лежат решения, чтобы не пересматривать их заново. Для каждого: причина и то, что решение пересмотрело бы. В `docs/backlog.md` такие пункты не дублируются: backlog живёт задачами, а не историей решений. Числа ниже — разовые замеры, а не текущие значения: помечены датой. Актуальные цифры даёт прогон (`docs/quality-gates.md`), по правилу `AGENTS.md` в документах нет величин, которые меняются вместе с кодом. ## 1. Детектор дублирования разметки — не вводим Ни свой AST-правило, ни готовая зависимость (jscpd, `eslint-plugin-sonarjs`). - Замер по корпусу `.svelte` в `components/**` и `routes/**` (сентябрь 2026): при пороге 5 нормализованных строк — одна осмысленная пара, при пороге 3 — 17 пар, и все они шум (``, `{/each}`, `{#if children}`). Семейство schema-контролов делит максимум 4 строки — законное сходство by design. - Причина: построчное сравнение Svelte-разметки принципиально ненадёжно — одинаковый контейнер с разным содержимым даёт ложное срабатывание, а намеренно общий класс — ложную тишину. Чтобы не ловить шум, порог пришлось бы поднять до 12+ строк, и тогда правило срабатывает ровно один раз. - Контроль остаётся на ревью (расхождение видно в диффе) и на поведенческих e2e-проверках; извлечение общей разметки закреплено конвенцией в `AGENTS.md`. - Пересмотреть, если появится реально «уехавшая» копипаста в компонентах или библиотека разрастётся на уровень композиций страниц. ## 2. Линтер согласованности комментариев — не вводим Описания инструментов различаются осознанно, и ловить это текстовым правилом дороже, чем смотреть на ревью. Действенная часть выполнена вручную: все `TODO`/`FIXME` перенесены в backlog, незарегистрированных пометок в коде нет; новые запрещены правилом в `AGENTS.md`. ## 3. Линтер «изменяемых чисел» в документации — не вводим Правило «не фиксировать числа, которые меняются вместе с кодом» живёт в `AGENTS.md` и держится на ревью. Автоматизация отклонена по замеру (сентябрь 2026): regex «число + существительное» на корпусе Markdown дал 15 совпадений, из которых 14 — ложные («30 дней» политики архива, «9 опций» описания поля, «4 проекта» факт из `playwright.config.ts», цитата самого правила). - Правило всё равно неполно: ловит «122 инструмента», но не «инструментов — 122», не «более 100», не «≈120»; на каждое обходное движение нужна правка правила, а allowlist легитимных чисел становится вторым источником долга. Худший исход — не «шумно», а «вроде гейт, а толку нет»: срабатывания на пустом месте забейзелят, и через месяц правило перестанет ловить настоящие нарушения. Видимое блокирующее правило, которое на деле ничего не проверяет, хуже отсутствия правила. - Соблюдение правила дешевле обхода: «список — в `docs/tools-map.md`» стоит столько же символов, сколько цифра, но не требует обновления. - Пересмотреть, если появится источник истины, из которого число можно **вычислить** и сравнить автоматически, без разбора прозы. Такой случай есть и решён отдельно — следующий пункт. ## 4. Сверка `docs/tools-map.md` с реестром — автоматизирована Правило про числа не закрывает более опасный класс расхождений: документ не устарел числом, а **перечисляет то, чего нет в коде**. В разделе «Реализовано» карты лежали несуществующие id (`png-info`, `color-wheel-generator`, `jpg-to-png`, `watermark-image-png`), которые агент принял бы за готовые инструменты. Счёт при этом был верный — число такой класс не ловит. Сверка множеств отвечает на вопрос однозначно и без allowlist, поэтому автоматизирована: `web/src/lib/registry/tools-map-doc.test.ts` парсит раздел «Реализовано» и сравнивает id с `TOOLS` в обе стороны (id без инструмента и инструмент без записи), плюс ловит повтор id между буллетами. Формат строки карты — всё до первого тире, id через `/` или `,` — закреплён в самом документе и в тесте. Чтобы сломанный парсер не выглядел как успех, у теста есть отдельная проверка «разбор не пустой»: если формат карты снова поменяется, тест упадёт с сообщением про парсер, а не молча перестанет что-либо проверять. Входит в обычный `pnpm --dir web test`; новых гейтов и конфигов не добавляет. ## 5. Visual snapshots — не вводим `toHaveScreenshot` сравнивает страницу с PNG-baseline из прошлого коммита, а не с замыслом дизайна. При активно меняющемся визуальном языке это превращает каждый дизайн-PR в регенерацию и ревью картинок, а baseline платформенные (снимок с Windows не совпадёт на `ubuntu-latest`). Потребность закрывают e2e-поведение, `lint:tokens` с token audit, i18n-гейт и ручной чеклист `docs/checklist-manual-testing.md`. Вернуться стоит, когда визуальный язык стабилизируется; тогда первым идёт `/kit` в двух темах, а baseline рождаются на Linux. ## 6. Fail-режим для unused-token аудита — не вводим Остаётся предупреждением: `verify` входит в deploy-workflow, поэтому стилевой долг блокировал бы деплой сайта. Кроме того, аудит видит только ссылки `var(--x)`, и чтение токена из JS дало бы ложное срабатывание. Правило «новый токен — вместе с потребителем» живёт в `AGENTS.md`. ## 7. Per-project `expect.timeout` — не задаём Firefox и WebKit отдают результат так же быстро, как Chromium: расхождения объясняются памятью, а не скоростью движка. Таймаут под конкретную машину — магическое число, которое придётся подстраивать на каждом раннере, поэтому Playwright-конфиг остаётся с дефолтами, а проблема решается лимитом воркеров. Практические правила — `docs/agent-workflow.md`, раздел 3. ## 8. Дублирование `verify` между workflow — сознательно `Deploy to GitHub Pages` и `Quality` оба зовут `verify`: deploy проверяет быстрый gate и собирает сайт, `Quality` прогоняет тот же `verify` и browser matrix. По замеру (сентябрь 2026) `verify` — единицы минут, matrix — около трёх, поэтому дублирование дешевле условных job-и, а matrix дёшево держать на каждом PR. Актуальные длительности — в логе прогона. Ручной `gh workflow run quality.yml` нужен только для перепрогона старого коммита. ## 9. Политика 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 — см. следующий раздел. ## 10. Чтение результатов 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 (`docs/agent-workflow.md`, раздел 3), а не увеличиваются таймауты.