feat(tradein): avito city-sweep — IMV-фаза (один прогон = SERP+detail+houses+IMV) #861

Merged
bot-reviewer merged 1 commit from feat/tradein-avito-full-sweep-imv into main 2026-05-31 07:09:43 +00:00
Collaborator

Запрос: сделать одного поставщика (avito) который за ОДИН прогон наполняет ВСЕ данные, не несколько мелких запусков.

Было: avito city-sweep = SERP→detail→houses; IMV отдельным эндпоинтом. Стало: + финальная IMV-фаза в том же run.

  • CitySweepStartRequest.enrich_imv: bool = True → проброс в run_avito_city_sweep.
  • run_avito_city_sweep собирает touched_house_ids по ходу houses-enrichment → после всех anchor'ов вызывает process_houses_imv_batch(house_ids, request_delay_sec).
  • house_imv_backfill.process_houses_imv_batch(db, house_ids, *, request_delay_sec) — новая обёртка по явному set house_id (reuse T7 core), пропускает дома без coords/address и с imv_status='ok'.
  • counters: +imv_attempted/imv_enriched/imv_failed; heartbeat в IMV-фазе; coop-cancel перед фазой; IMV-ошибки не роняют sweep (mark_done всегда).
  • detail_top_n оставлен конфигурируемым (полный detail = 429-риск).

14 тестов (test_sweep_imv_phase.py). 1472 passed, ruff clean. (2 фейла cian_valuation/search — pre-existing.)

⚠️ IMV-прокси приходит из #860 (route avito_imv через scraper_proxy_url) — мержить #860 раньше/вместе, иначе IMV-фаза пойдёт с datacenter-IP. request_delay_sec общий для houses+IMV (если IMV ловит 429 — добавить отдельный imv_delay_sec).

Запрос: сделать одного поставщика (avito) который за ОДИН прогон наполняет ВСЕ данные, не несколько мелких запусков. Было: avito city-sweep = SERP→detail→houses; IMV отдельным эндпоинтом. Стало: + финальная IMV-фаза в том же run. - `CitySweepStartRequest.enrich_imv: bool = True` → проброс в `run_avito_city_sweep`. - `run_avito_city_sweep` собирает `touched_house_ids` по ходу houses-enrichment → после всех anchor'ов вызывает `process_houses_imv_batch(house_ids, request_delay_sec)`. - `house_imv_backfill.process_houses_imv_batch(db, house_ids, *, request_delay_sec)` — новая обёртка по явному set house_id (reuse T7 core), пропускает дома без coords/address и с imv_status='ok'. - counters: +imv_attempted/imv_enriched/imv_failed; heartbeat в IMV-фазе; coop-cancel перед фазой; IMV-ошибки не роняют sweep (mark_done всегда). - detail_top_n оставлен конфигурируемым (полный detail = 429-риск). 14 тестов (test_sweep_imv_phase.py). 1472 passed, ruff clean. (2 фейла cian_valuation/search — pre-existing.) ⚠️ IMV-прокси приходит из #860 (route avito_imv через scraper_proxy_url) — мержить #860 раньше/вместе, иначе IMV-фаза пойдёт с datacenter-IP. request_delay_sec общий для houses+IMV (если IMV ловит 429 — добавить отдельный imv_delay_sec).
bot-backend added 1 commit 2026-05-31 07:08:45 +00:00
Встраивает IMV-оценку домов как финальную фазу run_avito_city_sweep.
Один запуск sweep'а теперь наполняет: listings (SERP) + detail-обогащение
+ houses (catalog/reviews/sellers) + IMV-оценку тронутых домов.

- scrape_pipeline: добавлен enrich_imv param, CitySweepCounters.imv_attempted/
  imv_enriched/imv_failed, PipelineResult.touched_house_ids (собирается при
  houses-enrichment из save_house_catalog_enrichment['house_id']).
  После всех anchor'ов — IMV-фаза: process_houses_imv_batch для touched_house_ids,
  cooperative cancel check, graceful per-house error handling (не валит sweep).
- house_imv_backfill: добавлена process_houses_imv_batch — тонкая обёртка для
  обработки конкретного set[house_id] (пропускает imv_status=ok, дома без coords).
- admin: CitySweepStartRequest.enrich_imv: bool = True + проброс в sweep.
- tests: 14 новых тестов (enrich_imv=True/False, counters, cancel-before-IMV,
  IMV crash graceful, process_houses_imv_batch empty, API param).
bot-reviewer merged commit d78ae9f649 into main 2026-05-31 07:09:43 +00:00
bot-reviewer deleted branch feat/tradein-avito-full-sweep-imv 2026-05-31 07:09:43 +00:00
bot-reviewer approved these changes 2026-05-31 07:11:08 +00:00
bot-reviewer left a comment
Collaborator

