feat(#126): Sub-PR A — NSPDClient.get_features_in_bbox_grid + engineering classifier #247
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
вторичка
ИРД
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#247
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/126-nspd-grid-walk-scraper"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Foundation для #126 → #231/#234 fix. Не меняет prod behaviour — старый
get_features_in_bbox(single-pixel, возвращает 0-3 features) депрекейтнут только в docstring; всё ещё вызывается изsearch_by_quarter. Switch произойдёт в Sub-PR B.Что добавлено
NSPDClient.get_features_in_bbox_grid(layer_id, bbox, *, grid_n=7, step_m=50)вbackend/app/services/scrapers/nspd_client.py:grid_n×grid_nWMSGetFeatureInfocalls черезNSPDBulkClient.wms_feature_infoSemaphore(3)для concurrency capfeature_id→cad_num→reg_numb_borderclassify_engineering_kind(properties)вnspd_denorm.py— regex classifier для layer 36328 structures:water | sewage | gas | heat | electric | other. Cyrillic patterns из post-mortem (gas —газопровод|ГРП|ГК, electric —ВЛ|КЛ|ТП|ЛЭП|подстанц, и т.д.).Pre-push review
deep-code-reviewer ✅ APPROVE с 1 minor yellow:
feature_id=None / cad_num=None / reg_numb_border=None— features без всех key полей могут проходить N раз через соседние ячейки. Не блокер для foundation PR; flag для Sub-PR B (геометрический hash fallback).asyncio.run()safety verified — NSPDClient импортируется только из Celery sync tasksSemaphore(3)thread-safe (Celery prefork = отдельный event loop per worker)Plan context (4 sub-PRs)
search_by_quarterна grid-walk (depends A)Test plan
cd backend && uv run pytest tests/scrapers/test_nspd_grid_walk.py -v→ 31 passed, 1 skippeduv run ruff check + ruff format --check→ All checks passedcd backend && uv run pytest tests/scrapers/ -k "not grid_walk" 2>&1 | tail -5(legacy tests still green)Related
fixes/Bug_NSPD_WMS_NotBulk_2026_May14.md(vault)code/modules/NSPD_Bulk_Client.mdupdatedRefs #126, #231, #234
Deep review — verdict ✅ APPROVE
Scope: foundation only, dead code до Sub-PR B. Bar для merge снижен — главное no regression в существующих тестах. Подтверждено.
Cross-file impact
from app.scrapers.nspd_bulk_client import NSPDBulkClient— путь существует (backend/app/scrapers/nspd_bulk_client.py:106),wms_feature_info()есть (line 321),_SEMAPHOREmodule-level (line 61).NSPDClient: толькоbackend/app/workers/tasks/nspd_sync.py:289(Celery syncdef harvest_quarter) + tests. Async caller отсутствует →asyncio.run()safe.get_features_in_bboxсохранён (используется вsearch_by_quarter:578). Legacy testtest_get_features_in_bbox_url_builds_correctlyзелёный.Correctness
asyncio.run()pattern OK (sync caller, fresh event loop per Celery worker process).Semaphore(3)per-event-loop — Celery prefork = process isolation.return_exceptions=True+ warning log per cell error — partial failures не валят весь grid.effective_nдля маленьких bbox (избегает деления на ноль).feature_id/cad_num/cad_number/reg_numb_border/labelвсе None — feature попадает вdedupedбез записи вseen, следующая такая же тоже попадёт. В практике NSPD WMS features почти всегда имеютid, но для Sub-PR B стоит добавить geometric hash fallback (e.g.hash(json.dumps(feat.geometry, sort_keys=True))).test_field_priority_params_name_over_purposedocstring говорит «params_name проверяется раньше purpose», но фактически логика склеивает все поля в одну строку и порядок решает_ENGINEERING_PATTERNS. Тест проходит, но название/docstring вводят в заблуждение. Nit, fix в Sub-PR B.Performance
_BACKOFF_BASE_S=2.0(на 429) — нужен budget-monitor. Не блокер для A.Conventions
print, norequests,httpxonly, no psycopg patterns (PR не трогает БД).re.IGNORECASE.ВЛ[\s\-]|ВЛ-?\dдостаточно safe — false positive на «вложение» исключён (требуется пробел/дефис/цифра после).Vault
fixes/Bug_NSPD_WMS_NotBulk_2026_May14.md— post-mortem существует, упомянут в docstring иnspd_denorm.py.code/modules/NSPD_Bulk_Client.md— Update section 2026-05-17 для Sub-PR A добавлена.research/Bulk_Cadastre_Ingest_Plan_May15.md.Risk / Reversibility
Мержу via squash. Yellow dedup flag оставляю как follow-up для Sub-PR B.