fix(tradein/estimate): не блокировать оценку — расширять подбор и честно предупреждать #2823

Merged
lekss361 merged 1 commit from fix/tradein-estimate-never-block into main 2026-08-10 15:42:23 +00:00

1 commit

Author SHA1 Message Date
bot-backend
fde784f015 fix(tradein/estimate): не блокировать оценку — расширять подбор и честно предупреждать
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / browser-tests (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 / changes (pull_request) Successful in 8s
CI Trade-In / frontend-checks (pull_request) Successful in 1m3s
CI Trade-In / backend-tests (pull_request) Successful in 3m59s
Прод-инцидент у первого заказчика: студия 23.1 м² в Екатеринбурге
(ул Академика Парина, 46/5) получала экран «НЕДОСТАТОЧНО ДАННЫХ».

Корневая причина — в UI не было варианта «Студия», и студия схлопывалась
в rooms=1 (initRoomsLabel). Оценщик ищет аналоги строгим совпадением
комнатности → в радиусе 2 км нашлось 4 объявления вместо 327 доступных
студий (rooms=0), после чего гейт #oblast-E подавил медиану.
Тот же адрес с rooms=0 даёт 34 аналога и медиану 3 765 452 ₽.

Что сделано:
- «Студия» добавлена в выбор комнатности, маппинг rooms=0 в обе стороны.
- Каскад послаблений при нехватке аналогов: комнатность (студия↔1-комн,
  иначе ±1) → свежесть 14→60 дней → новостройки → радиус 3/5 км.
  Каждый шаг только при n<5, применённые послабления отдаются наружу
  в relaxations и показываются пользователю.
- Медиана больше не обнуляется. Правило выбора headline:
  n>=5 → объявления; тонкая выборка + живой коридор ДКП → сделки
  (сохраняет смысл #oblast-E); тонкая без коридора → реальная медиана
  по объявлениям. «Недостаточно данных» — только при реальном нуле.
- Новые поля ответа relaxations / reliability (ok|low|very_low), красный
  баннер над оценкой, предупреждение и сноски в PDF-отчёте.
- Счётчики перестали брать сырой n_analogs там, где рядом список карточек
  (PDF, v1 HeroSummary/ListingsCard, v2 SourcesMap/mappers) — иначе
  печаталось «0 шт.» над непустой таблицей.
- extract_street_name: сокращения с необязательной точкой. DaData отдаёт
  «ул Академика Парина» без точки → улица не извлекалась → пустые блоки
  «сделки по улице» и «продажи vs объявления» на любом адресе из DaData.
2026-08-10 18:34:59 +03:00