docs телеграм-робот: промт следующей смене после сведения веток
Прежний промт помечен устаревшим - в нём закрыт хвост Х1, изменилось состояние ветки и у хвоста про тестовую базу нашёлся более грубый корень. Оставлен ради разбора, как разруливать столкновение номеров журнала схемы. В новом промте пять хвостов, и один из них новый и срочный: в полном прогоне одиннадцать падений подряд с ответом живого Яндекс Директа "Invalid OAuth token". Похоже, протух ключ доступа, а на бою в Директе запущена живая кампания с замороженными деньгами. Порядок разбора - сначала посмотреть, а не чинить, и доложить владельцу до любых действий с токеном. По тестовой базе записан готовый прибор: сравнить число записей о применённых миграциях с числом файлов миграций. Больше файлов - в базу лезет чужая рабочая папка, меньше - сборка оборвалась. Замер в промте: на общей базе телеграм давал 42 из 244, на своей 244 из 244 два раза подряд. Хвост про хрупкий тест внешних сервисов, возможно, отпал сам - в последнем прогоне на своей базе он не упал. В промте написано, как это проверить и как закрыть запись честно. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+6
-12
@@ -1,6 +1,6 @@
|
||||
# Brain Status (auto-generated)
|
||||
|
||||
Last updated: 2026-07-31T07:17:46.606Z
|
||||
Last updated: 2026-08-01T00:24:12.107Z
|
||||
|
||||
| Контролёр | Состояние | Детали |
|
||||
|---|---|---|
|
||||
@@ -15,7 +15,7 @@ Last updated: 2026-07-31T07:17:46.606Z
|
||||
|
||||
⚠️ **ПОСТ ПУСТОЙ** — не зарегистрированы: enforce-floor.mjs, enforce-supreme-gate.mjs, enforce-normative-content-rules.mjs, enforce-read-path-deny.mjs, enforce-mcp-classification.mjs, enforce-judge-gate.mjs, enforce-snapshot.mjs, enforce-floor-escape-consume.mjs, enforce-skill-journaler.mjs, enforce-verify-gate.mjs, enforce-criterion-gate.mjs, enforce-coverage-verify.mjs, enforce-todowrite-skill-verifier.mjs (оборона НЕ подтверждена; SE-B/Δ8)
|
||||
|
||||
Судья М4: **live-block** (inert $0 / shadow / floor-only / live-block)
|
||||
Судья М4: **inert** (inert $0 / shadow / floor-only / live-block)
|
||||
|
||||
| Машина / страж | Хук | Зарегистрирован |
|
||||
|---|---|---|
|
||||
@@ -112,9 +112,9 @@ Episodes since last run: 542 / threshold: 10
|
||||
|
||||
| PID | Имя | CPU-время | Возраст |
|
||||
|---|---|---|---|
|
||||
| 3544 | MsMpEng | 16.61ч | NaNч |
|
||||
| 23936 | Code | 4.76ч | 0.0ч |
|
||||
| 4 | System | 2.51ч | NaNч |
|
||||
| 3544 | MsMpEng | 24.19ч | 1328736.4ч |
|
||||
| 23936 | Code | 8.07ч | 0.0ч |
|
||||
| 4 | System | 3.50ч | 0.0ч |
|
||||
|
||||
⚠️ Проверь, не «осиротевшие» ли это процессы от завершённых Claude-сессий.
|
||||
|
||||
@@ -130,13 +130,7 @@ Episodes since last run: 542 / threshold: 10
|
||||
|
||||
## Целостность журналов действий
|
||||
|
||||
🔴 Битые цепочки (3 из 120):
|
||||
|
||||
| session | broken at seq |
|
||||
|---|---|
|
||||
| `03437265-6d58-4622-aeed-c0eeac0f2c32` | 1 |
|
||||
| `54594686-843c-4ea8-bcd3-5ae6a7244e30` | 14 |
|
||||
| `9c02276d-dabb-40e4-9c04-44c18d47485a` | 14 |
|
||||
Ключ подписанта не provisioned — проверка цепи недоступна (ключ — owner-шаг A3).
|
||||
|
||||
## Алерт-индикаторы
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Промт следующей смене — добить хвосты по телеграм-роботу и тестовой базе
|
||||
|
||||
> ⛔ **УСТАРЕЛ 01.08.2026 — читай `2026-08-02-PROMT-hvosty-posle-svedeniya.md`.**
|
||||
> Хвост Х1 закрыт, состояние ветки изменилось, у хвоста Х2 найден более грубый корень.
|
||||
> Этот файл оставлен ради разбора «как разруливать столкновение номеров журнала схемы».
|
||||
|
||||
Дата постановки: 31.07.2026, поздний вечер. Всё ниже проверено живыми командами.
|
||||
|
||||
**Коротко:** работа по телеграм-роботу закончена и запушена — на опрос переведены все
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
# Промт следующей смене — хвосты после сведения веток
|
||||
|
||||
Дата постановки: 01.08.2026, ночь. Всё ниже проверено живыми командами.
|
||||
Заменяет `2026-08-01-PROMT-dobit-hvosty.md` — там хвост Х1 уже закрыт, читать тот файл
|
||||
незачем, кроме как ради разбора «как разруливать столкновение номеров».
|
||||
|
||||
**Коротко:** телеграм-робот доделан, ветка сведена с основной, всё запушено. На бой ничего
|
||||
не выкачено. Осталось пять хвостов, и **один из них новый и срочный** — похоже, протух
|
||||
ключ доступа к Яндекс Директу.
|
||||
|
||||
---
|
||||
|
||||
## Где ты работаешь
|
||||
|
||||
Рабочая папка `.claude/worktrees/telegram-merge`, ветка `fix/robot-yandex-zamok`.
|
||||
Хранилище — **только gitea**, GitHub мёртв.
|
||||
|
||||
- верхушка `72db586a`, всё запушено;
|
||||
- ветка **впереди на 24** коммита и **не отстаёт** от `gitea/main` (сведено 01.08).
|
||||
|
||||
Папка снаряжена: свои `composer install` и `npm ci`, свои сторожа. В **главной** папке
|
||||
репозитория сторожа мертвы — см. хвост Х3.
|
||||
|
||||
🔴 **Тестовую базу бери свою.** Общая `liderra_testing` испорчена (подробности в Х2).
|
||||
Все прогоны ниже делай так:
|
||||
|
||||
```bash
|
||||
cd .claude/worktrees/telegram-merge/app
|
||||
DB_DATABASE=liderra_testing_tgmerge php artisan test
|
||||
```
|
||||
|
||||
База `liderra_testing_tgmerge` уже создана и собрана. Если развалится — лечится так:
|
||||
|
||||
```bash
|
||||
cd .claude/worktrees/telegram-merge/app
|
||||
DB_DATABASE=liderra_testing_tgmerge APP_ENV=testing php artisan db:wipe --drop-views --drop-types --force
|
||||
DB_DATABASE=liderra_testing_tgmerge APP_ENV=testing php artisan migrate --force
|
||||
```
|
||||
|
||||
## Что уже сделано — не переделывать
|
||||
|
||||
| Что | Где |
|
||||
|---|---|
|
||||
| Канал робота, очередь заданий, аренда | `TgRobotController`, `TelegramRobotQueue`, `RobotJob` |
|
||||
| Применение итога запуска / вердикта / пересдачи | три применяльщика `Telegram*ResultApplier` и `TelegramModerationVerdictApplier` |
|
||||
| Развилки по каналу у обоих джобов | `PollTelegramModerationJob`, `ResubmitTelegramCampaignJob` |
|
||||
| Развилка режимов у робота | `bots/mts-telegram-ads/src/poll-plan.js` |
|
||||
| Сборка тестовой БД один раз в начале прогона | `app/tests/TestCase.php` |
|
||||
| Сторож против пересборки посреди прогона | `app/tests/Feature/Database/TestDbRebuildGuardTest.php` |
|
||||
| Сведение с основной + перенумерация журнала схемы | коммит `72db586a` |
|
||||
|
||||
Переключатель `TG_ROBOT_TRANSPORT`: `process` (умолчание, старый путь) | `poll`.
|
||||
Сейчас `process` — поведение не изменилось. Откат = вернуть `process`.
|
||||
|
||||
**Чем проверено (на своей базе):** телеграм 244/244, робот 124/124, статанализ 0,
|
||||
код-стиль чисто, полный прогон **4063 теста / 4018 прошло / 17 упало**. До сведения было
|
||||
4039 тестов и 20 падений — тестов больше, падений меньше.
|
||||
|
||||
---
|
||||
|
||||
## Хвост Н1 🔴 НОВЫЙ и срочный — похоже, протух ключ доступа к Яндекс Директу
|
||||
|
||||
В полном прогоне **11 падений подряд** в `tests/Feature/Advertising/CreativeRobotEndpointTest.php`,
|
||||
и все с одним ответом живого Яндекса:
|
||||
|
||||
```
|
||||
Yandex Direct v5/creatives/get error: {"error_code":53,"error_detail":"Invalid OAuth token",
|
||||
"error_string":"Authorization error"}
|
||||
```
|
||||
|
||||
То есть тест реально ходит в Директ и получает отказ авторизации. Токен ставили 25.07.2026.
|
||||
|
||||
**Почему это срочно:** на бою в Директе 30.07 запущена живая кампания `713175197` с
|
||||
замороженными 3333.36 ₽. Если ключ протух — реклама могла встать, а мы об этом узнаём
|
||||
из упавшего теста, а не из тревоги.
|
||||
|
||||
Что сделать по порядку:
|
||||
|
||||
1. **Сначала посмотреть, а не чинить.** Проверить, тот же ли токен в `app/.env` на бою и
|
||||
локально, и когда он выдан. Доступ к бою — **только с разрешения владельца**, база по
|
||||
умолчанию только чтение.
|
||||
2. Спросить у самого Директа состояние кампании `713175197` (показ идёт или встал).
|
||||
3. Доложить владельцу **до** любых действий с токеном — это его учётка и его деньги.
|
||||
|
||||
🪤 Не чинить это правкой теста и не глушить его. Тест — единственное место, которое сейчас
|
||||
кричит правду.
|
||||
|
||||
---
|
||||
|
||||
## Хвост Х2 — тестовая база: две разные болезни, не путать
|
||||
|
||||
**Что уже вылечено** (не переделывай): база пересобиралась посреди прогона и сносила себя
|
||||
под уже отработавшими тестами. Корень был в самом Laravel — подробности в шапке
|
||||
`app/tests/TestCase.php`. Лечение: собираем базу сами один раз в начале и держим флаг
|
||||
взведённым на каждом тесте.
|
||||
|
||||
### Х2б — общая база на все рабочие папки. 🔑 Доказано замером
|
||||
|
||||
В `liderra_testing` оказалось **180 записей о применённых миграциях при 146 файлах** на
|
||||
диске. Записей БОЛЬШЕ, чем файлов — прямое доказательство, что в базу пишет ещё кто-то
|
||||
(другая рабочая папка со своим набором миграций).
|
||||
|
||||
Следствие: `db:wipe` рапортует успех, но остаётся призрачный составной тип `legal_entities`,
|
||||
и **первая же миграция** падает на `pg_type_typname_nsp_index`. Схема остаётся полусобранной,
|
||||
прогон рассыпается сотнями «таблицы не существует» — при полностью исправном коде.
|
||||
|
||||
Замер: на общей базе телеграм давал 42/244 и 48/244, на своей — **244/244 два раза подряд**,
|
||||
и база после прогона оставалась целой.
|
||||
|
||||
🔑 **Готовый датчик:** сравнить число записей в таблице `migrations` с числом файлов
|
||||
миграций. Больше файлов — в базу лезет чужой; меньше — сборка оборвалась. И то и другое
|
||||
значит «верить прогону нельзя».
|
||||
|
||||
```bash
|
||||
cd .claude/worktrees/telegram-merge/app
|
||||
DB_DATABASE=<база> APP_ENV=testing php artisan tinker --execute="echo DB::table('migrations')->count().' записей / '.count(glob(database_path('migrations').'/*.php')).' файлов'.PHP_EOL;"
|
||||
```
|
||||
|
||||
**Что осталось сделать:** закрепить это в репозитории — своя база на рабочую папку.
|
||||
🔴 Это **решение владельца**, потому что меняет общий конфиг. Готовое предложение:
|
||||
в `app/phpunit.xml` строку `<env name="DB_DATABASE" value="liderra_testing"/>` оставить как
|
||||
есть (она без `force="true"`, поэтому переменная окружения её перебивает), а порядок
|
||||
«перед прогоном задай свою базу» записать в `ЭТАЛОН.md`. Так ничего не ломается у тех,
|
||||
кто запускает по-старому.
|
||||
|
||||
### Х2а — нет изоляции между тестами
|
||||
|
||||
В `app/tests/Pest.php` строка `->use(RefreshDatabase::class)` закомментирована с 08.05.2026;
|
||||
изоляцию заказывают 81 файл из 570. Остальные 489 пишут в базу и ничего за собой не убирают.
|
||||
Отсюда оставшиеся счётные падения («ждали 1, получили 2»).
|
||||
|
||||
🔴 Включать изоляцию всем — **решение владельца**: её и выключили из-за тестов, которые
|
||||
ходят в базу по нескольким подключениям сразу (для них есть приёмы `SharesAdminPdo` /
|
||||
`SharesSupplierPdo`). Прежде чем предлагать — **замерь цену**: включи, прогони полный набор
|
||||
на своей базе, посчитай, сколько тестов покраснеет. Без этого числа разговора нет.
|
||||
|
||||
🪤 Не путать две болезни: изоляция даёт счётные падения, чужой писатель — «таблицы не существует».
|
||||
|
||||
---
|
||||
|
||||
## Хвост Х3 — сторожа мертвы в главной папке репозитория
|
||||
|
||||
В `c:\моя\проекты\портал crm\Документация\node_modules` лежит **3793 файла вместо 66 619**.
|
||||
Проверка разметки и орфографии там падает с `MODULE_NOT_FOUND` — правки в главной папке
|
||||
уходят **непроверенными**, и никто этого не видит.
|
||||
|
||||
```bash
|
||||
cd "c:/моя/проекты/портал crm/Документация" && npm ci
|
||||
```
|
||||
|
||||
Проверка, что помогло: `find node_modules -type f | wc -l` должно дать около 66 600, и
|
||||
`node node_modules/markdownlint-cli2/markdownlint-cli2-bin.mjs README.md` должен выдавать
|
||||
замечания, а не `MODULE_NOT_FOUND`.
|
||||
|
||||
🪤 Установка умеет молча положить десятую часть файлов и отрапортовать «added N packages».
|
||||
Сравнивать надо **объём папки**, а не текст отчёта.
|
||||
|
||||
---
|
||||
|
||||
## Хвост Х4 — хрупкий тест внешних сервисов (возможно, уже отпал)
|
||||
|
||||
`tests/Feature/External/ExternalServiceDownAlertTest.php` раньше падал в полном прогоне и
|
||||
проходил в одиночку. **В последнем полном прогоне на своей базе он НЕ упал.** Похоже, его
|
||||
валила испорченная общая база, а не порядок тестов.
|
||||
|
||||
Что сделать: прогнать полный набор на своей базе ещё раз и посмотреть, появится ли он в
|
||||
списке падений. Появится — делать тест самодостаточным. Не появится — вычеркнуть хвост,
|
||||
записав, что причиной была база.
|
||||
|
||||
---
|
||||
|
||||
## Хвост Х5 — мелочь, но врущая
|
||||
|
||||
В `tests/Feature/ClientTg/TgRobotDoneTest.php` служебный токен задан **русскими буквами**
|
||||
(`'секрет'`). В заголовок HTTP русские буквы не проходят физически — настоящий робот такой
|
||||
токен отправить не может. Тест закрепляет невозможное. Заменить на латиницу, как в новых
|
||||
тестах (`'tg-secret-1'`).
|
||||
|
||||
---
|
||||
|
||||
## Что НЕ трогать без явного «да» владельца
|
||||
|
||||
**Выкат на бой и включение опроса.** Упирается не в код: нужно решение, **где будет жить
|
||||
робот** — МТС не пускает адреса дата-центров. Зависит от разговора с поставщиком прокси
|
||||
(обращение **31074**). Порядок выката — `docs/superpowers/2026-07-31-tg-robot-ustanovka.md`.
|
||||
Ключевое оттуда:
|
||||
|
||||
1. Полный прогон + агент `prod-deploy-validator` — вердикт ГОДЕН/НЕГОДЕН.
|
||||
2. Миграции ролью `crm_migrator`, сперва `--pretend`.
|
||||
3. 🔴 **ПЕРЕзапустить `db/03_service_bypass_policies.sql`.** Файл таблично-агностичен,
|
||||
перечислять новую таблицу не надо — нужен именно **прогон**. Не прогонишь → канал
|
||||
робота увидит ноль заданий **молча**.
|
||||
4. `TG_ROBOT_TOKEN` в `.env` портала (**только латиница**), `config:clear` от `www-data`.
|
||||
5. `TG_ROBOT_TRANSPORT=poll` — **последним шагом**, когда робот уже стоит и отвечает.
|
||||
6. Приёмка — **глазами в кабинете МТС**. Журнал говорит, что портал ПОДУМАЛ, а не что было.
|
||||
|
||||
## Красные линии
|
||||
|
||||
**Прод — живые клиенты и деньги.** Любой выкат, миграция на бою, движение денег — только
|
||||
по явному «да» владельца. База по умолчанию **только чтение**.
|
||||
|
||||
🔴 Номера телефонов — ПДн. В задание робота их класть нельзя. Отдельный запрос, только пока
|
||||
задание в работе, без кеша, и только режимам запуска. Это сделано — не «улучшать».
|
||||
|
||||
🔴 Три применяльщика итога трогают деньги. Правки — только отдельным коммитом и только
|
||||
после того, как оба пути зелёные.
|
||||
|
||||
**Пуш только в gitea.** Коммит — по эскейпу, сообщение **без круглых скобок**, в файле,
|
||||
явные пути.
|
||||
|
||||
## Ловушки
|
||||
|
||||
- 🪤 **Число записей в `migrations` ≠ число файлов** — прогон недостоверен, см. Х2б.
|
||||
- 🪤 **`<env>` в `phpunit.xml` без `force="true"` НЕ перебивает** уже заданную переменную
|
||||
окружения. Поэтому `DB_DATABASE=... php artisan test` работает как надо.
|
||||
- 🪤 **`Artisan::call` исключений не бросает** — возвращает код возврата. Проверять надо и
|
||||
код, и факт.
|
||||
- 🪤 **`db:wipe` рапортует «Dropped all tables successfully» и при этом оставляет призрачный
|
||||
тип**, если базу параллельно правит кто-то ещё. Проверять фактом, а не текстом отчёта.
|
||||
- 🪤 **Джоб в тесте нельзя звать напрямую с подставным роботом** — статанализ ругается на
|
||||
тип. Принято `Job::dispatchSync()` + `app()->instance(Runner::class, $mock)`.
|
||||
- 🪤 **Тест опросчика вердикта не увидит кампанию без `SharesSupplierPdo`.**
|
||||
- 🪤 **Перед перегенерацией списка исключений статанализа пересчитай настоящие:**
|
||||
`composer stan 2>&1 | grep -o '"message":"[^"]*"' | grep -vc 'PendingCalls'`. Должно быть 0.
|
||||
- 🪤 **cspell может упасть на словах из ЧУЖОГО коммита** — не твоя опечатка. Смотри, чьи
|
||||
строки, и добавляй в `cspell-words.txt`, если это имя собственное.
|
||||
- 🪤 **`composer pint` правит и чужие файлы.** Перед коммитом откатить всё, что не твоё.
|
||||
- 🪤 **`docs/observer/STATUS.md` не пре-стейджить** — его перегенерирует хук после коммита.
|
||||
- 🪤 **Фабрики у `ClientTg\Campaign` нет** — кампания создаётся руками.
|
||||
- 🪤 **`grep 'pending'` по выводу `migrate:status` ловит имена колонок** (`add_pending_count`)
|
||||
и врёт про «есть неприменённые». Считать по факту, а не по подстроке.
|
||||
- 🪤 **`python -c` через bash съедает кавычки** — для разбора логов класть скрипт в файл.
|
||||
- 🪤 **`/tmp` в аргументе bash превращается в windows-путь, а внутри python-строки — нет.**
|
||||
- 🪤 `pkill -f` по ssh **убивает собственную сессию**. Бить по номеру процесса.
|
||||
- 🪤 Локально Node 24, на рендер-сервере Node 20: `node --test test/` работает только на 20.
|
||||
Локально запускать `npm test`.
|
||||
- 🪤 Полный прогон идёт **~14 минут**. Запускать фоном, не ждать в цикле со сном.
|
||||
|
||||
## Как разговаривать с владельцем
|
||||
|
||||
Он **не программист** — простым русским, короткими абзацами, без «эндпоинтов» и «деплоя».
|
||||
«Готово» — только если правда проверил; упало — сказать честно. Он ценит замер вместо
|
||||
догадки: утверждаешь «сломалось не от меня» — покажи прогон до и после, а не рассуждение.
|
||||
|
||||
## Чем кончается смена
|
||||
|
||||
Либо «хвосты закрыты, вот замеры», либо внятное «упёрлись вот в это, решает владелец».
|
||||
Код — с тестами, обычным пушем в gitea.
|
||||
Reference in New Issue
Block a user