feat(tradein/browser): имитация чтения страницы человеком, целиком opt-in (#3283) #3308

Merged
bot-backend merged 1 commit from feat/3283f-sidecar-humanized-reading into main 2026-09-01 07:34:50 +00:00

1 commit

Author SHA1 Message Date
bot-backend
8bb20c05ea feat(tradein/browser): имитация чтения страницы человеком, целиком opt-in (#3283)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 11s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Successful in 1m26s
У сайдкара не было ни одной строки имитации поведения: после page.goto шли
только wait_for_timeout и content(). grep по scroll/mouse/wheel/go_back давал
ноль совпадений.

Новое НЕОБЯЗАТЕЛЬНОЕ поле тела POST /fetch — behaviour:
  scroll         — 3-6 прокруток колесом с паузами 700-1800мс перед content();
  dwell_ms       — [min,max] дополнительной случайной паузы;
  hop_recommended — заход на ОДНУ соседнюю карточку того же хоста, результат
                   наружу не идёт, отказ глотается, только при reuse_context.

Поле отсутствует → не исполняется ни одна новая строка. Это осознанно: вклад
поведения в выход НЕ доказан. Замер 31.08 сравнивал «без ротации и без
поведения» против «ротация + поведение», то есть две переменные сразу; ротацию
мы выкатили отдельно, и сама по себе она выход не подняла (53% блоков до, 52%
после). Прежде чем включать поведение навсегда, его надо померить одно — а для
этого дефолт обязан остаться прежним.

Ссылки для hop отбираются в две ступени: CSS-селектор сужает раздел, шаблон URL
отличает карточку от рубрики и футера. Без второй ступени "a[href]" на карточке
Авито увёл бы на главную. Шаблон Авито (путь с /kvartiry/ и id из 7+ цифр) снят
на живом замере 31.08; Домклик — /card/sale__flat__<id> по логам сайдкара.
cian/yandex/generic шаблона не имеют осознанно: их вёрстку я не снимал, а
выдуманный шаблон хуже отсутствующего — при None сужение не применяется.

BROWSER_PAGE_INTERVAL_JITTER_S с дефолтом 0: джиттер пейсинга, в отличие от
остального, телом запроса не гейтится, поэтому ненулевой дефолт сломал бы ту же
измеримость. uniform(0,0)==0.0 — интервал численно прежний, но крутилка есть.

Тесты сайдкара: 231 passed.
2026-09-01 09:48:33 +03:00