fix(#244): harvest_quarter — CAST CASE WHEN params (psycopg3 AmbiguousParameter) #246
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#246
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/244-harvest-quarter-cast-ambiguous-parameter"
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?
Symptom
harvest_quarterпадает на INSERT вnspd_quarter_dumps:15+ events в GlitchTip.
nspd_quarter_dumps=0строк глобально. Блокировал #115, #231, #234, #235, #243.Root cause
_UPSERT_SQLиспользовал голые bind-параметры внутриCASE WHEN ... IS NULL. psycopg3 не может вывести тип$Nкогда один branch —NULLлитерал, другой — PostGIS geometry / float.Fix
backend/app/workers/tasks/nspd_sync.py:CAST(:geom_json AS text)дляST_GeomFromGeoJSONCAST(:bbox_xmin AS double precision)(ymin/xmax/ymax аналогично) дляST_MakeEnvelopeSide fix
Pre-existing тесты не обновлялись когда
QuarterDumpполучил обязательное полеopportunity. Добавленоopportunity={}в 3 inline-конструктора вtest_nspd_sync.py.Test plan
tests/test_nspd_sync.pyпроходятtest_upsert_dump_null_geom_executes_without_error+test_upsert_dump_with_geom_executes_without_errorpsycopg3 could not determine the type of bare bind params inside CASE WHEN ... IS NULL expressions in _UPSERT_SQL. Wrap geom_json as CAST(:geom_json AS text) and bbox coords as CAST(:bbox_xmin AS double precision) so Postgres has an explicit type hint in both branches. Also fixes pre-existing test breakage: QuarterDump gained required field `opportunity` in a prior PR; added opportunity={} to all 3 inline QuarterDump constructors in test_nspd_sync.py. Adds 2 regression tests for _upsert_dump (null-geom path and real-geom path) to catch re-introduction.Deep review — APPROVE
Verdict: APPROVE, мержу.
Что проверено
_UPSERT_SQL: все 5 параметров (geom_json,bbox_xmin/ymin/xmax/ymax) обёрнутыCAST(... AS ...)в обоих branch + в IS NULL; SRID3857корректно остаётся literal. Схемаnspd_quarter_dumps(88_*.sql) подтверждает nullablequarter_geom/bbox_3857.:geom_json/:bbox_*использованы вIS NULLи вST_*— двойной CAST правильный (psycopg3 выводит тип из любого branch).grep ':[a-z_]+::[a-z]'поnspd_sync.py— чисто, никаких::typeне осталось.ON CONFLICT (quarter_cad) DO UPDATEидемпотентен,region_codeкорректно исключён из UPDATE.opportunity={}× 3 —QuarterDump.opportunityобязательное в dataclass;{}semantically чищеNone.SessionLocal.execute()вызывается. Real-driver AmbiguousParameter они не воспроизведут, но smoke-curl после deploy это покроет.Blast radius (не в этом PR, отдельным fix)
Тот же anti-pattern в
backend/app/services/scrapers/nspd_denorm.py:81и:166:Denorm вызывается из
harvest_quarter(line 316) и упадёт на той же AmbiguousParameter, но молча — каждая строка обёрнутаwith db.begin_nested()+except → logger.warning. Подтверждено по БД:nspd_parcels=0,nspd_buildings=0— denorm ничего не записал. После merge #246 квартал-дампы заработают, но parcels/buildings всё ещё будут пустыми. Нужен follow-up PR — wrap:geom_jsonвCAST(... AS text)и в_PARCEL_UPSERT_SQL, и в_BUILDING_UPSERT_SQL.Vault
fixes/Bug_Nspd_Harvest_Quarter_Cast_May17.mdуже создан — отлично.Post-deploy smoke
После smoke — если
nspd_parcels=0, открывать follow-up issue наnspd_denorm.pyCAST.