feat(sf): parcel_ird_overlaps read-side для analyze (#1067 D9a) #1092

Merged
bot-reviewer merged 1 commit from feat/ird-parcel-overlaps into main 2026-06-06 19:01:07 +00:00
Owner

Что

backend/app/services/site_finder/ird_overlay_lookup.py — read-side ИРД-overlay lookup: по геометрии участка (WKT 4326) ST_Intersects против ird_overlays (м.132, PR #1078) → список ограничений с reg_numb_border + zone_index/zone_type_name (когда резолвлено) + группировка ird_by_kind.

Дизайн

  • Standalone-модуль, нулевой collision с parcels.py (Anton-hot файл). Wiring в analyze-surface — отдельный flag-gated PR (D9b).
  • Использует GIST idx_ird_overlays_geom. geom уже 4326 (harvest стор ST_Transform).
  • Graceful degrade: если ird_overlays ещё не задеплоена (pre-migration) или БД-ошибка → пустой результат, analyze не падает (паттерн quarter_dump_lookup).
  • Комплементарно quarter_dump_lookup (nspd_quarter_dumps blob): это выделенный per-feature ИРД-store с reg-номерами + content для геопортал-резолва.

Тесты

4 passed: группировка by_kind, empty без WKT, empty без пересечений, graceful при отсутствии таблицы (OperationalError). ruff clean.

Refs #1067 (D9a). Зависит от merged B3 (#1078) + наполняется B5 harvest (#1090). Next D9b: минимальный flag-gated блок в analyze (parcels.py) → поле ird в ответе.

## Что `backend/app/services/site_finder/ird_overlay_lookup.py` — read-side ИРД-overlay lookup: по геометрии участка (WKT 4326) `ST_Intersects` против `ird_overlays` (м.132, PR #1078) → список ограничений с `reg_numb_border` + `zone_index`/`zone_type_name` (когда резолвлено) + группировка `ird_by_kind`. ## Дизайн - Standalone-модуль, **нулевой collision с `parcels.py`** (Anton-hot файл). Wiring в analyze-surface — отдельный flag-gated PR (D9b). - Использует GIST `idx_ird_overlays_geom`. geom уже 4326 (harvest стор ST_Transform). - **Graceful degrade:** если `ird_overlays` ещё не задеплоена (pre-migration) или БД-ошибка → пустой результат, analyze не падает (паттерн `quarter_dump_lookup`). - Комплементарно `quarter_dump_lookup` (nspd_quarter_dumps blob): это выделенный per-feature ИРД-store с reg-номерами + content для геопортал-резолва. ## Тесты 4 passed: группировка by_kind, empty без WKT, empty без пересечений, graceful при отсутствии таблицы (OperationalError). ruff clean. Refs #1067 (D9a). Зависит от merged B3 (#1078) + наполняется B5 harvest (#1090). Next D9b: минимальный flag-gated блок в analyze (parcels.py) → поле `ird` в ответе.
lekss361 added 1 commit 2026-06-06 18:53:18 +00:00
feat(sf): parcel_ird_overlaps read-side для analyze (#1067 D9a)
All checks were successful
CI / changes (push) Successful in 9s
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Successful in 5m52s
CI / backend-tests (push) Successful in 6m13s
8df0f157a7
ИРД-overlay lookup: ST_Intersects участка по ird_overlays (м.132) → ограничения
(ЗОУИТ/ПЗЗ-границы/ОКН/ООПТ) с reg_numb_border + zone_index/type (когда резолвлено).
Standalone-модуль (нулевой collision с parcels.py). Graceful degrade если таблица
ещё не задеплоена. Комплементарно quarter_dump_lookup (per-quarter blob).

Refs #1067 (D9a). Next D9b: flag-gated wiring в analyze-surface.
lekss361 added the
status/review
label 2026-06-06 18:53:38 +00:00
bot-reviewer reviewed 2026-06-06 19:01:00 +00:00
bot-reviewer left a comment
Collaborator

APPROVE

Чистый read-side lookup, нулевой regression (standalone, parcels.py не тронут — Anton-hot; wiring деферится в D9b flag-gated):

  • SQL injection нет: parcel_wkt через bound :parcel_wkt + CAST(:x AS text), параметризован. psycopg v3 чисто (нет ::).
  • GIST path: ST_Intersects(geom, ST_GeomFromText(..., 4326))idx_ird_overlays_geom (м.132); geom уже 4326 (harvest ST_Transform), SRID-матч верен. Все 6 SELECT-колонок существуют в DDL м.132 (zone_index/zone_type_name — nullable content).
  • Graceful-degrade паттерн зеркалит quarter_dump_lookup.py; 4 теста (by_kind, no-WKT, no-overlap, OperationalError).

Минор (advisory, → follow-up для D9b):

  1. except (OperationalError, ProgrammingError) не ловит DataError/InternalError от malformed-WKT в ST_GeomFromText → analyze упал бы. parcel_wkt системно-генерируемый (не user-input) → low-risk; sibling использует те же 2 класса (консистентно). Расширить до DataError при wiring.
  2. Нет теста на ProgrammingError (реальный класс missing-table) — оба в одном except, low.
  3. IRD_EMPTY_RESULT экспортируется для caller-identity-check, функция возвращает fresh-литералы — намеренно, mutation-risk нет.

Заведу один follow-up на #1/#2. Merge → deploy-verify.

<!-- gendesign-review-bot: sha=8df0f15 verdict=approve --> ✅ **APPROVE** Чистый read-side lookup, нулевой regression (standalone, `parcels.py` не тронут — Anton-hot; wiring деферится в D9b flag-gated): - **SQL injection нет**: `parcel_wkt` через bound `:parcel_wkt` + `CAST(:x AS text)`, параметризован. psycopg v3 чисто (нет `::`). - **GIST path**: `ST_Intersects(geom, ST_GeomFromText(..., 4326))` → `idx_ird_overlays_geom` (м.132); geom уже 4326 (harvest ST_Transform), SRID-матч верен. Все 6 SELECT-колонок существуют в DDL м.132 (zone_index/zone_type_name — nullable content). - Graceful-degrade паттерн зеркалит `quarter_dump_lookup.py`; 4 теста (by_kind, no-WKT, no-overlap, OperationalError). **Минор (advisory, → follow-up для D9b):** 1. `except (OperationalError, ProgrammingError)` не ловит `DataError`/`InternalError` от malformed-WKT в `ST_GeomFromText` → analyze упал бы. parcel_wkt системно-генерируемый (не user-input) → low-risk; sibling использует те же 2 класса (консистентно). Расширить до `DataError` при wiring. 2. Нет теста на `ProgrammingError` (реальный класс missing-table) — оба в одном except, low. 3. `IRD_EMPTY_RESULT` экспортируется для caller-identity-check, функция возвращает fresh-литералы — намеренно, mutation-risk нет. Заведу один follow-up на #1/#2. Merge → deploy-verify.
bot-reviewer merged commit 9b9c6e85d3 into main 2026-06-06 19:01:07 +00:00
Sign in to join this conversation.
No reviewers
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#1092
No description provided.