(high) cad_territorial_zones.geom объявлена GEOGRAPHY(POLYGON) — MultiPolygon ПЗЗ-зоны молча отбрасываются при harvest #1344

Closed
opened 2026-06-14 18:08:46 +00:00 by bot-backend · 1 comment
Collaborator

Описание

_save_territorial_zones вставляет ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON(:geom),3857),4326)::geography в cad_territorial_zones.geom, которая объявлена GEOGRAPHY(POLYGON, 4326) (102_cad_nspd_overlay_tables.sql:24). Нет ни ST_Multi/ST_CollectionExtract-коэрции, ни фильтра geom_type. НСПД ПЗЗ-зоны часто MultiPolygon (многоконтурные). MultiPolygon-значение нарушает POLYGON-typmod → PostgreSQL бросает Geometry type (MultiPolygon) does not match column type (Polygon). Per-row with db.begin_nested() (строка 1473) ловит это и только логирует warning (1513) — многоконтурные зоны молча пропускаются, давая неполное ПЗЗ-покрытие в G1-gate логике без видимой ошибки.

Корень

Колонка имеет POLYGON-typmod вместо GEOMETRY/MULTIPOLYGON; saver не оборачивает geom в ST_Multi (в отличие от upsert_parcel:691,725-729 и upsert_zouit:1185,1216, которые и фильтруют по geom_type, и делают ST_Multi).

Evidence

102_cad_nspd_overlay_tables.sql:24: geom GEOGRAPHY(POLYGON, 4326)
bulk_harvest.py:1486:

ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON(CAST(:geom AS text)), 3857), 4326)::geography  -- нет ST_Multi

Suggested fix

Сделать колонку полиморфной (GEOGRAPHY(GEOMETRY,4326) / GEOMETRY(GEOMETRY), как cad_red_lines) через миграцию ИЛИ хранить как MULTIPOLYGON и обернуть в ST_Multi. Минимум — изменить typmod на GEOMETRY, чтобы многоконтурные зоны не отбрасывались. Добавить фильтр geom_type как в upsert_zouit.

Обоснование severity

high: данные молча неполны без видимой ошибки; путь достижим (НСПД layer 875838 реально содержит многоконтурные зоны), прямо влияет на G1-gate. confidence 0.97.


week ревью 1 · multi-agent аудит 2026-06-14 · severity=high · category=data-integrity

Затронутые файлы:

  • /Users/anton/Птица/gendesign/backend/app/services/cadastre/bulk_harvest.py
  • /Users/anton/Птица/gendesign/data/sql/102_cad_nspd_overlay_tables.sql
## Описание `_save_territorial_zones` вставляет `ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON(:geom),3857),4326)::geography` в `cad_territorial_zones.geom`, которая объявлена `GEOGRAPHY(POLYGON, 4326)` (`102_cad_nspd_overlay_tables.sql:24`). Нет ни ST_Multi/ST_CollectionExtract-коэрции, ни фильтра geom_type. НСПД ПЗЗ-зоны часто MultiPolygon (многоконтурные). MultiPolygon-значение нарушает POLYGON-typmod → PostgreSQL бросает `Geometry type (MultiPolygon) does not match column type (Polygon)`. Per-row `with db.begin_nested()` (строка 1473) ловит это и только логирует warning (1513) — многоконтурные зоны молча пропускаются, давая неполное ПЗЗ-покрытие в G1-gate логике без видимой ошибки. ## Корень Колонка имеет POLYGON-typmod вместо GEOMETRY/MULTIPOLYGON; saver не оборачивает geom в ST_Multi (в отличие от `upsert_parcel`:691,725-729 и `upsert_zouit`:1185,1216, которые и фильтруют по geom_type, и делают ST_Multi). ## Evidence `102_cad_nspd_overlay_tables.sql:24`: `geom GEOGRAPHY(POLYGON, 4326)` `bulk_harvest.py:1486`: ```sql ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON(CAST(:geom AS text)), 3857), 4326)::geography -- нет ST_Multi ``` ## Suggested fix Сделать колонку полиморфной (`GEOGRAPHY(GEOMETRY,4326)` / `GEOMETRY(GEOMETRY)`, как `cad_red_lines`) через миграцию ИЛИ хранить как MULTIPOLYGON и обернуть в ST_Multi. Минимум — изменить typmod на GEOMETRY, чтобы многоконтурные зоны не отбрасывались. Добавить фильтр geom_type как в upsert_zouit. ## Обоснование severity high: данные молча неполны без видимой ошибки; путь достижим (НСПД layer 875838 реально содержит многоконтурные зоны), прямо влияет на G1-gate. confidence 0.97. --- _week ревью 1 · multi-agent аудит 2026-06-14 · severity=**high** · category=`data-integrity`_ Затронутые файлы: - `/Users/anton/Птица/gendesign/backend/app/services/cadastre/bulk_harvest.py` - `/Users/anton/Птица/gendesign/data/sql/102_cad_nspd_overlay_tables.sql`
bot-backend added the
week ревью 1
label 2026-06-14 18:08:46 +00:00
bot-backend added the
scope/backend
label 2026-06-15 11:01:49 +00:00
Owner

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

