d26716ed90
Р1. Кампания, не добравшая смету показов, оставалась running навсегда, а заморозка денег клиента - ACTIVE навсегда: единственным переходом в completed было delivered >= paid_impressions, а задачи, закрывающей кампанию по истечении срока показа, не существовало вовсе. Для медийки по списку телефонов недокрут сметы - типовой исход, а не редкий случай. Новая колонка ad_campaigns.shows_until хранит последний день показа - ровно тот, что уходит в Директ параметром EndDate. Пишется вместе с yandex_campaign_id, то есть в момент, когда дату начинает держать Яндекс; возобновляемый запуск переиспользует уже записанную дату, чтобы портал и Директ считали срок одинаково. У выхода 1 в CampaignImpressionCharger появилось второе условие - новых мест вызова AdWalletService::release не добавилось, их по-прежнему ровно четыре. Запись v9.07 в журнале схемы, rls-reviewer GO. Р2. Отчёт робота принимался по любому заданию в любом состоянии: номер брался из адреса как есть. Готово по чужому ещё не выданному заданию разложило бы номера креативов чужой кампании по её баннерам - картинка одного клиента уехала бы в объявление другого; сбой по уже закрытому заданию переписал бы правильный результат на failed. Теперь done принимает отчёт только по заданию в статусе taken - 409 в остальных случаях, та же проверка продублирована в сервисе. Р3, первая половина. Проверка «в работе никого» в takeNext не блокировала строку: две одновременные выдачи обе её проходили и уносили разные задания. Слепки creatives.get перемешивались, а размеры блоков у всех клиентов одинаковые, поэтому итог - тихая привязка чужого номера креатива. Гарантию даёт частичный уникальный индекс uq_creative_job_single_taken, плюс advisory-замок первой строкой транзакции, чтобы штатный путь спокойно отвечал роботу «работы нет». Осталось по Р3: привязать выдачу файла к номеру задания, rls-reviewer по индексу, запись v9.08 в журнал схемы. Ход работы - в файле PROGRESS рядом с промтом v12. Тесты, прогнаны в одиночку: портал 256/256, робот 35/35. Все девять новых тестов были красными до правок, каждая защита проверена вырезанием. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>