fix(tradein): ingest/scheduler integrity — year sanity, propagate geo-guard, dkp_import counters + DO UPDATE (R2) #2496

Merged
bot-backend merged 1 commit from fix/tradein-ingest-scheduler-integrity into main 2026-07-12 19:20:11 +00:00
Collaborator

R2 MEDIUM ×4 — ingest/scheduler data-integrity

A [year_built backfill выбрасывал авторитетный год ДОМ.РФ]COALESCE(h.year_built,...) шилдил существующее значение даже если оно невозможное. Fix: sanity-gate (plausible_year 1850..текущий+2) в parse_int_field (для commission_year) + в backfill-SQL — NULL/невозможный существующий год больше не шилдит авторитетный commission_year; валидные значения сохраняются (COALESCE). Live: 7 staging-строк с невозможным годом (1841-1852) теперь режутся; 0 домов сейчас зашилжены (превентивно).

B [propagate_listings_year без link-гарда → фейк-годы] — join по house_id_fk без geo-предиката. Fix: ST_DWithin(listing.geom, house.geom, 500m) (или address-fallback без координат). Live: propagate-кандидаты 10→9 (блокирует 1 листинг >500м от FK-дома).

C [dkp_import: INSERT-ошибки смешаны с dedup-skip → silent false-green] — Fix: счётчики разделены (rows_updated/rows_skipped/rows_errored); per-row except → batch_errored; error-rate > 5% → RuntimeErrormark_failed (не тихий success).

D [ON CONFLICT DO NOTHING → исправленные кварталы не обновлялись] — Fix: DO UPDATE SET сырых фактов Росреестра (address/region_code/city/rooms/area_m2/floor/year_built/price_rub/price_per_m2/deal_date) с WHERE ... IS DISTINCT FROM (идемпотентно для неизменных). Обогащение (lat/lon/geom/geocode/cadastral/total_floors/house_type) НЕ в SET → сохраняется. RETURNING (xmax=0) различает insert/update. NB: city — сырой факт из FDW-источника (region-66 всегда заполнен), не обогащение. Live-проверено (rolled-back txn): изменённая цена → update, lat сохранён; идентичные факты → 0 rows (skip).

Тесты: 37 (domrf+dedup) + 184 regression sweep = 221 passed; ruff clean.

## R2 MEDIUM ×4 — ingest/scheduler data-integrity **A [year_built backfill выбрасывал авторитетный год ДОМ.РФ]** — `COALESCE(h.year_built,...)` шилдил существующее значение даже если оно невозможное. Fix: sanity-gate (`plausible_year` 1850..текущий+2) в `parse_int_field` (для commission_year) + в backfill-SQL — NULL/невозможный существующий год больше не шилдит авторитетный `commission_year`; валидные значения сохраняются (COALESCE). Live: 7 staging-строк с невозможным годом (1841-1852) теперь режутся; 0 домов сейчас зашилжены (превентивно). **B [propagate_listings_year без link-гарда → фейк-годы]** — join по `house_id_fk` без geo-предиката. Fix: `ST_DWithin(listing.geom, house.geom, 500m)` (или address-fallback без координат). Live: propagate-кандидаты 10→9 (блокирует 1 листинг >500м от FK-дома). **C [dkp_import: INSERT-ошибки смешаны с dedup-skip → silent false-green]** — Fix: счётчики разделены (`rows_updated`/`rows_skipped`/`rows_errored`); per-row except → `batch_errored`; error-rate > 5% → `RuntimeError` → `mark_failed` (не тихий success). **D [ON CONFLICT DO NOTHING → исправленные кварталы не обновлялись]** — Fix: `DO UPDATE SET` сырых фактов Росреестра (address/region_code/city/rooms/area_m2/floor/year_built/price_rub/price_per_m2/deal_date) с `WHERE ... IS DISTINCT FROM` (идемпотентно для неизменных). Обогащение (lat/lon/geom/geocode/cadastral/total_floors/house_type) НЕ в SET → сохраняется. `RETURNING (xmax=0)` различает insert/update. NB: `city` — сырой факт из FDW-источника (region-66 всегда заполнен), не обогащение. Live-проверено (rolled-back txn): изменённая цена → update, lat сохранён; идентичные факты → 0 rows (skip). Тесты: 37 (domrf+dedup) + 184 regression sweep = 221 passed; ruff clean.
bot-backend added 1 commit 2026-07-12 19:16:21 +00:00
fix(tradein/ingest): 4 data-integrity дефекта в бэкфилле годов и импорте ДКП
All checks were successful
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 57s
CI Trade-In / changes (pull_request) Successful in 10s
CI / changes (pull_request) Successful in 11s
CI Trade-In / frontend-checks (pull_request) Has been skipped
6487813ec5
A. ДОМ.РФ year backfill: авторитетный commission_year больше не экранируется
   невозможным существующим year_built. Валидное существующее значение
   выигрывает (COALESCE-семантика #2013 сохранена), но NULL/impossible
   (< 1850, > текущий+2, 0) заменяется валидным commission_year → zhkh_year.
   parse_int_field получил sanity-гейт [min,max] — мусорный commission_year
   не попадает в staging (7 таких строк в текущем staging).

B. propagate_listings_year: добавлен link-consistency guard. Раньше копировал
   houses.year_built на listings по house_id_fk без проверки — перепривязанный
   FK впрыскивал чужой когортный год. Теперь пропагация только если координаты
   объявления в пределах 500м от геометрии дома (ST_DWithin), либо (без коорд.)
   консервативный address-фоллбек по short_address. Live: блокирует 1 из 10
   текущих кандидатов (>500м mislink).

C. rosreestr_dkp_import: per-row INSERT-ошибки отделены от dedup-skip. Раньше
   except инкрементил тот же batch_skipped, что и легитимный ON CONFLICT — сбой
   маскировался под дедуп и run рапортовал success. Отдельный rows_errored +
   гейт по доле ошибок (> 5% → run FAILED, не silent-green).

D. rosreestr_dkp_import: ON CONFLICT DO NOTHING → DO UPDATE изменяемых сырых
   фактов Росреестра (price/area/rooms/floor/year/deal_date/...), чтобы
   исправленный/переопубликованный квартал обновлялся. Обогащение
   (lat/lon/geom/geocode_tried_at и пр.) не в SET-списке — не затирается.
   IS DISTINCT FROM guard сохраняет идемпотентность resume; RETURNING (xmax=0)
   отличает insert от update (rows_inserted vs rows_updated).
bot-backend merged commit b1ac551451 into main 2026-07-12 19:20:11 +00:00
bot-backend deleted branch fix/tradein-ingest-scheduler-integrity 2026-07-12 19:20:11 +00:00
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#2496
No description provided.