49 KiB
План: линтеры, тесты и качество кодовой базы
Статус: draft — Q0–Q5 и Q6a–Q6f.5 готовы к ревью; Q7 — следующий этап.
Источник:
docs/backlog.md, аудит конфигурацииweb/, e2e-тестов и инфраструктурных скриптов. Q0–Q5 и Q6a–Q6f.5 выполнены; Q7–Q8 выполняются отдельными атомарными шагами.Цель: сделать качество кодовой базы воспроизводимым, убрать ложную «зелёность» проверок, стабилизировать тестовые контракты и только после этого расширять автоматические правила.
1. Границы и принципы
- Сначала stabilизировать существующие проверки и тестовые контракты, а не добавлять новые сложные lint-правила.
- Старый UI удалён: production работает на корневых маршрутах, а
/v1/**и v1-specific код больше не являются частью приложения. - Не добавлять новые v1-фичи, не чинить v1-баги и не расширять v1-тесты.
core/иtheme/— общие модули. Их изменения проверяются unit-тестами и smoke-сценариями production-потребителей.- Изменения делаются небольшими атомарными частями, в соответствии с
AGENTS.md. - Каждый новый lint-rule сначала появляется в report-only/warn-only режиме, получает fixtures и тесты, и только после очистки baseline становится blocking.
- Детали реализации правил остаются в
web/eslint-plugins/README.md;AGENTS.mdсодержит краткие обязательные политики, понятные агенту без дополнительных поисков, и ссылки на подробные документы.
Политика удаления legacy v1
- Q3 — отдельная атомарная cleanup-задача; поддержка v1 не возвращается.
- Старые маршруты и UI-файлы удаляются без redirects и без совместимого maintenance-режима.
- В рабочей кодовой базе не оставлять UI-v1-пути, исключения или документацию, которые выглядят как действующий источник совместимости.
- Исторические упоминания допустимы только в
docs/archive/. - Будущий API-контракт
POST /v1/processизdocs/plan-platform.mdне связан с удалённым UI-v1 и остаётся в планах.
2. Текущее состояние quality-контура
pnpm verifyобъединяет typecheck, unit, rule-тесты, lint, форматирование, docs и production build; deploy выполняет его перед сборкой.i18n/dict-consistencyдаёт 0 warnings на текущем baseline; после Q7 вычищены 4 неиспользуемых design token, token audit тоже чист.- E2E-контракт использует semantic locators и общий source-aware schema
resolver; активных known-issue
test.fixmeнет. ToolErrorхранится как key/vars и переводится только при выводе; смена локали обновляет уже видимый alert.- E2E гоняется в четырёх Playwright-проектах: полный Chromium, Firefox и WebKit для browser-critical спецификаций и mobile Chromium 390×844. Job остаётся non-blocking, число воркеров ограничено из-за памяти.
3. Этапы выполнения
Q0. Зафиксировать baseline и синхронизировать документацию
Статус: готов к ревью. Оценка: S. Зависимости: нет.
- Проверить фактические команды и зафиксировать их в quality-gate документации.
- Вынести расширенный workflow агента в
docs/agent-workflow.md, оставив вAGENTS.mdтолько обязательные инварианты и ссылки. - Обновить
docs/backlog.md:- отметить dictionary linter как реализованный, но не доведённый до zero-warning;
- убрать противоречие по кнопке Generate;
- синхронизировать числа инструментов и тестовых сценариев.
- Восстановить или исправить ссылку на раздел G в
docs/checklist-manual-testing.md. - Убрать устаревшее утверждение про hardcoded debt в
kitизAGENTS.md, если оно больше не соответствует коду. - Перенести явно устаревшие
docs/analysis.mdиdocs/sorting-backend.mdвdocs/archive/, добавить даты архивирования и удаления через 30 дней. - Создать
docs/README.mdкак индекс активных документов и карту источников истины; подробные правила не дублировать в корневых файлах.
Готово, когда: один документ описывает текущие команды, актуальный baseline
и все известные test.fixme имеют ссылки на зарегистрированный баг.
Q1. Единый quality gate и CI
Статус: готов к ревью. Проверено: pnpm verify проходит; E2E оставлен
отдельным non-blocking job. Оценка: S–M. Зависимости: Q0.
Добавить read-only verify-команду, которая запускает:
pnpm --dir web check
pnpm --dir web test
pnpm --dir web test:rules
pnpm --dir web lint:all
pnpm --dir web exec prettier --check .
pnpm check:docs
pnpm --dir web build
E2E оставить отдельным тяжёлым гейтом:
pnpm --dir web test:e2e
- Не дублировать вручную аргументы ESLint/Stylelint в нескольких скриптах; оркестратор должен вызывать package scripts или единый общий модуль.
- Описать фактические команды и semantics ошибок/warnings в
docs/quality-gates.md; здесь нужна точная процедура, а не длинный дубль вAGENTS.md. - На первом этапе явно разделить
errorsиwarnings. - После очистки i18n baseline добавить строгий режим
--max-warnings=0. - Добавить отдельный workflow для pull request: typecheck, unit, rule-тесты, lint, format и build.
- E2E сначала запускать отдельным job; сделать его blocking после закрытия известных ошибок и стабилизации baseline. Решение отложено: условия matrix пересматриваются после Q6f.3, см. раздел 7 «Отложенное решение».
Готово, когда: одна команда воспроизводит все быстрые проверки, а deploy не может пройти при type/unit/lint/build-ошибке.
Q2. Политика i18n и zero-warning baseline
Статус: готов к ревью. Проверено: i18n lint даёт 0 warnings, rule-тесты
и полный pnpm verify проходят. Оценка: M. Зависимости: Q0, Q1.
BASE_LOCALE— единственный источник registry-English fallback дляtools.*.titleиtools.*.description; остальные локали требуют физические ключи.- Временно неиспользуемые
tools.*.paramsисключены pattern-based policy до отдельной очистки мёртвого словаря; пустые значения и placeholders не подавляются. - Исправлены три реальных RU option-label gaps и удалены неиспользуемые
option-группы из
ru.ts. - Исправлен tie-break placeholder parity: при равенстве голосов выбирается
BASE_LOCALE. lint-allзапускает ESLint с--max-warnings=0; unused-token сообщение оставалось неблокирующим и закрыто в Q7.- Plural-формы остаются отдельной задачей после Q2 и не смешиваются с этим этапом.
Q3. Удалить UI-v1 (cleanup завершён)
Статус: выполнен. Проверено: pnpm verify и production E2E smoke
проходят; после проверки обновлены конфиги и активные документы. Оценка: M.
Зависимости: Q0, Q1, Q2.
- Удалены
web/src/routes/v1/**,web/src/lib/v1/**,app_v1.css, v1-specific i18n/tests и fixtures. - Удалены isolation plugin, его тест и все v1-исключения из lint-конфигураций.
- Убраны v1-ссылки из production-кода и активных документов; исторические
упоминания остаются в
docs/archive/. - Проверены production build, verify и отдельный E2E smoke production-маршрутов.
Результат: /v1/**, UI-v1-файлы и legacy-конфигурация отсутствуют;
следующий этап — Q5.
Q4. Тестовый контракт e2e
Статус: выполнен. Проверено: pnpm verify и полный Playwright smoke
проходят; 105 тестов passed, 4 known-issue теста skipped. Оценка: M.
Зависимости: Q0–Q3.
- Добавлен
docs/testing-strategy.mdс locator, fixture, i18n иtest.fixmepolicy. - В production markup добавлены только разрешённые hooks для source/result/
verdict/empty-state; текстовые элементы получили accessible labels, фильтры —
aria-pressed, а каталог — семантические heading/status landmarks. - E2E переведён на
role, label и stablehref; удаленыTOTAL/GROUPS, exact fuzzy counts, internal CSS selectors,alt-locators и полные verdict strings. Точные verdict-переводы перенесены в unit-тесты. - Helpers централизованы в
web/e2e/helpers/page.ts; исправлены stale theme/source/locale checks. Theme fixme снят. - Q5-фиксы resize/crop, generator, Reset и error-сценария не смешивались с этим этапом.
Результат: изменение формулировки, класса или порядка элементов не ломает поведенческий тест без изменения пользовательского контракта; следующий этап — Q6.
Q5. Закрыть известные preview-баги
Статус: выполнен. Проверено: unit, Q5 E2E smoke и полный pnpm verify
проходят; активных known-issue test.fixme нет. Оценка: M–L.
Зависимости: Q4.
- Добавлен общий opt-in
defaultFromSourceresolver вregistry-schema: он принимает source dimensions, обновляет только source-aware поля при upload и используется в UI, executor и worker.resize-pngиcrop-pngполучают размеры текущего source; static/generator/text schemas не затронуты. - Reset сохраняет source/text, восстанавливает source-aware defaults и запускает deferred auto-run через debounce.
- Генераторы проверены в auto-run без кнопки Generate; кнопка не добавляется.
ToolErrorхранится как key/vars, переводится derived-значением при выводе и обновляется при смене локали. E2E использует независимый invalid pixel-count сценарий.- Resize/crop, generator, Reset и localization fixme сняты; Q6a расширяет покрытие, не смешиваясь с исправлением этих контрактов.
Результат: Q5 known issues закрыты и отражены в docs/backlog.md и
docs/checklist-manual-testing.md; Q6a выполнен, следующий этап — Q6b.
Q6. Расширение unit и browser-покрытия
Оценка: M–L. Зависимости: Q4, Q5.
Q6a. Executor protocol, fallback и debounce
Статус: выполнен. Unit-тесты покрывают debounce, worker image/string/
verdict/files protocol, ToolError transport, constructor/postMessage/onerror/
malformed fallback, source-aware sanitization и DOM metadata. Browser smoke
проверяет rapid auto-run и no-worker fallback; deferred transport fallback
покрыт unit-тестами.
execute(tool, ctx)сохраняет публичный API;createExecutorи protocol handler являются внутренними test seams.ToolErrorне запускает direct retry повторно; transport/protocol failures отключают worker и переходят в direct fallback.- DOM-зависимые registry entries помечены
domOnly, поэтому зелёный smoke не скрывает нормальный worker fallback. debounceпокрыт fake timers; E2E подтверждает последние значения при быстрых последовательных изменениях генератора.
Q6b. FileResult → ZIP → download
Статус: выполнен. Q6a закрыл worker-транспорт; Q6b добавил проверяемый ZIP
seam, unit round-trip для FileResult, защиту пустого результата и error/busy
контракт download. Отдельный browser-сценарий скачивает архив и проверяет имена
частей и PNG-сигнатуры.
buildZipEntriesне зависит от DOM;downloadZipостаётся UI-обёрткой.SchemaToolViewпереиспользуетdownloadBlob, ловит ошибки кодирования и блокирует повторный download на время сборки.- E2E использует
downloadResultFileиunzipSync, не добавляя новыеdata-testid; files-инструменты не проходят через image-smoke.
Q6c. Output MIME/quality
Статус: выполнен. Q6c покрывает текущий фиксированный output-контракт JPG/WebP/BMP, не превращаясь в UX-райз кнопки Download. Registry проверяет согласованность MIME/extension/quality-поля, unit — границы quality, browser — реальные сигнатуры файлов и разницу размера при изменении quality.
ToolEntry.outputостаётся декларативным описанием формата; новый селектор форматов не добавляется.validateOutputQualityотделяет проверку 0..1 от DOM-рендеринга; JPEG/WebP используют quality1..100из schema, BMP не имеет quality-параметра.- E2E проверяет JPEG
FF D8 FF, WebPRIFF/WEBP, BMPBMи PNG-фолбэк. - Ошибки кодирования и unsupported MIME используют существующие i18n-ключи.
Q6d. Malformed и special PNG fixtures
Статус: выполнен. Runtime-fixtures покрывают CRC, truncated, palette и
16-bit без бинарных файлов в git. E2E фиксирует браузерный контракт: critical
CRC/truncated отклоняются без падения, ancillary CRC и хвост после IEND
допускаются, palette/16-bit декодируются. Unit фиксирует контракт анализаторов
для RGBA-данных, которые браузер отдаёт после нормализации.
web/e2e/helpers/fixtures.tsсобирает indexed, 16-bit, CRC-mutation, truncation и tail-варианты из уже существующихcrc32/chunk.- Отклонение битых файлов — свойство декодера движка, а не единый продуктовый
контракт: Q6f.3 зафиксировал, что Firefox и WebKit декодируют
idat-cutиtruncated-no-iend, а WebKit ещё иcrc-bad-idat. Это ожидаемое поведение, которое закреплено per-engine вweb/e2e/png-fixtures.spec.ts. - Обязательное требование при любом исходе: файл не роняет страницу, ошибка показывается alert-ом, а не «пустым» результатом.
- Поведение
createImageBitmapявляется частью browser-контракта, а не самостоятельного PNG-парсера product-кода. - Сырое сообщение браузера при decode-ошибке не локализуется в Q6d; это отдельная задача в backlog.
Q6e. Registry-wide smoke
Статус: выполнен. Smoke расширен до всех 122 production tools из registry: image→image, image→text, text→image, generator input→image и verdict. FileResult и malformed/special PNG не дублируются — они уже покрыты Q6b/Q6d.
tools-smoke.spec.tsрасширен image/text-output кейсами, включая все незакрытые color/geometry инструменты.generators.spec.tsиспользует единый data-harness для всех генераторов;single-color-pngсохраняет отдельную проверку auto-run/размеров.- Text-input сценарии используют общий
renderTexthelper, включаяdata-uri-to-png. - Component-тесты не добавлены: Vitest работает в node без DOM/Testing Library, а текущий e2e-контракт уже покрывает поведение preview. Выбор test seam или DOM-окружения перенесён в Q6f.
Q6f.1. Layout resolver seam
Статус: выполнен. Чистая логика группировки полей вынесена из
SchemaFields.svelte в resolveLayoutGroups и покрыта unit-тестами на
дедупликацию, неизвестные поля, пустые группы, cols и default-хвост.
- Компонент использует общий resolver, поэтому unit-тесты блокируют изменения layout-логики без DOM/Testing Library.
SchemaPreviewview-model и DOM-компоненты не менялись; их seam остаётся отдельным решением Q6f.2.- Новые зависимости, vitest-конфиг и browser matrix не добавлялись.
Q6f.2. SchemaPreview model seam
Статус: выполнен. Вычисления sourceValue, resultValue, formatValue и
hasResult вынесены в buildSchemaPreviewModel; Svelte-компонент использует
модель, а unit-тесты проверяют все input/result-ветки без DOM.
- Translator передаётся в модель явно, поэтому unit-тесты не зависят от locale state и проверяют только view-model.
- image/text/verdict/files и пустые результаты покрыты в
pnpm verify. - Новые зависимости, vitest-конфиг и browser matrix не добавлялись.
Q6f.3. Browser matrix и mobile viewport
Статус: выполнен. Playwright запускает четыре проекта: полный Chromium,
Firefox и WebKit для browser-critical спецификаций и mobile Chromium 390×844 с
hasTouch для навигации, каталога, генераторов и pipeline.
web/playwright.config.ts:browserContractTests—pipeline.spec.ts,png-fixtures.spec.ts,text-and-verdicts.spec.ts;mobileTests—navigation.spec.ts,catalog.spec.ts,generators.spec.ts,pipeline.spec.ts.workers— 1 локально и 2 в CI. Browser matrix ограничена памятью: при 12 воркерах на машине с 16 GB RAM браузеры не успевают поднять worker, и тесты падают без ошибок (проверено и в Chromium). Локально matrix поэтому медленная, но почти не нагружает компьютер. Per-project лимита воркеров в Playwright нет.- Per-project
expect.timeoutне задаётся: Firefox и WebKit отдают результат так же быстро, а расхождения объясняются памятью, а не скоростью движка. - Декодеры движков расходятся, и это зафиксировано как ожидаемое поведение:
png-fixtures.spec.tsхранит список движков, отклоняющих каждый битый файл, и не пропускает проверки. В любом браузере файл не должен ронять страницу, а отказ декодера показывается alert-ом. - CI устанавливает
chromium firefox webkit; job остаётся non-blocking. - Локальный прогон: 276 passed, 0 skipped, 0 failed. Visual snapshots и coverage thresholds не добавлялись — это Q6f.4.
Q6f.4. Coverage thresholds
Статус: выполнен для чистой логики. Vitest считает покрытие только по
src/lib, с явным списком исключений, и pnpm verify падает при падении ниже
порога.
web/vitest.config.ts: providerv8,reporter: text-summary, пороги statements 90, branches 82, functions 72, lines 91.- Пороги поставлены на 1.5–2.5 п.п. ниже измеренного baseline (91.77 / 83.3 / 74.31 / 92.53), поэтому gate ловит регрессию, а не текущий долг.
- Scope — логика, которую node-Vitest вообще может исполнить. Исключены
браузерные модули
core/domText.tsиcore/io.ts(canvas,createImageBitmap), data-модулиi18n/en.ts,i18n/ru.ts,tool-icons.ts, rune-файлы*.svelte.ts, entry worker-а и type-onlycomponents/define.ts. Причина каждого исключения зафиксирована в конфиге и вdocs/testing-strategy.md. registry/*(47–81% statements, 25–47% functions) в scope остаётся: это обычная непокрытая логика, а не ограничение окружения. Покрывается e2e-smoke Q6e, но unit-порог её не скрывает.verifyтеперь выполняетtest:coverageвместоtest: набор тестов тот же, двойного прогона нет.- Порог functions самый слабый (74.31% против 91.77%): добавление инструмента с
непокрытым
runбыстрее всего опускает именно его. Это ожидаемо, порог держит запас. - DOM-тесты
SchemaToolView/controls не начаты: браузерные модули исключены из coverage сознательно, а их перенос в scope — отдельное решение вместе с visual snapshots, см. Q6f.5.
Не применять один одинаковый smoke-сценарий к image-, text-, generator- и file-result-инструментам.
Q6f.5. Visual snapshots — решение отложено
Статус: сознательно не делаем. Это решение, а не долг.
- Механика:
toHaveScreenshotсравнивает отрендеренную страницу с PNG-baseline, закоммиченным вweb/e2e/<spec>-snapshots/. Эталон — картинка из прошлого коммита, а не замысел дизайнера; обновление идёт через--update-snapshotsи ревью картинок. - Почему отложено:
- визуальный язык сейчас активно меняется, поэтому каждый дизайн-PR превращается в перегенерацию и ревью картинок, а соблазн обновить снапшот не глядя появляется постоянно;
- baseline привязан к платформе (ОС, шрифты, особенности рендеринга): снимок с
Windows не совпадёт на
ubuntu-latest, значит эталоны должны рождаться на Linux, а локальные прогоны будут постоянно расходиться; - при матрице из четырёх проектов плюс тема и viewport число файлов Baseline растёт нелинейно.
- Что закрывает потребность сейчас: e2e-поведение (276 тестов),
lint:tokensи token audit, i18n-гейт, ручной чеклистdocs/checklist-manual-testing.md. Не закрыто только «элемент визуально наехал» — это ловится чеклистом и ревью. - Условие возврата: визуальный язык стабилен, изменения редкие, ручной чеклист
перестал справляться. Тогда первым идёт
/kitв двух темах, а эталоны генерируются на Linux (docker-образ Playwright или отдельный CI-job).
Q7. Укрепление lint-инфраструктуры
Оценка: M. Зависимости: Q1, Q2, Q3.
Q7a. Очистка неиспользуемых design tokens
Статус: выполнен. Token audit чист: All app.css tokens are used somewhere.
- Удалены
--color-text-accent-muted(light и dark, иначе ломается parity),--space-text-s: 0,--size-content-max: 880pxи--duration-m: 0.3s. - Проверено, что мёртвые токены — это пыль, а не признак хардкода: дублирующих
значений (
max-width,0.3s, muted-цвет) вsrcнет. Потребителиspace-text-m/xl/2xl,size-content-max-wideиsize-workspace-minиспользуются, поэтому шкалы не тронуты. - Шкалы остались неполными намеренно (
duration-s/lбезm,space-textбезs): мёртвый элемент шкалы хуже, чем «дырявая» шкала, а вернуть его можно вместе с потребителем. - Второй пункт («после очистки решить, должен ли unused audit быть fail-режимом») остаётся открытым: сам audit пока только сообщает.
Q7b. Тесты token audit и PostCSS HCT-плагина
Статус: выполнен. У обоих не было ни одного теста, хотя HCT-плагин
(web/scripts/postcss-hct.mjs, 430 строк) пересчитывает всю палитру.
web/scripts/__tests__/postcss-hct.test.mjs— 17 тестов: literal и производныйhct(), seed из:rootи из hex, цепочка hct-токенов, refsh/c/t,calc/min/max/clamp, обёртка hue, клампы tone/chroma, несколько вызовов в одном объявлении, а также warn-and-keep для неизвестного seed, циклической ссылки и битого телаhct().web/scripts/__tests__/token-audit.test.mjs— 15 тестов на parity (light-only, dark-only, derived, не-цвет), authorship (hct, color-mix, seed-токены, хардкод с локацией, игнор не-цветов и обычных свойств), unused и предикатыisColorValue/isDerived.- Ожидания не зашивают вывод плагина, а сравнивают его с эквивалентной
литеральной записью:
hct(from var(--seed) h c calc(t + 10))должен совпасть сhct(120 40 60), если seed —hct(120 40 50). Иначе тест просто зафиксировал бы текущее поведение. - Единственный seam:
checkUnused(root, used = collectUsedTokens())— зависимость от чтенияsrcстала инъецируемой, production-вызов не изменился. vitest.config.tsподхватываетscripts/**/*.test.mjs, поэтому скрипты покрываются обычным прогоном иverify;test:rulesне трогали.- Проверка мутацией выявила дыру: первая версия тестов не ловила кламп tone в
ветке
from(сменаclamp(t, 0, 100)на0, 90проходила зелёной). Добавлен отдельный тест на производный кламп; после этого мутация падает.
Q7c. Базовый JS recommended для инфраструктуры линтинга
Статус: выполнен. eslint-plugins/** и scripts/** больше не вне линта.
web/eslint.config.js:toolingFiles = ["**/eslint-plugins/**/*.js", "**/scripts/**/*.mjs"]получаютjs.configs.recommendedплюсlanguageOptionsсglobals.node(иначеno-undefругается наconsole,processиURLв Node-скриптах).- Полные TS/svelte-наборы туда не подключаются: это
.mjsи конфиги, а не продуктовый код. - Масштаб оказался небольшим: 28 проблем, из них 26 —
no-undefна Node-глобалах и только 2 настоящие: мёртвые импортыexistsSyncиresolveвscripts/serve-static.mjs. Линтер сразу нашёл пыль в инфраструктуре, для которой его раньше не было. eslint-plugins/**дал ноль проблем, а новые тестыscripts/__tests__тоже попали под правило.- Проверено пробой: после включения неиспользуемая переменная и вызов
неопределённого глобала в
scripts/дают ошибки, то есть правило применилось, а не молча пропустило файлы.
Q7d. Решения по оставшимся вопросам
Статус: закрыт тремя решениями.
- Обычный CSS под те же токен-правила, что Svelte styles — узко. В
srcвсего один CSS-файл, и он же словарь токенов, поэтому переносить тудаno-hardcoded-in-svelteи подобные нечего: stylelint уже проверяетsrc/**/*.css(префиксы, запрет!important, цвет только у brand-токенов), аcheck-tokens.mjsдублирует проверку цвета. Реальный пробел был один —var()может ссылаться на несуществующий токен, — его закрыл новый модульweb/scripts/token-audit/refs.mjs(см. Q7e). Широкую унификацию механизмов решено не делать: это лишний слой поверх дублирующихся проверок. - Конфиги под рекомендации — только JS.
*.config.js(eslint/postcss/stylelint) добавлены вtoolingFiles; по измерению они дают 0 проблем, поэтому это бесплатно. TS-конфиги (vite,vitest,playwright) не подключены: им потребовался быtseslint-парсер и записьvite.config.tsвallowDefaultProject, а выигрыш близок к нулю. Попутно удалена мёртвая записьsvelte.config.jsвallowDefaultProject— такого файла нет. - Unused-аудит остаётся предупреждением. Правило «новый токен — вместе с
потребителем» закреплено в
AGENTS.md. Причина:verifyвходит в deploy-workflow, поэтому стилевой долг блокировал бы деплой сайта; кроме того, чтение токена из JS (getPropertyValue) аудит не видит и дал бы ложное срабатывание. Baseline чистый, пыль вычищена в Q7a.
Q7e. Проверка резолва var() в app.css
Статус: выполнен. Аудит падает, если var(--x) в app.css указывает на
токен, которого нет в этом же файле.
web/scripts/token-audit/refs.mjs+ вызов вcheck-tokens.mjs; режим — ошибка, а не предупреждение, потому что это дефект (объявление молча отбрасывается), а не стилистический долг.var(--x, fallback)не считается ошибкой: fallback легален без определения токена.- 7 тестов в
scripts/__tests__/token-audit.test.mjs: резолв в обеих темах, опечатка с локацией, fallback, дедуп повторов, ссылка внутри определения токена,var()в обычном свойстве. - Проверено на живом файле: временная опечатка
var(--color-bordr)далаUnresolved var() referencesи код выхода 1;app.cssвосстановлен байт в байт.
Q7f. Оставшиеся направления
- Новые правила подключать только после fixtures,
test:rulesи baseline. - Если в коде появится чтение токенов из JS,
collectUsedTokensпридётся расширить — иначе unused-аудит начнёт считать используемые токены пылью.
Q8. Новые автоматические правила
Оценка: L. Зависимости: Q4, Q7.
Дублирование HTML/Svelte-разметки
Сначала провести report-only аудит новых components/** и routes/**.
Определить:
- минимальный размер клона;
- нормализацию Svelte blocks и динамических классов;
- список допустимых fixture/allowlist-случаев.
Только после оценки false positives выбирать между готовым detector и собственным AST-правилом. Не включать detector в blocking gate сразу.
Пользовательские тексты вне i18n
Сделать warn-only пилот с исключениями для:
- бренда и версии;
- форматов и имён файлов;
X/Yи технических значений;- registry source strings;
/kit;- тестовых данных и внутренних сообщений.
Blanket-запрет всех string literals не использовать.
Согласованность комментариев
Автоматический lint не делать. Это review/process policy: комментарий должен
объяснять причину исключения, а TODO/FIXME — ссылаться на backlog или issue
и иметь критерий закрытия.
4. Что описать в AGENTS.md
В AGENTS.md добавить только следующие неочевидные правила:
- Какой набор команд считается полным quality gate и что означает успешный результат при warnings.
- Production-scope и политику удаления v1: новые изменения относятся только к production UI; исторические UI-v1-упоминания остаются в архиве.
- Политику e2e: semantic locators, допустимый
data-testid, запрет бессмысленных counts/classes/alt/exact prose. - Политику i18n: новые пользовательские тексты через i18n; registry source,
brand, formats и
/kit— явные исключения. - Жизненный цикл
test.fixme: только для зарегистрированного бага, с ссылкой; исправление и удаление теста происходят вместе. - Комментарии и
TODO/FIXMEдолжны объяснять «почему» и иметь ссылку на работу. - Shared-модули
core/themeтребуют проверки production-потребителей.
Синтаксические списки ESLint-правил и подробные токены остаются в
web/eslint-plugins/README.md.
Политика документации для агентов
AGENTS.md не должен превращаться в полный справочник проекта. В нём оставляем
только обязательный рабочий контракт: команды, production-scope, ключевые
инварианты, исключения и ссылки на подробные документы. Если агенту нужно понять
причину или workflow, в AGENTS.md должна быть короткая понятная формулировка;
длинные примеры, точные процедуры, таблицы и критерии проверки переносятся в
docs/ или в README рядом с соответствующей подсистемой.
Принцип выбора места документа:
- Поведение агента, которое нельзя пропустить — кратко в
AGENTS.md. - Точная команда, скрипт, параметр или критерий качества — в
docs/quality-gates.mdили в README соответствующей подсистемы. - Архитектурное решение, поток данных и границы модулей — в
docs/architecture-overview.mdили существующем плане. - Реализация конкретного lint-правила и его fixtures — только в
web/eslint-plugins/README.mdи исходниках правила. - Продуктовая задача, backlog и ручная приёмка — в
docs/backlog.md, активном плане илиdocs/checklist-manual-testing.md.
Подробные документы не дублируются в нескольких местах: у документа должен быть
один источник истины, а остальные файлы ссылаются на него. Все подробные
материалы хранятся в docs/, чтобы не засорять корень репозитория.
Активный документ должен иметь статус (draft, active, completed или
archived) и понятную область применения. Архивные планы не используются как
текущие критерии приёмки без отдельной сверки с кодом. Новый документ создаётся
только когда темы нет в существующем файле; иначе обновляется существующий.
Архивирование и срок хранения
Завершённые, отменённые или явно устаревшие документы переносятся в
docs/archive/, а не остаются в корне docs/ как рабочие планы. При переносе
добавляются дата архивирования, дата удаления и причина. Архивный документ —
временная справка для быстрого просмотра прошлых решений, но не источник текущих
требований.
Срок хранения после архивирования — 30 дней. После этой даты документ можно
удалить после проверки ссылок; если он снова нужен, его восстанавливают из git
history или пересоздают как новый активный документ. Подробная процедура и
шаблон метаданных находятся в docs/archive/README.md.
Какие документы подготовить
| Документ | Назначение | Когда создавать/обновлять |
|---|---|---|
docs/README.md |
Индекс активных документов, карта источников истины и краткий порядок чтения для агента | Q0; при добавлении нового активного документа |
docs/agent-workflow.md |
Подробный workflow: исследование, изменение, проверка и обновление документации | Q0–Q1; только для процессов, не описанных кратко в AGENTS.md |
docs/quality-gates.md |
Команды проверки, semantics errors/warnings, порядок запуска и требования CI | Q1; при изменении scripts/config/CI |
docs/testing-strategy.md |
Слои тестов, locator policy, i18n assertions, fixtures, test.fixme и правила e2e |
Q4; при изменении тестовой архитектуры |
docs/architecture-overview.md |
Карта core, registry, executor, production UI и shared-модулей |
Q5 или перед крупным рефакторингом; не дублировать существующие планы |
web/eslint-plugins/README.md |
Детали custom lint rules, token policy и fixtures | Уже существует; менять только вместе с правилами |
docs/archive/README.md |
Политика временного архива, даты и удаления через 30 дней | Q0; обновлять при изменении архивной политики |
Не создавать отдельные docs/commands.md, docs/known-issues.md или копию
backlog: команды принадлежат quality-gates, известные проблемы — backlog и
checklist. README.md в корне остаётся кратким обзором продукта, а не вторым
руководством агента.
5. Порядок PR
- Q0 — синхронизация backlog/checklist/AGENTS.
- Q1 —
verifyи PR quality gate. - Q2 — i18n parity и strict warning gate.
- Q3 — удалить v1 отдельной атомарной задачей.
- Q4 — тестовый контракт и stale-тесты для production UI.
- Q5 — preview-баги и снятие
fixme. - Q6 — расширенное покрытие.
- Q7 — тесты lint-инфраструктуры и unused tokens.
- Q8 — report-only duplicate/text audits; blocking — только после baseline.
Каждый PR должен быть атомарным и небольшим; не объединять SchemaPreview
refactor, новые i18n-правила и исправление продуктовых багов в одну работу.
6. Отдельные направления и что не начинать автоматически
- полноценный browser/visual/coverage matrix;
- полноценная PWA/API/WASM-платформа;
SchemaPreviewstate/view-model refactor;- plural-формы до модели словаря;
- универсальный линтер одинаковых комментариев;
- batch/архивы, region-инструменты и остальные продуктовые волны из backlog.
7. Решения, которые нужно принять на ревью
- Какие executor/worker/fallback сценарии войдут в первый Q6 coverage PR?
- Нужны ли browser/mobile matrix и visual snapshots до coverage thresholds? Решено: matrix — Q6f.3, coverage — Q6f.4, visual snapshots отложены с обоснованием в Q6f.5.
- Какие unused design tokens можно удалить, а какие должны остаться? Решено в Q7a: удалены все четыре, audit чист.
- Какие browser/e2e проверки должны быть обязательными для PR, а какие — отдельным ночным прогоном?
Отложенное решение: условия matrix и blocking e2e
Окончательное решение про e2e в CI принимается не сейчас, а после
пересмотра условий тестов. К этому моменту нужно вернуться и решить одним шагом:
- Пересмотреть условия matrix: какие спецификации обязаны идти в
browserContractTestsиmobileTests, нужен лиpng-fixturesвне Chromium и что делать с engine-специфичными расхождениями декодеров. - Накопить стабильные прогоны
e2eна раннере (сейчас ориентир — 276 тестов, ~3 мин на job) без падений по таймингу. - Только после этого решать, делать ли
e2eblocking, и если да — сниматьcontinue-on-error, иначе общий conclusion прогона останется зелёным при красномe2e(проверено на run36225579363).
До этого решения e2e остаётся non-blocking baseline, а его фактический статус
проверяется по отдельному job, а не по conclusion прогона.