Commit Graph

6 Commits

Author SHA1 Message Date
Дмитрий a1567ff545 fix реклама Яндекса: сегмент Аудиторий указывается с приставкой 20 — без неё Директ отвечает «объект не найден»
Настоящая причина, по которой портал не мог завести кампанию. Прежний диагноз «сегменту
нужно не меньше 1000 опознанных людей» оказался ВЫДУМКОЙ: он был построен на статьях,
а не на замере, и увёл в ожидание, которое ничего не решало.

Что происходит. Сегмент Аудиторий указывается в условии ретаргетинга не своим номером,
а номером с приставкой 20: сегмент 58034825 уходит как ExternalId 2058034825. Без приставки
Директ ищет цель Метрики с таким номером и честно отвечает 8800 «Object not found» — тем же
отказом, что и на несуществующий сегмент. Поэтому поломка выглядела как «аудитория не готова».

Замер на боевом кабинете 30.07 на одном и том же ГОТОВОМ сегменте:
   ExternalId 58034825   -> отказ 8800 «Object not found»
   ExternalId 2058034825 -> условие создано, № 41678818
После починки то же самое кодом портала: условие № 41678854 создано и убрано за собой.

Приставку показал сам Яндекс: у уже существующего в кабинете условия на этот сегмент
retargetinglists.get возвращает ровно "ExternalId": 2058034825. Документация про приставки
говорит глухо и только «для интересов» — живой ответ кабинета оказался надёжнее документации.

Попутно снят ложный «дефект продукта». Порога в 1000 человек НЕ существует: сегмент годится
для Директа при 134 опознанных людях из 151 номера. Минимум портала менять не нужно.

Ещё один замер, важный на будущее: статус is_processed у сегмента — это НЕ «готов»,
у готового статус processed, заполнены matched_quantity и cookies_matched_quantity,
и стоит can_create_dependent. Судить о готовности только по can_create_dependent.

Тестов на приставку было ДВА, и оба закрепляли поломку: проверяли, что уходит номер БЕЗ
приставки. Оба были зелёные всё время. Тест, написанный по нашему представлению о правде,
а не по ответу живой системы, охраняет баг и делает его невидимым. Теперь оба проверяют
приставку и падают без неё; реклама портала 43 из 43.

Вместе с починкой ложатся три промта смен: 29.07 сведение телеграма и прокси, 29.07 робот
креативов в работу и 30.07 состояние после живой приёмки. В последнем ложный диагноз про
порог в 1000 человек помечен как неверный прямо в шапке — чтобы следующая смена не пошла
по нему второй раз.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 10:57:38 +03:00
Дмитрий f2bfe3f1da fix реклама Яндекса: пять поломок, которые вскрыл первый живой запуск связки портал-робот-кабинет
Ни одну нельзя было увидеть без настоящего прогона: часть закрыта песочницей Яндекса,
часть — швами между кусками, которые по отдельности покрыты тестами.

1. Слепок креативов уходил с SelectionCriteria пустым МАССИВОМ. Живой Яндекс отвечает
   отказом 8000 «SelectionCriteria cannot contain an array», портал не может снять слепок,
   задание роботу не выдаётся, клиент видит вечное «готовим картинки». В JSON нужен пустой
   ОБЪЕКТ. Песочница до этой проверки не доходила — отвергала запрос раньше, на входе.

2. Отказы Яндекса ПО ПОЗИЦИИ внутри ответа глотались молча. Запрос успешен, а нужного Id
   в позиции нет — вместо него Errors с человеческим объяснением. Портал падал ошибкой PHP
   «Undefined array key Id», ни клиенту, ни в журнал не попадало ни слова из ответа Яндекса.
   Теперь слова Яндекса выходят наружу — именно это и позволило найти пункт 3.

3. В условии ретаргетинга не передавался MembershipLifeSpan — срок хранения человека
   в сегменте. Живой Яндекс отказывает «Required field: Not specified time for goal or
   segment», и следом «Object not found»: довод негоден целиком, запуск встаёт. Берём
   audience_days кампании, границы Яндекса 1..540.

4. Робот не отдавал набор Яндексу: заливал файлы, нажимал «Создать» и уходил. Оказалось,
   «набор» в кабинете и «креатив» в creatives.get — разные вещи: пока набор не отмечен
   галочкой и не нажато «Добавить выбранные», Яндекс креативы не регистрирует. Замер:
   14 залитых картинок были невидимы для creatives.get, после добавления в ЧЕРНОВИК формы
   счётчик прыгнул 18 -> 32 в ту же секунду. Объявление при этом не сохраняется,
   «Сохранить изменения» робот по-прежнему не трогает никогда.

