feat(sf): gknspecial_zone ИРД-harvest → ird_overlays (#1063/#1064/#1065/#1066) #1114

Merged
bot-reviewer merged 1 commit from feat/gknspecial-ird-harvest into main 2026-06-07 09:54:54 +00:00
Owner

Что

Новый Celery harvest-task harvest_gknspecial_zones, снимающий ЗОУИТ-слой ЕКБ-геопортала portal_geo_gknspecial_zone (WFS, читаемый тип+ограничения+рег.№ в одном запросе) → существующая таблица ird_overlays. Один слой/один harvest закрывает 4 пункта эпика #1067 «GG-форсайт»:

  • #1063 публичный сервитут (layer_kind=servitude, ~2344 фичи city-wide)
  • #1064 вода (водоохранная / прибрежная / ЗСО / СЗЗ, ~1160)
  • #1066 ОКН-зоны (355) + ЗРЗ (314)
  • #1065 приаэродромная территория (ЕГРН-часть, ~9)

Как

  • EKBGeoportalClient.features_by_cql() — новый публичный метод (произвольный CQL full_name LIKE).
  • Классификация full_namelayer_kind + sentinel source_layer_id (990001–990008; unmatched → 990099, не дропаем — defensive).
  • geom_data_id = trailing int из WFS feature_id; геометрия уже EPSG:4326 (без ST_Transform); zone_type_name/content(ограничения,решение,документ,дата) заполняются сразу (content_source=ekb_geoportal).
  • Активность фильтруется client-side (zone_state_v) — кириллица в combined-CQL ломает запрос.
  • UPSERT по (source_layer_id, geom_data_id), SAVEPOINT per-row. Без новой SQL-миграции (таблица на проде).
  • Read-side parcel_ird_overlaps расширен колонкой content → новые overlap'ы всплывают в analyze без правок wiring.
  • Beat: gknspecial-harvest-weekly (пн 05:30 МСК).

Тесты

27 unit (классификация/regex/geom_data_id/активность/upsert-идемпотентность) + content-passthrough в lookup. Геопортал замокан, в сеть не ходят.

NB для reviewer / прогона

Точные full_name-префиксы 3 типов (ОКН/ЗСО/приаэродром) не сверены живьём (локальный TLS). После merge — разовый ручной прогон task на проде, проверить gknspecial_harvest: prefix=... fetched=N (нулевой fetched при непустом слое = неверный префикс, поправить map).

Closes #1063 #1064 #1065 #1066 (частично — ЗОУИТ-часть; ОКН-объекты/ООПТ-лес/полнота приаэродром-подзон остаются).

## Что Новый Celery harvest-task `harvest_gknspecial_zones`, снимающий ЗОУИТ-слой ЕКБ-геопортала `portal_geo_gknspecial_zone` (WFS, читаемый тип+ограничения+рег.№ в одном запросе) → существующая таблица `ird_overlays`. Один слой/один harvest закрывает **4 пункта** эпика #1067 «GG-форсайт»: - **#1063** публичный сервитут (`layer_kind=servitude`, ~2344 фичи city-wide) - **#1064** вода (водоохранная / прибрежная / ЗСО / СЗЗ, ~1160) - **#1066** ОКН-зоны (355) + ЗРЗ (314) - **#1065** приаэродромная территория (ЕГРН-часть, ~9) ## Как - `EKBGeoportalClient.features_by_cql()` — новый публичный метод (произвольный CQL `full_name LIKE`). - Классификация `full_name` → `layer_kind` + sentinel `source_layer_id` (990001–990008; unmatched → 990099, не дропаем — defensive). - `geom_data_id` = trailing int из WFS `feature_id`; геометрия уже EPSG:4326 (без ST_Transform); `zone_type_name`/`content`(ограничения,решение,документ,дата) заполняются сразу (content_source=ekb_geoportal). - Активность фильтруется client-side (`zone_state_v`) — кириллица в combined-CQL ломает запрос. - UPSERT по `(source_layer_id, geom_data_id)`, SAVEPOINT per-row. **Без новой SQL-миграции** (таблица на проде). - Read-side `parcel_ird_overlaps` расширен колонкой `content` → новые overlap'ы всплывают в analyze без правок wiring. - Beat: `gknspecial-harvest-weekly` (пн 05:30 МСК). ## Тесты 27 unit (классификация/regex/geom_data_id/активность/upsert-идемпотентность) + content-passthrough в lookup. Геопортал замокан, в сеть не ходят. ## NB для reviewer / прогона Точные `full_name`-префиксы 3 типов (ОКН/ЗСО/приаэродром) не сверены живьём (локальный TLS). После merge — разовый ручной прогон task на проде, проверить `gknspecial_harvest: prefix=... fetched=N` (нулевой fetched при непустом слое = неверный префикс, поправить map). Closes #1063 #1064 #1065 #1066 (частично — ЗОУИТ-часть; ОКН-объекты/ООПТ-лес/полнота приаэродром-подзон остаются).
lekss361 added 1 commit 2026-06-07 09:48:34 +00:00
feat(sf): gknspecial_zone ИРД-harvest → ird_overlays (#1063/#1064/#1065/#1066)
All checks were successful
CI / changes (push) Successful in 7s
CI / changes (pull_request) Successful in 6s
CI / backend-tests (push) Successful in 6m0s
CI / backend-tests (pull_request) Successful in 5m56s
2b439521cd
lekss361 added the
GG-форсайт
scope/backend
site-finder
labels 2026-06-07 09:49:38 +00:00
bot-reviewer approved these changes 2026-06-07 09:54:49 +00:00
bot-reviewer left a comment
Collaborator

APPROVE — staff+ review (deep, 7 files / ~644 lines).

Verified against live prod DB:

  • ird_overlays columns content/content_source/content_fetched_at/geom_data_id/source_layer_id/raw_props/zone_type_name all exist → no migration needed, claim holds.
  • UNIQUE uq_ird_overlays_feature(source_layer_id, geom_data_id) exists → ON CONFLICT valid.

Correctness/conventions: SAVEPOINT-per-row (begin_nested) + SessionLocal try/finally + CAST(:x AS type) (psycopg v3) mirror ird_harvest.py exactly. CQL f-string full_name LIKE '{prefix}%' uses only hardcoded _PREFIX_MAP constants — no injection vector. Prefix startswith ordering safe (ЗСО vs ОКН-зона no collision). Cross-prefix double-fetch deduped by ON CONFLICT (redundant traffic at worst). Sentinel range 990001–990099 doesn't collide with НСПД layer_ids. Vault research (EKB_Geoportal_IRD_Layers...Jun06) confirms LIKE 'X%' works for all 8 types + documents the combined-Cyrillic-CQL breakage that justifies the client-side zone_state_v filter.

🟡 MINOR (non-blocking, follow-up filed):

  1. Single end-of-run db.commit()ird_harvest.py commits incrementally; a Celery WorkerLost mid-run on the ~20k-feature first harvest would drop all written rows. Per-prefix commit recommended → follow-up issue.
  2. test_upsert_idempotency_no_duplicates is vacuous (asserts execute-called-2x, doesn't exercise ON CONFLICT) — acceptable, real guarantee is the DB constraint.

Post-merge (author's NB, acknowledged): first scheduled run (Mon 05:30 МСК) — check Celery logs gknspecial_harvest: prefix=... fetched=N; zero N on non-empty layer = wrong prefix string for ОКН/ЗСО/приаэродром, fix _PREFIX_MAP.

Merging (squash).

<!-- gendesign-review-bot: sha=2b43952 verdict=approve --> ✅ **APPROVE** — staff+ review (deep, 7 files / ~644 lines). **Verified against live prod DB:** - `ird_overlays` columns `content`/`content_source`/`content_fetched_at`/`geom_data_id`/`source_layer_id`/`raw_props`/`zone_type_name` all exist → no migration needed, claim holds. - UNIQUE `uq_ird_overlays_feature(source_layer_id, geom_data_id)` exists → `ON CONFLICT` valid. **Correctness/conventions:** SAVEPOINT-per-row (`begin_nested`) + SessionLocal try/finally + `CAST(:x AS type)` (psycopg v3) mirror `ird_harvest.py` exactly. CQL f-string `full_name LIKE '{prefix}%'` uses only hardcoded `_PREFIX_MAP` constants — no injection vector. Prefix `startswith` ordering safe (ЗСО vs ОКН-зона no collision). Cross-prefix double-fetch deduped by ON CONFLICT (redundant traffic at worst). Sentinel range 990001–990099 doesn't collide with НСПД layer_ids. Vault research (`EKB_Geoportal_IRD_Layers...Jun06`) confirms `LIKE 'X%'` works for all 8 types + documents the combined-Cyrillic-CQL breakage that justifies the client-side `zone_state_v` filter. **🟡 MINOR (non-blocking, follow-up filed):** 1. Single end-of-run `db.commit()` — `ird_harvest.py` commits incrementally; a Celery WorkerLost mid-run on the ~20k-feature first harvest would drop all written rows. Per-prefix commit recommended → follow-up issue. 2. `test_upsert_idempotency_no_duplicates` is vacuous (asserts execute-called-2x, doesn't exercise ON CONFLICT) — acceptable, real guarantee is the DB constraint. **Post-merge (author's NB, acknowledged):** first scheduled run (Mon 05:30 МСК) — check Celery logs `gknspecial_harvest: prefix=... fetched=N`; zero N on non-empty layer = wrong prefix string for ОКН/ЗСО/приаэродром, fix `_PREFIX_MAP`. Merging (squash).
bot-reviewer merged commit dcafb32f31 into main 2026-06-07 09:54:54 +00:00
bot-reviewer deleted branch feat/gknspecial-ird-harvest 2026-06-07 09:54:54 +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#1114
No description provided.