Мелочи приёмочного листа v12 §8. Каждая правка с тестом; где защита уже стояла в коде — тест проверен вырезанием этой защиты. Предел веса картинки. Две прежние проверки были пустышками: сравнивали константу саму с собой и с тем же числом в ответе сервера. Вырезание правила max: оставляло обе зелёными. Настоящий тест грузит перевес и ждёт отказа — это четвёртая найденная пустышка за ветку. Обход модерации. Объявление без статуса и причина отказа длиннее колонки роняли запись в базу ВНЕ защиты, и обход обрывался на середине: остальные клиенты не узнавали, приняли их рекламу или отклонили, а деньги за отклонённый набор не возвращались. Запись ответа теперь под той же защитой, что и сеть; пустой статус не пишем вовсе, причину храним обрезанной. Робот. Адрес файла приходил в ответе сервера, а шли по нему со своим токеном без всякой сверки. Теперь адрес обязан вести на портал. Папка снимков экрана росла бесконечно, а на снимках видны логин и остаток счёта — старше двух недель убираются. Ещё: порядок посредников служебного канала — токен раньше служебного соединения; BannerGenerator больше не отдаёт молча файл тяжелее предела и берёт предел из общей константы; нулевой номер креатива ловится намеренно, а не случайно нестрогим сравнением. Портал 300/300, робот 60/60. Мест снятия заморозки денег по-прежнему четыре. Не тронуто намеренно: цена за 1000 показов и бюджет приходят от клиента — но это видимое поле мастера и принятое продуктовое решение, а не недосмотр. Решает владелец.
Робот-грузчик креативов в кабинет Яндекс Директа
Зачем он нужен
Портал заводит рекламную кампанию «за показы» в Яндексе целиком через программный
интерфейс — кроме одного шага. Картиночный креатив через него создать нельзя: приём
creatives.add принимает только видео, а конструктор креативов Яндекс закрыл 01.06.2026.
Остался единственный путь — загрузить готовые файлы руками в веб-кабинете.
Этот робот и есть «руки»: он относит готовые файлы клиента в кабинет и говорит порталу «готово». Всё остальное портал делает сам.
Что робот делает
- Спрашивает у портала, есть ли работа.
- Скачивает файлы баннеров.
- Открывает кабинет в своём браузере и проверяет, жив ли вход.
- Загружает файлы через «Загрузить креативы».
- Отчитывается порталу и чистит за собой скачанные картинки.
Чего робот НЕ делает
- Не создаёт кампаний и не запускает показы.
- Не тратит деньги — он вообще не может: таких действий у него нет.
- Не читает номера созданных креативов — их портал добывает сам, сравнивая список креативов кабинета до и после загрузки.
- Не нажимает «Сохранить изменения» — единственную кнопку, которая меняет кабинет. На это есть отдельный тест-сторож.
При любом сбое робот останавливается, отчитывается порталу «сбой» и шлёт письмо со снимком экрана. Кампания при этом остаётся черновиком.
Настройка
Скопировать .env.example в .env и заполнить. Отдельного пояснения стоят:
YC_CABINET_LOGIN— логин рекламного кабинета.YC_ANTEROOM_CAMPAIGN_IDиYC_ANTEROOM_GROUP_ID— «прихожая»: существующие кампания и группа, форму нового объявления которых робот открывает только чтобы добраться до окна загрузки. Ничего в них не сохраняется. Своей кампании у робота в этот момент ещё нет: портал ставит задание до создания кампании в Яндексе, потому что кампания заводится сразу с готовыми номерами креативов. Надёжнее всего назначить прихожей отдельную остановленную кампанию — тогда робот не приближается к работающей рекламе вовсе.
Как завести вход в кабинет
Вход заводится один раз глазами и дальше живёт в папке профиля браузера:
npm run login
На боевом сервере экрана нет, поэтому команда запускается внутри виртуального рабочего стола, к которому подключаются по удалённому рабочему столу через SSH-туннель. Наружу порт не открывается. Владелец вводит пароль и код из СМС — профиль сохраняется на диск.
Как запускать
npm run run:once # один проход: взять задание, если оно есть
npm run keepalive # тихо зайти в кабинет, чтобы вход не заснул
npm test # проверки, браузер не нужен
По расписанию: run:once — часто, keepalive — раз в ~15 минут.
Наложиться друг на друга они не могут: браузерный профиль один, и оба запуска берут общий
файл-замок robot.lock в папке робота. Занят замок — процесс молча уходит с кодом 0 и
пробует в следующий раз; задание при этом остаётся в очереди. Замок, брошенный убитым
процессом (перезагрузка сервера), перехватывается через полчаса.
Снимки экрана в папке screenshots/ робот убирает сам: старше двух недель — удаляет при
очередном запуске. Свежие нужны, чтобы разобрать вчерашний сбой; лежать вечно им нельзя —
на снимке видна боковая панель кабинета с логином и остатком счёта.
Пришло письмо-алярм — что делать
В письме указан шаг, на котором робот встал, и приложен снимок экрана.
- «Вход в кабинет слетел» — зайти по удалённому рабочему столу и выполнить
npm run login. - «Кабинет не принял файлы» — посмотреть снимок: скорее всего, файл не тех размеров или слишком тяжёлый.
- «Окно загрузки не закрылось» — в письме будет текст, который показал сам кабинет. Задание при этом закрыто как выполненное: правду об успехе знает портал, он сверяет список креативов до и после. Если креативы не появились, портал сам пометит задание сбойным.
🔑 Смотрите на концовку письма — она честно говорит, что происходило в кабинете:
- «Робот остановился и ничего в кабинете не менял» — работа не начиналась, кампания осталась черновиком, деньги не потрачены. В кабинет идти незачем.
- «Креативы в кабинет уже загружены» — робот дошёл до конца, файлы лежат в кабинете. Загляните туда и в очередь заданий: повторная заливка оставит дубли, а вычистить их можно только руками.
Где почитать подробности
- Разметка экранов кабинета, снятая живьём — docs/cabinet-flow.md.
- Замысел целиком —
docs/superpowers/specs/2026-07-27-yandex-creative-robot-design.md. - Почему конструктор закрыт —
docs/superpowers/findings/2026-07-27-yandex-konstruktor-zakryt/.