3c72560139
Приёмка Г1 02.08.2026 прошла: задание прошло насквозь, робот создал кампанию 2234762 в кабинете МТС, заголовок объявления и ссылка проверены ГЛАЗАМИ на шаге «Объявление». Песочница, 445 номеров из 450 опознано, деньги не двигались. Следы пробы убраны, копия — app/storage/app/proba-priemki-2026-08-02.json. Приёмка вскрыла мину. Первое из двух заданий упало с «Вход слетел — нужен повторный логин», хотя вход был ЖИВ: тем же кодом робота минутой позже проверка ответила «да». Кабинет МТС завис на пустой странице, робот принял это за разлогин. Цена — одна осечка сразу хоронила кампанию: задание в failed, кампания в failed, второй попытки нет. На приёмке это 1 прогон из 2. Робот (bots/mts-telegram-ads): - ensureLoggedIn в src/session.js — три попытки с паузой 5с; сбой самой проверки считается попыткой, а не падением; - SessionLostError несёт признак retryable; - runner.js во всех трёх режимах (запуск, чтение вердикта, пересдача) зовёт ensureLoggedIn и протаскивает retryable в отчёт; - bin/poll.js протаскивает retryable из своей обёртки. Портал (app): - RobotResult читает retryable (только при ok:false); - TgRobotController::done на временный отказ возвращает задание в очередь (queued, taken_at=null) и кампанию НЕ трогает, пока attempts < max_attempts; - client_tg.robot.max_attempts, по умолчанию 3, env TG_ROBOT_MAX_ATTEMPTS. Считаются выдачи задания, а не отказы: тем же счётчиком attempts пользуется возврат по сроку аренды, поэтому бесконечного круга не выйдет. Тесты писались красными: портал 254/254 (720 проверок, +4 новых), робот 134/134 (+4 новых). Pint чист, статанализ 0 ошибок. В phpstan-baseline.neon дописаны 27 записей про $this в Pest-замыканиях — тем же порядком, что у соседнего TgRobotDoneTest. На боевой НЕ выкачено. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>