fix(tradein/scraper-kit): клампить diff_percent перед INSERT offer_price_history #2404

Merged
lekss361 merged 1 commit from fix/tradein-scraper-kit-price-history-clamp into main 2026-07-04 10:44:26 +00:00
Owner

Summary

Прод (tradein-postgres, 2026-07-04) спамит numeric field overflow на прямых INSERT в offer_price_history. Колонка diff_percentNUMERIC(8,2) (max ±999999.99, миграция 131_fix_diff_percent_overflow.sql), которая также заменила DB-триггер record_listing_price_change() клампящей версией — но триггер срабатывает только на UPDATE listings, а есть три отдельных app-level INSERT-пути, которые пишут diff_percent/diffPercent из распарсенного priceHistory/priceChanges источника напрямую, без клампа:

  • scraper_kit/providers/domclick/detail.py::save_detail_enrichment (текущий боевой путь — legacy domclick_detail.py уже удалён)
  • scraper_kit/providers/cian/detail.py::save_detail_enrichment
  • legacy app/services/scrapers/cian_detail.py::save_detail_enrichment (пока живой, удаление — отдельный шаг #2277)

Гарантированное значение из битого парсинга/redesign страницы источника переполняет колонку.

Fix:

  • новый scraper_kit/offer_price_history.py::clamp_diff_percent() — клампит в [-999999.99, 999999.99], зеркалит формулу DB-триггера из миграции 131; None/boolNone
  • применён в обоих kit-провайдерах на bind-сайте перед CAST(:diff AS numeric) (парсеры не тронуты — клампинг только на границе персистентности)
  • в legacy cian_detail.py — inline-копия того же клампа (без нового cross-package импорта в код, ожидающий удаления)

Review (adversarial, code-reviewer subagent): verdict minor (non-blocking). Два follow-up без блокировки мержа:

  1. legacy cian_detail.py дублирует логику клампа вместо импорта из scraper_kit.offer_price_history — некритично, файл всё равно скоро удаляется по #2277
  2. два standalone dev/backfill-скрипта (scripts/local-cian/playwright_history.py, backend/scripts/domclick_local_runner.py) содержат тот же паттерн, но не подключены ни к одному прод-контейнеру/workflow — вне scope этого PR, стоит завести отдельный тикет

Test plan

  • uv run pytest -q tests/scrapers/test_domclick_detail.py tests/test_cian_detail.py — 80 passed (новые тесты кламп-логики на всех 4 сценариях: extreme+/extreme-/in-range unchanged/None, для обоих save_detail_enrichment путей + standalone unit-тесты clamp_diff_percent)
  • ruff check на изменённых файлах — чисто
  • CAST-trap grep (:[a-z_]+::[a-z]) — пусто
  • post-deploy smoke (qa-tester)

Refs #2277

## Summary Прод (tradein-postgres, 2026-07-04) спамит `numeric field overflow` на прямых INSERT в `offer_price_history`. Колонка `diff_percent` — `NUMERIC(8,2)` (max ±999999.99, миграция `131_fix_diff_percent_overflow.sql`), которая также заменила DB-триггер `record_listing_price_change()` клампящей версией — но триггер срабатывает только на UPDATE `listings`, а есть три отдельных app-level INSERT-пути, которые пишут `diff_percent`/`diffPercent` из распарсенного priceHistory/priceChanges источника напрямую, без клампа: - `scraper_kit/providers/domclick/detail.py::save_detail_enrichment` (текущий боевой путь — legacy `domclick_detail.py` уже удалён) - `scraper_kit/providers/cian/detail.py::save_detail_enrichment` - legacy `app/services/scrapers/cian_detail.py::save_detail_enrichment` (пока живой, удаление — отдельный шаг #2277) Гарантированное значение из битого парсинга/redesign страницы источника переполняет колонку. **Fix:** - новый `scraper_kit/offer_price_history.py::clamp_diff_percent()` — клампит в `[-999999.99, 999999.99]`, зеркалит формулу DB-триггера из миграции 131; `None`/`bool` → `None` - применён в обоих kit-провайдерах на bind-сайте перед `CAST(:diff AS numeric)` (парсеры не тронуты — клампинг только на границе персистентности) - в legacy `cian_detail.py` — inline-копия того же клампа (без нового cross-package импорта в код, ожидающий удаления) **Review (adversarial, code-reviewer subagent):** verdict `minor` (non-blocking). Два follow-up без блокировки мержа: 1. legacy `cian_detail.py` дублирует логику клампа вместо импорта из `scraper_kit.offer_price_history` — некритично, файл всё равно скоро удаляется по #2277 2. два standalone dev/backfill-скрипта (`scripts/local-cian/playwright_history.py`, `backend/scripts/domclick_local_runner.py`) содержат тот же паттерн, но не подключены ни к одному прод-контейнеру/workflow — вне scope этого PR, стоит завести отдельный тикет ## Test plan - [x] `uv run pytest -q tests/scrapers/test_domclick_detail.py tests/test_cian_detail.py` — 80 passed (новые тесты кламп-логики на всех 4 сценариях: extreme+/extreme-/in-range unchanged/None, для обоих save_detail_enrichment путей + standalone unit-тесты `clamp_diff_percent`) - [x] `ruff check` на изменённых файлах — чисто - [x] CAST-trap grep (`:[a-z_]+::[a-z]`) — пусто - [ ] post-deploy smoke (qa-tester) Refs #2277
lekss361 added 1 commit 2026-07-04 10:38:53 +00:00
fix(tradein/scraper-kit): клампить diff_percent перед INSERT offer_price_history (#2277)
All checks were successful
CI / changes (pull_request) Successful in 9s
CI Trade-In / changes (pull_request) Successful in 10s
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 / backend-tests (pull_request) Successful in 1m40s
f814f222a1
Прямые app-level INSERT-пути (domclick/cian kit-провайдеры + legacy cian_detail)
читают diff_percent из скрапленного HTML/JSON и не проходят через БД-триггер
из миграции 131 — гарбадж/экстремальное значение с редизайна source-страницы
переполняет NUMERIC(8,2) и спамит "numeric field overflow" в проде.
lekss361 merged commit 2e345acb82 into main 2026-07-04 10:44:26 +00:00
lekss361 deleted branch fix/tradein-scraper-kit-price-history-clamp 2026-07-04 10:44:27 +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#2404
No description provided.