fix(tradein/domklik): diff_percent — проценты из соседних price_rub вместо рублей источника, гейт отвергает |x|>100, миграция 285 пересчитывает историю #3370
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#3370
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/3225-domklik-diff-percent"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #3225.
offer_price_history.diff_percentу domklik содержал рубли: лоадер клалdiffисточника как есть,clamp_diff_percentзажимал ±999999.99 вместо отказа. Прод: 8900 из 11 075 значений с |diff| > 50; у одного listing соседствовали −200000 (бэкфилл) и −0.82 (триггер).Что сделано
providers/domclick/detail.py): процент из соседнихprice_rub(сортировка поchange_time), первая запись → NULL.scraper_kit/offer_price_history.py):clamp_diff_percent→validate_diff_percent(value, listing_id=None): |x| > 100 → NULL + warning с listing_id и сырым значением, не кламп. Гейт общий — переименован вызов и у cian. Осознанный размен: настоящий рост цены >2× тоже уйдёт в NULL (в докстринге).285_domklik_diff_percent_recompute.sql; номер свободен по всем 419 веткам origin): пересчёт всех domklik-строк оконнойlag()по(listing_id, change_time, id); бэфилл-строки от триггерных не отличаются намеренно — триггер пишет тот жеsource='domklik'и ту же формулу, у него пересчёт даёт то же значение иIS DISTINCT FROMего не трогает; фильтр|x|>100не берётся — пропустил бы рублёвые diff вроде −50. Идемпотентно, lock_timeout,RAISE NOTICE.Тесты
246 passed, 3 skipped(-k domclick/price_history/diff); гейт lock_timeout/нумерации281 passed. Фальсификация (откат только вычисления процента):assert [-300000] == [None]— рубли в колонке, по значению.Прод-замер до мержа
SQL воркера — комментарием ниже.
Прод-замер радиуса миграции 285 ДО мержа (SQL воркера, 05.09 19:50 UTC):
offer_price_historyIS DISTINCT FROMпересчёта)Разница 10 832 − 10 335 ≈ 500 строк — рублёвые diff с |x| ≤ 100 (например −50 ₽), которые фильтр по порогу пропустил бы: пересчёт всех domklik-строк — правильное решение. Триггерные строки в изменяемых почти не участвуют (иначе
will_changeбыл бы кратно больше) — косвенное подтверждение совпадения формул; deep-ревью сверяет по тексту триггера 131.Критерий приёмки после деплоя:
SELECT count(*) FILTER (WHERE abs(diff_percent) > 100) FROM offer_price_history WHERE source='domklik'→ 0; повторный прогон миграции → 0 изменённых строк.Доводка по deep-ревью (
afa93f9a): партицияlag()только по строкам загрузчика (change_time <> recorded_at), триггерные строки не пересчитываются и не служат базой; окно сужено до листингов domklik.Прод-замер ДО/ПОСЛЕ доводки (05.09 20:10 UTC):
Разница 454 = ровно
rewrittenиз SQL ревьюера — те триггерные строки, чья база (listings.OLD.price_rub) отличается от соседа по oph. Блокер закрыт числом, не словом. Признак триггера точный: обе метки однимnow()(стабилен в транзакции); загрузчик пишет дату источника,recorded_at— DEFAULT NOW() (023:19) — закреплено тестом (фальсификация: дописатьrecorded_atв INSERT загрузчика → красный).Критерий приёмки после деплоя:
count(*) FILTER (WHERE abs(diff_percent) > 100)уsource='domklik' AND change_time <> recorded_at→ 0; триггерные 3 381 — значения не изменились (сверка поid-выборке).