fix(tradein): обход Домклика начинается со сдвигом — комнатности 2+ перестают быть слепой зоной (#2854) #2932

Merged
bot-backend merged 1 commit from fix/2854-domclick-bucket-rotation into main 2026-08-19 12:48:41 +00:00
Collaborator

Цена задачи видна в данных, а не в счётчиках

buckets_completed = 0 во всех прод-прогонах, включая тот, где собрано 389 лотов — значит блок QRATOR бьёт внутри первой корзины. А обход всегда стартовал со студий. Результат за месяцы:

комнат домклик циан яндекс
студии 575 3 2 451
1 408 6 461 4 769
2 1 7 352 4 895
3 0 4 581 3 175
4 0 873 780

Одна двушка и ноль трёшек. У соседних площадок 2+ комнат — около двух третей выдачи. Домклик как источник структурно не покрывает большую часть рынка, и увеличение глубины первой корзины этого не изменит.

Что делает правка и чего НЕ делает

Не лечит блок. Раздаёт то, что успевает собраться, по всем корзинам: точка входа в ROOM_BUCKETS циклически сдвигается от прогона к прогону, состав корзин прежний.

Почему именно так, а не ротация lease (которую задача предлагает первой):

узлов в пуле          4
включено              3
забанено Домкликом    2   (до 21.08)

Свободен один узел. Ротация lease сегодня упёрлась бы в NoProxyAvailableError, а сдвиг работает и при одном узле. Расширение пула — не кодовый вопрос (#2704). Ротацию lease имеет смысл делать поверх этого, когда узлы появятся.

Почему run_id, а не дата

Детерминирован — тест воспроизводим; не зависит от часов; не требует нового состояния в БД. Строгого round-robin не даёт (run_id общий на все источники и растёт неравномерно), но за 30 суток каждая корзина получает порядка пяти стартов. Это записано в коде явно, чтобы следующий читатель не принял «примерно равномерно» за «строго по кругу».

bucket_start_index добавлен в counters: без него прогон неатрибутируем — «двушек не собрали» и «до двушек не дошли» выглядят в данных одинаково.

Проверенный риск, который не подтвердился

Более редкий сбор корзины мог бы дать ложные деактивации. Данные это снимают — сторож здоровья источника работает и это видно:

15.08  confirmations=94   skipped_unhealthy=1   <- деактивация пропущена
16-19.08  confirmations≈455-469  deactivated=0

Проверка

тест origin/main с правкой
test_fetch_city_rotates_bucket_order красный (TypeError) зелёный
test_fetch_city_start_index_is_normalized красный зелёный
test_blocked_run_collects_shifted_bucket_not_studios красный зелёный
test_default_start_index_keeps_previous_behaviour зелёный зелёный
test_pipeline_passes_rotating_start_index зелёный

Главный из них — третий: он воспроизводит прод (блок в первой же корзине) и требует, чтобы единственной собранной оказалась сдвинутая корзина, а не студии.

Тест на проводку добавлен отдельно: без него передачу сдвига можно снять из pipeline, и все проверки скрейпера останутся зелёными — он умеет сдвигать, просто его никто не просит. Фальсифицирован снятием передачи: AssertionError: pipeline не передал сдвиг корзины (получено None).

uv run pytest (tradein-mvp/backend, тем же путём, что CI): 4635 passed, 23 skipped, rc=0.

Приёмка на проде

Проверяемо по данным, а не по логам: через 7 суток в listings должны появиться домкликовские объявления с rooms >= 2 — сейчас их 1 на весь источник. buckets_completed > 0 — необходимое, но не достаточное условие.

Refs #2854

## Цена задачи видна в данных, а не в счётчиках `buckets_completed = 0` во всех прод-прогонах, включая тот, где собрано 389 лотов — значит блок QRATOR бьёт **внутри первой корзины**. А обход всегда стартовал со студий. Результат за месяцы: | комнат | домклик | циан | яндекс | |---:|---:|---:|---:| | студии | 575 | 3 | 2 451 | | 1 | 408 | 6 461 | 4 769 | | **2** | **1** | 7 352 | 4 895 | | **3** | **0** | 4 581 | 3 175 | | **4** | **0** | 873 | 780 | Одна двушка и ноль трёшек. У соседних площадок 2+ комнат — около двух третей выдачи. Домклик как источник структурно не покрывает большую часть рынка, и увеличение глубины первой корзины этого не изменит. ## Что делает правка и чего НЕ делает Не лечит блок. Раздаёт то, что успевает собраться, по всем корзинам: точка входа в `ROOM_BUCKETS` циклически сдвигается от прогона к прогону, состав корзин прежний. Почему именно так, а не ротация lease (которую задача предлагает первой): ``` узлов в пуле 4 включено 3 забанено Домкликом 2 (до 21.08) ``` Свободен один узел. Ротация lease сегодня упёрлась бы в `NoProxyAvailableError`, а сдвиг работает и при одном узле. Расширение пула — не кодовый вопрос (#2704). Ротацию lease имеет смысл делать поверх этого, когда узлы появятся. ## Почему run_id, а не дата Детерминирован — тест воспроизводим; не зависит от часов; не требует нового состояния в БД. Строгого round-robin не даёт (`run_id` общий на все источники и растёт неравномерно), но за 30 суток каждая корзина получает порядка пяти стартов. Это записано в коде явно, чтобы следующий читатель не принял «примерно равномерно» за «строго по кругу». `bucket_start_index` добавлен в counters: без него прогон неатрибутируем — «двушек не собрали» и «до двушек не дошли» выглядят в данных одинаково. ## Проверенный риск, который не подтвердился Более редкий сбор корзины мог бы дать ложные деактивации. Данные это снимают — сторож здоровья источника работает и это видно: ``` 15.08 confirmations=94 skipped_unhealthy=1 <- деактивация пропущена 16-19.08 confirmations≈455-469 deactivated=0 ``` ## Проверка | тест | `origin/main` | с правкой | |---|---|---| | `test_fetch_city_rotates_bucket_order` | **красный** (`TypeError`) | зелёный | | `test_fetch_city_start_index_is_normalized` | **красный** | зелёный | | `test_blocked_run_collects_shifted_bucket_not_studios` | **красный** | зелёный | | `test_default_start_index_keeps_previous_behaviour` | зелёный | зелёный | | `test_pipeline_passes_rotating_start_index` | — | зелёный | Главный из них — третий: он воспроизводит прод (блок в первой же корзине) и требует, чтобы единственной собранной оказалась **сдвинутая** корзина, а не студии. Тест на проводку добавлен отдельно: без него передачу сдвига можно снять из pipeline, и все проверки скрейпера останутся зелёными — он умеет сдвигать, просто его никто не просит. Фальсифицирован снятием передачи: `AssertionError: pipeline не передал сдвиг корзины (получено None)`. `uv run pytest` (tradein-mvp/backend, тем же путём, что CI): **4635 passed, 23 skipped, rc=0**. ## Приёмка на проде Проверяемо по данным, а не по логам: через 7 суток в `listings` должны появиться домкликовские объявления с `rooms >= 2` — сейчас их 1 на весь источник. `buckets_completed > 0` — необходимое, но не достаточное условие. Refs #2854
bot-backend added 1 commit 2026-08-19 12:41:27 +00:00
fix(tradein): обход Домклика начинается со сдвигом — комнатности 2+ перестают быть слепой зоной (#2854)
All checks were successful
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 10s
CI Trade-In / browser-tests (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 / backend-tests (pull_request) Successful in 4m55s
705c98801c
Блок QRATOR прилетает ВНУТРИ первой корзины: buckets_completed=0 во всех прод-
прогонах, включая тот, где собрано 389 лотов. Обход при этом всегда стартовал со
студий, поэтому корзины '2', '3', '4', '5+' не начинались вовсе.

Цена видна не в счётчиках, а в самих данных. Активные объявления по комнатности
(замер 19.08):

    комнат   домклик   циан   яндекс
    студии       575      3    2 451
    1            408  6 461    4 769
    2              1  7 352    4 895
    3              0  4 581    3 175
    4              0    873      780

Одна двушка и ноль трёшек. У соседних площадок 2+ комнат — около двух третей
выдачи, то есть Домклик как источник структурно не покрывает большую часть рынка.

Правка НЕ лечит блок. Она раздаёт то, что успевает собраться, по всем корзинам:
точка входа в ROOM_BUCKETS циклически сдвигается от прогона к прогону, состав
корзин не меняется. Работает при ОДНОМ свободном узле — это существенно, потому
что ротация lease, которую задача предлагает первой, сегодня упирается в пул: 3
включённых узла, 2 забанены Домкликом до 21.08.

Источник сдвига — run_id, не дата и не случайность: детерминирован (тест
воспроизводим), не зависит от часов, не требует нового состояния в БД. Строгого
round-robin не даёт, но за 30 суток каждая корзина получает порядка пяти стартов.

bucket_start_index попадает в counters: без него прогон неатрибутируем — «двушек
не собрали» и «до двушек не дошли» выглядят в данных одинаково.

Ложные деактивации при более редком сборе проверены и не подтвердились: сторож
здоровья источника работает, 15.08 прогон deactivate_stale_domklik показал
skipped_unhealthy=1 при confirmations=94.

Тесты: 3 красных на origin/main (TypeError на новом аргументе), 5 зелёных с обеих
сторон. Отдельный тест на ПРОВОДКУ — без него передачу сдвига можно снять, и
проверки скрейпера останутся зелёными; фальсифицирован снятием передачи.
bot-backend merged commit a9e9707018 into main 2026-08-19 12:48:41 +00:00
bot-backend deleted branch fix/2854-domclick-bucket-rotation 2026-08-19 12:48:42 +00:00
Sign in to join this conversation.
No reviewers
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#2932
No description provided.