diff --git a/docs/superpowers/2026-08-06-PROMT-smena-23-chetyre-progona-i-vozvrat-po-sroku.md b/docs/superpowers/2026-08-06-PROMT-smena-23-chetyre-progona-i-vozvrat-po-sroku.md new file mode 100644 index 00000000..acd5b824 --- /dev/null +++ b/docs/superpowers/2026-08-06-PROMT-smena-23-chetyre-progona-i-vozvrat-po-sroku.md @@ -0,0 +1,239 @@ +# Промт смене 23 — забрать четыре прогона и поймать возврат по сроку + +**Составлен:** 05.08.2026, 13:05 UTC (16:05 МСК). +Продолжает [промт смены 22](2026-08-06-PROMT-smena-22-vozvrat-po-sroku-i-chto-dalshe.md), +а через него смены 21–17 — всё, что там про доступы, метод, ранбуки и церемонию записи, +**остаётся в силе**. Здесь только то, что изменилось. + +🎯 **Работа смены: снять урожай с четырёх запущенных прогонов, поймать возврат по сроку +и провести последний оставшийся прогон Я5.** + +🪤 **Не вываливай владельцу эти файлы.** Он их не читает — они для тебя. Спрашивай коротко, +человеческим языком, к каждому варианту цена и выгода, и говори, что советуешь сам. + +--- + +## 0. ⏰ Первое — что случилось ночью + +### 0.1 Возврат по сроку у #13 (карточка Я-Д5, вторая половина) + +Срок #13 — **05.08 включительно**, закрытие произошло при первом часовом обходе после +полуночи МСК. Это **последняя бесплатная карточка приёмки** и ловится она один раз. + +Проверить: статус стал `completed`; заморозка под #13 обнулилась; свободные выросли ровно +на возврат; `delivered_impressions` совпал с кабинетом; в `ad_wallet_transactions` есть +строка `release` по кампании 13. + +🪤 К твоему приходу всё уже случилось — сверяй **по летописи проводок**, а не «глазами в +момент»: строка `release` с суммой и временем и есть доказательство. + +### 0.2 Показы у #19 и #21 — сколько накапало + +Оба прогона крутятся ради одного столбца: **показов**. + +| Кампания | Что закрывает | Порог | +|---|---|---| +| **#21 «Я4»** | половина сметы | **834 показа** из 1667 | +| **#19 «Я3»** | вся смета | **1667 показов** | + +🔴 **Скорость мерить ПОСЛЕДНИМ ЧАСОМ, а не средним за сутки.** Яндекс медийную кампанию +разгоняет: у #13 по часам было 6 показов, 5, 13, **25**. Смена 22 на этом ошиблась дважды +и брала слова назад. Часовые списания видно так: + +```sql +select created_at, type, amount_rub from ad_wallet_transactions +where related_type='campaign' and related_id=19 order by id; +``` + +Цена показа 0,50 ₽ — делишь списание на 0,5 и получаешь показы за час. + +🔴 **#19 и #21 НЕ ОСТАНАВЛИВАТЬ.** Им нужно открутиться. Владелец про это знает. + +--- + +## 1. 🏆 Что сделала смена 22 + +**Приёмка Яндекса: из 29 карточек закрыты 28.** Осталась одна — Я-Д5, вторая половина (§0.1). +**Комбинации: закрыты 5 из 9** (Я1, Я6, Я7, Я8, Я9), четыре в работе. + +**Четыре записи, все отправлены в gitea, две выкачены на боевой:** + +| Запись | Что | +|---|---| +| `a0761a5c3` | отказ по деньгам говорил клиенту по-английски — **выкачено** | +| `1ceba0c56` | журнал: Я1 и Я2 запущены | +| `49ef80cd5` | возобновление выдавало непроверенную кампанию за крутящуюся — **выкачено** | +| `ad4a41fb9`, `a9de42ccb` | журнал: порог предупреждения разобран; Я3 и Я4 запущены | + +**Две настоящие находки, обе тихие:** + +1. 🔴 **Отказ по деньгам говорил по-английски.** Клиент видел + `Insufficient balance: price_kopecks=1500000, balance_rub=9122.76`. + `InsufficientBalanceException` наследует `RuntimeException`, а ручка запуска ловила его + общим уловителем и отдавала текст исключения наружу. Кнопка «Возобновить» этой болезнью + **не болела** — там свой уловитель, и он-то и показал, что сломан именно запуск. +2. 🔴 **Возобновление врало о состоянии.** Кампанию, которую Яндекс ещё проверяет, на паузу + поставить можно (задумано), а «Возобновить» ставило `running` **безусловно** — портал + зажигал зелёное «Крутится» рекламе, которой Яндекс показываться не разрешал. + +**Плюс закрыт порог предупреждения о деньгах** (владелец сказал «забудь», см. §5) и +**включены письма о событиях кампаний** — раньше `SendWarnings` было `NO` у всех шести +наших кампаний, то есть об отказах модерации владелец не узнавал вовсе. + +Прогоны на закрытие: **430 тестов рекламы**, статанализ **0**, pint чисто. + +--- + +## 2. Сперва перемеряй + +```bash +git rev-parse --abbrev-ref HEAD +git rev-list --left-right --count gitea/feat/prospects-manual-testing-kp...HEAD +git status --porcelain -- app/ db/ | grep -v '^??' +``` + +**На закрытие смены 22:** ветка `feat/prospects-manual-testing-kp`. Мои записи отправлены; +позади них соседняя смена дописала свои (обзвон), они могут быть неотправленными. + +🔴 **В той же папке и той же ветке работает ВТОРАЯ смена** (обзвон, СМС, тарифы). Её записи +идут вперемешку с твоими. + +🪤 **Сторож зависимостей `deptrac` красный НЕ из-за тебя.** Он смотрит весь код сразу, а у +соседней смены в работе лежат недоделанные `app/app/Models/ObzvonCall.php` и +`ObzvonTariff.php` — пять нарушений оттуда запирают ЛЮБУЮ запись. Чужое не чинить. Коммит — +с `LEFTHOOK_EXCLUDE=markdownlint,cspell,deptrac` **и только с разрешения владельца**; +остальные сторожа (gitleaks, pint, larastan) оставлять включёнными. + +🪤 **В индексе может лежать ЧУЖОЕ.** Записывать **только своими путями**, никогда `-A`. + +🕘 **Часы машины врут на 4–5 часов.** Время для замеров брать серверное (`ssh liderra-prod date`). + +🪤 **Тестовая база — своя:** `DB_DATABASE=liderra_testing_s19 ./vendor/bin/pest ...` + +--- + +## 3. 🧵 Что осталось + +| Что | Состояние | +|---|---| +| **Я-Д5, вторая половина** | ловится по летописи, §0.1. Последняя карточка из 29 | +| **Я3 (#19), Я4 (#21)** | крутятся, ждут показов. Пороги — §0.2 | +| **Я5** | **не проводился, но теперь ВОЗМОЖЕН** — см. ниже | +| **Я2** | отказ модерации получен (#17). Осталось оформить недостижимые ячейки как `SKIP` | + +### Как провести Я5 — «впритык + отклонили» + +Условия: К=впритык, М=отклонили, П=вся смета (**недостижимо по построению** — отклонённая +реклама не показывается, писать `SKIP`), Д=ничего. + +🔑 **Управляемый отказ модерации у нас ЕСТЬ, и это две конкретные картинки:** креативы +**1163668189 (320×50)** и **1163668188 (320×100)**. 05.08 Яндекс забраковал их дважды +подряд: в кампании только из них — полный отказ, в смеси с хорошими — частичный приём. +Прежнее решение «добывать отказ текстом про займы под залог» **не работает**: название +кампании до модерации не доезжает. + +🔑 **Как добиться «впритык», не трогая летопись денег** — два способа, оба проверены живьём: + +- свободных МЕНЬШЕ круглой суммы → **долить** до неё, смета ровно на неё + (показов = сумма × 1000 / цена за 1000; при 500 ₽ это вдвое больше рублей); +- свободных БОЛЬШЕ → **временно занять** лишнее кампанией-подпоркой: пока она на модерации, + показов не делает и денег не тратит. Запустить нужную, потом подпорку снять. + +Условие К проверяется **в момент запуска**, поэтому приём честный. Прогон стоит **ноль**: +отклонённая кампания не показывается, заморозка возвращается целиком. + +🪤 Подпорку потом **не удалить** — удаляются только черновики. Останется в кабинете на паузе. + +--- + +## 4. Живое состояние на 13:05 UTC 05.08 + +| Кампания | Состояние | Показов | Баннеры | +|---|---|---|---| +| #6 | пауза, стоит из-за документов | 0 | 13 приняты, 2 отклонены | +| #11 | пауза, срок вышел | 2 | все приняты | +| #13 | **крутится**, закроется ночью | 101 | все приняты | +| #16 «Я1» | крутится, владелец остановит | 0 | все приняты | +| #17 «Я2» | **отклонена**, деньги вернулись целиком | 0 | обе отклонены | +| #18 «Я6» | пауза | 0 | на модерации | +| #19 «Я3» | **крутится, не трогать** | 0 | 13 приняты, 2 отклонены | +| #20 подпорка | пауза, служит «прихожей» роботу картинок | 0 | — | +| #21 «Я4» | **крутится, не трогать** | 0 | приняты | + +**Кошелёк тенанта 2:** баланс 9 999,50 ₽, заперто 3 316,50 ₽, свободно 6 683,00 ₽. +Из баланса 77,24 ₽ — долив 05.08 под прогон «впритык». + +**Счёт в Директе:** номер 712890032, логин `sasha261185`, на счету ~8 700 ₽. + +--- + +## 5. ⚠️ Что владелец уже решил — не поднимать заново + +- 🔕 **Порог предупреждения о деньгах** (20 ₽) — «забудь». Программой его менять нельзя: + у кампании потолок 50 ₽, у общего счёта ручка на запись отвечает «сервис временно + недоступен». Только руками в кабинете, владелец знает. +- 🔕 **Документы для показа в регионах** (из-за них стоит #6) — «забудь». +- 🔕 **Лиды от поставщика** — «забудь» (решение смены 21). +- ✋ **#16 и #17 владелец останавливает сам.** +- ✅ **Ночная сводка** оставлена включённой намеренно — придёт письмо ни о чём, это не сбой. + +**Осталось нерешённым:** + +1. **ЮKassa** — магазин 1392092, ключ на месте, тумблер включён, но **живой успешной оплаты + не было ни разу**. Путь «заплатил → зачислилось» в бою не проверен. Проверяется одной + оплатой на 100 ₽. +2. **Две смены в одной ветке и одной папке** — предложено развести, решения нет. + +--- + +## 6. 🔴 Боевой: что трогать нельзя + +Всё из §7 промтов смен 17–22 в силе. Коротко: потолок робота МТС **1 000 ₽** (в рабочем +`.env` `C:\liderra\mts-telegram-robot\`, не в репозиторном); `allowed_operators` только +`mts`; рубильник Директа **не выключать**; чужие кампании в кабинете только читать +(713051718 — эталон); стоп-лист СМС не чистить; миграции только под `crm_migrator` +(Lockbox `e6qeooj45vqtn2fju58r`); **кампании #6, #11, #13, #19, #21 не удалять**. + +🪤 **Форматтер трогает чужое.** `composer pint` без списка файлов переписывает чужие файлы. +Звать **только со своими путями**, после — смотреть `git status`. + +🔴 **ПДн.** Список 1693 номера — личные мобильные. В git не тащить, в переписку не выводить. + +🔴 **В адресе gitea логин и пароль открытым текстом.** В переписку целиком не выводить. + +**Откатные копии на бою:** `/tmp/otkat-s22` (контроллер рекламы до обеих правок дня), +`/tmp/otkat-s22-env` (боевой `.env` до правки даты прокси). + +--- + +## 7. 🔑 Уроки смены 22 — четыре ложные тревоги одного корня + +Все четыре — вывод **по косвенному признаку** вместо вопроса той стороне, которая знает +ответ. Если ловишь себя на «похоже, что…» — остановись и найди команду, дающую ответ. + +1. **«Робота картинок никогда не устанавливали».** Проверил две машины из трёх — эту винду + и боевой сервер. У Лидерры их **ТРИ**: есть ещё **виртуалка-рендер 51.250.1.97**, и + робот живёт там, спрашивая работу каждые 2 минуты. Успел поставить вторую копию + с боевым токеном, прежде чем понял. 🔑 Ответ давала одна команда: + `sudo grep 'creative-robot' /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c` + — 365 обращений с виртуалки против 1 с моей машины. +2. **«Показов на полтора месяца».** Померил одной точкой: показы за сутки делить на 24. + Яндекс разгоняется — мерить последним часом. +3. **«Управляемого отказа модерации не добыть».** Сказал это владельцу, а через час те же + две картинки дали полный отказ. Гипотезу проверять запуском, а не рассуждением. +4. **Мост МТС «сломан»** — код ошибки в Планировщике был от перезапуска. 🔑 Датчик: + `curl` с боевого через туннель — ответ за 0,4 с. + +🪤 **Отдельный урок про запись на бою:** `tinker` через stdin **молча глотает** длинные +и многострочные куски — отчитывается успехом и не делает ничего. Для любой работы сложнее +одной короткой строки писать самостоятельный php-скрипт с загрузкой приложения: + +```php +make(Illuminate\Contracts\Console\Kernel::class)->bootstrap(); +DB::statement("SELECT set_config('app.current_tenant_id', '2', false)"); // без этого RLS отдаёт пусто БЕЗ ошибки +``` + +Запуск: `scp файл liderra-prod:/tmp/ && ssh liderra-prod "cd /var/www/liderra/app && sudo -u www-data php /tmp/файл.php"`.