Самая дорогая правка 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. Поэтому выводы ограничены данными модели, а не реальными устройствами или пользовательскими исследованиями.
Пять причин одинакового визуального симптома
| Наблюдение | Вероятная причина | Минимальный факт | Обратимое действие |
|---|---|---|---|
| В одном экране другой синий | literal value обошёл named token | значение не ссылается на button.primary.background | вынести только это usage на существующий token и проверить inventory |
| Focus исчез после refactor | focus-visible отсутствует в required states | state 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 без inventory | profile-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 обязан был сам выбрать дизайн.
Маршрут: симптом → причина → проверка → действие
- Симптом. Зафиксируйте один экран, state и значение: например, primary button в loading использует другой background или не имеет focus-visible.
- Причина. Проверьте, это literal, неизвестный token, отсутствующий state или другой component role. Не лечите все варианты одним global rename.
- Инвентарь. Выпишите известные usage с name, role и state. Отделите подтверждённые места от предположений из поиска.
- Проверка модели. Запустите
node web/scripts/upgrade-2022-05.mjs --verify-fixture. Она должна отклонить invalid configuration и восстановить previous value после rollback. - Действие. Внесите один допустимый token correction или заведите отдельный variant после review. Не добавляйте undeclared key как «быстрое исключение».
- Проверка платформы. В отдельном реальном запуске проверьте собранный 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 результаты здесь сознательно не заявляются.
Проверяемые источники
- CSS Custom Properties for Cascading Variables Module Level 1, Candidate Recommendation Draft от 11 ноября 2021 года — датированный нормативный снимок: custom properties имеют имена --* и подставляются через var(). Он не определяет taxonomy дизайн-токенов и не подтверждает результат visual regression.
- WAI-ARIA 1.2, Candidate Recommendation Draft от 8 декабря 2021 года — датированный нормативный снимок, доступный в мае 2022 года. Он описывает роли и состояния, но не выбирает за продукт токены, текст кнопки или набор variants.
- Web Content Accessibility Guidelines 2.1, Recommendation от 5 июня 2018 года — неизменяемая W3C Recommendation с проверяемыми критериями, включая Keyboard, Focus Visible, Name/Role/Value и Non-text Contrast. Fixture пакета их не измеряет.