5. Гонка при заливке. Три живых прогона подряд из 15 картинок доносили 14, и каждый раз
   пропадала ДРУГАЯ: 480x320, потом 300x600, потом 336x280. Замер объяснил: кнопка
   «Создать» разблокируется на 4-й секунде, когда принято 11 файлов из 15, остальные
   дозагружаются к 7-й. Робот жал сразу по разблокировке. Ждём теперь по строкам принятых
   файлов и по исчезновению слова «Загружается».

   Первая попытка этой починки НЕ РАБОТАЛА и выглядела рабочей: сторож считал размеры
   в окне, не заметив постоянного фильтра из тех же 15 размеров вверху. Поймано по тому,
   что прогон занял ровно столько же секунд, сколько до починки. Отсюда тире в признаке
   приёма — фильтр его не содержит.

Каждая починка закрыта тестом, который сначала падал на своей поломке. Прежние тесты
проверяли разбор ОТВЕТОВ и путь ДО «Создать» — форму запросов и то, что после, не смотрел
никто. Робот 84 из 84, реклама портала 42 из 42.

Проверено живьём на боевом: задание роботу отработало со статусом done, опознано
15 креативов из 15.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 07:14:33 +03:00
Дмитрий abb3941ec0 feat реклама за показы: удаление отклонённых объявлений в кабинете Яндекса 2026-07-28 11:10:54 +03:00
Дмитрий 0548fc0d8f fix реклама за показы: слепок креативов при выдаче, сверка размера перед объявлением, один баннер на слот
Хвосты портала П1-П8 из приёмочного листа v12.

П1 обрыв постановки задания больше не даёт клиенту голый 500 — 503 с человеческим
текстом и записью в журнал. Таймаут у HTTP-клиента Laravel уже был, эта половина
находки не подтвердилась.

П2 и П6 роботу отдаются только баннеры без номера креатива — тот же список
сопоставляется при отчёте. Раньше стороны расходились и опознание падало на
безупречной работе робота, плодя дубли в кабинете. Плюс постраничный обход описи
креативов: слепок обрывался на первой странице.

П3 слепок «до» снимается при выдаче задания, а не при постановке, и в той же
транзакции, что и перевод в работу. Два задания в очереди получали одинаковый
слепок, второе падало всегда. Постановка перестала зависеть от живости Яндекса.

П4 перед созданием объявлений сверяется настоящий размер каждого креатива одним
запросом. Не сошлось или креатива нет — запуск не идёт.

П5 уникальный индекс uq_ad_campaign_banner_slot, запись v9.09 в CHANGELOG схемы,
rls-reviewer GO.

П7 замок на правку расширен на сегмент Аудиторий — он создаётся раньше кампании.
Смежная находка: перезаливка картинки теперь обнуляет номер креатива.

П8 и Р-х5 файл отдаётся под настоящим расширением и типом содержимого, имя от
номера баннера; робот берёт расширение из ответа портала.

Портал 287/287, робот 43/43. Денежных выходов снятия заморозки по-прежнему четыре.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 05:37:56 +03:00
Дмитрий c9406533bf feat реклама показы: ядро переведено на набор креативов вместо одного адаптивного
Конструктор креативов Яндекса закрыт 01.06.2026 — адаптивного креатива на все
размеры не существует. Медийная кампания состоит из объявления на каждый размер
блока со своим креативом, поэтому строка баннера стала единицей
размер плюс файл плюс креатив плюс объявление.

Что сделано:
- у баннера появились номер креатива, номер объявления и статус модерации
- кап веса баннера поднят со 150 КБ до предела Яндекса 512 КБ
- слепок картиночных креативов аккаунта через creatives.get
- опознание своих креативов разницей слепков до и после загрузки по размеру
- запуск заводит объявление на каждый включённый баннер
- модерация считается по каждому объявлению: кампания работает, если принято
  хотя бы одно, а деньги возвращаются только когда отклонены все

Заморозка и возврат денег не тронуты, денежных выходов по-прежнему четыре.

После выката на прод ПЕРЕзапустить db/03_service_bypass_policies.sql, иначе
джоб модерации молча увидит ноль баннеров.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 14:33:02 +03:00
Дмитрий 12ef186a43 feat(реклама): показы — медийные методы клиента Директа для запуска за показы
Аддитивно в YandexDirectClient пять методов под медийную кампанию, старый клик-путь не тронут:
- addCpmBannerCampaign — CpmBannerCampaign, стратегия CP_MAXIMUM_IMPRESSIONS, FrequencyCap, суммы в микросах
- addCpmBannerAdGroup — пустая группа CpmBannerKeywordsAdGroup как JSON-объект {}, регионы
- addMediaAudienceTarget — привязка сегмента к группе без клик-ставки ContextBid
- addCpmBannerAd — объявление CpmBannerAdBuilderAd по номеру готового креатива + href
- getCreativePreview — превью креатива для показа клиенту, null если не найден

Всё за рубильником, к реальному Яндексу не обращается. Тесты Http::fake 7/7 зелёные,
весь реклама-модуль 186/186 не сломан. Контракт — findings 2026-07-26-direct-media-api-contract.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 23:53:31 +03:00