feat(tradein/houses): журнал слияний домов — слияние стало обратимым #2740
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
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#2740
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/2690-merge-audit-log"
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?
Зачем
house_dedup_mergeудалял проигравшие дома вместе с дочерними строками и не оставлял восстановимого следа. Единственной записью «кто в кого» была строкаlogger.info, а логи контейнера ротируются быстрее суток.Это не гипотетика. Расписание на проде
enabled=true,dry_run=false, такт 7 дней. Шесть прогонов с 27.06 уже удалили 119 строкhouses(losers_deletedвscrape_runs: 2 / 39 / 31 / 9 / 6 / 32). Следующий — 08.08 04:15 UTC; замер тем же выражением, что и код, даёт 93 проигравших.#2690 требует журнал как предусловие любой дальнейшей работы по схлопыванию.
Что записывается и почему именно это
loser_rowjsonbkeeper_beforejsonbchildren_repointed{"таблица.колонка": [id]}. Строки целы, сменилась только ссылка → id, а не содержимое (иначе одни listings дали бы ~7 КБ/строку)children_deleted{"таблица": [{строка}]}. Уничтожены коллизией UNIQUE — id недостаточно, нужен снимокmerge_pass/cluster_key/geo_guard/distance_mbatch_id/run_id/initiator/merged_atБез FK на
houses/scrape_runs: журнал обязан переживать строки, которые описывает.Атомарность
Журнал пишется в той же транзакции, что и слияние — разрыв «слияние прошло, запись не легла» невозможен по построению,
dry_runоткатывает оба.Обратная операция
Построчный отчёт, включая то, что вернуть не удалось. Проверено на живом Postgres end-to-end.
Объём
~5.3 КБ на запись (2.5 + 2.5 КБ снимки + списки id). Наблюдаемый темп 20 слияний/нед → ~5.5 МБ/год. Потолок при схлопывании всех 9 571 домов — ~50 МБ против 23 МБ самой
houses. Retention не нужен.Нейтральность
Ключ схлопывания, правило выбора победителя и гео-страж не тронуты — это отдельные спорные задачи.
distance_mпишется и на fias-проходе, где страж выключен: измерение не есть проверка, но раньше не было и измерения.Сторож полноты
Если у
housesпоявится FK-ребёнок, которого не знает_STEPS, слияние падает вместо молчаливого уничтожения его строк по CASCADE (9 из 11 FK —ON DELETE CASCADE). На пропущенном ребёнке сломалась миграция 133 — там отказ был громким, здесь был бы тихим.Побочно: 4 живых теста этого модуля были мертвы
Они самоотключаются без Postgres, поэтому в CI не запускались ни разу и молча разошлись со схемой:
houses.urlстал NOT NULL, а у пары в первом тесте проигравший безgeom— канон-страж #2187 справедливо отказывается такое сливать. Починены; фикстуры, не утверждения.Test plan
43 passedвtest_house_dedup_merge.py, из них 6 на реальном Postgres (16-3.4, схема из всех 218 миграций)3855 passed, 10 skippedhouse_merge_undo→ сравнениеto_jsonbпо всем колонкам всех 9 засеянных строк, а не по пареRefs #2690