Files
easy-png-tools/docs/plan-audit.md
T

14 KiB
Raw Blame History

План: аудит верности preview/* против refs-html (DOM → CSS)

Статус: к выполнению. Ветка feat/redesign. Источник правды по пикселям: refs-html/*.html (статический экспорт рефа). Актуальный рабочий аудит сейчас — pnpm refs-audit (scripts/audit.mjs), но он сломан (см. «Почему текущий аудит не работает») и подлежит замене.

Почему текущий аудит не работает

scripts/audit.mjs сопоставляет элементы только по тексту и берёт в сравнение только листовые узлы (у которых нет детей). Контейнеры/карточки/ панели, несущие border-radius, отступы и позиционирование, в сравнение вообще не попадают (byText кладёт в мапу только элементы с непустым text). Следствия:

  • разница радиусов у карточек невидима (карточка — родитель без своего текста);
  • позиция кнопки (Download result) не ловится — это структурная разница;
  • onlyOurs / onlyRef — это просто счётчик текстовых строк на одной стороне, не метрика верности.

Плюс он не делает пиксельного сравнения, то есть принципиально не может сказать «выглядит по-другому». Это текстовый дифф стилей листовых текстов — и всё.

Решения (подтверждены автором)

  1. Копирайт превью — через i18n t() с EN-базой. Сейчас RU-литералы хардкодом только в preview/+page.svelte:26-27 и preview/list-tools/+page.svelte:31 (эти страницы не используют i18n, в отличие от (old)/ и компонентов DownloadButton/ChainToolBlock/…). Заводим их через t() — совпадёт с рефом (EN).
  2. Имена классов НЕ сводим к рефу. Матчинг делаем по структурному пути, а не по классу. Компоненты kit/ остаются идиоматичными, Stage 0 не откатываем. Требуется только эквивалентность структуры (теги, вложенность, порядок сиблингов, наличие узлов, текст).
  3. Пиксельный дифф (Playwright + pixelmatch) пока НЕ делаем. DOM+CSS-аудита достаточно; добавим как сеть позже, если стили что-то упустят.
  4. Порядок прогона маршрутов: demolist-tools → затем 2 инструмента (tools/linear-gradient-pnggradient.html, tools/remove-background-pngbackground-remover.html).

Принципы

  • Никаких правок старого дизайна (old)/ и старого ui/.
  • Коммиты атомарные (< ~500 строк), по 1–2 компонента/скрипта; после каждого — lint + svelte-check + build + соответствующий аудит (diff не должен расти без причины).
  • Коммиты делает автор (агент не коммитит).
  • Шрифты уже совпадают: design2.css:1-6 грузит IBM Plex Sans/Mono через @fontsource, токены :34-35"IBM Plex Sans"/"IBM Plex Mono" (как в рефе demo.html:67-68). Пиксельный шум от шрифтов не предвидится.

Подход: две фазы

Корень проблемы — нет стабильного ключа сопоставления. Разбиваем на две фазы: сначала доводим DOM до структурного равенства с рефом (фаза A), затем на стабильном DOM сравниваем стили по тому же пути (фаза B). Фаза A сама по себе ловит именно то, из-за чего возникли претензии (кнопка не в том родителе, лишние/недостающие обёртки, перепутанный порядок) — и без эстетических решений.


Фаза A — DOM/структурный аудит (scripts/audit-dom.mjs)

Цель: Svelte рендерит структуру, идентичную refs-html (дерево тегов, вложенность, порядок сиблингов, наличие узлов, текст). Имена классов могут отличаться.

Нормализация узла (ключ сравнения)

Для каждого элемента (пропускаем SCRIPT/STYLE/NOSCRIPT и скрытые поддеревья, игнорируем служебное):

  • тег (tagName в lower-case);
  • классы — как отсортированный набор (для инфо, не для матчинга);
  • нормализованный текстtrim, collapse-whitespace, без SVG-иконок внутри (текст иконок игнорируем);
  • порядок детей — позиция среди сиблингов (nth-child).

Матчинг — по структурному пути от корня сравнения: tag:nth-child(i) > tag:nth-child(j) …. Не по классу и не по тексту.

Полное соответствие, без IGNORE

Оболочка (наш TopBar/AppShell/preview-footer vs рефовый .topbar/.footer/.language) тоже сводим к рефу — IGNORE-список не заводим. Сравниваем всё дерево от <body> (без пропуска служебного, кроме Svelte-атрибутов и комментов гидрации), чтобы получить полное структурное соответствие, а не только контента. Шапка/футер/переключатель языка — часть верности; позже, после полного фикса дизайна, всё равно планируется рефакторинг компонентов, где оболочку приведём в порядок и унифицируем. Аудит на этом этапе просто показывает все расхождения, включая оболочечные.

Дифф

Для каждого маршрута — набор дельт:

  • added — у нас, нет в рефе;
  • removed — в рефе, нет у нас;
  • moved — тот же текст/тег, другой путь (перепутанный порядок/родитель);
  • textMismatch — нормализованный текст различается (в т.ч. RU vs EN).

Класс-мисматч — только информационно, не блокирует (классы свои по решению №2). Счётчики: added / removed / moved / textMismatch.

Рендеринг

  • наше: dev-сервер на 5179 (как сейчас в audit.mjs).
  • реф: pathToFileURL к refs-html/<ref>.html (file://). Реф — самодостаточный (инлайн <style>), рендерится полностью. Шрифты для фазы A не важны (сравниваем структуру/текст, не растеризацию).
  • Переиспользуем из текущего audit.mjs: discoverRoutes(), EXCLUDE (/preview), DYNAMIC (tools/[id]gradient.html / background-remover.html), refNameFor().

Шаги (на каждом маршруте)

  1. Прогнать pnpm refs-dom-audit, получить дельты.
  2. Поправить структуру Svelte под реф (добавить/убрать/переставить узлы, вынести тексты в t() с EN-базой).
  3. Перезапустить, пока added/removed/moved/textMismatch ≃ 0 (кроме IGNORE).

Фаза B — CSS-аудит по стабильному DOM (scripts/audit-css.mjs)

Цель: на совпадающем дереве сравнить вычисленные стили по тому же структурному пути и получить «элемент по пути X: свойство → наше/реф».

Сравниваемые свойства (computed)

borderRadius, позиция/размер (getBoundingClientRect: x/y/w/h), padding (все стороны), margin, color, backgroundColor, borderTop/Right/Bottom/Left Width|Color, fontFamily, fontSize, fontWeight, letterSpacing, lineHeight, gap, display, boxShadow.

Дифф

Для каждого состыкованного по пути элемента — список свойств с дельтой (наше значение → реф). Элементы, не совпавшие по пути (остаток из фазы A), идут в unmatched. Отчёт: элемент → свойство → наше/реф. Правится одной строкой CSS, без брутфорса.

Шаги

  1. Прогнать pnpm refs-css-audit (только после того, как фаза A по маршруту дала ≃ 0 структурных расхождений).
  2. Поправить стили в design2.css / стилях компонентов.
  3. Перезапустить, пока delta% по свойствам ≃ 0.

Порядок маршрутов и особенности

  1. /preview/demo (↔ demo.html) — уже ближе всего; идеальная «обкатка» тулинга фаз A и B. Здесь же проверим, что Download result стоит в шапке .preview-top (как в рефе), а не внизу панели.
  2. /preview/list-tools (↔ list-tools.html) — объёмнее; зависит от docs/plan-list-tools.md: реальный аудит имеет смысл только после того, как страница переписана на CatalogHeader/CatalogToolbar/CatalogGroup (шаги 15 плана list-tools). То есть фаза A/B для list-tools стартует после landing этих шагов.
  3. tools/linear-gradient-png (↔ gradient.html) и tools/remove-background-png (↔ background-remover.html) — последние. Известные расхождения: наши инструменты могут иметь другие наборы параметров / UI, чем конкретные рефовые тулзы. Ожидаются структурные и стилевые дельты, которые не сводятся к «подровнять паддинг». Для них — триаж после прогона:
    • реальный разрыв верности → фиксим;
    • принципиальное отличие (параметр, которого нет в реф-тулзе; иной контрол) → либо аккуратно приводим наш UI параметра к рефу, либо документируем как допустимое расхождение / заносим в allowlist конфига аудита (селектор + причина). «Скипы/фиксы» для инструментов оформляем явно, чтобы аудит не шумел на осознанных отличиях.

Структура скриптов

  • scripts/audit-dom.mjs — фаза A (нормализация + структурный дифф).
  • scripts/audit-css.mjs — фаза B (матчинг по пути + дифф стилей).
  • package.json: refs-dom-audit, refs-css-audit (опционально refs-audit, прогоняющий обе фазы).
  • Переиспользуем из старого audit.mjs: discoverRoutes, EXCLUDE, DYNAMIC, refNameFor, waitFor (fast-fail на 4xx/5xx).
  • Отчёты: web/audit/dom-report.{md,json} и web/audit/css-report.{md,json} (старый audit-report.* заменяем).

Верификация (после каждого коммита)

  • pnpm lint, pnpm exec svelte-check --tsconfig ./tsconfig.json, pnpm build — без ошибок.
  • pnpm refs-dom-audit (фаза A) / pnpm refs-css-audit (фаза B) по затронутому маршруту: счётчики расхождений не растут без причины.

Риски / заметки

  • Стабильность матчинга: нужна аккуратная нормализация (сортировка классов, игнор svelte-атрибутов/data-*, игнор whitespace-текстовых узлов, игнор внутренностей SVG-иконок). Подстраивается по первым прогонам demo.
  • Оболочка (TopBar/footer/язык) сейчас отличается по дизайну — сводим к рефу в рамках полного соответствия (без IGNORE); финальная унификация компонентов — отдельным рефакторингом позже.
  • Динамические маршруты: DYNAMIC уже есть; оставляем.
  • Hover / адаптив / тёмная тема — вне объёма статического аудита (initial state, 1440×900, light). Отмечаем как будущие прогоны.
  • list-tools зависит от landing plan-list-tools.md (шаги 1–5) — не аудируем вслепую.