DarkRiDDeR13 мин

Правка токена без сюрпризов: инвентарь кнопок, диагностика и обратимый шаг

FrontendТестирование

Самая дорогая правка design token часто выглядит как одна строка. Например, цвет primary button меняют, чтобы исправить один экран, а после merge другой сценарий теряет ожидаемый contrast или focus ring. Другой симптом: в новом usage написали удобное имя token, которого система не знает, и оно тихо живёт рядом с исходным. Цена не в самом hex-значении. Команда перестаёт понимать, какой change общий, какой локальный и как вернуть предыдущее состояние без отката чужих исправлений.

Диагностика начинается с факта, а не с косметического решения. Нужно назвать usage, state и значение, которые расходятся; затем проверить, существует ли token в контракте, относится ли он к роли button и какие известные места затронет правка. Эта статья не показывает production regression и не делает скриншоты. Она использует локальную модель с deliberate invalid configuration, declared visual payload и обратимым correction. Поэтому выводы ограничены данными модели, а не реальными устройствами или пользовательскими исследованиями.

Пять причин одинакового визуального симптома

Диагностика разрыва малого design-system contract
НаблюдениеВероятная причинаМинимальный фактОбратимое действие
В одном экране другой синийliteral value обошёл named tokenзначение не ссылается на button.primary.backgroundвынести только это usage на существующий token и проверить inventory
Focus исчез после refactorfocus-visible отсутствует в required statesstate matrix не содержит focus-visible или не проходит к payloadдобавить state в contract до CSS-правки
Новая кнопка неясна без иконкиname и role добавили после visual слояusage inventory содержит пустой name либо role не buttonзадать semantic fields и проверить native host
Visual review назван успешным без артефактаpayload спутали с фактическим запускоместь viewports, но boundary говорит visualRegression not-executedсоздать отдельный реальный job и хранить его output отдельно
Правка задела платёжный экранизменили общий token без inventoryprofile-save и billing-pay используют одну рольвернуть previous value, затем выделить variant только по подтверждённой причине

Сначала построить маленький радиус изменения

Usage inventory — не список «всех кнопок мира». Это честная таблица того, что известно перед правкой: profile-save, billing-pay, dialog-cancel; контекст, name, role, state. Она делает две вещи. Во-первых, reviewer видит возможный blast radius токена. Во-вторых, команда замечает, когда похожий control на самом деле отличается: cancel может не быть primary button, а payment в loading нуждается в дополнительном поведенческом contract. В этом случае не надо включать его ради красивого числа usage.

Инвентарь полезен и при поиске. Сначала ищут известные component entry points и literal values, затем вручную классифицируют найденное. Автоматический поиск не понимает, что text link стилизован под button или что label появляется после локализации. Поэтому результат поиска — вход в review, не доказательство полноты. В fixture inventory задан вручную и прямо помечен как учебный; он не создаёт ложного claim, что репозиторий просканирован.

Invalid configuration должна останавливаться до изменения

У модели есть два плохих входа. Первый пытается поменять button.primary.shadow, хотя такого named token нет. Второй пытается записать в background строку brand-blue, хотя учебный validator принимает только #RRGGBB или целые px. Оба входа возвращают invalid-configuration и не меняют объект. Это не полный CSS parser и не политика production token format. Это маленькая защита против тихого расширения contract в процессе срочной правки.

Когда допустимая правка всё же нужна, функция сохраняет прежнее значение рядом с результатом. Тогда rollback не «угадывает» цвет из истории, а применяет конкретную пару name/value. Это полезный минимальный инвариант: неожиданный effect можно убрать небольшим обратным действием. Он не равен откату релиза, git revert, CSS build или компенсации серверного платежа. В статье о кнопке достаточно не потерять собственное предыдущее token value; более широкий rollback требует отдельного процесса и артефактов.

Исполнимый пример: correction и возврат

const system = createButtonSystem();
const result = applyTokenCorrection(system, {
  name: "button.primary.background",
  value: "#1D4ED8",
});
rollbackTokenCorrection(system, result.rollback);

// background снова "#2457D6". Это rollback локального объекта,
// а не отмена CSS build, deploy или результата visual-regression.

