Авито/Домклик: ban_kind теряет явное большинство при схлопывании + причина в алерте захардкожена #3178

Closed
opened 2026-08-28 16:57:50 +00:00 by bot-backend · 1 comment
Collaborator

Sub-issue #3177, делать первым — нужен независимо от того, чем кончится история с аккаунтами.

Проблема

ban_kind во всех прогонах unknown (единственное исключение за неделю — platform в 5120), а в алерт уходит уверенная строка, которую код не проверял:

  • backend/app/tasks/avito_detail_backfill.py:604"%d consecutive blocks, IP rate-limited"
  • backend/app/tasks/domclick_detail_backfill.py:343"blocks, QRATOR reputation likely burned for the session/proxy"

Формулировка «IP rate-limited» дважды уводила диагностику вбок — в том числе меня: она звучит как измеренный факт, хотя это литерал в f-строке.

Что сделать

  1. Заполнять ban_kind из реального признака ответа. Минимальный набор значений — по тому, что различимо в ответе:
    • firewall — страница-заглушка Авито (в замере 28.08: 6 756 байт против 740-807 КБ у нормальной карточки; размер + маркер в теле — надёжный дискриминатор)
    • auth_required — редирект/запрос авторизации
    • platform — 5xx / ответ инфраструктуры источника
    • gone — карточка снята
    • unknown — только если ни один признак не сошёлся; и тогда логировать статус + размер + первые 200 байт тела, чтобы следующий случай стал классифицируемым
  2. Текст алерта собирать из заполненного ban_kind, не из литерала. Нет признака — так и писать «причина не определена», а не выдумывать.
  3. То же самое для Домклика.

Приёмка

  • В новых прогонах ban_kind не unknown (кроме честно неопознанных, с телом в логе)
  • Текст алерта соответствует ban_kind
  • Тест: заглушка 6 756 б классифицируется как firewall, нормальная карточка не классифицируется как блок

Оценка S. Refs #3177

Sub-issue #3177, **делать первым** — нужен независимо от того, чем кончится история с аккаунтами. ## Проблема `ban_kind` во всех прогонах `unknown` (единственное исключение за неделю — `platform` в 5120), а в алерт уходит уверенная строка, которую код не проверял: - `backend/app/tasks/avito_detail_backfill.py:604` — `"%d consecutive blocks, IP rate-limited"` - `backend/app/tasks/domclick_detail_backfill.py:343` — `"blocks, QRATOR reputation likely burned for the session/proxy"` Формулировка «IP rate-limited» **дважды уводила диагностику вбок** — в том числе меня: она звучит как измеренный факт, хотя это литерал в f-строке. ## Что сделать 1. Заполнять `ban_kind` из реального признака ответа. Минимальный набор значений — по тому, что различимо в ответе: - `firewall` — страница-заглушка Авито (в замере 28.08: **6 756 байт** против 740-807 КБ у нормальной карточки; размер + маркер в теле — надёжный дискриминатор) - `auth_required` — редирект/запрос авторизации - `platform` — 5xx / ответ инфраструктуры источника - `gone` — карточка снята - `unknown` — только если ни один признак не сошёлся; и тогда логировать статус + размер + первые 200 байт тела, чтобы следующий случай стал классифицируемым 2. **Текст алерта собирать из заполненного `ban_kind`**, не из литерала. Нет признака — так и писать «причина не определена», а не выдумывать. 3. То же самое для Домклика. ## Приёмка - [ ] В новых прогонах `ban_kind` не `unknown` (кроме честно неопознанных, с телом в логе) - [ ] Текст алерта соответствует `ban_kind` - [ ] Тест: заглушка 6 756 б классифицируется как `firewall`, нормальная карточка не классифицируется как блок Оценка S. Refs #3177
bot-backend added the
bug
priority/p1
scope/backend
scrapers
tradein
labels 2026-08-28 16:57:50 +00:00
Author
Collaborator

Поправка: моя постановка задачи была неверной. Я написал, что ban_kind не заполняется из реального признака. Проверил — механизм #2686 работает, признак снимается, а честный диагноз всё это время лежал в error_text. Его просто никто не читал, потому что в алерт уходил литерал.

5190 unknown  blocked=5  причина: AvitoBlockedError: Avito detail firewall/soft-block (browser-mode)  (4 из 5)
5182 unknown  blocked=5  причина: AvitoBlockedError: ... (browser-mode)                               (4 из 5)
5169 unknown  blocked=8  причина: AvitoBlockedError: ... (browser-mode)                               (7 из 9)
5152 unknown  blocked=5  причина: AvitoBlockedError: ... (browser-mode)                               (3 из 5)
5140 unknown  blocked=5  причина: AvitoBlockedError: ... (browser-mode)                               (4 из 5)
5120 platform blocked=5  причина: AvitoBlockedError: ... (browser-mode)                               (5 из 5)

