fix(cadastre): cad_parcels.geom Polygon → MultiPolygon (migration 93) #185

Merged
lekss361 merged 1 commit from fix/cadastre-parcels-geom-multipolygon into main 2026-05-15 15:52:38 +00:00
lekss361 commented 2026-05-15 15:47:57 +00:00 (Migrated from github.com)

Summary

Pilot v10 hung again on parcel `66:41:0105017:4` (Многоконтурный участок) — `Geometry type (MultiPolygon) does not match column type (Polygon)`. cad_parcels.geom was strict POLYGON, but NSPD returns MultiPolygon for legit multi-contour parcels.

Changes

  • Migration 93 (`data/sql/93_cad_parcels_geom_multipolygon.sql`):
    • DROP back-compat VIEW `cad_parcels_geom` (dependency on column)
    • ALTER COLUMN geom TYPE `geometry(MultiPolygon, 4326)` USING `ST_Multi(geom)` (1199 existing rows safely converted, idempotent via DO block)
    • DROP+RECREATE GIST index (type-specific)
    • RECREATE VIEW cad_parcels_geom (same SELECT)
  • upsert_parcel SQL: wrap `ST_Transform` in `ST_Multi()` — coerces incoming Polygon → MultiPolygon
  • Test: `test_upsert_parcel_sql_uses_st_multi_for_multipolygon_schema` verifies SQL contains ST_Multi

Test plan

  • 40 tests passing locally
  • After merge: auto-apply migration 93 in deploy.yml
  • Pilot v11 → expect 50/50 done без crash на Многоконтурный участки
## Summary Pilot v10 hung again on parcel \`66:41:0105017:4\` (Многоконтурный участок) — \`Geometry type (MultiPolygon) does not match column type (Polygon)\`. cad_parcels.geom was strict POLYGON, but NSPD returns MultiPolygon for legit multi-contour parcels. ## Changes - **Migration 93** (\`data/sql/93_cad_parcels_geom_multipolygon.sql\`): - DROP back-compat VIEW \`cad_parcels_geom\` (dependency on column) - ALTER COLUMN geom TYPE \`geometry(MultiPolygon, 4326)\` USING \`ST_Multi(geom)\` (1199 existing rows safely converted, idempotent via DO block) - DROP+RECREATE GIST index (type-specific) - RECREATE VIEW cad_parcels_geom (same SELECT) - **upsert_parcel SQL**: wrap \`ST_Transform\` in \`ST_Multi()\` — coerces incoming Polygon → MultiPolygon - **Test**: \`test_upsert_parcel_sql_uses_st_multi_for_multipolygon_schema\` verifies SQL contains ST_Multi ## Test plan - [x] 40 tests passing locally - [ ] After merge: auto-apply migration 93 in deploy.yml - [ ] Pilot v11 → expect 50/50 done без crash на Многоконтурный участки
lekss361 commented 2026-05-15 15:52:27 +00:00 (Migrated from github.com)

Review

CI зелёный (backend 1m2s + frontend 1m35s) + cross-check (agent):

