gendesign/backend/tests/api/v1
Light1YT 46f021e1c8
Some checks failed
CI / changes (pull_request) Successful in 7s
CI / openapi-codegen-check (pull_request) Successful in 1m51s
CI / backend-tests (pull_request) Failing after 11m59s
CI / frontend-tests (pull_request) Has been skipped
fix(site-finder): разгейтить geoportal зон-резолвер от gappy NSPD-дампа
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>
2026-06-24 03:25:06 +05:00
..
__init__.py feat(cadastre): bulk_harvest worker + grid-walker + admin API (#168 PR3/5) (#171) 2026-05-15 13:31:32 +03:00
test_admin_cadastre.py test(suite): re-align drifted tests with current code (CI-rehab 2/3) 2026-06-03 19:05:43 +05:00
test_admin_ekburg_permits.py test(suite): re-align drifted tests with current code (CI-rehab 2/3) 2026-06-03 19:05:43 +05:00
test_admin_jobs_settings.py fix(admin-jobs): UPSERT в PUT /admin/jobs/settings — не терять изменения (#1223) 2026-06-13 08:36:23 +00:00
test_admin_scrape_freshness.py feat(admin): freshness endpoint (#73) + README Forgejo refresh (#83) + migrations doc (#72) 2026-06-13 18:25:32 +00:00
test_analyze_competitors_status.py perf(site-finder): pushdown obj_pricing CTE to nearby competitors (#70/#307) (#1335) 2026-06-14 16:58:43 +00:00
test_analyze_inline_weights.py perf(site-finder): air-quality TTL-кэш + neighbors_summary 2→1 SQL (#1130 Phase B) 2026-06-12 22:42:32 +05:00
test_analyze_market_price.py perf(site-finder): air-quality TTL-кэш + neighbors_summary 2→1 SQL (#1130 Phase B) 2026-06-12 22:42:32 +05:00
test_analyze_parcel_meta.py perf(site-finder): air-quality TTL-кэш + neighbors_summary 2→1 SQL (#1130 Phase B) 2026-06-12 22:42:32 +05:00
test_analyze_recent_permits.py perf(site-finder): air-quality TTL-кэш + neighbors_summary 2→1 SQL (#1130 Phase B) 2026-06-12 22:42:32 +05:00
test_analyze_zoning_regulation.py fix(site-finder): разгейтить geoportal зон-резолвер от gappy NSPD-дампа 2026-06-24 03:25:06 +05:00
test_chat.py fix(backend): экранировать Excel formula-injection (#1244) + увести chat-чтение с event loop (#1245) 2026-06-13 18:10:21 +05:00
test_custom_pois.py perf(site-finder): air-quality TTL-кэш + neighbors_summary 2→1 SQL (#1130 Phase B) 2026-06-12 22:42:32 +05:00
test_insights.py feat(insights): manual-entry Insight entity CRUD + §19 audit (#948 part A) 2026-06-08 12:41:39 +05:00
test_locations.py feat(location): district-level Location entity + indices (#948 part B) 2026-06-08 13:28:19 +05:00
test_own_projects.py feat(site-finder): own-portfolio data source for §25.3 cannibalization (#1169 PR1) 2026-06-08 16:21:53 +05:00
test_parcel_best_layouts.py test(suite): re-align drifted tests with current code (CI-rehab 2/3) 2026-06-03 19:05:43 +05:00
test_parcel_by_bbox.py fix(analyze): district KeyError 500 in #994 persist + revive by-bbox tests 2026-06-03 18:04:37 +05:00
test_parcel_competitors.py feat(site-finder): additive objective_lots price fallback for competitors (#307 OBJ-3) (#1332) 2026-06-14 16:10:02 +00:00
test_parcel_connection_points.py feat(parcels): connection-points endpoint (Forgejo #115 Phase 1 backend) (#190) 2026-05-16 05:58:27 +00:00
test_parcel_snapshot_exclude_dev.py feat(site-finder): snapshot.pdf exclude_dev param — hide competitor by developer name 2026-06-18 15:23:28 +03:00
test_parcels_forecast.py fix(site-finder): 5 дефектов из боевого фидбека analyze (#1736 #1737 #1738 #1739 #1740) 2026-06-18 11:47:21 +05:00
test_run_history_and_response_contract.py perf(site-finder): air-quality TTL-кэш + neighbors_summary 2→1 SQL (#1130 Phase B) 2026-06-12 22:42:32 +05:00