Текущее состояние кода:

  • data/sql/102_cad_nspd_overlay_tables.sql:24geom GEOGRAPHY(POLYGON, 4326) (POLYGON-typmod). Сравн. соседние таблицы в той же миграции: cad_red_lines/прочие — GEOGRAPHY(GEOMETRY, 4326) (:39,53,70,85).
  • backend/app/services/cadastre/bulk_harvest.py:1259-1265_save_territorial_zones вставляет ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON(:geom),3857),4326)::geography БЕЗ ST_Multi и БЕЗ фильтра geom_type. Обёрнуто в with db.begin_nested() (:1246); исключение ловится и только логируется warning (:1287-1292).

Корень: колонка имеет POLYGON-typmod, а saver не коэрцит geom в MultiPolygon. НСПД ПЗЗ-зоны (layer 875838) часто многоконтурные (MultiPolygon) → нарушение POLYGON-typmod → Geometry type (MultiPolygon) does not match column type (Polygon) → SAVEPOINT откатывает только эту строку, зона молча пропускается → неполное ПЗЗ-покрытие в G1-gate без видимой ошибки. Контраст: upsert_parcel (bulk_harvest.py:502 ST_Multi) и upsert_zouit (:989 ST_Multi + фильтр geom_type на :954) делают это правильно.

Что править:

  • Миграцией сменить typmod: cad_territorial_zones.geomGEOGRAPHY(GEOMETRY, 4326) (как cad_red_lines) ИЛИ GEOGRAPHY(MULTIPOLYGON, 4326). Idempotent guarded ALTER TABLE ... ALTER COLUMN ... TYPE.
  • В _save_territorial_zones обернуть geom в ST_Multi(...) (как upsert_parcel:502) и добавить geom_type-фильтр (Polygon/MultiPolygon only, как upsert_zouit:954), чтобы Point/LineString не роняли INSERT.

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

  • Код: bulk_harvest.py:1209-1294 (_save_territorial_zones), reference upsert_parcel:497-510, upsert_zouit:936-995. Миграция 102_cad_nspd_overlay_tables.sql:16-30. GIST-индекс :27-28 переживёт смену typmod. SQL через CAST(:x AS type) (psycopg v3). Проверить на реальном многоконтурном квартале НСПД, что зоны больше не теряются (count до/после).
  • Vault: релевантных заметок не найдено (искал «cad_territorial_zones MultiPolygon ST_Multi» — пусто).
**🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)** **Текущее состояние кода:** - `data/sql/102_cad_nspd_overlay_tables.sql:24` — `geom GEOGRAPHY(POLYGON, 4326)` (POLYGON-typmod). Сравн. соседние таблицы в той же миграции: `cad_red_lines`/прочие — `GEOGRAPHY(GEOMETRY, 4326)` (`:39,53,70,85`). - `backend/app/services/cadastre/bulk_harvest.py:1259-1265` — `_save_territorial_zones` вставляет `ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON(:geom),3857),4326)::geography` БЕЗ `ST_Multi` и БЕЗ фильтра geom_type. Обёрнуто в `with db.begin_nested()` (`:1246`); исключение ловится и только логируется warning (`:1287-1292`). **Корень:** колонка имеет POLYGON-typmod, а saver не коэрцит geom в MultiPolygon. НСПД ПЗЗ-зоны (layer 875838) часто многоконтурные (MultiPolygon) → нарушение POLYGON-typmod → `Geometry type (MultiPolygon) does not match column type (Polygon)` → SAVEPOINT откатывает только эту строку, зона молча пропускается → неполное ПЗЗ-покрытие в G1-gate без видимой ошибки. Контраст: `upsert_parcel` (`bulk_harvest.py:502` ST_Multi) и `upsert_zouit` (`:989` ST_Multi + фильтр geom_type на `:954`) делают это правильно. **Что править:** - Миграцией сменить typmod: `cad_territorial_zones.geom` → `GEOGRAPHY(GEOMETRY, 4326)` (как `cad_red_lines`) ИЛИ `GEOGRAPHY(MULTIPOLYGON, 4326)`. Idempotent guarded `ALTER TABLE ... ALTER COLUMN ... TYPE`. - В `_save_territorial_zones` обернуть geom в `ST_Multi(...)` (как `upsert_parcel:502`) и добавить geom_type-фильтр (Polygon/MultiPolygon only, как `upsert_zouit:954`), чтобы Point/LineString не роняли INSERT. **Что посмотреть:** - Код: `bulk_harvest.py:1209-1294` (`_save_territorial_zones`), reference `upsert_parcel:497-510`, `upsert_zouit:936-995`. Миграция `102_cad_nspd_overlay_tables.sql:16-30`. GIST-индекс `:27-28` переживёт смену typmod. SQL через `CAST(:x AS type)` (psycopg v3). Проверить на реальном многоконтурном квартале НСПД, что зоны больше не теряются (count до/после). - Vault: релевантных заметок не найдено (искал «cad_territorial_zones MultiPolygon ST_Multi» — пусто).
bot-backend added the
needs-human
label 2026-06-15 16:43:56 +00:00
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#1344
No description provided.