fix(site-finder): разгейтить geoportal зон-резолвер от gappy NSPD-дампа — починить видимость финмодели (#1881) #1891
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
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
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#1891
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/zoning-resolution-decouple"
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?
Проблема (прод-замер 2026-06-24, postgres-gendesign MCP)
financial_estimateфаерит ~0% (0/542 анализов analyze-1.0 за 90д). Резолв ПЗЗ-зоны на участок проваливается на 94%:max_farесть у 15/542,can_build_mkd=trueу 4/542, пересечение = 0.В analyze два резолвера зоны:
_get_zoning(nspd_quarter_dumps, точныйST_Intersects) — терзоны не замощают квартал плотно, центроид участка падает в 45–86 м зазор между валидными зонами →nspd_zoning=Noneу 512/542.get_or_fetch_zone_regulation→EKBGeoportalClient.zone_index_at(живой геопортал, cache-first) — РАБОТАЕТ, резолвит gap-участки (проверено: возвращает Ж-5/ПК-1/ЦС-3 там, где дамп пуст).Но (2), дающий
max_far, был загейчен за_nspd_zoning is not None(parcels.py:2074) — зазор дампа глушил рабочий резолвер. Плюс дамп кладёт кадастровый рег-номер вzone_code, аgate.is_residential_zoneматчит^Ж→ не срабатывал.Фикс (PR-A)
_nspd_zoning is not Noneиз условия — geoportal-резолвер работает при centroid (region-guard: только КН66:41, геопортал ЕКБ-only).nspd_zoningиз geoportal:zone_code= индекс зоны ("Ж-2") →is_residential_zone^Жсрабатывает →can_build_mkdрезолвится для Ж-* зон. Write-back вnspd_dump_data["nspd_zoning"]доходит до gate / финмоста / ответа (читают по ключу).zone_codeне перетираем (raw_props.subcategory детектит жильё), только добавляем regulation-поля. Расширение на Ц-/ЦС- → PR-B.Геопортал — authoritative (point-in-zone по ПОЛНОМУ слою ПЗЗ); «зазор» только в нашем кэше-дампе. Hot-path-safe (try/except, timeout 3с, cache-first).
Ожидаемый эффект
Прод-замер до:
66:41:0303006:930(Ж-5 gap) →zone_code/max_far/financial=None, can_build=False. После деплоя ожидаем Ж-5 / max_far=4 / can_build=True / financial=PRESENT (провалидирую на проде).Test plan
is_residential_zoneЖ-2=True / ПК-1/ЦС-3=False. Кейс синтеза ассертит РЕАЛЬНЫЙ gatecan_build_mkd=True.⚠️ Известные follow-ups
is_residential_zoneна Ц-/ЦС- МКД-зоны черезzone_regulation_cache.main_vri(нужна ПЗЗ-валидация какие индексы разрешают МКД).zone_index_at— живой WFS-вызов на каждый ЕКБ-analyze (~1-2с, был только у 6%). Приемлемо (gated 3с timeout); оптимизация (dump-buffer-first) — отдельно.Refs #1881
🤖 Generated with Claude Code
financial_estimate фаерил ~0% в проде (0/542 анализов, 90д): резолв ПЗЗ-зоны на участок проваливался на 94%. Причина — в analyze ДВА резолвера зоны: (1) get_quarter_dump_data/_get_zoning (nspd_quarter_dumps, точный ST_Intersects) — терзоны НЕ замощают квартал плотно, центроид участка падает в 45-86м ЗАЗОР между валидными зонами → nspd_zoning=None у 512/542; (2) get_or_fetch_zone_regulation → EKBGeoportalClient.zone_index_at (живой геопортал, cache-first) — РАБОТАЕТ, резолвит gap-участки. Но (2), дающий max_far, был ЗАГЕЙЧЕН за `_nspd_zoning is not None`, т.е. зазор дампа глушил рабочий резолвер. Плюс: dump кладёт кадастровый рег-номер ("66:41-7.14") в zone_code, а gate.is_residential_zone матчит ^Ж → не срабатывал. Фикс (PR-A): убран `_nspd_zoning is not None` из условия — резолвер геопортала работает при наличии centroid (region-guard: только КН 66:41, геопортал ЕКБ-only). Когда dump зону не дал — синтезируем минимальный nspd_zoning из geoportal: zone_code = индекс зоны ("Ж-2") → is_residential_zone ^Ж срабатывает → can_build_mkd резолвится для Ж-* зон. Запись обратно в nspd_dump_data["nspd_zoning"] доходит до gate / финмоста / ответа (читают по ключу). Когда dump зону ДАЛ — zone_code не перетираем (raw_props.subcategory детектит жильё), только добавляем regulation-поля. Геопортал — authoritative источник (point-in-zone по ПОЛНОМУ слою ПЗЗ); «зазор» только в нашем кэше-дампе, не в реальности. Хот-path-safe (try/except, timeout 3с, cache-first). Расширение dump-резидентности на Ц-*/ЦС-* → PR-B. Тесты: +7 (синтез при dump=None+geoportal; нет синтеза при обоих None; dump zone_code не перетёрт; геопортал падает→деградация; is_residential_zone Ж-2=True, ПК-1/ЦС-3=False). Кейс синтеза ассертит РЕАЛЬНЫЙ gate can_build_mkd=True. 47 passed (вкл. pre-existing zoning+gate), ruff+mypy чисто. Схема не менялась (api-types regen не нужен). Прод-замер: 66:41:0303006:930 (Ж-5 gap) сейчас zone_code/max_far/financial=None, can_build=False → после деплоя ожидаем Ж-5/max_far=4/can_build=True/financial=PRESENT. Refs #1881 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>PR-A синтезировал zone_code = geoportal-индекс ("Ж-2") → gate.is_residential_zone матчил ^Ж и считал ЛЮБУЮ Ж-* зону жилой-МКД. Но по zone_regulation_cache.main_vri (authoritative ВРИ): Ж-1/Ж-2 = только ИЖС (нет кодов МКД) → ^Ж давал FALSE POSITIVE ("можно МКД" на ИЖС-участке — реальный дефект для девелопера); Ц-2 = разрешает МКД (коды 2.5/2.6) но без Ж-префикса → FALSE NEGATIVE. Фикс: is_residential_zone получил приоритет-0 — при наличии main_vri решает по нему авторитетно (mkd_permitted_from_vri: коды 2.1.1/2.5/2.6 = МКД, точное совпадение токена, "2.50"/"2.59"/"12.0" не матчат), переопределяя ^Ж/subcategory/keyword. Эвристики остаются ТОЛЬКО как fallback при main_vri=None (dump-путь без geoportal). parcels.py прокидывает _regulation.main_vri в nspd_zoning на ОБОИХ путях (synth + dump-augment) → dump-зоны (Ц-2 и пр.) тоже апгрейдятся на main_vri-детекцию. Унифицирует PR-A+PR-B. Обратная совместимость: main_vri default None. Проверено по зонам: Ж-3/4/5 permit_mkd=True, Ж-1/2=False(ИЖС), Ц-2=True, Ц-1/3/4+ЦС-*=False. Тесты: +22 (mkd_permitted_from_vri true/false/none + no-false-prefix; override suppress ИЖС / enable Ц-2 / overrides subcategory; fallback при None unchanged; synth ИЖС-кейс не даёт residential). Полный бэкенд локально: 3442 passed, 0 failed, coverage 70.3% (gate 65%). ruff чисто. Схема не менялась. Code-review 2×approve 0 major. Refs #1881 #1891 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>