fix(tradein): поштучный процент гаснет вместе со сводным, когда причина — сама пара (#2672) #2774
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#2774
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/2672-per-row-percentage"
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?
Что и почему
Гейт #2706 (PR к этому же issue) гасит «медианный торг», а таблица пар под ним продолжала показывать проценты, посчитанные из тех же пар. Пункт 3 issue #2672.
Постановка подтверждена числами с прода (2026-08-07, 427 реальных запросов из
trade_in_estimates, 135 групп с парами, прогон через задеплоенный эндпоинт):Что выбрано и почему не первое попавшееся
Строка гаснет там, и только там, где причина — свойство самой пары:
«Мало пар» строку НЕ гасит. Это свойство ВЫБОРКИ; про отдельную пару оно не говорит ничего, и микрокопия «пар всего 4, поэтому процент в строке не показываем» была бы ложной причиной. Цена исключения названа числом: 3 группы / 20 строк на проде, где медианы нет, а проценты в строках есть.
Флаги (а)/(б) считаются независимо от порядка веток гейта: порядок «мало пар → одно объявление → диапазон» прячет вторую причину за первой — на проде 55 групп гаснут как «мало пар», хотя стоят ещё и на ОДНОМ объявлении. Гаси мы по ветке гейта — гасили бы не там.
Вариант «показывать с пометкой» отклонён: пометка повторялась бы в каждой из 10-100 строк. Вариант «оставить как есть» отклонён числами выше. Данные из строки не исчезают — цена сделки, цена объявления, срок и ссылка остаются; убирается наша подпись «торг» под их разностью.
ВИДИМОЕ СОКРАЩЕНИЕ (решение владельца, не побочный эффект)
Вчерашняя правка убрала половину сводных чисел; эта убирает ещё 72% поштучных процентов. Сводное число не трогает.
Замер ДО/ПОСЛЕ на том коде, что мержится
origin/mainи ветка загружены черезimportlibв один процесс, каждой скормлены ОДНИ И ТЕ ЖЕ живые пары из ответа прода (один вход, две трактовки). Инварианты в замере:total_dealsиlinkage_rate_pctсовпадают у обеих версий — виджет цел.Те же 4 сценария, что и в новых тестах, прогнаны через обе версии:
Первые два — новые тесты, они падают на старом коде. Последние два сторожат обратное направление (не съесть лишнего).
Микрокопия называет причину (живой прод, все 4 сочетания)
Значение медианы в объяснении строк не повторяется: в ветке диапазона оно уже названо предложением выше, а в ветке «мало пар» его намеренно не показывают — печатать его в пояснении было бы отказом на словах. Закреплено тестом.
Почему бэкенд, а не фронт
Мест показа два — карточка
/(StreetDealsCard) и HUD/v2(mapHistory). Гейт один. Обнулениеdiscount_pctна границе API чинит оба сразу и любого будущего потребителя;median_discount_explanationоба фронта уже рендерят рядом с таблицей — правок во фронте не потребовалось, новых полей API нет (codegen не нужен).Пороги не понижены
Ни одна константа не изменена.
MIN_PAIRS = 10,MIN_DISTINCT_LISTINGS = 2, диапазон[−35%, +20%]— как в #2706.Что остаётся (в шапке секции, не в PR-описании)
Test plan
pytest tests/test_sales_vs_listings.py— 29 passed (4 новых; 2 старых обновлены: они кодировали ровно опровергнутую посылку «пара — наблюдаемый факт, отдаём как есть»)Closes #2672