feat(tradein): бесплатная проба покрытия POST /coverage (#2894) #2909
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#2909
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/tradein-coverage-probe"
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?
Первый бэкенд-контур под публичный лэндинг: до оплаты человек видит, сколько похожих квартир продаётся рядом — и ни одной рублёвой цифры.
Один SQL, ноль внешних вызовов, ноль записей — ручка будет открыта анонимам, поэтому обязана быть дешёвой.
EXPLAIN ANALYZEна проде: Bitmap Index Scan поlistings_geom_geog_idx, ~81 мс, отдельная миграция индекса не потребовалась.Три круга ревью — что нашли и починили
Ветка прошла независимую проверку в свежем контексте трижды. Два MAJOR и один посеянный по дороге дефект — все с замерами на проде, не по рассуждению.
MAJOR-1. Проба обещала больше, чем платный расчёт может дать. В когорте не было трёх предикатов, которые есть у эстиматора: guard новостроек,
geo_precision IS DISTINCT FROM 'city'иprice_rub > 0. Замер: точка 56.868904/60.837955, 2к, 50 м² — проба насчитала 22 аналога, когорта эстиматора в тех же 1000 м пустая (все 54 строки — новостройки). Человек платит по обещанию и получает расчёт без аналогов. В активном пуле 28% новостроек, 421 строка на городском центроиде.Починено копией канона из
estimator.pyсо ссылками на строки. Мутационная проверка: удаление любого из трёх предикатов роняет ровно один тест.MAJOR-2. «Срок продажи» считался бы по одному источнику.
days_on_marketзаполнен только у Яндекса (8127/8127; Avito 0/8663, Циан 0/7133, ДомКлик 0/470). Возраст известен у 23,5% строк когорты; в 8% случаев медиана считалась бы по одному-двум объявлениям, 15% значений больше года (максимум 4261 день).Починено: в ответ добавлено
n_with_age, медиана отдаётся только приn_with_age >= 5, значения свыше 365 дней в расчёт не берутся. Поле называетсяmedian_listing_age_days, а не «срок продажи» — у активного объявления это возраст висящего объявления, выборка цензурированная; в докстринге зафиксировано, что данные фактически по одному источнику.NEW (посеян фиксом MINOR).
listings.city— город обхода скрапера, а не адреса. Замер: в Берёзовском 90/90 объявлений имеютcity='Екатеринбург', в Ревде 74/74 —city='Первоуральск'. Приоритет моды когорты над клиентской подсказкой означал бы, что продавец в Берёзовском видит «Екатеринбург», а три города из списков недостижимы вовсе.Починено: город определяется по координатам запроса — ближайший центроид из восьми поддерживаемых городов в пределах 25 км, иначе
not_covered. Ни данные объявлений, ни клиентская подсказка на порог больше не влияют. Факт проlistings.cityзафиксирован комментарием со ссылкой на замер, чтобы следующий раз не наступить.Дыра в тестах.
test_max_age_outlier_days_passed_to_sqlискал подстроку, встречающуюся в SQL дважды, — мутация «убрать FILTER уpercentile_cont, оставив уcount» проходила зелёной. Запинено поведением: строка с возрастом 4000 дней вставляется в когорту, медиана обязана остаться 8.Плюс закрыта утечка соединений в тестах (
_live_session()вskipifоткрывал висящую сессию на каждый collect): после полного прогонаpg_stat_activity→ 0.Проверено
ci-tradein.yml): 4507 passed, 1 skip (WeasyPrint native deps, не связан).skip_allowlist.txt.ruffчисто, pre-commit без правок.Что этот PR НЕ делает
RBAC не тронут —
/coverageостаётся закрытой. Открытие анонимного периметра это #2895, и у него свой гейт: согласие 152-ФЗ до первого INSERT, переписанная privacy-страница, rate-limit. Фронт к ручке пока не подключён — карточка на лэндинге по-прежнему показывает пример из макета.Остаточное: координаты восьми центроидов внесены руками из общедоступных сведений и не сверены с геодезическим источником. Для радиуса матчинга 25 км это некритично, но формально это не выверенные данные.
Closes #2894