fix(tradein-v2): пустая выборка сделок больше не рисуется нулями — «0,00 млн · −100%» зелёным исчезает #3328

Merged
bot-backend merged 2 commits from fix/3320-v2-honest-zeros into main 2026-09-02 10:00:49 +00:00
Collaborator

Closes #3320, пп. 1-3 (п.4 про бейдж квоты закрыт ранее в #3326). Аудит 01-02.09, линза v2-front.

Пункт 1 (high) — count=0 рендерился как данные

Бэкенд при отсутствии сделок по улице возвращает нули по схеме (не трогали), фронт пропускал их как числа: «0,00 млн ₽ · −100% к цене объявления» зелёным. Фикс — один guard usableStreetDeals() на границе маппера (count <= 0 или медиана не > 0 → null), применён во всех четырёх местах-потребителях: mapResultPanel, mapSummary, mapSources, KPI в mapHistory — тот же нулевой ответ кормил и §03 СВОДКУ, и ДКП-KPI истории. null ниже по коду уже везде = «нет данных» (прочерк + существующий EmptyTableNote), нового состояния не заводили. Если у оценки есть СВОИ actual_deals — блок не гасится, а падает на них (закреплено тестом).

Пункт 2 (medium) — «Показано N из M» из разных выборок

N был из estimate.actual_deals, M из streetDeals.count — возможно «Показано 10 из 3». Тотала у выборки actual_deals в контракте нет, поэтому знаменатель честно убран: «Показано N фактических сделок».

Пункт 3 (medium) — deals-only полоса врала про источник

При n_analogs=0 полоса оставалась «ДИАПАЗОН ЦЕН В ОБЪЯВЛЕНИЯХ», данные — из ДКП. Теперь: «РЕКОМЕНДОВАННЫЙ ДИАПАЗОН / ПО СДЕЛКАМ РОСРЕЕСТРА (ДКП)» — формулировка согласована с карточкой 1 после #2629. Полоса не скрыта: её числа = числа карточки 1, это единственная визуализация диапазона.

Тесты

Новый __tests__/honestZeros.test.tsx (5 тестов). Полный прогон: Test Files 28 passed (28) / Tests 218 passed (218), tsc --noEmit rc=0.

Фальсификация (git apply -R только по mappers/SourcesView, тесты не тронуты) — 4 из 5 красные ПО ЗНАЧЕНИЮ (expected { median: '0,00' } to deeply equal { median: '—' } и т.п.); пятый зелёный по построению — он про нетронутую ветку с объявлениями.

Проверка глазами после деплоя

§05 для адреса без ДКП по улице: три прочерка + плашка, ни одного «−100%»; футер без «из M»; §02 при n_analogs=0: полоса подписана сделками Росреестра.

Оговорка воркера: цвет «МЕДИАНА СДЕЛОК» остаётся зелёным и при «—» — вне рамок, одна строка в SourcesView, если понадобится.

