diff --git a/docs/superpowers/2026-08-03-PROMT-smena-14-posle-vykata-koshelka.md b/docs/superpowers/2026-08-03-PROMT-smena-14-posle-vykata-koshelka.md new file mode 100644 index 00000000..b11aae1d --- /dev/null +++ b/docs/superpowers/2026-08-03-PROMT-smena-14-posle-vykata-koshelka.md @@ -0,0 +1,203 @@ +# ПРОМТ смене 14 — после выката кошелька телеграма и починки сторожей + +**Составлен:** 03.08.2026, 15:08 по местным (красноярским) часам. Продолжает +`2026-08-03-PROMT-smena-13-operator-nomera.md` и `2026-08-03-PROMT-vykat-koshelka-telegrama.md`. + +🎯 **Задачи смены владелец ещё не назначил.** Ниже — измеренное состояние и четыре открытых +вопроса, каждый из которых требует его решения. Спроси, с чего начинать, и не хватайся за всё. + +--- + +## 0. С чего начать + +1. **Перемеряй числа командой** (§1). Числа в промте протухают первыми. +2. **Прочитай §4 — открытые хвосты.** Там деньги и единственная точка отказа поиска. +3. **Спроси разрешение владельца перед любым действием на боевом.** Между шагами работай + автономно. + +🪤 **Не вываливай ему этот файл.** Он его не читает — файл для тебя. Спрашивай коротко, +человеческим языком, к каждому варианту цена и выгода, и назови, что советуешь сам. + +--- + +## 1. Сперва перемеряй + +```bash +git rev-parse --abbrev-ref HEAD +git rev-list --left-right --count main...HEAD +git status --porcelain -- app/ bots/ db/ | grep -v '^??' +``` + +**Состояние на закрытие смены 13 (15:08 местного, 08:08 UTC 03.08.2026):** + +- Рабочая ветка `feat/prospects-manual-testing-kp`: позади `main` — **0**, впереди — **104**. + Своего незаписанного в коде нет. +- Последняя запись — `2dab5f2f8`. +- 🟢 **Бой и рабочая ветка совпадают байт в байт: 2629 файлов, ноль расхождений.** +- 🕘 Часы машины и владельца — **красноярские (МСК+4)**, сервер живёт в UTC. Разница 7 часов. + +--- + +## 2. Что сделано сменой 13 — переделывать не надо + +- ✅ **Модуль СМС научился определять оператора и час номера** — `d4ccb5ac`, `ec026f1b`. + Бесплатный справочник Россвязи вместо одной лишь платной ДаДаты. Выкачено, покрытие + мобильных диапазонов часом **95,9 %**. +- ✅ **Кошелёк и заморозка телеграм-рекламы выкачены** — робот и портал, в правильном + порядке. Робот работает с потолком траты **1 000 ₽** (снижен с 5 000 по решению владельца). +- ✅ **Сторож рендер-виртуалки читает `ok`** — `cfc2c55a`. Прежний не мог покраснеть никогда. +- ✅ **Телеграм-работа сведена в рабочую ветку** — `3ea706e5`, ветка снова равна боевому. +- ✅ Снимок боевого `ПИЛОТ.md` дописан: записи «03.08 (день)» и «03.08 (вечер)». + +--- + +## 3. 🔑 Уроки этой смены — они дороже кода + +- 🔑 **Состав выката считать КОМАНДОЙ, а не по списку из промта.** Промт выката называл + 12 файлов — побайтовая сверка показала **29**. По списку бой остался бы разъехавшимся. +- 🔑 **Причину не объявлять, пока не замерил.** Я дважды за смену сказал владельцу неверное: + сперва «ключа ДаДаты на бою нет» (он есть), потом принял разницу слепков робота за чужую + правку (это были переводы строк). Оба раза поправился вслух — так и надо, но лучше не + говорить до замера. +- 🔑 **Приёмка на ЖИВЫХ данных вскрывает то, чего нет в тестовых.** Тесты были зелёные, а на + бою Москва и Питер не отправлялись: в справочнике у них регион записан ПАРОЙ и кода + субъекта нет вовсе. Тестовые данные были чище жизни. +- 🔑 **Сторожа принимать только вырезанием — и это можно делать прямо на бою**, ничего там + не меняя: подменить настройку ТОЛЬКО в памяти процесса через `config([...])` в tinker и + посмотреть, покраснел ли. +- 🪤 **Своя же правка может создать перегрузку.** Справочник по одному номеру дал + **20 044 запроса и 22 секунды** на предпросмотр списка в 20 000. Поймал сторож, считающий + ЗАПРОСЫ (не время — время на стенде плавает). Пачкой стало 64 запроса и 4,6 секунды. + +--- + +## 4. 🔴 Открытые хвосты — каждый требует решения владельца + +### 4.1. Боевой «Поиск клиентов» отстаёт от ветки на 9 файлов + +Замер 03.08 вечером: из 35 рабочих файлов `/opt/sales-finder` **9 расходятся** — `web/app.py`, +`web/bulk.py`, `web/ui.py`, `salesfinder/rubrics.py`, `cities.py`, `models.py`, `portal.py`, +`bulkops.py`, `tools/crawl_rubricator.py`. Тесты туда не кладут, их отсутствие — не расхождение. + +🔴 Боевой — это **старая основа плюс точечная заплатка рендера от 03.08**; такого дерева нет +ни в одной ветке. Слепая перезапись может сломать поиск: там невыкаченный «прогрев» от 22.07. + +**Спросить владельца:** догонять боевой поиск до ветки отдельной работой или оставить. + +### 4.2. Чтение вердикта модерации МТС живьём не проверено ни разу + +Именно оно решает, списать деньги клиента или отпустить заморозку. Не прочитает робот ответ +МТС — кампания провиснет, деньги останутся замороженными. **Первый живой прогон +телеграм-рекламы смотреть в оба.** Живого платного прогона ещё не было. + +### 4.3. Токен робота засветился в выводе команды + +02.08 и снова 03.08. В файлы и коммиты не попал. **Перевыпустить.** + +### 4.4. На бою копятся по две сборки каждого экрана + +Распаковка старые файлы не удаляет, решает только `manifest.json`. Пока безвредно, мусор +растёт с каждым выкатом. Чистить — отдельная аккуратная работа: удалять можно только то, на +что манифест не показывает. + +--- + +## 5. 🔴 Порядок выката — соблюдать дословно + +**На этот сервер выкатывают несколько смен, каждая из своего дерева.** За сутки работу друг +друга затёрли трижды, и один раз поломка была невидимой: портал отвечал 200, журнал чист, а +экраны исчезли из сборки. Полные правила — `2026-08-03-ZAPISKA-sosednei-smene-vykat.md`. + +**Перед выкладкой:** забрать чужое (`git merge` их ветки), прогнать проверки, пересобрать фронт +из дерева с ОБЕИМИ работами. + +**После выкладки — сверка боя с веткой:** + +```bash +git ls-tree -r HEAD --name-only -- app | ssh liderra-prod 'cd /var/www/liderra && cat > /tmp/sp.txt + && while IFS= read -r p; do if [ -f "$p" ]; then printf "%s %s\n" "$(git hash-object "$p")" "$p"; + else printf "NETFAYLA %s\n" "$p"; fi; done < /tmp/sp.txt' | sort > /tmp/boy.txt +git ls-tree -r HEAD -- app | awk '{print $3" "$4}' | sort > /tmp/vetka.txt +comm -3 /tmp/vetka.txt /tmp/boy.txt | awk '{print $NF}' | sort -u +``` + +🪤 **Ответ ssh может прийти пустым** — тогда «расходится всё». Сперва `wc -l`, потом выводы. +🪤 **Проверять состав сборки ПО СУЩЕСТВУ:** искать в обслуживаемом куске текст, который рисует +нужный экран, а не считать файлы. Манифест показывает, какой из кусков реально отдаётся. +🪤 **Распаковка поверх** требует `sudo tar --overwrite` — файлы уже есть, каталоги не наши. +После неё обязательно `chown ubuntu:www-data` и перезапуск `php8.3-fpm` **И** `liderra-queue`. +🪤 **Папку `db/` сверять через `tr -d '\r'`** — у `app/**` в `.gitattributes` задан `eol=lf`, +у `db/**` нет. +🪤 **Файлы «есть на бою, нет в ветке»** — обычно мёртвые хвосты; проверять `git log --all -- <файл>`. + +--- + +## 6. 🔴 Боевой: что трогать нельзя без разговора + +- **`client_sms_settings.allowed_operators = ["mts"]`** — имя отправителя `liderra.ru` + подключено у МТС только на одного оператора. Снимать, когда подключат остальных. +- **Потолок робота `BUDGET_CAP_RUB=1000`** в `C:\liderra\mts-telegram-robot\.env` — решение + владельца на первый боевой прогон. Баланс кабинета МТС около 5 010 ₽. +- **`.env` боевого** — там боевые ключи, в посылку не попадает. +- **Миграции — только под `crm_migrator`**, пароль в Lockbox по **ID `e6qeooj45vqtn2fju58r`** + (по имени команда молча отдаёт пустоту). `yc` на бою лежит в + `/home/ubuntu/yandex-cloud/bin/yc`, в PATH его нет. +- 🪤 **Чтение боевой базы через `tinker` режется защитой строк.** Датчики: + `set_config('app.current_tenant_id', ...)`, `pg_stat_user_tables.n_live_tup` либо соединение + `pgsql_supplier` (политики `srv_bypass`). +- 🪤 **`php artisan tinker <файл>` на бою ЗАВИСАЕТ.** Работает только код **через stdin** с + полными именами классов. + +**Откаты, лежат в `/var/www/liderra`:** `_deploy-bak-sms-20260803.tgz`, +`_deploy-bak-operator-20260803.tgz`, `_deploy-bak-para-20260803.tgz`, +`_deploy-bak-tgkoshelek-20260803.tgz`, `_bak-storozh-vm-20260803.php`. +Робот — `C:\liderra\_bak-koshelek-20260803`. Вся телеграм-реклама целиком — `TG_SANDBOX=true`. + +--- + +## 7. Что владелец решил раньше — не переспрашивать + +1. **Копий веток вне этого диска нет.** Напомнить один раз в итоге смены. +2. **Перевод `main` на рабочую ветку отклонён.** `main` отстаёт на 104 записи; кто выкатит + `main` — откатит боевой. Местная и серверная `main` вдобавок разъехались в обе стороны. +3. **Время в интерфейсе показываем по МОСКВЕ.** +4. **Описание базы остаётся в ДВУХ файлах.** +5. **Тариф МТС «Оплата по факту» + цена 5,03 ₽**; клиенту СМС считается по 9 ₽. +6. **Ограничение «только МТС»** и **потолок робота 1 000 ₽** — его решения от 03.08. +7. **След пробы СМС в боевой базе оставлен как есть** (две рассылки и контакт с его личным + номером, у которого оператор проставлен руками). Обход не снят. +8. **Шесть планов СМС вне git не забирать** — чужая папка. + +--- + +## 8. Общие правила — их нарушение и есть источник всех бед + +- 🔑 **Сначала замер, потом лечение, потом замер снова.** Числа записывать. +- 🔑 **Всё, что промт говорит о БОЕВОМ, — гипотеза, пока не замерена командой.** +- 🔑 **Зелёный тест ничего не доказывает, пока не видел его красным.** +- 🔑 **Тест, который собирает состояние руками, охраняет дыру.** +- 🔴🔑 **Есть доступ к чужой системе — открой её ГЛАЗАМИ.** +- 🪤 **Файлы править только Edit/Write.** Запись из-под Bash может молча исчезнуть; + создание, удаление и проверку делать разными вызовами. +- 🪤 **`composer stan`, а не голый phpstan** — сторож встроен в команду проекта. +- 🪤 **Статанализ может упасть не из-за кода:** `_ide_helper_models.php` лежит вне git, у + каждой рабочей папки свой. Лечение — догнать местную базу миграциями и пересобрать + `php artisan ide-helper:models -M -n`. Пересборка убирает пустую строку перед `@mixin` в + 34 моделях — это косметика форматтера, откатывать. +- 🪤 **`pint` в этой ветке правит 11 давних чужих файлов** — откатывать, не записывать. +- 🪤 Тестовая база — `liderra_testing_prospects`, звать прогон с явной базой. + +--- + +## 9. Церемония записи + +- Запись делает смена сама, **попросив эскейп**: `AskUserQuestion`, где **метка опции — + ТОЧНАЯ команда**. +- Сообщение держать **в файле вне репозитория**, звать `git commit -F <файл> <пути>`. + Для новых файлов нужен `git add`. Временный файл после записи убрать. +- В командной строке **не должно быть круглых скобок**. +- Записывать **перечисленные пути**, не `-A`. +- 🪤 `docs/observer/STATUS.md` пре-стейджит хук — снимать `git restore --staged`. +- 🪤 **Слияние нельзя записать по путям** — `git commit -F <файл>` без путей, поэтому сперва + проверь подготовленное: `git diff --cached --name-only`. +- 🪤 Бумаги с разметкой писать с `LEFTHOOK_EXCLUDE=markdownlint,cspell`.