From bba56f6a1cd4f845aaa491ad747facfcf8a5fab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Sat, 1 Aug 2026 03:39:14 +0300 Subject: [PATCH] =?UTF-8?q?docs=20=D1=82=D0=B5=D0=BB=D0=B5=D0=B3=D1=80?= =?UTF-8?q?=D0=B0=D0=BC-=D1=80=D0=BE=D0=B1=D0=BE=D1=82:=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=BC=D1=82=20=D1=81=D0=BB=D0=B5=D0=B4=D1=83=D1=8E=D1=89?= =?UTF-8?q?=D0=B5=D0=B9=20=D1=81=D0=BC=D0=B5=D0=BD=D0=B5=20=D0=BF=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B5=20=D1=81=D0=B2=D0=B5=D0=B4=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=B2=D0=B5=D1=82=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Прежний промт помечен устаревшим - в нём закрыт хвост Х1, изменилось состояние ветки и у хвоста про тестовую базу нашёлся более грубый корень. Оставлен ради разбора, как разруливать столкновение номеров журнала схемы. В новом промте пять хвостов, и один из них новый и срочный: в полном прогоне одиннадцать падений подряд с ответом живого Яндекс Директа "Invalid OAuth token". Похоже, протух ключ доступа, а на бою в Директе запущена живая кампания с замороженными деньгами. Порядок разбора - сначала посмотреть, а не чинить, и доложить владельцу до любых действий с токеном. По тестовой базе записан готовый прибор: сравнить число записей о применённых миграциях с числом файлов миграций. Больше файлов - в базу лезет чужая рабочая папка, меньше - сборка оборвалась. Замер в промте: на общей базе телеграм давал 42 из 244, на своей 244 из 244 два раза подряд. Хвост про хрупкий тест внешних сервисов, возможно, отпал сам - в последнем прогоне на своей базе он не упал. В промте написано, как это проверить и как закрыть запись честно. Co-Authored-By: Claude Opus 5 (1M context) --- docs/observer/STATUS.md | 18 +- .../2026-08-01-PROMT-dobit-hvosty.md | 4 + ...2026-08-02-PROMT-hvosty-posle-svedeniya.md | 248 ++++++++++++++++++ 3 files changed, 258 insertions(+), 12 deletions(-) create mode 100644 docs/superpowers/2026-08-02-PROMT-hvosty-posle-svedeniya.md diff --git a/docs/observer/STATUS.md b/docs/observer/STATUS.md index bb8fb852..bce0808c 100644 --- a/docs/observer/STATUS.md +++ b/docs/observer/STATUS.md @@ -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). ## Алерт-индикаторы diff --git a/docs/superpowers/2026-08-01-PROMT-dobit-hvosty.md b/docs/superpowers/2026-08-01-PROMT-dobit-hvosty.md index 5fb0e0a0..f0ff811d 100644 --- a/docs/superpowers/2026-08-01-PROMT-dobit-hvosty.md +++ b/docs/superpowers/2026-08-01-PROMT-dobit-hvosty.md @@ -1,5 +1,9 @@ # Промт следующей смене — добить хвосты по телеграм-роботу и тестовой базе +> ⛔ **УСТАРЕЛ 01.08.2026 — читай `2026-08-02-PROMT-hvosty-posle-svedeniya.md`.** +> Хвост Х1 закрыт, состояние ветки изменилось, у хвоста Х2 найден более грубый корень. +> Этот файл оставлен ради разбора «как разруливать столкновение номеров журнала схемы». + Дата постановки: 31.07.2026, поздний вечер. Всё ниже проверено живыми командами. **Коротко:** работа по телеграм-роботу закончена и запушена — на опрос переведены все diff --git a/docs/superpowers/2026-08-02-PROMT-hvosty-posle-svedeniya.md b/docs/superpowers/2026-08-02-PROMT-hvosty-posle-svedeniya.md new file mode 100644 index 00000000..4351ceee --- /dev/null +++ b/docs/superpowers/2026-08-02-PROMT-hvosty-posle-svedeniya.md @@ -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` строку `` оставить как +есть (она без `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б. +- 🪤 **`` в `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.