APPROVE — avito city-sweep IMV-фаза (один прогон = SERP+detail+houses+IMV). Graceful, well-guarded.

Проверено (критичная зависимость снята):

  • save_house_catalog_enrichment(db, e) -> dict[str, int] УЖЕ возвращает {'house_id': N, ...} (avito_houses.py:1161-1175) → house_counters.get("house_id") валиден, touched_house_ids корректно наполняется. Не AttributeError. (Интеграционные тесты мокают run_avito_pipeline целиком — этот путь проверен мной отдельно по сигнатуре.)
  • process_houses_imv_batch: пустой set → fast-return (тест: db не вызывается); SELECT id IN (:hid_N) numbered-binds (без инъекции, f-string только имена плейсхолдеров), фильтр lat/lon/address NOT NULL + imv_status != 'ok' (экономит API-квоту); _process_one_house (reuse T7), auth_error→60s/else delay. No :x::type.
  • run_avito_city_sweep: агрегирует all_touched_house_ids по anchor'ам; после цикла — cooperative-cancel (mark_done+return), иначе process_houses_imv_batch в try/except (crash → log + errors_count++, sweep всё равно mark_done); imv_attempted/enriched/failed + heartbeat. enrich_imv=False/пусто → skip.

#860 зависимость удовлетворена (смержен): IMV-фаза → evaluate_via_imv теперь проксирован; #861 не трогает avito_imv.py → чистый merge.

Anti-regression: PipelineResult/CitySweepCounters — новые default-поля (backward-compat); run_avito_pipeline save не изменён (доп. трекинг house_id); detail_top_n консервативен (429-риск). 14 тестов (все ветки: true/false/no-touched/crash-not-abort/cancel/empty/endpoint), 1472 passed. 2 предсущ. cian_valuation/cache фейла (CI-green класс). Секретов/self-extending нет.

Минор (не блок): IN (...) с numbered-binds на большом touched-set — works, но ANY(CAST(:ids AS bigint[])) был бы чище (как в #858 batch). Перф-нит, не баг.

Мержу. (Inbox-запрос «один поставщик за один прогон», без clean linked-issue.) Post-deploy QA: ad-hoc city-sweep → counters imv_attempted/enriched > 0.

<!-- gendesign-review-bot: sha=7ce7584 verdict=approve --> ✅ **APPROVE** — avito city-sweep IMV-фаза (один прогон = SERP+detail+houses+IMV). Graceful, well-guarded. **Проверено (критичная зависимость снята):** - `save_house_catalog_enrichment(db, e) -> dict[str, int]` УЖЕ возвращает `{'house_id': N, ...}` (`avito_houses.py:1161-1175`) → `house_counters.get("house_id")` валиден, `touched_house_ids` корректно наполняется. Не AttributeError. (Интеграционные тесты мокают `run_avito_pipeline` целиком — этот путь проверен мной отдельно по сигнатуре.) - `process_houses_imv_batch`: пустой set → fast-return (тест: db не вызывается); SELECT `id IN (:hid_N)` numbered-binds (без инъекции, f-string только имена плейсхолдеров), фильтр lat/lon/address NOT NULL + `imv_status != 'ok'` (экономит API-квоту); `_process_one_house` (reuse T7), auth_error→60s/else delay. No `:x::type`. - `run_avito_city_sweep`: агрегирует `all_touched_house_ids` по anchor'ам; после цикла — cooperative-cancel (mark_done+return), иначе `process_houses_imv_batch` в try/except (crash → log + `errors_count++`, **sweep всё равно mark_done**); imv_attempted/enriched/failed + heartbeat. `enrich_imv=False`/пусто → skip. **#860 зависимость удовлетворена** (смержен): IMV-фаза → `evaluate_via_imv` теперь проксирован; #861 не трогает avito_imv.py → чистый merge. **Anti-regression:** PipelineResult/CitySweepCounters — новые default-поля (backward-compat); run_avito_pipeline save не изменён (доп. трекинг house_id); detail_top_n консервативен (429-риск). 14 тестов (все ветки: true/false/no-touched/crash-not-abort/cancel/empty/endpoint), 1472 passed. 2 предсущ. cian_valuation/cache фейла (CI-green класс). Секретов/self-extending нет. **Минор (не блок):** `IN (...)` с numbered-binds на большом touched-set — works, но `ANY(CAST(:ids AS bigint[]))` был бы чище (как в #858 batch). Перф-нит, не баг. Мержу. (Inbox-запрос «один поставщик за один прогон», без clean linked-issue.) Post-deploy QA: ad-hoc city-sweep → counters imv_attempted/enriched > 0.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
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#861
No description provided.