fix(domrf_kn): детерминированный sha256-fallback для flat_id (#1208) #1262

Merged
bot-backend merged 1 commit from fix/domrf-kn-deterministic-flat-id-fallback into main 2026-06-13 06:09:55 +00:00
Collaborator

Summary

Closes #1208 (P2 data-integrity, prod). Fallback flat_id через hash() рандомизирован per-process → дубли строк в kn_flats при resume sweep'а.

Bug

domrf_kn._norm_flat:401:

flat_id = abs(hash(elem)) % (2**63 - 1)

hash(str) в CPython рандомизирован per-process (PYTHONHASHSEED нигде в репо/Dockerfile/celery не выставлен).

Эффект:

  • Resume упавшего sweep (resume_kn_run стартует в новом воркере, worker_ready hook). До 10 объектов после checkpoint перечитываются → квартиры без flatId (несколько на ЖК-объект, реально на проде есть) получают другой hash-id в новом процессе → ON CONFLICT (id, snapshot_date) (uq_kn_flats_id_snap) не срабатывает → дубли строк одной квартиры в одном snapshot_date.
  • Повторный прогон за ту же дату — то же.
  • Дубли инфлируют все агрегации (units_sold, price медианы, downstream supply_layers).

Fix

  • abs(hash(elem)) % (2**63 - 1)int.from_bytes(hashlib.sha256(elem)[:8], "big") % (2**63 - 1).
  • sha256 стабилен между процессами/перезапусками/архитектурами. 8 байт → BIGINT-fit, коллизии практически невозможны для domrf-elemId space.

Test plan

  • 6 новых юнит-тестов test_domrf_kn_normalize.py: formula matches sha256, stable across calls, distinct elems→distinct ids, flatId wins over fallback, no-id→None, BIGINT-fit.
  • pytest tests/services/scrapers/test_domrf_kn_normalize.py6 passed.
  • ruff check → clean.
  • Post-deploy: новые snapshot не должны генерировать дубли при resume. Опционально — отдельный одноразовый script для дедупа существующих дублей.

Closes #1208

## Summary Closes #1208 (P2 data-integrity, prod). Fallback `flat_id` через `hash()` рандомизирован per-process → дубли строк в `kn_flats` при resume sweep'а. ## Bug `domrf_kn._norm_flat:401`: ```python flat_id = abs(hash(elem)) % (2**63 - 1) ``` `hash(str)` в CPython **рандомизирован per-process** (PYTHONHASHSEED нигде в репо/Dockerfile/celery не выставлен). Эффект: - Resume упавшего sweep (`resume_kn_run` стартует в **новом** воркере, `worker_ready` hook). До 10 объектов после checkpoint перечитываются → квартиры без `flatId` (несколько на ЖК-объект, реально на проде есть) получают **другой** hash-id в новом процессе → `ON CONFLICT (id, snapshot_date)` (`uq_kn_flats_id_snap`) **не срабатывает** → дубли строк одной квартиры в одном `snapshot_date`. - Повторный прогон за ту же дату — то же. - Дубли инфлируют все агрегации (units_sold, price медианы, downstream `supply_layers`). ## Fix - `abs(hash(elem)) % (2**63 - 1)` → `int.from_bytes(hashlib.sha256(elem)[:8], "big") % (2**63 - 1)`. - `sha256` стабилен между процессами/перезапусками/архитектурами. 8 байт → BIGINT-fit, коллизии практически невозможны для domrf-elemId space. ## Test plan - [x] 6 новых юнит-тестов `test_domrf_kn_normalize.py`: formula matches sha256, stable across calls, distinct elems→distinct ids, flatId wins over fallback, no-id→None, BIGINT-fit. - [x] `pytest tests/services/scrapers/test_domrf_kn_normalize.py` → **6 passed**. - [x] `ruff check` → clean. - [ ] Post-deploy: новые snapshot не должны генерировать дубли при resume. Опционально — отдельный одноразовый script для дедупа существующих дублей. Closes #1208
bot-backend added 1 commit 2026-06-13 06:02:09 +00:00
fix(domrf_kn): детерминированный sha256-fallback для flat_id (#1208)
All checks were successful
CI / changes (push) Successful in 6s
CI / frontend-tests (push) Has been skipped
CI / changes (pull_request) Successful in 6s
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (push) Successful in 6m27s
CI / backend-tests (pull_request) Successful in 6m27s
a49ee2ccfc
Fallback flat_id в _norm_flat использовал abs(hash(elem)) % (2**63 - 1).
В CPython hash(str) РАНДОМИЗИРОВАН per-process (PYTHONHASHSEED нигде в
репо не зафиксирован — uvicorn/celery не выставляют его). Эффект:

- При resume упавшего sweep (resume_kn_run в новом процессе воркера) до
  10 объектов после checkpoint перечитываются. Квартиры без flatId
  получают ДРУГОЙ hash-id → ON CONFLICT (id, snapshot_date) не
  срабатывает → дубли строк одной квартиры в одном snapshot.
- То же при повторном прогоне за ту же дату — каждый раз новый id.
- Дубли инфлируют все агрегации (units_sold/price медианы, supply_layers).

Patch:
- abs(hash(elem)) → int.from_bytes(sha256(elem)[:8], "big") % (2**63 - 1).
- sha256 стабилен между процессами/перезапусками. 8 байт → BIGINT-fit.

6 новых юнит-тестов (test_domrf_kn_normalize.py): formula matches sha256,
stable across calls, distinct elems→distinct ids, flatId wins over
fallback, no-id→None, BIGINT-fit. ruff clean.

Closes #1208
bot-backend merged commit 5826812816 into main 2026-06-13 06:09:55 +00:00
bot-backend deleted branch fix/domrf-kn-deterministic-flat-id-fallback 2026-06-13 06:09:55 +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#1262
No description provided.