(medium) ScoreBreakdownStackedBar.tsx / source-view barWidth: знаменатель = макс. знаковый вклад, а не макс. модуль — шкала ломается при отрицательном лидере #1451

Closed
opened 2026-06-15 05:55:49 +00:00 by bot-backend · 1 comment
Collaborator

Severity: medium · Категория: report · Файл: frontend/src/components/site-finder/ScoreBreakdownStackedBar.tsx:122-127, 376-381

ScoreBreakdownStackedBar.tsx:376-381 (режим «По фактору»). barWidth = min(100, abs(contribution)/(abs(sourceAgg[0]?.contribution)||1)*100). sourceAgg отсортирован по ЗНАКОВОМУ вкладу (строка 124), поэтому sourceAgg[0] — самый ПОЛОЖИТЕЛЬНЫЙ фактор, а не с максимальным модулем. Импакт: когда сильнейший по модулю фактор отрицателен (или все вклады <0 — плохой участок: трамвай, шум, нет POI), sourceAgg[0] — наименее отрицательный, и у остальных abs(contribution)>abs(sourceAgg[0]) → все полоски клампятся в 100% full-width, относительная сила теряется. Фикс: знаменатель = Math.max(...sourceAgg.map(s=>Math.abs(s.contribution))). Severity medium (а не high): это вторичный toggle-режим, основной режим «По категории» нормирует корректно (totalPositive/totalNegative), деградация визуальная, fmtV показывает верные числа.

Почему баг: barWidth = min(100, abs(contribution)/abs(sourceAgg[0].contribution)*100). Если самый сильный по модулю фактор отрицательный (или вообще все вклады < 0 — типично для плохого участка: шум, трамвай, нет POI), то sourceAgg[0] — это наименее отрицательный (наименьший модуль). Тогда у всех остальных abs(contribution) > abs(sourceAgg[0]) → barWidth клампится в 100. Все полоски становятся одинаково full-width, относительная величина вкладов теряется — клиент видит «все факторы равны по силе», что неверно. Корректный знаменатель — max по модулю всех вкладов.

Как чинить: Нормировать на максимум модуля: const maxAbs = Math.max(...sourceAgg.map(s => Math.abs(s.contribution)), 1); barWidth = Math.min(100, Math.abs(contribution)/maxAbs*100). (Сортировку для отбора топ-10 при желании тоже сделать по модулю.)


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

**Severity:** medium · **Категория:** report · **Файл:** `frontend/src/components/site-finder/ScoreBreakdownStackedBar.tsx:122-127, 376-381` ScoreBreakdownStackedBar.tsx:376-381 (режим «По фактору»). barWidth = min(100, abs(contribution)/(abs(sourceAgg[0]?.contribution)||1)*100). sourceAgg отсортирован по ЗНАКОВОМУ вкладу (строка 124), поэтому sourceAgg[0] — самый ПОЛОЖИТЕЛЬНЫЙ фактор, а не с максимальным модулем. Импакт: когда сильнейший по модулю фактор отрицателен (или все вклады <0 — плохой участок: трамвай, шум, нет POI), sourceAgg[0] — наименее отрицательный, и у остальных abs(contribution)>abs(sourceAgg[0]) → все полоски клампятся в 100% full-width, относительная сила теряется. Фикс: знаменатель = Math.max(...sourceAgg.map(s=>Math.abs(s.contribution))). Severity medium (а не high): это вторичный toggle-режим, основной режим «По категории» нормирует корректно (totalPositive/totalNegative), деградация визуальная, fmtV показывает верные числа. **Почему баг:** barWidth = min(100, abs(contribution)/abs(sourceAgg[0].contribution)*100). Если самый сильный по модулю фактор отрицательный (или вообще все вклады < 0 — типично для плохого участка: шум, трамвай, нет POI), то sourceAgg[0] — это наименее отрицательный (наименьший модуль). Тогда у всех остальных abs(contribution) > abs(sourceAgg[0]) → barWidth клампится в 100. Все полоски становятся одинаково full-width, относительная величина вкладов теряется — клиент видит «все факторы равны по силе», что неверно. Корректный знаменатель — max по модулю всех вкладов. **Как чинить:** Нормировать на максимум модуля: const maxAbs = Math.max(...sourceAgg.map(s => Math.abs(s.contribution)), 1); barWidth = Math.min(100, Math.abs(contribution)/maxAbs*100). (Сортировку для отбора топ-10 при желании тоже сделать по модулю.) --- <sub>deep-audit «армия ботов 2» · verify+harden, confidence 0.92 · unit U93</sub>
bot-backend added the
week ревью 1
label 2026-06-15 05:55:49 +00:00
bot-backend added the
scope/frontend
label 2026-06-15 11:02:06 +00:00
Owner

🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)

Текущее состояние кода: frontend/src/components/site-finder/ScoreBreakdownStackedBar.tsx:122-126 (агрегация+сортировка sourceAgg) и :374-381 (barWidth в режиме «По фактору»).

Корень: sourceAgg сортируется по ЗНАКОВОМУ вкладу — .sort((a, b) => b.contribution - a.contribution) (стр.124), значит sourceAgg[0] это самый ПОЛОЖИТЕЛЬНЫЙ фактор, а не максимальный по модулю. barWidth нормирует на Math.abs(sourceAgg[0]?.contribution) || 1 (стр.378-379). Когда сильнейший по модулю фактор отрицателен (или все вклады <0 — плохой участок), знаменатель — наименьший модуль; у остальных abs(contribution) > abs(sourceAgg[0])Math.min(100, …) клампит все полоски в 100% full-width, относительная сила теряется.

Что править:

  • Знаменатель = максимум модуля: const maxAbs = Math.max(...sourceAgg.map(s => Math.abs(s.contribution)), 1); затем barWidth = Math.min(100, Math.abs(contribution) / maxAbs * 100).
  • Опционально: сортировку отбора топ-10 (стр.124) тоже по модулю, если нужен показ сильнейших по абсолютной величине.
  • Severity medium корректна: вторичный toggle-режим, основной «По категории» нормирует через totalPositive/totalNegative; деградация чисто визуальная, fmtV показывает верные числа.

Что посмотреть:

  • Код: ScoreBreakdownStackedBar.tsx:122-126, :374-381; тест с набором вкладов где лидер по модулю отрицательный.
  • Vault: релевантных заметок не найдено.
**🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)** **Текущее состояние кода:** `frontend/src/components/site-finder/ScoreBreakdownStackedBar.tsx:122-126` (агрегация+сортировка `sourceAgg`) и `:374-381` (`barWidth` в режиме «По фактору»). **Корень:** `sourceAgg` сортируется по ЗНАКОВОМУ вкладу — `.sort((a, b) => b.contribution - a.contribution)` (стр.124), значит `sourceAgg[0]` это самый ПОЛОЖИТЕЛЬНЫЙ фактор, а не максимальный по модулю. `barWidth` нормирует на `Math.abs(sourceAgg[0]?.contribution) || 1` (стр.378-379). Когда сильнейший по модулю фактор отрицателен (или все вклады <0 — плохой участок), знаменатель — наименьший модуль; у остальных `abs(contribution) > abs(sourceAgg[0])` → `Math.min(100, …)` клампит все полоски в 100% full-width, относительная сила теряется. **Что править:** - Знаменатель = максимум модуля: `const maxAbs = Math.max(...sourceAgg.map(s => Math.abs(s.contribution)), 1);` затем `barWidth = Math.min(100, Math.abs(contribution) / maxAbs * 100)`. - Опционально: сортировку отбора топ-10 (стр.124) тоже по модулю, если нужен показ сильнейших по абсолютной величине. - Severity medium корректна: вторичный toggle-режим, основной «По категории» нормирует через totalPositive/totalNegative; деградация чисто визуальная, `fmtV` показывает верные числа. **Что посмотреть:** - Код: `ScoreBreakdownStackedBar.tsx:122-126`, `:374-381`; тест с набором вкладов где лидер по модулю отрицательный. - Vault: релевантных заметок не найдено.
Sign in to join this conversation.
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#1451
No description provided.