Closes #3320, пп. 1-3 (п.4 про бейдж квоты закрыт ранее в #3326). Аудит 01-02.09, линза v2-front. ## Пункт 1 (high) — count=0 рендерился как данные Бэкенд при отсутствии сделок по улице возвращает нули по схеме (не трогали), фронт пропускал их как числа: «0,00 млн ₽ · −100% к цене объявления» зелёным. Фикс — один guard `usableStreetDeals()` на границе маппера (`count <= 0` или медиана не > 0 → `null`), применён во всех четырёх местах-потребителях: `mapResultPanel`, `mapSummary`, `mapSources`, KPI в `mapHistory` — тот же нулевой ответ кормил и §03 СВОДКУ, и ДКП-KPI истории. `null` ниже по коду уже везде = «нет данных» (прочерк + существующий `EmptyTableNote`), нового состояния не заводили. Если у оценки есть СВОИ `actual_deals` — блок не гасится, а падает на них (закреплено тестом). ## Пункт 2 (medium) — «Показано N из M» из разных выборок N был из `estimate.actual_deals`, M из `streetDeals.count` — возможно «Показано 10 из 3». Тотала у выборки `actual_deals` в контракте нет, поэтому знаменатель честно убран: «Показано N фактических сделок». ## Пункт 3 (medium) — deals-only полоса врала про источник При `n_analogs=0` полоса оставалась «ДИАПАЗОН ЦЕН В ОБЪЯВЛЕНИЯХ», данные — из ДКП. Теперь: «РЕКОМЕНДОВАННЫЙ ДИАПАЗОН / ПО СДЕЛКАМ РОСРЕЕСТРА (ДКП)» — формулировка согласована с карточкой 1 после #2629. Полоса не скрыта: её числа = числа карточки 1, это единственная визуализация диапазона. ## Тесты Новый `__tests__/honestZeros.test.tsx` (5 тестов). Полный прогон: `Test Files 28 passed (28)` / `Tests 218 passed (218)`, `tsc --noEmit` rc=0. Фальсификация (`git apply -R` только по mappers/SourcesView, тесты не тронуты) — 4 из 5 красные ПО ЗНАЧЕНИЮ (`expected { median: '0,00' } to deeply equal { median: '—' }` и т.п.); пятый зелёный по построению — он про нетронутую ветку с объявлениями. ## Проверка глазами после деплоя §05 для адреса без ДКП по улице: три прочерка + плашка, ни одного «−100%»; футер без «из M»; §02 при `n_analogs=0`: полоса подписана сделками Росреестра. Оговорка воркера: цвет «МЕДИАНА СДЕЛОК» остаётся зелёным и при «—» — вне рамок, одна строка в SourcesView, если понадобится.
bot-backend added 1 commit 2026-09-02 09:43:57 +00:00
fix(tradein-v2): пустая выборка сделок больше не рисуется нулями
All checks were successful
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m0s
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 11s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
08cabe8d98
Бэкенд по контракту не умеет отдать null в street-deals: «сделок на улице
нет» приезжает как count=0 с нулевыми ценами. Витрина сохраняла этот ноль
через ?? и показывала его как данные — «0,00 млн ₽ · −100% к цене
объявления» зелёным и диапазон «0,00 – 0,00».

- usableStreetDeals() схлопывает пустую оболочку в null на границе мапперов
  (mapSources / mapSummary / mapHistory / mapResultPanel) — дальше null уже
  везде означает «нет данных», отдельного состояния заводить не нужно;
- футер таблицы сделок брал N и M из РАЗНЫХ выборок (строки — actual_deals
  оценки, знаменатель — коридор по улице), выходило «Показано 10 из 3»;
  тотала у той же выборки в ответе нет, поэтому знаменатель убран;
- в deals-only ветке (n_analogs=0) полоса диапазона строилась из ДКП-цен,
  но была подписана «В ОБЪЯВЛЕНИЯХ» — подпись согласована с карточкой 1.

Closes #3320
Light1YT added 1 commit 2026-09-02 09:50:57 +00:00
fix(tradein-v2): футер 04, падеж сделок и цвет дельты по знаку
All checks were successful
CI Trade-In / changes (pull_request) Successful in 12s
CI / changes (pull_request) Successful in 13s
CI Trade-In / backend-tests (pull_request) Has been skipped
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 Trade-In / frontend-checks (pull_request) Successful in 1m31s
35db6608ee
Ревью PR #3328:
- HistoryView: «Показано N из M сделок» брало M из street-deals, а строки —
  из sales-vs-listings; после гашения пустого коридора выходило «из —».
  Знаменатель убран, как в 05 РЫНОК;
- обе подписи склоняются через pluralRu («3 фактические сделки», «2 сделки»);
- цвет дельты медианы сделок считается по знаку (mapSources.deltaColor):
  зелёным красились и минус, и прочерк — это второй причинный узел жалобы
  «−100% зелёным»;
- подпись полосы совпала с карточкой 1 буквально («ПО СДЕЛКАМ РОСРЕЕСТРА»);
- тест: убран тавтологичный assert про EmptyTableNote (её рисует пустой
  dealRows, а не guard), добавлены кейсы на футер 04 и на цвет дельты.
bot-backend merged commit 5cdf2bd74c into main 2026-09-02 10:00:49 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#3328
No description provided.