Аудит §2 переписан под решения (var-гейт, LF, дедуп закрыт — дублей нет); backlog: TD-COMMENTS-IFACE п.1–3 закрыты, TD-STYLE-ANALYZERS закрыт; STATUS.md — новый блок захода, устаревший блок «Осталось (в backlog)» в шапке удалён; план и ledger захода.
42 lines
5.6 KiB
Markdown
42 lines
5.6 KiB
Markdown
# 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
|
||
3. **Single-key PATCH ломает инвариант min ≤ max пауз** — `PATCH {discJoinDelayMax: 5}` при сохранённом min=600 давал инверсию → `random.uniform` падал на каждом join-тике.
|
||
→ **Исправлено** в двух местах: `settings_routes.patch_settings` клампит одиночный конец интервала относительно сохранённого другого; `ban_guard.wait_join_delay` защитно меняет концы местами (и выходит без паузы, если обе настройки 0).
|
||
4. **UPDATE join_failures / delete на 3-й неудаче без ре-валидации status='review'** — узкая гонка: человека отклонил кандидата между re-read и падением join.
|
||
→ **Исправлено**: перед инкрементом счётчика статус перечитывается (`row_now`); UPDATE идёт с `AND status='review'`; при выходе из review воркер выходит молча, не трогая запись.
|
||
5. **Ручной join в API ждал inline-backfill ~15–30 с** (`backfill_dialog` спит 1.5–3 с/сообщение) — кнопка «Вступить» висела, прокси с коротким таймаутом показал бы ложную ошибку.
|
||
→ **Исправлено**: `POST /candidates/{id}/join` запускает backfill в фоне через `_spawn(_backfill_quiet(...))` (паттерн set_monitor_all), ответ API быстрый, ошибки backfill не роняют запрос.
|
||
6. **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/форумы офлайн не воспроизводятся.
|