После correction значение background становится #1D4ED8, после rollback — снова #2457D6. Fixture дополнительно проверяет, что недекларированный token не появился в объекте и неверная строка не изменила baseline. Это позволяет отделить две причины. Если правка отвергнута — сначала договоритесь о расширении contract. Если она принята, но usage ведёт себя иначе — проблема в радиусе применения или variant, а не в том, что validator обязан был сам выбрать дизайн.

Диагностическая схема: inventory ведёт к проверке named token и required state. Недекларированный token или неверное значение останавливаются без изменения; допустимая смена background сохраняет previous value и может быть возвращена. Отдельный блок visual payload помечен как объявление входов без запуска visual regression.
Диаграмма показывает обратимый путь: сначала остановить неверную конфигурацию, затем менять один известный token и хранить точное значение для возврата.

Маршрут: симптом → причина → проверка → действие

  1. Симптом. Зафиксируйте один экран, state и значение: например, primary button в loading использует другой background или не имеет focus-visible.
  2. Причина. Проверьте, это literal, неизвестный token, отсутствующий state или другой component role. Не лечите все варианты одним global rename.
  3. Инвентарь. Выпишите известные usage с name, role и state. Отделите подтверждённые места от предположений из поиска.
  4. Проверка модели. Запустите node web/scripts/upgrade-2022-05.mjs --verify-fixture. Она должна отклонить invalid configuration и восстановить previous value после rollback.
  5. Действие. Внесите один допустимый token correction или заведите отдельный variant после review. Не добавляйте undeclared key как «быстрое исключение».
  6. Проверка платформы. В отдельном реальном запуске проверьте собранный CSS, нужные viewports, states и accessibility scenario. Сохраните screenshot/diff/версии там, где это действительно выполнялось.

Visual payload — это очередь работы, не доказательство

Payload перечисляет 375 и 1280, состояния default/hover/focus-visible/disabled/loading и пять token names. Такой формат полезен: он заставляет заранее назвать, что именно должен покрыть будущий visual check. Но пустой payload не видит pixels, а заполненный payload не знает, как конкретный browser применил cascade. Не стоит добавлять к нему synthetic score, ticks или «green» статус. Эти числа создают видимость измерения и затем мешают найти реальный артефакт, когда change нужно объяснить.

Для настоящей visual-regression проверки понадобится другой слой: stable fixture page, поддерживаемый browser/version, viewport, screenshot baseline, правило допустимого diff и путь к output. Для доступности нужны ещё keyboard route и выбранная комбинация технологий. В 2022 году это уже нормальная инженерная дисциплина, но она начинается с честной границы. Нельзя заявить, что control проверен, только потому что его token names красиво лежат в JSON-like объекте.

Ограничение и следующий проверяемый шаг

Учебная модель намеренно не знает CSS inheritance, media queries, dark theme, locale, permissions, сетевой submit и всех usage в кодовой базе. Она не вычисляет contrast и не определяет, будет ли кнопка удобна. WAI-ARIA и WCAG помогают сформулировать нормы для семантики и доступности, но не превращают token correction в универсальное решение. Если один продукт требует destructive action или progress indicator, ему нужен отдельный contract, а не новый optional flag в primary button без обсуждения.

Следующий проверяемый шаг — выбрать одну фактическую правку и оформить короткий change record: исходный token, причина, inventory до правки, expected states, previous value для rollback и ссылка на настоящий visual/a11y result после запуска. Если этой ссылки пока нет, record должен так и говорить. Такой скромный документ удерживает границу между планом и наблюдением, а затем позволяет расширять малую систему только по повторяющимся доказанным случаям.

Историческая граница мая 2022

Нормативные ссылки зафиксированы датами до мая 2022 года: CSS Custom Properties Candidate Recommendation Draft 11 ноября 2021 года, WAI-ARIA 1.2 Candidate Recommendation Draft 8 декабря 2021 года и WCAG 2.1 Recommendation 2018 года. Они не описывают данный inventory, token format или rollback API. Это учебные решения пакета; настоящие visual и accessibility результаты здесь сознательно не заявляются.

Проверяемые источники