(low) prinzip/page.tsx KpiCard «Средний метраж»: двойной минус при avg≥49 и ложный «-0» при null #1409

Closed
opened 2026-06-15 05:53:40 +00:00 by bot-backend · 0 comments
Collaborator

Severity: low · Категория: report · Файл: frontend/src/app/analytics/prinzip/page.tsx:66-74

page.tsx:71. В delta.value карточки «Средний метраж» зашит литеральный минус: vs рынок 49 м² · разрыв -${d?.avg_area_sqm ? Math.round(49 - d.avg_area_sqm) : 0} м². Знак не нормализуется. (1) Если avg_area_sqm ≥ 49 — Math.round(49 - avg) уже ≤ 0, и UI печатает «разрыв --N м²» (двойной минус). (2) Если avg_area_sqm null/undefined/0 (falsy) — ветка : 0 даёт «разрыв -0 м²», при этом value карточки показывает «—» (d?.avg_area_sqm?.toFixed(1) ?? "—"), т.е. строка дельты сообщает клиенту несуществующее сравнение «рынок 49 м², разрыв 0». KpiCard.tsx выводит delta.value дословно, своего знака не добавляет — весь знак формируется на странице. Импакт: краевое искажение числа в клиентском дашборде (двойной минус / ложный «-0» рядом с пустым значением). Починка: вычислять gap = Math.round(49 - avg) один раз, форматировать со знаком через gap > 0 ? \-${gap}` : gap < 0 ? `+${-gap}` : '0' (или Intl/gap.toLocaleString` с явным знаком), а при отсутствии avg_area_sqm вообще не передавать delta (или показывать «нет данных»). Дополнительно: константа «49 м²» зашита литералом, тогда как живой рыночный метраж приходит из usePrinzipInsights().key_gaps[].market (PrinzipGapBar.tsx) — два источника одной цифры рассинхронизируются; стоит брать из единого источника.

Почему баг: KpiCard (components/analytics/KpiCard.tsx) рендерит delta.value дословно, своего знака не добавляет — значит весь знак формирует страница. Конкатенация литерала '-' с Math.round(49 - avg) даёт верный знак ТОЛЬКО при avg < 49; при avg ≥ 49 получается '--N' (битый минус), а при null печатается ложный «-0 м²» рядом со значением «—». Это краевой/вторичный дефект числового отображения в клиентском дашборде, а не косметика.

Как чинить: Считать diff = Math.round((d.avg_area_sqm ?? NaN) - 49) и форматировать знак из самого числа (diff>=0 ? +${diff} : ${diff}), а при отсутствии avg вообще не показывать строку «разрыв»/дельту. Рыночные 49 брать из того же источника, что и PrinzipGapBar (key_gaps market), а не из литерала.


deep-audit «армия ботов 2» · verify+harden, confidence 0.85 · unit U75

**Severity:** low · **Категория:** report · **Файл:** `frontend/src/app/analytics/prinzip/page.tsx:66-74` page.tsx:71. В delta.value карточки «Средний метраж» зашит литеральный минус: `vs рынок 49 м² · разрыв -${d?.avg_area_sqm ? Math.round(49 - d.avg_area_sqm) : 0} м²`. Знак не нормализуется. (1) Если avg_area_sqm ≥ 49 — Math.round(49 - avg) уже ≤ 0, и UI печатает «разрыв --N м²» (двойной минус). (2) Если avg_area_sqm null/undefined/0 (falsy) — ветка `: 0` даёт «разрыв -0 м²», при этом value карточки показывает «—» (`d?.avg_area_sqm?.toFixed(1) ?? "—"`), т.е. строка дельты сообщает клиенту несуществующее сравнение «рынок 49 м², разрыв 0». KpiCard.tsx выводит delta.value дословно, своего знака не добавляет — весь знак формируется на странице. Импакт: краевое искажение числа в клиентском дашборде (двойной минус / ложный «-0» рядом с пустым значением). Починка: вычислять gap = Math.round(49 - avg) один раз, форматировать со знаком через `gap > 0 ? \`-${gap}\` : gap < 0 ? \`+${-gap}\` : '0'` (или Intl/`gap.toLocaleString` с явным знаком), а при отсутствии avg_area_sqm вообще не передавать delta (или показывать «нет данных»). Дополнительно: константа «49 м²» зашита литералом, тогда как живой рыночный метраж приходит из usePrinzipInsights().key_gaps[].market (PrinzipGapBar.tsx) — два источника одной цифры рассинхронизируются; стоит брать из единого источника. **Почему баг:** KpiCard (components/analytics/KpiCard.tsx) рендерит delta.value дословно, своего знака не добавляет — значит весь знак формирует страница. Конкатенация литерала '-' с Math.round(49 - avg) даёт верный знак ТОЛЬКО при avg < 49; при avg ≥ 49 получается '--N' (битый минус), а при null печатается ложный «-0 м²» рядом со значением «—». Это краевой/вторичный дефект числового отображения в клиентском дашборде, а не косметика. **Как чинить:** Считать diff = Math.round((d.avg_area_sqm ?? NaN) - 49) и форматировать знак из самого числа (diff>=0 ? `+${diff}` : `${diff}`), а при отсутствии avg вообще не показывать строку «разрыв»/дельту. Рыночные 49 брать из того же источника, что и PrinzipGapBar (key_gaps market), а не из литерала. --- <sub>deep-audit «армия ботов 2» · verify+harden, confidence 0.85 · unit U75</sub>
bot-backend added the
week ревью 1
label 2026-06-15 05:53:40 +00:00
bot-backend added the
scope/frontend
label 2026-06-15 11:02:00 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
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#1409
No description provided.