fix(tradein/deactivate): потолок эффективного TTL — защита от разгона пола и опечатки в расписании #2907
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
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#2907
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/tradein-ttl-effective-cap"
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?
Что это и чем НЕ является
Изначально задача была сформулирована как «сжать раздутый пул активных объявлений». Три круга ревью показали, что этим она не является, и заголовок переписан честно.
Замер на проде: дельта деактиваций следующим прогоном — ноль строк на всех четырёх джобах, и до правки, и после. Раздутый пул лежит вне их скоупа. Подробности — в поправке к аудиту; настоящий дефект (протухшие строки с пустым сегментом, которые оценщик берёт) чинится отдельной веткой.
Ценность этого PR в другом.
Проблема, которая реальна
effective_ttl_days = max(ttl_days, revisit_floor_days)без верхней границы. Пол — это квантиль разрывов переобхода, он растёт сам по себе при медленном обходе. Живой факт: у yandexttl_days_effectiveдержался 75/75/75/39/52/54 шесть прогонов подряд приdeactivated=0, сейчас пол 79.2 суток. Это положительная обратная связь — медленный обход поднимает пол, высокий пол продлевает жизнь снятым лотам.Что сделано
Потолок
min(max(ttl_days, floor), ttl_days * cap_mult)с калибровкой per-source, посчитанной по живымcounters, а не по статической константе. avito получаетcap_mult=6, yandex —cap_mult=3(потолок 90 при живом поле 79).Guard от опечатки в jsonb. Это то, ради чего PR стоит мержить.
default_paramsрасписания не валидируется, и"cap_mult": 0дал быeffective_ttl = 0— деактивацию всего активного пула источника одним прогоном.Первый вариант guard'а сам имел дыру:
bool— подклассintв Python, поэтому"cap_mult": trueпроходило как1и молча отключало защиту. Ровно тот класс опечатки, ради которого guard написан. Теперьisinstance(x, bool)стоит до числового сравнения, для обоих параметров.Что поймали три круга ревью
ttl_daysразличается втрое — у источника с худшим обходом самый жёсткий потолокbool; тест «пиннит калибровку», но значение захардкожено в самом тесте — мутация миграции 6→2 оставляла тест зелёнымТест теперь читает значение из
264_*.sqlрегуляркой; мутация проверена — краснеет.Отдельным коммитом — исправление вранья в комментарии
В шапке модуля и в тексте миграции стояло «23 687 из 44 744 avito-объявлений не подтверждались >7 суток» под заголовком «ЗАМЕР НА ПРОДЕ». Число реальное, но приписано не тому источнику: это все источники вместе, две трети — новостройки вне выборки оценщика, а у самого avito просроченных ноль.
Убрал. Оставлять такое в коде хуже, чем не писать вовсе: следующий человек проверит, не найдёт — и перестанет доверять остальным числам в том же абзаце, которые верны и сверены с
scrape_runs.counters.Известный остаток
Зеркальный пин-тест для yandex односторонний: ослабление потолка (
3 → 100) он не ловит, только ужесточение. У avito пин двусторонний. Не блокер, вынесу отдельно.Test plan
ttl_days_effectiveу yandex не должен превышать 90