Дата публикации: 10 ноября 2026 г.
MetaMask – это некастодиальная финансовая платформа, которую скачали более 100 миллионов раз примерно в 190 странах. Расширение для браузера разрабатывается в открытом доступе, поэтому pull-запросы постоянно поступают как от сотрудников компании, так и от сторонних разработчиков.
UX-инженер MetaMask Фрэнсис Непомусено (Francis Nepomuceno) проверил многие из этих pull-запросов и захотел найти способ помочь участникам применять лучшие практики доступности и использовать современные веб-функции. В редакторе он уже использовал Modern Web Guidance – набор навыков, который предоставляет агентам программирования рекомендации по работе с веб-платформами и данные о совместимости браузеров. Чтобы помочь другим разработчикам, он создал бота, который проверяет каждый pull-запрос в репозитории MetaMask с открытым исходным кодом, независимо от того, какие инструменты использовал автор.
Проблема: как не отставать от современных веб-технологий
В современных HTML и CSS постоянно появляются новые функции, которые улучшают специальные возможности и удобство для пользователей. Отслеживать, какие из них работают в разных браузерах, сложно. Поскольку участников много, эти знания должны дойти до каждого, кто открывает pull-запрос.
Безопасность добавляет ещё одну причину для беспокойства: MetaMask по умолчанию изолирует каждую стороннюю зависимость, что делает встроенную функцию браузера более дешёвой в использовании, чем альтернативную библиотеку. Как выразился Непомучено, "доступ к этим современным API, например возможность использовать диалоговые окна и раскрывающиеся списки без JavaScript, стал большой победой".
Решение: Modern Web Guidance проверяет каждый pull-запрос
16 сентября 2026 г. в pull-запросе к MetaMask/metamask-extension была добавлена страница "Как это работает" с разделом часто задаваемых вопросов, созданным так, как создается большинство таких разделов в React:
// Before: Custom React state (removes content from DOM)
const [expanded, setExpanded] = useState(false);
<button type="button" aria-expanded={expanded} onClick={() => setExpanded(c => !c)}>
<Text>{question}</Text>
</button>
{expanded ? <Text>{answer}</Text> : null}
Примерно через пять минут бот оставил комментарий. Ссылаясь на руководство search-hidden-content, он выделил три пункта:
- Условная отрисовка каждого ответа удаляет его из DOM, поэтому свернутый текст нельзя найти с помощью функции поиска по странице в браузере, и его сложнее обнаружить с помощью специальных возможностей.
- Нативный элемент раскрытия
<details>/<summary>(Baseline с 2020 года) сохраняет контент в DOM с правильной семантикой. Для взаимоисключающих панелей общий атрибутname(Baseline, доступен с 2024 г.) автоматически закрывает другие панели. Для часто задаваемых вопросов с несколькими открытыми панелями этот атрибут не используется. - Если бы команда предпочла существующий компонент Disclosure, ей следовало бы по крайней мере сохранить ответы в DOM с помощью
hidden="until-found"и прослушивателяbeforematch, который синхронизируетaria-expandedи состояние значка.
// After: Native <details> / <summary> disclosure (findable with find-in-page)
<details>
<summary>
<Text>{question}</Text>
</summary>
<Text>{answer}</Text>
</details>
Через 13 минут автор опубликовал исправление. Компонент стал нативным раскрывающимся списком <details>/<summary>, свернутые ответы остались в DOM для поиска на странице, а две кнопки навигации стали ссылками.
Этот бот – автоматизация курсора, работающая на основе Modern Web Guidance. Непомусено настроил его с помощью запроса из трех строк. К 21 октября 2026 г. (через пять недель):
- Бот был запущен примерно на 480 pull-запросах и прокомментировал 64 из них (57 pull-запросов на добавление функций и исправление ошибок, а также 7 автоматических pull-запросов на выпуск и синхронизацию) от 26 авторов.
- В pull-запросах на добавление функций и исправление ошибок инженеры исправили 43 проблемы и частично исправили ещё 3 в 22 pull-запросах.
- Инженеры действовали быстро: из 38 исправлений с идентифицируемым коммитом 19 были внесены в течение 15 минут, а 26 – в течение часа.Медианное время от комментария до исправления составило 15, 2 минуты.
Вот как MetaMask настроил бота, что он поймал и где он был шумным.
Запрос состоит из трех строк.
На вопрос о том, как настроена автоматизация, Непомусено ответил: "В наших настройках нет ничего особенного. Мы просто делаем его кратким и ограниченным". Полная инструкция:
- Run /modern-web-guidance for any client-facing changes
- Run /chrome-extensions for any relevant extension changes
- Comment on the PR only when there are issues to address. Keep the comment focused on actionable items
Как это работает на практике:
- Рекомендательный характер. В первые два дня бот публиковал отзывы с запросом изменений (и одно одобрение), которые авторы отклоняли после того, как устраняли проблемы. С 18 сентября каждый отзыв представляет собой комментарий. Оно не блокирует слияние, поэтому авторы могут сами решать, что делать с каждым предложением.
- Он ссылается на конкретные руководства и файлы в репозитории. В 64 pull-запросах, которые он прокомментировал, бот выявил 122 проблемы. В 63 из 102 pull-запросов на добавление функций и исправление ошибок указано конкретное руководство Modern Web Guidance, которое применяется, например
search-hidden-content,state-aware-sticky-headersилиsms-otp-form, и дана ссылка на существующий файл в репозитории, если в нем уже используется рекомендуемый шаблон. - Бот не вмешивается, если pull-запрос не затрагивает интерфейс. Из примерно 480 pull-запросов за эти пять недель по крайней мере 100 затрагивали интерфейс или клиентский код. Бот находил в среднем по две проблемы на каждый pull-запрос, который он комментировал. Команды, работающие в основном с репозиториями интерфейса, могут ожидать, что он будет комментировать большую долю.
Сам запрос работает с любым агентом. Modern Web Guidance устанавливается как навык или плагин для Cursor, Claude Code, Codex, GitHub Copilot, Antigravity и других агентов программирования. Когда агент запускает навык, он ищет подходящие руководства в локальном индексе без ключей API и сравнивает их с различиями, используя модель, которую уже предоставляет средство запуска агента команды.
Что обнаружил агент Modern Web Guidance, но не заметили линтеры
Статический линтер может отметить отсутствующий атрибут в одном элементе, но приведенные ниже результаты сводятся к поведению взаимодействия, семантике HTML и тому, как компоненты сочетаются в файлах.
Поле комиссии за транзакцию, которое выглядело редактируемым, но не сохраняло введенные данные.
В расширенных настройках комиссии за транзакцию в MetaMask поле лимита газа (которое ограничивает сетевую комиссию, которую может потреблять транзакция) выглядело редактируемым, но молча игнорировало ввод пользователей. Это происходило, когда расчетная комиссия ещё загружалась или произошел сбой. При этом кнопка "Сохранить" была отключена без объяснения причин, которое могло бы быть прочитано технологией специальных возможностей.
Ссылаясь на руководство по формам, бот отметил три исправления:
- Отключите поле лимита газа, когда оценка недоступна, и свяжите его видимый текст статуса с полем, чтобы технология специальных возможностей прочитала объяснение.
- Свяжите неактивную кнопку "Сохранить" с тем же текстом статуса, чтобы программы чтения с экрана могли сообщить пользователю, почему она неактивна.
- Переключите поле в режим ввода чисел, чтобы у пользователей мобильных устройств открывалась цифровая клавиатура.
Автор применил все три исправления к обоим модальным окнам настроек и объединил их в один компонент.
Кнопки баннера, которые скрывали свои URL
В баннере статуса для одной из торговых функций MetaMask встроенные действия "Часто задаваемые вопросы" и "Связаться со службой поддержки MetaMask" были созданы как кнопки, которые открывали новую вкладку с помощью JavaScript, а не как ссылки. Через три минуты бот, ссылаясь на руководства по HTML и специальным возможностям, сообщил, что программы чтения с экрана объявляют их как кнопки и что пользователи теряют такие возможности ссылок, как копирование URL или открытие его в новой вкладке из контекстного меню. Также в базе кода MetaMask был обнаружен компонент баннера, который уже отображает эти действия как реальные ссылки.
Через 12 минут автор заменил оба действия ссылками. "Очень удобно, что после принятия рекомендаций в будущих проверках они упоминаются в качестве примера", – говорит Непомусено.
Поля для ввода данных, ярлыки которых находятся в другом месте.
Способность бота читать разные файлы также пригодилась при работе с многоэтапной формой. Статический линтер видит только текстовое поле с текстом-плейсхолдером внутри каждого шага и не может определить, что видимый заголовок и инструкции находятся в родительском компоненте макета. Ссылаясь на руководства по формам и специальным возможностям, бот обнаружил, что плейсхолдер был единственным ярлыком поля, что название шага и инструкции в родительском макете не были связаны с вводом, а также что сообщения об ошибках и повторной отправке кода не озвучивались программами чтения с экрана. Через 15 минут все три были исправлены, а код специальных возможностей остался нетронутым, когда последующий pull-запрос изменил стиль ввода кода на шесть визуальных полей для цифр.
Что ещё обнаружил бот
Вот ещё пять выводов, сделанных за те же пять недель:
- Деталь CSS, которую упустил инженер, создавший бота. В собственном pull-запросе Непомусено для закрепленных вкладок на главном экране были вложены запросы состояния прокрутки CSS без указания названий контейнеров и переключалась граница, что приводило к сдвигу макета в середине прокрутки. Бот сослался на руководство по закрепленным заголовкам, учитывающим состояние, и разработчик исправил обе ошибки. Он нашел отзывы полезными для позиционирования привязки и запросов состояния прокрутки.
- Ограничение проскальзывания при вводе. При вводе пользователем допустимого проскальзывания (изменения цены, на которое он согласен при совершении сделки) значения выше 100 % ограничивались при каждом нажатии клавиши. Например, если пользователь вводил 101, значение автоматически менялось на 100. Следуя руководству по формам, исправление переместило проверку на момент, когда поле теряет фокус, и добавило видимый баннер с предупреждением.
- Индикатор загрузки, который не могли использовать программы чтения с экрана. Скелет загрузки списка токенов помещал ярлык "Загрузка" на общий элемент без роли, что запрещено ARIA. Бот указал на два компонента в базе кода, в которых уже использовался шаблон MetaMask для программ чтения с экрана (оба были обновлены после проверки Modern Web Guidance шестью днями ранее), и через восемь минут автор привел скелет в соответствие с этим шаблоном.
- Незащищенное асинхронное действие. Асинхронная кнопка "Посмотреть на сайте поставщика" не имела защиты от повторного нажатия, поэтому двойной клик мог привести к открытию дублирующихся вкладок и фоновых наблюдателей. Автор добавил защиту менее чем через четыре минуты после комментария.
- Проверка нажатия клавиш без формы. На странице импорта NFT проверка выполнялась при каждом нажатии клавиши, и на ней не было элемента
<form>для отправки семантики. Обе проблемы были устранены через 19 минут после проверки.
Все отзывы общедоступны. Полные комментарии бота можно найти в каждом связанном pull-запросе, а также на GitHub.
Что не удалось исправить и насколько шумно в помещении
Не все выводы были приняты. В таблице ниже показано, как MetaMask подсчитал 102 замечания в pull-запросах на добавление функций и исправление ошибок (ещё 20 замечаний было сделано в семи pull-запросах на выпуск и синхронизацию, где проверка не должна была привести к изменению кода).
Разбивка по темам для всех 122 результатов (включая 20 результатов по pull-запросам на выпуск и синхронизацию):
Вот несколько закономерностей:
- Исправления, которые остаются внутри одного компонента, применяются гораздо чаще, чем сквозные изменения специальных возможностей. Исправления форм и HTML остаются внутри проверяемого компонента, поэтому авторы обычно применяют их сразу (исправлено 19 из 31). Больше всего замечаний (38) касалось специальных возможностей, но исправлено было только 12. Обычно это происходило потому, что исправление выходило за рамки pull-запроса или требовало общего компонента системы проектирования, которого ещё не существовало.
- "Другое" – это то, что выходит за рамки рекомендаций для веб-платформ. Шестнадцать находок касались согласованности системы проектирования, логических ошибок, копирования, качества тестирования, тёмной темы и гигиены кода. Три из них были устранены, одна из них была реальной регрессией (изменение списка сетей, которое нарушило предварительное заполнение формы). Большинство из этих 16 ошибок можно было проигнорировать, но обнаружение регрессии стоило того, чтобы их проверить.
- Ложные срабатывания были связаны с тем, как агент применял руководства, и большую часть шума можно устранить в настройках. Поскольку бот для проверки кода – это агент, который читает diff, а не статический линтер, его ложные срабатывания были вызваны неправильным пониманием окружающего кода или более строгим применением правила, чем в связанном руководстве. Очевидные следующие шаги – пропустить ветки выпуска и синхронизации и сделать запрос более строгим, чтобы агент придерживался правил, явно указанных в руководстве.
Непомусено описывает, как это повлияло на команду и время проверки:
"Отзывы очень полезны. Они помогли нам найти и изучить современные API, такие как Interest Invokers и Popover API".
"Это не увеличило время проверки запросов на извлечение, а скорее сократило его. Многие инженеры используют агентов для обработки отзывов. Проблемы, которые обнаружил Modern Web Guidance, в противном случае потребовали бы проверки специалистом, знакомым с этими современными веб-технологиями".
Дэвид Мердок, инженер MetaMask, также внес свой вклад в руководство. Когда в одном из примеров руководства по макетам CSS была обнаружена ошибка, он сообщил о ней, и через два дня команда Modern Web Guidance внесла исправление.
Что MetaMask говорит командам, которые рассматривают его
- Прежде чем писать, ознакомьтесь с рекомендациями. Выполните команду
npx modern-web-guidance@latest search "accordion find in page", чтобы узнать, какие руководства агент получит для задачи. Вы также можете ознакомиться с полным набором руководств по Modern Web Guidance. - Начните с запроса из трех строк и агента, который у вас уже есть. Установите навык (
npx modern-web-guidance@latest installили команду плагина агента), укажите на него все, что может работать с pull-запросами, и настройте его так, чтобы он комментировал только тогда, когда есть что-то, требующее действий, и придерживался правил, явно указанных в руководстве. Именно поэтому инженеры MetaMask до сих пор читают его комментарии. - Некоторые проблемы могут остаться нерешенными. Из 102 результатов по pull-запросам на исправление и добавление функций 43 были исправлены, а 36 – отклонены или не устранены. Такое соотношение хорошо подходит для бота, который дает рекомендации, но не для блокирующей проверки.
- Продолжайте проверять контент вручную. Бот хорошо разбирается в семантике веб-платформ, современном CSS и шаблонах взаимодействия, но не знает продукт.
Есть и то, что в MetaMask ещё не измерили. За пять недель команда не отслеживала стоимость одного pull-запроса, время выполнения, сравнения моделей и поведение бота-рецензента за пределами базы кода React.
Добавив три строки конфигурации, MetaMask получил бота для проверки, который цитирует конкретное руководство для большинства результатов (и существующий пример в репозитории, если он есть). Принятые предложения обычно исправляются в течение часа.