---
name: bot-ux-audit-skill
description: "Скилл bot-ux-audit — дизайн-аудит Telegram-бота живым прогоном; probe.py снимает разговор с раскладкой кнопок, measure.py считает нарушения по порогам Telegram"
metadata: 
  node_type: memory
  type: reference
  originSessionId: b11e39bd-4f6f-47c9-ba7b-680ccf041a5b
  modified: 2026-08-13T17:14:18.515Z
---

06.08.2026 заведён скилл **`bot-ux-audit`** (`~/.claude/skills/bot-ux-audit/`): у ботов нет CSS,
поэтому «дизайн» — это структура сообщения, тон, длина, раскладка клавиатуры, имена кнопок,
состояния визарда и поведение на ошибку. По исходникам это не судится: ответ собирается из
шаблонов, данных и состояния, — только живым прогоном поверх [[tg_playwright_probe_addressing]].

- `tools/probe.py <bot> <out.json> <шаг>…` — снимает ВСЕ сообщения ответа (боты шлют по два-три
  подряд), ряды и подписи кнопок, задержку. Шаг: текст или `tap:Подпись`.
- `tools/measure.py <снимок>…` — механика: длина сообщения, эмодзи на символ, ряды и длина
  подписей, штампованные обороты, молчание, задержка; с несколькими снимками — общий словарь
  кнопок семьи.

Пороги выведены из Telegram и телефона, а не из вкуса: подпись >20 символов режется на 360px,
3 кнопки в ряду не помещаются, >700 символов — стена, ≥3 сообщения подряд заставляют ленту прыгать.

**Сценарий-минимум обязан включать заведомо неизвестную команду** — именно на ней боты молчат.

**Три ложных срабатывания собственного инструмента, пойманные до отчёта** (все того же класса, что
[[wcag_contrast_over_video]]): инлайн-кнопка **редактирует** сообщение, а не шлёт новое, и ожидание
роста `data-mid` не даёт ничего; Playwright набирает текст посимвольно, и включённый в замер набор
давал ровно ~4.4 с на КАЖДОМ шаге — все боты выглядели тормозящими, честная задержка оказалась
2.3–2.6 с; Telegram Web кладёт в подпись кнопки служебный глиф из Private Use Area с переводом
строки, и это летело в отчёт как «перенос строки в подписи».

**Состав семьи на дату:** живы `@VakHunter_bot` и `@avtero_bot`. Бот Механта выключен вместе
с проектом ([[mehant_decommissioned_2026-08]]), `@CodoCeh` ботом не является — это бэкенд кабинета
студии на :8210.

**Клавиатуру должно быть можно свернуть.** `ReplyKeyboardMarkup(..., is_persistent=True)` просит
клиент показывать её ВСЕГДА и отбирает кнопку-переключатель (иконка-сетка слева от смайлика).
На телефоне нижняя клавиатура съедает половину экрана. 06.08.2026 параметр снят у шести ботов:
ВакХантер (2 места), ТБР, Делор (2), CryptoPilot, FreeTierRadar, CebersPost, плюс выключенный
Механт (3 файла). У Автеро и Земли его и не было — по ним и опознали разницу. Проверка живьём:
после `/start` в `.chat-input` должен быть `.btn-menu-toggle`.

**08.08.2026 — снятие `is_persistent` не долетает до старых чатов само.** Владелец увидел
у ВакХантера кнопку-переключатель отсутствующей, у CebersPost — присутствующей, хотя параметр
снят в коде обоих ещё 06.08. Причина: Telegram запоминает клавиатуру ПО ЧАТУ — клиент продолжает
показывать старый объект (с `is_persistent=True`), пока бот не пришлёт новый. У ВакХантера
клавиатура пересылается только по `/start`; если конкретный чат не отправлял `/start` после
правки, там залипает старое поведение НАВСЕГДА без ошибки в коде и без способа поймать это
статическим чтением исходника. Проверено на живом тестовом аккаунте через DOM
(`.chat-input .btn-menu-toggle`) — на нём различия нет вообще, оба бота отдают идентичный
элемент; расхождение владельца — в его личном чате с историей до фикса.
**How to apply:** после снятия `is_persistent` у любого бота — либо попросить владельца/юзеров
разово прислать `/start`, либo намеренно приложить свежую клавиатуру к более частому событию
(как уже сделано у CebersPost — `main_keyboard()` уходит почти с каждым ответом, поэтому там
чат сам себя обновил). Диагностировать такое расхождение владельца можно только вопросом
«когда последний раз жали /start», а не повторной проверкой кода.

**08.08.2026 — сплошная проверка всей семьи, чисто.** По запросу «проверь остальных ботов так
же» прогнан сплошной grep по `~/Services` и `~/Разработки` (кроме venv/node_modules/бэкапов) —
живого `is_persistent=True` нет НИГДЕ. Совпадения были только: библиотека aiogram (не наш код),
исторические бэкапы ВакХантера (апрель-июнь, до всех фиксов), песочница `cryptopilot/notion-agent-sandbox`
(не деплоится), сам скрипт-проверка `kodoceh-web/kbtoggle.py` (упоминает параметр в докстроке),
и комментарий в `vsub-tg-bot/keyboards.py`, поясняющий, что параметр НЕ ставится намеренно.
Живым прогоном `kbtoggle.py` (без единой команды в чат, только чтение DOM) переключатель
`.btn-menu-toggle` подтверждён у ВакХантера, CebersPost, ТБР, CryptoPilot, КодИнвест, Автеро,
ФриТирРадар, VPN-бота — восемь из восьми. У Земли/ЗБР и Оддикса своей нижней клавиатуры нет
вообще (только инлайн-кнопки) — проверять там нечего, `is_persistent` неприменим по конструкции.
Осталось непроверенным живьём (код чист, бот не идентифицирован по username без чтения токена
дольше, чем стоило): Делор/cebers-pulse advisor.