Причина одна и та же во всех шести прогонах. Разница между unknown и platformодин нетипичный блок из пяти.

Настоящий дефект, их два

1. Правило схлопывания обнуляет явное большинство.
scrape_runs.py:885-891: kinds.pop() if len(kinds) == 1 else BAN_KIND_UNKNOWN. Четыре platform плюс один infra дают unknown. Замысел #2764 правильный — не назначать причину, которой не видели, — но реализация не различает «ничья» и «4 из 5». Информация уже собрана и выбрасывается на последнем шаге.

Как чинить: сохранять перепись в counters.ban_kinds ({"platform": 4, "infra": 1}) и ставить ban_kind по доминирующему при явном большинстве; unknown оставить для настоящей ничьей. Перепись полезна и сама по себе — видно, что примешивается к блокам площадки.

2. Текст алерта — по-прежнему литерал. Эта часть исходной задачи в силе. Измеренная подпись — firewall/soft-block (browser-mode), а в алерт уходит «IP rate-limited» (avito_detail_backfill.py:604) и «QRATOR reputation likely burned» (domclick_detail_backfill.py:343). Ровно этот литерал и скрыл настоящий диагноз, лежавший рядом в error_text.

Уточнённая приёмка

  • counters.ban_kinds содержит перепись диагнозов прогона
  • Явное большинство → ban_kind = доминирующий; настоящая ничья → unknown
  • Текст алерта собирается из ban_kind + подписи отказа, литералов причины не остаётся
  • Тест на «4 из 5» → platform, на «2 из 4» → unknown
  • То же для Домклика

Пути в исходной постановке без префикса — верные: tradein-mvp/backend/app/tasks/….

**Поправка: моя постановка задачи была неверной.** Я написал, что `ban_kind` не заполняется из реального признака. Проверил — механизм #2686 работает, признак снимается, а честный диагноз всё это время лежал в `error_text`. Его просто никто не читал, потому что в алерт уходил литерал. ``` 5190 unknown blocked=5 причина: AvitoBlockedError: Avito detail firewall/soft-block (browser-mode) (4 из 5) 5182 unknown blocked=5 причина: AvitoBlockedError: ... (browser-mode) (4 из 5) 5169 unknown blocked=8 причина: AvitoBlockedError: ... (browser-mode) (7 из 9) 5152 unknown blocked=5 причина: AvitoBlockedError: ... (browser-mode) (3 из 5) 5140 unknown blocked=5 причина: AvitoBlockedError: ... (browser-mode) (4 из 5) 5120 platform blocked=5 причина: AvitoBlockedError: ... (browser-mode) (5 из 5) ``` Причина одна и та же во всех шести прогонах. Разница между `unknown` и `platform` — **один нетипичный блок из пяти**. ## Настоящий дефект, их два **1. Правило схлопывания обнуляет явное большинство.** `scrape_runs.py:885-891`: `kinds.pop() if len(kinds) == 1 else BAN_KIND_UNKNOWN`. Четыре `platform` плюс один `infra` дают `unknown`. Замысел #2764 правильный — не назначать причину, которой не видели, — но реализация не различает «ничья» и «4 из 5». Информация уже собрана и выбрасывается на последнем шаге. Как чинить: сохранять **перепись** в `counters.ban_kinds` (`{"platform": 4, "infra": 1}`) и ставить `ban_kind` по доминирующему при явном большинстве; `unknown` оставить для настоящей ничьей. Перепись полезна и сама по себе — видно, что примешивается к блокам площадки. **2. Текст алерта — по-прежнему литерал.** Эта часть исходной задачи в силе. Измеренная подпись — `firewall/soft-block (browser-mode)`, а в алерт уходит «IP rate-limited» (`avito_detail_backfill.py:604`) и «QRATOR reputation likely burned» (`domclick_detail_backfill.py:343`). Ровно этот литерал и скрыл настоящий диагноз, лежавший рядом в `error_text`. ## Уточнённая приёмка - [ ] `counters.ban_kinds` содержит перепись диагнозов прогона - [ ] Явное большинство → `ban_kind` = доминирующий; настоящая ничья → `unknown` - [ ] Текст алерта собирается из `ban_kind` + подписи отказа, литералов причины не остаётся - [ ] Тест на «4 из 5» → `platform`, на «2 из 4» → `unknown` - [ ] То же для Домклика Пути в исходной постановке без префикса — верные: `tradein-mvp/backend/app/tasks/…`.
bot-backend changed title from Авито/Домклик: честный ban_kind вместо захардкоженной причины в алерте to Авито/Домклик: ban_kind теряет явное большинство при схлопывании + причина в алерте захардкожена 2026-08-28 16:59:24 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#3178
No description provided.