fix(report): вывести ПЗЗ-градрегламент НСПД в Раздел 1 + coerceFloat КСИТ (#1962) #1987

Merged
bot-backend merged 2 commits from fix/report-nspd-zoning-1962 into main 2026-06-27 12:22:52 +00:00
Collaborator

Батч 3b аудита (эпик #1953). code-reviewer APPROVE.

#1962 — «где NSPD?»

nspd_zoning РЕЗОЛВИТСЯ (синтез #1891) и есть в ответе, но light-отчёт показывал только мёртвый zoning.data_available=false (закрытый PKK6). Теперь в Раздел 1 — карточка «Градрегламент (НСПД)»:

  • тер.зона (regulation_zone_index=ПК-1 / zone_code), КСИТ (max_far=2.4), этажность (max_floors=2), коэф. застройки (max_building_pct=80%), КСИТ-ёмкость (max_far×площадь), пятно застройки, источник (ekb-geoportal-urbancard), список ВРИ (main_vri, 20 шт).
  • Микрокопия с расшифровкой КСИТ; graceful empty-state «регламент не определён»; UI-токены, Lucide.
  • Реюз маппинга adaptUrbanDrawer (light-отчёт ↔ /ptica консистентны).

Бонус: латентный баг кокпита (coerceFloat)

max_far/max_building_pct приходят строками на wire (NUMERIC→Decimal→JSON-строка). Гарды typeof maxFar === "number" в massing/insolation 3D-пути их молча отбрасывали → 3D считал по дефолту 3.5 вместо реального КСИТ. Введён единый coerceFloat, прокинут во все потребители (light-отчёт + ptica-adapt/InsolationCard/DrawerContent/MassingScene). Ревью подтвердило: без NaN-регрессии, 3D теперь использует настоящий КСИТ.

Качество

  • tsc --noEmit clean; next lint clean; prettier 3.9.0 clean.
  • Тесты: 189/189 (+6 mapper: string-coercion/empty-state/ВРИ; ptica honesty 23/23).
  • coerceFloat возвращает null на junk → fallback (без NaN). Типы расширены string|number|null.

Follow-up (нит из ревью): max_height_m — тот же класс string-бага (раздельный тикет). Closes #1962.

Батч 3b аудита (эпик #1953). code-reviewer ✅ APPROVE. ## #1962 — «где NSPD?» `nspd_zoning` РЕЗОЛВИТСЯ (синтез #1891) и есть в ответе, но light-отчёт показывал только мёртвый `zoning.data_available=false` (закрытый PKK6). Теперь в Раздел 1 — карточка **«Градрегламент (НСПД)»**: - тер.зона (`regulation_zone_index`=ПК-1 / `zone_code`), КСИТ (`max_far`=2.4), этажность (`max_floors`=2), коэф. застройки (`max_building_pct`=80%), КСИТ-ёмкость (max_far×площадь), пятно застройки, источник (`ekb-geoportal-urbancard`), список ВРИ (`main_vri`, 20 шт). - Микрокопия с расшифровкой КСИТ; graceful empty-state «регламент не определён»; UI-токены, Lucide. - Реюз маппинга `adaptUrbanDrawer` (light-отчёт ↔ /ptica консистентны). ## Бонус: латентный баг кокпита (coerceFloat) `max_far`/`max_building_pct` приходят **строками** на wire (NUMERIC→Decimal→JSON-строка). Гарды `typeof maxFar === "number"` в massing/insolation 3D-пути их молча отбрасывали → 3D считал по дефолту 3.5 вместо реального КСИТ. Введён единый `coerceFloat`, прокинут во все потребители (light-отчёт + `ptica-adapt`/`InsolationCard`/`DrawerContent`/`MassingScene`). Ревью подтвердило: без NaN-регрессии, 3D теперь использует настоящий КСИТ. ## Качество - `tsc --noEmit` clean; `next lint` clean; prettier 3.9.0 clean. - Тесты: **189/189** (+6 mapper: string-coercion/empty-state/ВРИ; ptica honesty 23/23). - coerceFloat возвращает null на junk → fallback (без NaN). Типы расширены `string|number|null`. Follow-up (нит из ревью): `max_height_m` — тот же класс string-бага (раздельный тикет). Closes #1962.
bot-backend added 2 commits 2026-06-27 12:19:23 +00:00
Light report (Section1ParcelInfo) only rendered the dead top-level
zoning.data_available=false (closed-PKK6 path) and never showed the
resolved nspd_zoning, so the resolved regulation (synth #1891) was
invisible to the user («мы выгружали НСПД — где они?»).

- Add «Градрегламент (НСПД)»-card to Раздел 1 (right column, под ЕГРН):
  тер.зона, КСИТ/max_far, пред. высота, этажность, коэф. застройки,
  КСИТ-ёмкость/пятно (от площади ЕГРН), источник + список разрешённых
  ВРИ зоны. Empty-state когда регламент не определён (gap-зоны / не-ЕКБ).
  КСИТ-microcopy расшифровывает жаргон на первой странице.
- New pure mapper adaptNspdRegulation (nspd-regulation.ts) reused by
  ptica-adapt so light report и /ptica остаются consistent.
- coerceFloat: max_far/max_building_pct приходят с провода СТРОКАМИ
  ("2.4"/"80") — фикс латентного бага cockpit'а (typeof===number
  глушил реальный строковый КСИТ в massing/insolation).
- Widen NspdZoning.max_far/max_building_pct to string|number, add
  main_vri; expose nspd_zoning on ParcelAnalyzeResponse.
- Unit test для field-mapping + coercion + empty-state.
fix(report): уникальный React key для ВРИ-списка (дубль-VRI warning) (#1962)
All checks were successful
CI / changes (pull_request) Successful in 14s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 1m29s
CI / openapi-codegen-check (pull_request) Successful in 2m22s
63d685a105
bot-backend merged commit 16f375782b into main 2026-06-27 12:22:52 +00:00
Sign in to join this conversation.
No reviewers
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#1987
No description provided.