feat(tradein/estimator): switch core valuation call sites to scraper_kit (#2337) #2348

Merged
lekss361 merged 1 commit from feat/tradein-estimator-kit-switch into main 2026-07-03 23:49:11 +00:00
Owner

Summary

Финальный шаг Group E (scraper_kit migration epic #2277) — переключение импортов estimator.py (core valuation) с legacy app.services.scrapers.* на scraper_kit.providers.*. Самая рискованная часть эпика (регрессия = неверная оценка стоимости клиенту), последней в последовательности A→B→C→D→E1→E2→E3→E4.

  • estimator.py: все 3 call sites (avito IMV ×2, cian valuation, yandex valuation) переключены на kit-эквиваленты, включая все 7 имён avito_imv (в т.ч. классы исключений IMVAddressNotFoundError/IMVAuthError/IMVTransientError — иначе except на legacy-классах тихо перестал бы ловить kit-исключения из-за разной идентичности классов).
  • Config-footgun (паттерн, встречавшийся в E1/E2/E3/Group B/C): добавлен явный config=RealScraperConfig() на всех 3 call sites + delay_provider=get_scraper_delay для yandex — иначе kit молча отключает proxy/throttle-поведение, которое legacy включал всегда безусловно.
  • Observability: оба except-блока (cian ~3132, yandex ~602) апгрейднуты logger.warninglogger.exception — Sentry в app/main.py/app/scheduler_main.py настроен event_level=ERROR, WARNING в GlitchTip как event не долетал (только breadcrumb), т.е. будущая config-регрессия была бы невидима в проде.
  • house_imv_backfill.py::_process_one_house — тот же import switch + config=; RealScraperConfig импорт сделан function-local (lazy) — module-level создавал бы circular import через scraper_adapters.py, который на своём module-level импортирует функции из house_imv_backfill.py.
  • Тесты обновлены (test_backfill_wave2.py, test_estimator_{imv,cian,yandex}_integration.py) + regression-guard asserts на config=/delay_provider= kwargs.
  • cian_history_backfill.py умышленно НЕ тронут (4-й call site estimate_via_cian_valuation, deferred на отдельный issue) — legacy cian_valuation.py остаётся живым по этой причине; legacy avito_imv.py/yandex_valuation.py становятся orphaned (0 importers), test-only.

Wiring подтверждён 3 смерженными golden-parity PR: #2344 (E1/avito_imv), #2342 (E2/cian_valuation), #2345 (E3/yandex_valuation) — diff=0 legacy vs kit на реальных фикстурах.

Review

deep-code-reviewer APPROVE (все 7 заявленных фактов проверены независимо: Sentry event_level семантика, circular-import fix, exception-identity necessity, cian_history_backfill deferral safety — все подтверждены как true и обоснованные, blocking issues не найдены).

Test plan

  • 3 целевых integration-файла + test_backfill_wave2.py: 49/49 passed (venv Python 3.12, реальный Postgres)
  • Full backend suite: 3242 passed, 6 skipped, 1 failed — test_search_api.py::test_search_cache_hit (401 vs 200, auth-фикстура) воспроизведён идентично на родительском коммите (до этого диффа) — подтверждено pre-existing, не связано
  • ruff check / ruff format — clean
  • Rollback — single-commit revert, ни SQL/схема/данные не тронуты

Closes #2337
Closes #2308

## Summary Финальный шаг Group E (scraper_kit migration epic #2277) — переключение импортов `estimator.py` (core valuation) с legacy `app.services.scrapers.*` на `scraper_kit.providers.*`. Самая рискованная часть эпика (регрессия = неверная оценка стоимости клиенту), последней в последовательности A→B→C→D→E1→E2→E3→E4. - `estimator.py`: все 3 call sites (avito IMV ×2, cian valuation, yandex valuation) переключены на kit-эквиваленты, включая все 7 имён avito_imv (в т.ч. классы исключений `IMVAddressNotFoundError`/`IMVAuthError`/`IMVTransientError` — иначе `except` на legacy-классах тихо перестал бы ловить kit-исключения из-за разной идентичности классов). - Config-footgun (паттерн, встречавшийся в E1/E2/E3/Group B/C): добавлен явный `config=RealScraperConfig()` на всех 3 call sites + `delay_provider=get_scraper_delay` для yandex — иначе kit молча отключает proxy/throttle-поведение, которое legacy включал всегда безусловно. - Observability: оба except-блока (cian ~3132, yandex ~602) апгрейднуты `logger.warning` → `logger.exception` — Sentry в `app/main.py`/`app/scheduler_main.py` настроен `event_level=ERROR`, WARNING в GlitchTip как event не долетал (только breadcrumb), т.е. будущая config-регрессия была бы невидима в проде. - `house_imv_backfill.py::_process_one_house` — тот же import switch + config=; `RealScraperConfig` импорт сделан function-local (lazy) — module-level создавал бы circular import через `scraper_adapters.py`, который на своём module-level импортирует функции из `house_imv_backfill.py`. - Тесты обновлены (`test_backfill_wave2.py`, `test_estimator_{imv,cian,yandex}_integration.py`) + regression-guard asserts на `config=`/`delay_provider=` kwargs. - `cian_history_backfill.py` умышленно НЕ тронут (4-й call site `estimate_via_cian_valuation`, deferred на отдельный issue) — legacy `cian_valuation.py` остаётся живым по этой причине; legacy `avito_imv.py`/`yandex_valuation.py` становятся orphaned (0 importers), test-only. Wiring подтверждён 3 смерженными golden-parity PR: #2344 (E1/avito_imv), #2342 (E2/cian_valuation), #2345 (E3/yandex_valuation) — diff=0 legacy vs kit на реальных фикстурах. ## Review `deep-code-reviewer` — ✅ APPROVE (все 7 заявленных фактов проверены независимо: Sentry event_level семантика, circular-import fix, exception-identity necessity, cian_history_backfill deferral safety — все подтверждены как true и обоснованные, blocking issues не найдены). ## Test plan - [x] 3 целевых integration-файла + test_backfill_wave2.py: 49/49 passed (venv Python 3.12, реальный Postgres) - [x] Full backend suite: 3242 passed, 6 skipped, 1 failed — `test_search_api.py::test_search_cache_hit` (401 vs 200, auth-фикстура) воспроизведён идентично на родительском коммите (до этого диффа) — подтверждено pre-existing, не связано - [x] `ruff check` / `ruff format` — clean - [x] Rollback — single-commit revert, ни SQL/схема/данные не тронуты Closes #2337 Closes #2308
lekss361 added 1 commit 2026-07-03 23:44:51 +00:00
feat(tradein/estimator): switch core valuation call sites to scraper_kit (#2337)
All checks were successful
CI / changes (pull_request) Successful in 9s
CI Trade-In / changes (pull_request) Successful in 9s
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 / frontend-checks (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 1m48s
4a6820b8f7
Group E4 (final, highest-risk step of scraper_kit migration epic #2277):
estimator.py and house_imv_backfill.py's avito_imv/cian_valuation/
yandex_valuation call sites now import from scraper_kit.providers.* instead
of app.services.scrapers.*, following the exact wiring proven safe by E1/E2/E3
(#2334/#2335/#2336):

- estimator.py's avito IMV (_get_or_fetch_imv_cached, both call sites) and
  house_imv_backfill.py's _process_one_house: add config=RealScraperConfig()
  — kit's evaluate_via_imv silently drops the configured proxy without it.
- estimator.py's cian valuation (Stage 9): add config=RealScraperConfig() —
  mandatory kwarg on the kit function (TypeError if omitted).
- estimator.py's yandex valuation: add config=RealScraperConfig() (mandatory)
  and delay_provider=get_scraper_delay — without it kit silently falls back
  to a hardcoded 5.0s throttle instead of the DB-configured anti-ban delay.
- All exception classes imported consistently from the same kit module as
  evaluate_via_imv (not just the function) — mixing legacy/kit exception
  classes would break `except IMVAddressNotFoundError` etc. via identity
  mismatch (caught by an existing test that assumed the legacy class,
  fixed alongside).

Observability: both cian_valuation and yandex_valuation graceful-degradation
except-blocks upgraded from logger.warning to logger.exception. GlitchTip's
LoggingIntegration listens at event_level=ERROR (main.py/scheduler_main.py) —
a WARNING never reaches GlitchTip as an event regardless of exc_info, so a
future config-wiring mistake at these call sites needs ERROR level to be
visible in monitoring.

house_imv_backfill.py: RealScraperConfig is imported lazily inside
_process_one_house (not at module level) to avoid a circular import —
app.services.scraper_adapters imports backfill_house_imv/
process_houses_imv_batch from this module at module level. Verified via
direct import in both orders plus a full `app.main` import.

Also fixes a stale docstring claiming process_houses_imv_batch is "not wired
into scheduler" — it is, via scrape_pipeline.py's run_avito_city_sweep.

Test updates: 2 pre-existing tests (test_backfill_wave2.py) mocked the legacy
IMVAddressNotFoundError/IMVEvaluation/IMVGeo classes, now updated to import
from scraper_kit to match the production exception identity. Added
config=/delay_provider= regression-guard asserts to the relevant estimator
and backfill tests, mirroring the existing #2306 cian_price_history pattern.

Legacy app/services/scrapers/{avito_imv,cian_valuation,yandex_valuation}.py
are untouched and still imported by cian_history_backfill.py's valuation
block (separately scoped, not touched here) — revert is a clean single-commit
revert, no schema/data migration involved.
lekss361 merged commit 7ebeddc2bc into main 2026-07-03 23:49:11 +00:00
lekss361 deleted branch feat/tradein-estimator-kit-switch 2026-07-03 23:49:11 +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#2348
No description provided.