Files
Deal/.superpowers/sdd/channel-discovery/final-review-report.md
T
Rustam Khalimov 27c7831910
ci / build-test (push) Canceled after 0s
Deal — единая кодовая база
SaaS-мониторинг Telegram: ядро (модули Cards/Kanban/Pipeline/Tenants/Settings/
Discovery, Api, Infrastructure), сервисы telegram/ai/ml/storage, фронт Vue,
контракты и grpc-hosting, деплой-конфиги (dev/prod/observability/CI-раннер),
Gitea Actions CI, документация (ТЗ, техдок, api-map, код-стайл, планы, бэклог).

Текущее состояние: все этапы роадмапа 0–12 закрыты, сборка 5 sln 0/0,
тесты 1340/130/52/38/9 зелёные.
2026-09-11 23:56:47 +03:00

5.6 KiB
Raw Blame History

Discovery — scoped-ревью фикс-волны: вердикт и доработки

Вердикт ревьюера: Ready — With fixes (все 8 заявленных фиксов I1–I4/M1–M5/m1–m6 подтверждены код-ревью; 2 Important + 4 Minor). Смоук-прогон новых веток после правок — зелёный (A–E), образ пересобран, контейнер поднят, API 200.

Findings ревьюера и что сделано

Important

  1. Search-flood retry storm (discovery_worker.py) — при FloodWaitError ключ не двигался, а тик каждые 5 с снова дёргал discovery_search весь день (флуд > 60 с Telethon не гасит сам), спамя лог flood и блокируя eval/join всех задач. → Исправлено: tick() теперь при ban_guard.flood_today() возвращает none (полный стоп discovery-сетевых действий до конца суток — согласуется с «стоп до конца суток» из note_flood); generic-ошибка ключа — после 3 попыток подряд ключ пропускается (advance_search + лог «ключ пропущен»), счётчик ошибок сбрасывается при успешном поиске.
  2. Re-check после wait_join_delay без BanGuard (_join_step) — за паузу 50–70 с пользователь мог нажать стоп-кран / случиться флуд, а pending-join всё равно выполнялся. → Исправлено: в условие после паузы добавлено not ban_guard.can_auto_join() (покрывает стоп-кран, flood дня и суточный лимит).

Minor

  1. Single-key PATCH ломает инвариант min ≤ max паузPATCH {discJoinDelayMax: 5} при сохранённом min=600 давал инверсию → random.uniform падал на каждом join-тике. → Исправлено в двух местах: settings_routes.patch_settings клампит одиночный конец интервала относительно сохранённого другого; ban_guard.wait_join_delay защитно меняет концы местами (и выходит без паузы, если обе настройки 0).
  2. UPDATE join_failures / delete на 3-й неудаче без ре-валидации status='review' — узкая гонка: человека отклонил кандидата между re-read и падением join. → Исправлено: перед инкрементом счётчика статус перечитывается (row_now); UPDATE идёт с AND status='review'; при выходе из review воркер выходит молча, не трогая запись.
  3. Ручной join в API ждал inline-backfill ~1530 с (backfill_dialog спит 1.5–3 с/сообщение) — кнопка «Вступить» висела, прокси с коротким таймаутом показал бы ложную ошибку. → Исправлено: POST /candidates/{id}/join запускает backfill в фоне через _spawn(_backfill_quiet(...)) (паттерн set_monitor_all), ответ API быстрый, ошибки backfill не роняют запрос.
  4. Skip-лог на каждого человека в поиске — известный minor из отчёта фиксера (concern #2). Оставлен как есть: по одному логу на источник информативно для истории задачи; при желании можно агрегировать («пропущено личных чатов: N») — не критично.

Smoke новых веток (временный скрипт в data/, удалён после прогона)

A_FLOOD_GATE_OK                  # flood_today -> tick none, search не вызван
B_PAUSE_DURING_DELAY_OK          # стоп-кран во сне -> join не выполнен, кандидат review
C_JOIN_FAILURES_REVIEW_GONE_OK   # кандидат rejected во время падения join: счётчик 0, запись жива
D_INVERTED_DELAYS_OK             # min>max: wait_join_delay не падает (swap)
E_SEARCH_KEY_SKIP_OK             # 3 ошибки ключа -> ключ пропущен, searchDone, лог «ключ пропущен»
LR_REVIEW_FIX_SMOKE_OK

Проверки

  1. python -m py_compile изменённых файлов (discovery_worker.py, ban_guard.py, discovery_routes.py, settings_routes.py) — OK.
  2. docker compose build app — Built (внутри образа повторный vite build — ok).
  3. docker compose up -d app — контейнер Recreated/Started.
  4. GET /api/health — 200 {"ok":true,...}; login admin — 200; /api/settings отдаёт disc-ключи и discPaused: false; /api/discovery/tasks и /blacklist — 200 {"items":[]}.

Осталось

  • Живой E2E с Telegram-аккаунтом (шаги в task-10-report.md §«Осталось для ручной проверки») — вместе с пользователем: поиск → кандидаты → вступить/отклонить → авто-вступление с паузами и расходом лимита. Реальные flood/форумы офлайн не воспроизводятся.