Migration 93 — корректна

  • Idempotency: geometry_columns.type — правильный PostGIS metadata view. Возвращает 'POLYGON' (uppercase) — матчит DO block check. На re-run ALTER skipped → RAISE NOTICE.
  • VIEW recreation: DROP VIEW обязателен перед ALTER COLUMN TYPE на dependent column. Recreated SELECT (cad_num, geom, raw_props, fetched_at) идентичен mig92:672-679.
  • GIST index name match: mig92:310-311 создаёт cad_parcels_geom_gist, mig93 DROP+CREATE использует то же имя — нет orphaned index.
  • Migration ordering: deploy.yml:235 применяет data/sql/*.sql | sort alphabetical → 93 после 92, tracking через _schema_migrations (PR #151).

Other consumers safe

  • cad_buildings/constructions/oncs/enkGEOMETRY(Geometry, 4326) generic, ST_Multi не нужен (writers unchanged).
  • cad_zouit.geomGEOMETRY(MultiPolygon, 4326), upsert_zouit:937 уже использует ST_Multi.
  • upsert_quarter_geom_from_feature:1028 уже использует ST_Multi (PR #181).
  • parcels.py:518-523 _polygon_suitability explicitly принимает оба Polygon/MultiPolygon, picks largest part.
  • cadastre_fetch.py использует cad_parcels_geom VIEW для existence checks (type-agnostic).
  • ST_Intersects/ST_DWithin/ST_Distance — type-agnostic.

ST_Multi wrap корректен

ST_Multi на already-MultiPolygon = no-op (returns same). На Polygon coerce'ит в MultiPolygon. NULL проваливается через CASE WHEN — никогда не доходит до ST_Multi.

Test coverage

test_upsert_parcel_sql_uses_st_multi_for_multipolygon_schema — substring assert "ST_Multi(" in sql. SQL template single-statement, ST_Multi appears once → acceptable safety net.

Rollback path documented

DROP VIEW; ALTER COLUMN TYPE Polygon USING ST_GeometryN(geom,1); recreate view/index. 1199 multi-contour rows потеряли бы parts при rollback, но текущих violations Polygon нет.

Минор (не блокер)

  • DO block обрабатывает current_type IS NULL через ELSE branch → safe falls through.

approve merge

## Review CI зелёный (backend 1m2s + frontend 1m35s) + cross-check (agent): ### ✅ Migration 93 — корректна - **Idempotency**: `geometry_columns.type` — правильный PostGIS metadata view. Возвращает 'POLYGON' (uppercase) — матчит DO block check. На re-run ALTER skipped → RAISE NOTICE. - **VIEW recreation**: DROP VIEW обязателен перед ALTER COLUMN TYPE на dependent column. Recreated SELECT `(cad_num, geom, raw_props, fetched_at)` идентичен mig92:672-679. - **GIST index name match**: mig92:310-311 создаёт `cad_parcels_geom_gist`, mig93 DROP+CREATE использует то же имя — нет orphaned index. - **Migration ordering**: deploy.yml:235 применяет `data/sql/*.sql | sort` alphabetical → 93 после 92, tracking через `_schema_migrations` (PR #151). ### ✅ Other consumers safe - `cad_buildings/constructions/oncs/enk` — `GEOMETRY(Geometry, 4326)` generic, ST_Multi не нужен (writers unchanged). - `cad_zouit.geom` — `GEOMETRY(MultiPolygon, 4326)`, `upsert_zouit:937` уже использует ST_Multi. - `upsert_quarter_geom_from_feature:1028` уже использует ST_Multi (PR #181). - `parcels.py:518-523` `_polygon_suitability` explicitly принимает оба Polygon/MultiPolygon, picks largest part. - `cadastre_fetch.py` использует `cad_parcels_geom` VIEW для existence checks (type-agnostic). - `ST_Intersects`/`ST_DWithin`/`ST_Distance` — type-agnostic. ### ✅ ST_Multi wrap корректен ST_Multi на already-MultiPolygon = no-op (returns same). На Polygon coerce'ит в MultiPolygon. NULL проваливается через CASE WHEN — никогда не доходит до ST_Multi. ### ✅ Test coverage `test_upsert_parcel_sql_uses_st_multi_for_multipolygon_schema` — substring assert `"ST_Multi(" in sql`. SQL template single-statement, ST_Multi appears once → acceptable safety net. ### ✅ Rollback path documented `DROP VIEW; ALTER COLUMN TYPE Polygon USING ST_GeometryN(geom,1); recreate view/index`. 1199 multi-contour rows потеряли бы parts при rollback, но текущих violations Polygon нет. ### Минор (не блокер) - DO block обрабатывает `current_type IS NULL` через ELSE branch → safe falls through. approve merge
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#185
No description provided.