[HIGH] tradein: 781 дубль домов не схлопнуть — «независимый идентификатор здания» оказался тем же адресом, а слияние необратимо и без аудита #2690
Open
opened 2026-08-06 00:18:46 +00:00 by bot-backend
·
5 comments
No Branch/Tag specified
main
fix/3469-showcase-schedule
fix/3443-caddy-selfdowntime
fix/3463-db-statement-timeout
fix/3448-caddy-only-detection
fix/metrics-deploy-reloads-prometheus
feat/landing-showcase-band
fix/3452-corridor-advisory-zone
fix/alert-value-is-not-the-ratio
fix/3449-geocoder-cancel-orphan
fix/3451-tvf-deals-rooms
fix/msk-collector-net-retry
feat/msk-yandex-import
fix/3051-fetch-deals-rooms-dropped
feat/msk-collector-cian
fix/3256-asking-to-sold-buckets
fix/3083-estimate-throughput
fix/3274-part2b-gate
fix/3274-part2a-caddy-retry
fix/perimeter-smoke-retry-on-no-response
fix/3274-zero-downtime-frontend
fix/3274-part1-deploy-swap
fix/3412-cian-instance-relaunch
fix/3415-bucket-done-only-if-phases-ok
chore/backend-pool-wiring-tails
fix/3398-pool-ops-off-event-loop
fix/3402-followups-ban-kinds-curl
feat/3404-proxy-run-attribution
fix/cian-captcha-is-platform-refusal
refactor/3390-single-runs-module
fix/3398-estimator-valuations-proxy-pool
fix/3386-estimator-imv-proxy-pool
fix/3394-cian-sweep-houses-proxy-pool
fix/3393-interrupted-runs-outside-streaks
fix/drain-marks-inflight-app-tasks
fix/3384-no-proxy-at-batch-start
fix/3197-yandex-newbuilding-proxy-pool
fix/3376-price-history-decimal-slips
fix/backend-proxy-pool-flags
fix/3197-cian-history-backfill-proxy-pool
fix/3288-sidecar-ban-status-code
fix/3375-yandex-fullload-on-bucket-contract
fix/3380-deploy-metrics-alloy-recreate
fix/3354-alloy-query-secret-scrub
fix/3360-admin-prefix-anon-404
fix/3368-yandex-leaf-complete-flag
fix/3369-domclick-cancel-checkpoint
fix/3225-domklik-diff-percent
fix/smoke-history-path
fix/3288-breaker-block-kind
fix/3355-drain-mark-fullloads
fix/3191-yandex-detail-completeness
fix/3359-containment-cian-yandex
fix/3323-payment-init-fail-409
fix/3172-freshness-by-data
fix/3288-avito-ban-per-source
fix/3253-domclick-house-fields
fix/3312-defer-interval-minutes
fix/3324-rbac-401-oracle
fix/3274-deploy-window-error-page
fix/3343-auth-latency-flaky
fix/3315-exhaustive-containment-skip
fix/3338-backfill-save-false
fix/3339-thin-market-badge
fix/3154-glitchtip-secret-log-leak
fix/3333-drain-mark-all-sweeps
fix/3323-imv-thin-market-gate
fix/3324-mera-perimeter
fix/3323-coverage-copy-honesty
fix/3332-domclick-counter-identity
fix/3324-ptica-deploy-gate
fix/3316-role-single-source
fix/3319-citysweep-checkpoint
fix/3322-rosseti-stable-key
fix/3320-v2-honest-zeros
fix/3321-draft-fields-survive
fix/mera-mobile-nav-and-sticky
fix/audit-form-ux
fix/audit-coverage-500
fix/audit-dkp-price
fix/audit-accuracy-window
fix/audit-faq-contradiction
fix/perimeter-smoke-after-payments
feat/b2c-landing-honest-copy
feat/b2c-landing-live-numbers
feat/b2c-v3-becomes-root
feat/b2c-v3-port-v1-blocks
feat/b2c-report-redesign
feat/b2c-landing-v3-full
feat/3192b-yandex-phones
feat/3168-backfill-cursor-resume
fix/3118-domclick-no-proxy
fix/3170-yandex-combo-checkpoint
feat/3074-newbuilding-sweep-resume
fix/3163-infra-topic-default
fix/3156-tgbot-error-type
feat/3163-infra-topic-split
fix/3161-alertmanager-route-prefix
fix/3155-prometheus-no-alertmanager
feat/2997-drop-listings-geom-idx
fix/3122-boot-reap-observable
feat/3122-boot-reap
feat/3051-houses-region-code
feat/3074-cian-anchor-checkpoint
feat/3051-region-registry
fix/2656-anchor-ratio-freshness
fix/3114-scrub-credentials-in-logs
fix/3078-grafana-single-auth
fix/3081-honest-progress
fix/3063-pro-seller-derive
fix/3074-checkpoint-survives-claim
fix/3082-estimate-concurrency
fix/3044-enriched-total-seen
fix/telegram-pin-selectel-override
chore/compose-host-parameterised-resources
fix/revisit-floor-lateral-lookup
fix/avito-detail-fields
fix/3034-avito-fingerprint
fix/avito-offers-per-page
feat/3033-avito-secondary-filter
fix/2203-restore-drill-readiness
feat/2203-backup-staleness-and-forgejo
fix/2990-clean-start-initdb
fix/2924-yandex-jk-resolve-tried-at
fix/2992-upsert-distinct-gate
fix/2998-rosreestr-q2-partitions
feat/2936-null-penalty-flag
fix/2996-mislocated-houses-watchdog
fix/1781-secondary-only-param
fix/2934-risks-coverage
fix/2464-three-small
fix/2464-two-docstrings
fix/2464-zouit-label
fix/2464-building-pct-guard
fix/2464-download-binary-retry
fix/2986-permits-key
fix/2464-tep-docstring
fix/2464-act-date-backfill
fix/2464-area-bin-null
fix/2464-act-date-citation
fix/2464-detect-kind
fix/2464-status-negation
fix/2464-objective-zombie-sweep
fix/2464-inert-retry-config
fix/2464-default-profile-unique
fix/2464-zombie-any-running
fix/2464-catalog-skipped-counter
fix/2464-heat-loader-tx
fix/2464-objective-run-stuck
fix/2464-catalog-waf-breaker
fix/2464-lock-key-order
fix/2464-backfill-waf-abort
fix/2464-docs-vs-code
fix/2464-land-reservation-dedup
fix/2464-manual-list-validation
fix/2464-capacity-savepoints
fix/2464-leads-window-naming
fix/2464-zouit-count-label
fix/2464-catalog-batch-commits
fix/2464-html-zoning-fallback
fix/2950-lock-wait-observable
fix/2956-freshness-counts-failed-harvest
fix/2950-host-lock
fix/2953-nominatim-throttle
fix/2950-deploy-docker-lock
fix/2464-ird-lookups-savepoint
fix/2464-parcels-savepoint-pair
fix/2674-deal-floor-display
docs/2854-stale-justifications
chore/2857-drop-placeholder-columns
fix/2855-probe-protected-path
fix/2674-has-panorama
fix/house-imv-anchor-era
fix/2674-quality-cadastre-column
fix/sber-freshness-guard
fix/dkp-corridor-as-of
fix/scheduler-resume-checkpoint
fix/quarter-target-from-neighbour
fix/2687-domclick-ban-kind-platform
fix/2814-address-backfill
fix/2677-house-anchor-renovation
feat/tradein-paid-retention
chore/ci-config-cleanup
feat/mera-b2c-privacy
feat/tradein-payments-schema
chore/2674-dead-code-sweep
fix/2674-matching-tiers-honesty
fix/2674-avito-full-load-coverage
fix/2674-admin-metrics-honesty
fix/2674-writers-honor-schema
fix/2674-alerts-actually-fire
fix/2679-scraper-deploy-parity
fix/2674-house-imv-params
fix/2666-discount-plausibility-gate
feat/2435-cian-house-enrichment
fix/2657-domclick-block-not-done
feat/2571-login-throttle
fix/2660-display-freshness-segment
fix/2658-loud-skip-status
fix/2603-geocode-city-hint-tails
feat/2600-per-source-proxy-health
feat/tradein-v2-exposure-in-result-card
fix/tradein-avito-browser-proxy-pool
chore/tradein-cut-wasteful-scraping
fix/tradein-v2-deals-fallback-visible
fix/tradein-city-stamp-geo-guard
fix/tradein-cian-oblast-secondary
fix/tradein-implausible-build-year
fix/tradein-snapshot-query-perf
fix/tradein-asking-sold-city-scope
chore/tradein-purge-dead-mobileproxy
feat/tradein-asocks-rotation
fix/tradein-region-code-foreign-cities
fix/tradein-proxy-pool-self-healing
fix/tradein-backfill-listing-city-from-url
fix/tradein-geocode-queue-active-only
fix/tradein-geocode-city-hint
chore/tradein-remove-yandex-scripts
fix/tradein-listing-city-from-sweep
chore/tradein-remove-yandex-geocoder
chore/tradein-remove-n1
fix/tradein-geocoder-fail-closed
fix/tradein-ui-city-label-clip
feat/tradein-ui-city-hint
fix/tradein-coords-backfill-city-gate
fix/tradein-geocoder-city-default
fix/tradein-anchor-geo-scope
fix/tradein-avito-detail-oblast
feat/tradein-price-bands-refresh
feat/tradein-caddy-cutover
fix/tradein-team-nav-and-401
feat/tradein-team-dashboard
fix/tradein-team-list-order
feat/tradein-team-api
feat/tradein-login-ui
feat/tradein-auth-core
feat/tradein-auth-password-foundation
feat/tradein-auth-users-schema
fix/tradein-rbac-test-user2-expired
fix/tradein-auth-revoke-user2
fix/2013-avito-cohort-null
fix/rbac-test-user2-expired
fix/expire-brusnika-trial-access
feat/tradein-domclick-house-sku-schema
chore/design-sync-tradein
fix/tradein-deploy-scraper-paths-filter
fix/tradein-no-numberless-house-insert
fix/tradein-dedup-fias-pass-no-geoguard
feat/tradein-fias-estimate-frontend
fix/tradein-dedup-by-fias
feat/tradein-fias-tier-matching
fix/tradein-v2-uiux-p1
fix/objective-lots-dedup-1964
fix/audit-followups-1953
feat/concept-house-picker-1965-stage3b
feat/concept-house-catalog-1965-stage3a
feat/concept-live-massing-1965-stage2b
feat/concept-recompute-1965-stage2a
feat/concept-section-1965-stage1
fix/best-layouts-per-object-snapshot-1956
fix/deficit-segmentation-1959
feat/tradein-hedonic-ground-floor
fix/report-map-points-1961
fix/report-microcopy-1963
fix/report-nspd-zoning-1962
fix/report-frontend-display-1953
perf/tradein-estimate-audit
perf/best-layouts-objects-first
fix/171-migration-path
perf/171-objective-crm-report-month-idx
fix/1926-app-log-stdout
fix/estimator-tiebreaker-nanalogs
fix/1917-fetch-json-network-retry
fix/1926-scrape-runs-total-seen
fix/1781-house-fk-source-identity
feat/39-osrm-per-category
feat/1746-utility-infra-map
fix/test-849-savepoint-count
fix/parking-economics-by-class
fix/zouit-engineering-area-gate
fix/zoning-resolution-decouple
feat/dcf-velocity-schedule
feat/zone-regulation-backfill
chore/mock-financial-estimate
fix/finmodel-split-disclosure-threshold
feat/finmodel-financing
feat/finmodel-sitefinder-bridge
feat/finmodel-dcf
feat/finmodel-price-calibration
feat/finmodel-cost-cascade
audit/1871-p2-estimator-dedup-split
audit/1871-p2-avito-coord
audit/1871-p3-uiux
audit/1871-p2-invest-moi
audit/1871-p2-velocity-market
audit/1871-p1-3-isreal-stubs
audit/1871-p1-2-ghost-anchor-guard
audit/1871-p1-scenarios-collapse
revert/site-finder-v2
fix/v2-remove-resource-legend
fix/v2-map-legend-position
feat/site-finder-v2-map-light-polish
rollback/site-finder-home-light
feat/site-finder-v2-cockpit
rollback/sf-old-analysis-design
feat/ptica-tabs-6-6-reports-params
fix/ptica-vri-row
feat/ptica-map-glyphs-sitefinder-dark
fix/ptica-3d-preview-product-verdict
fix/ptica-button-fontsize
fix/ptica-parity-data-mapping
chore/ptica-iso-preview-spin
fix/ptica-inter-map-product
fix/ptica-visual-parity
fix/ptica-left-rail
feat/ptica-cockpit-complete-bottom
feat/ptica-default-and-rich-map
feat/ptica-real-ksit-frontend
feat/tradein-ekb-geoportal-buildings
fix/sf-feedback-batch
feat/avito-newbuilding-sweep
feat/browser-concurrent-pool
fix/backfill-kadastr-column
fix/avito-proactive-ip-rotate
feat/activate-domclick-sweep
feat/avito-newbuilding-capture
fix/house-id-fk-realtime-link
fix/migration-162-table-if-exists
feat/riasurt-sverdl-layers-108
fix/sber-dataset-paths-902
fix/conflict-resolution-freshness-1539
feat/objective-lots-history-writer-307-obj6
feat/velocity-mv-61
fix/objective-mapping-is-reviewed-gate-307-obj2
fix/cian-detail-rich-fields
fix/avito-novostroyki-segment
feat/yandex-novostroyki-newflat
fix/ci-dedup-runner-storm-1709
fix/emiss-pk-granularity-1687
feat/listings-segment-param-1188
fix/inn-regex-word-boundary-1682
fix/excel-deficit-horizon-1590
fix/admin-scrape-validation
fix/admin-leads-interval-cast-1694
fix/dkp-corridor-doc-p10p90-1695
fix/weather-wind-d-allnone
test/residential-zone-rawprops-1681
fix/domrf-badge-regex-narrow-1686
feat/yandex-camoufox-transport
fix/score-sat-factor-1509
fix/base-pace-room-bucket-1593
fix/gate-verdict-no-blocker-1617
fix/confidence-deal-count-window-1637
fix/match-economics-1511-1512
fix/listings-partial-indexes-1398
fix/smart-suggestions-threshold-1503
fix/dkp-corridor-percentile-1520
fix/enrich-economics-window-1513
fix/leads-stats-window-1383
fix/poi-score-scale-1486
fix/geo-weight-floor-1633
fix/inn-regex-context-1640
fix/domrf-status-classify-1609
fix/emiss-period-dedup-1606
fix/cian-paginate-tail-1393
fix/normalize-zero-fill-guard-1638
fix/supply-view-devgroup-key-1650
fix/residential-zone-detect-1353
fix/score-label-threshold-1357
fix/trend-ratio-vprior-zero-1508
fix/district-median-dedup-1352
fix/supply-layers-overlap-1355
fix/pdf-expires-at-1530
fix/quartirography-area-bucket-1406
fix/cad-zones-multipolygon-1344
fix/sold-pct-market-verdict-1407
fix/week-review-finish
fix/week-review-backend-v2
feat/plan-vectorization-spike-299
fix/1668-analyze-confidence
fix/1667-metro-block
fix/1666-layout-velocity-beat
chore/remove-n1-scraper
fix/cian-kitchen-area
feat/yandex-detail-backfill
feat/avito-detail-backfill
fix/best-layouts-bucket-normalization
fix/gknspecial-incremental-commit-per-prefix
fix/okn-objects-full-registry-load
fix/parcel-ird-overlap-except-expand
fix/report-assembler-confounded-keys
fix/job-settings-json-persist-v2
fix/nspd-geo-soft-time-limit-passthrough
fix/nspd-soft-time-limit-v2
fix/pilot-request-modal-validation
fix/recommend-mix-saturation-latest-snapshot
fix/scrape-cadastre-fail-counter-v2
fix/izyatie-ocr-cad-normalize
fix/job-settings-panel-json-state-persist
fix/noise-loader-savepoint-per-row
fix/objective-sync-config-bare-except
fix/parcel-snapshot-mdash-double-escape
fix/poi-loader-leap-year-date-replace
fix/scrape-cadastre-permanent-fail-counter
fix/usermenu-analyst-role-label
feat/location-948b-r
feat/location-entity-948b
feat/insight-entity-948a
feat/analyst-role-audit-962
feat/cbr-inflation-macro-946
feat/cian-zhk-resolve-972
perf/forecast-parallel-horizons-1129
feat/newbuilding-enrich-backfill-972
feat/emiss-macro-indicators-946
feat/rosstat-emiss-macro-946
ci/frontend-vitest-job
chore/frontend-vitest-wkt-tests
feat/forecast-meta-footer
feat/forecast-future-supply-competitors
feat/forecast-docx-pptx-buttons
feat/forecast-scoring-panel
feat/forecast-product-tz-block
feat/market-map-layers-999
feat/forecast-chart-section6
feat/forecast-export-pptx-959
feat/forecast-export-docx-959
feat/forecast-export-ui-959
feat/forecast-export-telegram-959
feat/forecast-export-md-959
feat/analyze-response-contract-961
feat/competitor-velocity-spatial-fallback-968
fix/frontend-healthcheck-hostname
feat/analyze-market-coords-999
fix/site-finder-entry-crash-1001
feat/horizon-selector-996
feat/forecast-section-998
feat/forecast-endpoint-horizon-enqueue
feat/forecast-celery-task-persist
feat/forecast-orchestrator-service
feat/demand-supply-months-of-inventory
feat/wire-district-resolver
feat/district-vocab-reconciliation
fix/affordability-market-spread
fix/backtest-sig-gate
feat/wire-978-almon-rate-regime
feat/backtest-oos-almon-seasonal
ci/forgejo-pytest-gate
fix/tradein-praktika-logo-form-scroll
feat/yandex-exhaustive-price-room
feat/794-sber-time-adjust
chore/bot-harness-tuning
docs/agent-usage-throttle-qa-terminal
fix/avito-sweep-single-run-guard
chore/analyst-inbound-queue-tradein-db
feat/801-preview-full-wt
chore/bot-safety-followups
feat/tradein-avito-imv-fix
feat/tradein-repair-coef-calibration
feat/tradein-avito-houses-fix
feat/tradein-address-precision
feat/tradein-backfill-prioritize-listings
feat/tradein-geocode-deals-nominatim
feat/tradein-geocode-deals-from-houses
feat/tradein-same-building-match
feat/claude-envvars-and-stale-cron
No results found.
Labels
Clear labels
Находки полного мульти-агентного ревью (Claude Fable 5, 2026-06-09)
Новое ТЗ от Ген Геныча (июнь 2026): Site Finder v2 — ИИ-прогноз продуктовой стратегии девелопера. Актуальный приоритет.
Admin UI / internal tools / pipeline tracker
Аналитика данных / matching
Authentication / authorization / multi-tenancy
Автоматизация / cron / scheduler
Something isn't working
Коммерческая воронка / пилоты / pipeline / реестр ПО
Operational housekeeping
Forgejo Actions / build pipeline
152-ФЗ / реестр ПО / legal / TOS
Data sources, parsers, ETL
Уникальные данные — sales tracker, CRM aggregation
README / runbooks / onboarding
This issue or pull request already exists
Developer experience / build speed
New feature or request
Feedback from Max (Senior partner)
Generative Design — concept generation engine
Pending team sync / decision
Human review/decision required
Monitoring / metrics / logs / Sentry / Uptime
Kill-switch — all autonomous bots pause
Latency / throughput / DB query tuning
Critical / production-blocker
High priority
Normal priority
Низкий приоритет (follow-up, tech-debt)
Backend Python — FastAPI, Celery, scrapers
DB migrations, indexes, SQL
docker-compose, Caddy, workflows
Frontend — Next.js, React, TypeScript
Tests, smoke, Playwright
Скрапперы (Avito/Cian/Yandex/Rosreestr)
Security audit / secrets / vulnerabilities
Site Finder scoring quality & data layer
Stage 1: Generative MVP (нед 2-7)
Stage 2: Site Finder MVP (нед 8-12)
Blocked — needs human intervention
Closed, completed
Raw/fuzzy task filed by human — auto-analyst подхватывает: code-archeology + декомпозиция в actionable scope/* + status/ready (или split на под-issues)
Reviewer/QA вернул worker на доработку — worker сам чинит свой PR (fixup), НЕ требует human (в отличие от status/blocked)
PR merged, awaiting smoke test
Ready for pickup by worker bot
PR open, awaiting code review
Work in progress (worker claimed)
Технический долг
Trade-In MVP проект
User experience / responsive / conversion
Week review 1 — находки multi-agent аудита проекта (2026-06-14)
This will not be worked on
Исходно-разрешительная документация — слой ограничений участка для analyze-таблицы
Trade-In Estimator — проект оценки вторичного жилья
Fable 5 ревью
Находки полного мульти-агентного ревью (Claude Fable 5, 2026-06-09)
GG-форсайт
Новое ТЗ от Ген Геныча (июнь 2026): Site Finder v2 — ИИ-прогноз продуктовой стратегии девелопера. Актуальный приоритет.
admin
Admin UI / internal tools / pipeline tracker
analytics
Аналитика данных / matching
auth
Authentication / authorization / multi-tenancy
automation
Автоматизация / cron / scheduler
bug
Something isn't working
business
Коммерческая воронка / пилоты / pipeline / реестр ПО
chore
Operational housekeeping
ci
Forgejo Actions / build pipeline
compliance
152-ФЗ / реестр ПО / legal / TOS
data
Data sources, parsers, ETL
data-moat
Уникальные данные — sales tracker, CRM aggregation
docs
README / runbooks / onboarding
duplicate
This issue or pull request already exists
dx
Developer experience / build speed
enhancement
New feature or request
feedback/max
Feedback from Max (Senior partner)
generative
Generative Design — concept generation engine
needs-discussion
Pending team sync / decision
needs-human
Human review/decision required
observability
Monitoring / metrics / logs / Sentry / Uptime
pause-bots
Kill-switch — all autonomous bots pause
performance
Latency / throughput / DB query tuning
priority/p0
Critical / production-blocker
priority/p1
High priority
priority/p2
Normal priority
priority/p3
Низкий приоритет (follow-up, tech-debt)
scope/backend
Backend Python — FastAPI, Celery, scrapers
scope/db
DB migrations, indexes, SQL
scope/devops
docker-compose, Caddy, workflows
scope/frontend
Frontend — Next.js, React, TypeScript
scope/qa
Tests, smoke, Playwright
scrapers
Скрапперы (Avito/Cian/Yandex/Rosreestr)
security
Security audit / secrets / vulnerabilities
site-finder
Site Finder scoring quality & data layer
stage/1
Stage 1: Generative MVP (нед 2-7)
stage/2
Stage 2: Site Finder MVP (нед 8-12)
status/blocked
Blocked — needs human intervention
status/done
Closed, completed
status/needs-analysis
Raw/fuzzy task filed by human — auto-analyst подхватывает: code-archeology + декомпозиция в actionable scope/* + status/ready (или split на под-issues)
status/needs-fix
Reviewer/QA вернул worker на доработку — worker сам чинит свой PR (fixup), НЕ требует human (в отличие от status/blocked)
status/qa
PR merged, awaiting smoke test
status/ready
Ready for pickup by worker bot
status/review
PR open, awaiting code review
status/wip
Work in progress (worker claimed)
tech-debt
Технический долг
tradein
Trade-In MVP проект
ux
User experience / responsive / conversion
week ревью 1
Week review 1 — находки multi-agent аудита проекта (2026-06-14)
wontfix
This will not be worked on
ИРД
Исходно-разрешительная документация — слой ограничений участка для analyze-таблицы
вторичка
Trade-In Estimator — проект оценки вторичного жилья
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
ИРД
вторичка
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
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#2690
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Отдельная задача из #2688. Правку сняли из PR перед мержем — три независимых ревью показали, что предложенный ключ обходит защиту, а не усиливает её.
Проблема остаётся: 781 лишняя запись
Измерено независимым от сопоставителя ключом: 653 кластера, 1 434 дома, 781 лишняя строка — 8.3% таблицы домов, 6 389 объявлений (6.8% корпуса) висят на дублях, худший случай шесть записей на одно здание. Это прямое #1772.
Два верхних тира сопоставления не срабатывали ни разу за всю историю (0 из 49 502), то есть 100% домов сматчено слабыми способами — отсюда и дробление.
Почему очевидная починка не годится
Проход схлопывания работает по идентификатору здания, и напрашивалось расширить ключ вторым полем — тем же идентификатором ГАР, который заполняет другой загрузчик. Сухой прогон давал 781 пару вместо нуля.
Но это поле — не независимое наблюдение. Загрузчик проставляет его, сопоставляя нормализованный адрес выражением, побайтово совпадающим с ключом основного прохода. То есть два дома получают «общий идентификатор» тогда и только тогда, когда у них одинаковый адрес после нормализации.
Числа: из 1 434 участников слияния 1 418 (98.9%) получили идентификатор именно так. Пар, где нормализованный адрес совпадает и гео-страж заблокировал бы слияние — 764 из 781 (97.8%). Пар, опирающихся на два действительно независимых наблюдения, — ноль.
А этот проход идёт с выключенным гео-стражем, на основании «общий идентификатор здания старше близости». Для 764 пар аргумент круговой: идентификатор здесь и есть адрес. Основной проход отказывается слить дома в шести километрах друг от друга, а этот сливает их же.
Что слилось бы
Фильтр по городу у загрузчика стоит только на стороне справочника, на стороне наших домов его нет. Поэтому дом в посёлке штатно наследует идентификатор одноимённой городской улицы:
Это дословно тот класс коллизии, который описан в шапке самого модуля схлопывания. Плюс сам нормализованный адрес не однозначен: 7 590 из 37 416 (20.3%) значений накрывают больше одного здания справочника, худшие — 34 и 31 здание на одно значение.
Проверка по координатам объявлений: из 384 пар с геокодом с обеих сторон 70 разъехались больше 250 м, 35 — больше километра, максимум 47 км.
Отдельная проблема: слияние необратимо и не оставляет следа
Проигравшие записи удаляются жёстко вместе с дочерними строками. Единственный след «кто в кого» — строка в логе, а логи контейнера ротируются: самая старая запись сейчас моложе суток, следов прошлых прогонов уже нет. Счётчики прогона хранят только итоги, не соответствие.
Через сутки после слияния нельзя даже назвать, какой дом в какой свернули, не говоря о восстановлении удалённых метаданных. Единственный путь отката — восстановление всей базы на момент до прогона, что выбросит неделю сбора.
Это предусловие для любой будущей работы по схлопыванию: пока нет журнала слияний, каждый проход необратим вслепую.
Что нужно
Что уже сделано в #2688: исправлено правило выбора победителя (сортировка ставила запись без объявлений выше записи со 192 — 48% пар выбирали пустого победителя), и закрыт приёмник, из-за которого кадастр квартиры попадал бы в ключ здания и порождал новое дробление.
Связано: #2688, #2674, #1772, #2187.
Существенная поправка к этой задаче: проход НЕ остановлен, он живой и удаляет каждую неделю
Задача (и мои комментарии к ней) описывает слияние как то, что остановлено на грани. Остановлено было расширение ключа. Сам проход работает и удаляет дома шестую неделю подряд.
Проверено на проде:
Миграция 135 сеяла это расписание как
enabled=false … DESTRUCTIVE. Кто-то его включил, и с тех пор оно исполняется молча.По замеру тем же выражением, что и код, следующий прогон удалит 93 дома.
Числа 781 в этой задаче относятся к другому
Замер read-only на текущем коде:
То есть 781 — это про
gar_house_guid, которого в ключе нет и не было. Вывод задачи при этом не колеблется: 1586 против 93 — цена гео-стража примерно шестнадцатикратная, ровно тот масштаб, вокруг которого спор.Что изменилось сегодня и что нет
Изменилось: слияние стало обратимым. PR #2740 — журнал
house_merge_log(полный снимок удаляемой строки, состояние победителя ДО переноса метаданных, перенесённые и уничтоженные дочерние строки, основание, расстояние) плюс функция отката, проверенная сквозным прогоном на живом Postgres. Журнал пишется в той же транзакции, что и слияние. Успел к прогону 08.08.Не изменилось: ключ схлопывания, правило выбора победителя (то самое, где сортировка
DESCв Postgres даёт NULLS FIRST) и гео-страж — не тронуты. Правка нейтральна к тому, каким проход станет.Не обратимы задним числом: те 119 домов, которые уже удалены. Журнала на момент их слияния не было.
Что осталось решить
Вопрос «нужны ли эти 93» открыт ровно так же, как был открыт вопрос про ключ. Теперь его можно решать без риска — но никто этих 93 не заказывал, они произойдут по расписанию, которое было засеяно выключенным. Выношу это владельцу отдельным пунктом.
Побочно: единственная поведенческая проверка модуля была мертва
Четыре теста на живой БД самоотключаются без Postgres, поэтому в CI не запускались ни разу и разошлись со схемой — на чистом
mainпротив верной схемы они падают. Починены. Это третий за сутки случай одного класса (тесты сайдкара, деселект в конфигурации, теперь эти): проверка, которая молча пропускается, со временем перестаёт быть верной, и об этом узнают только когда на неё понадобится опереться.Соседний замер, и сразу поправка к тому, как я его сначала описал.
В #2704 я написал, что отсутствие координат — «судя по всему, настоящее содержание #2690». Прочитав эту задачу целиком, снимаю формулировку: здесь измерено другое и другим ключом. Ваши 764 из 781 блокируются расстоянием (гео-страж отверг бы) и круговой природой ключа — идентификатор ГАР ставится по тому же нормализованному адресу. Это самостоятельный дефект, к координатам не сводящийся.
Что действительно рядом — вынес в #2771: 1945 домов (20.2%) вообще без координат, и в основном проходе схлопывания по канон-адресу 1024 проигравших отбраковываются не расстоянием, а отсутствием координат у одной из сторон.
Разница существенная и в обе стороны:
Поэтому #2771 не следует читать как «поднимет число слияний». Он даёт ограждению возможность оценить эти пары; часть после этого сольётся, часть будет отвергнута правильно.
Одно наблюдение из #2771 прямо усиливает вашу шапку. Коллизия Кедровка/Екатеринбург, которую вы приводите между двумя записями, встречается и внутри одной: 17 домов имеют объявления, разбросанные дальше 10 км, худший — 384 км на пяти объявлениях «ул. Кирова,4». То есть сопоставитель сшивает в одну запись дома разных населённых пунктов, и это видно без всякого схлопывания. Ещё один довод, что слабые тиры сопоставления — корень, а не ключ слияния.
Проверка на проде 2026-08-07: сделан п.1, п.2 и п.3 не тронуты
п.1 (журнал слияний) — на проде. Таблица
house_merge_logсуществует, 16 колонок,включая полный снимок удаляемой строки и состояние победителя до переноса:
Функция отката тоже на проде:
house_merge_undo(2 аргумента). Индексы поbatch_id,keeper_id,loser_idна месте.Записей 0 — прогонов слияния с момента деплоя не было; последний был 01.08 (32 удалённых),
ближайший — 2026-08-08 04:15 UTC. То есть журнал ещё не проверен на настоящем прогоне,
только сквозным тестом.
п.2 (ключ, независимый от нормализованного адреса) и п.3 (гео-страж для этого прохода) —
не сделано. Ни одной правки ключа схлопывания, правила выбора победителя или гео-стража после
c86a5378нет. Расписание при этом живое и разрушительное как было:То есть завтра утром проход снова пойдёт с тем же ключом, тем же дефектным правилом выбора
победителя и с выключенным гео-стражем — только теперь обратимо. Обратимость снимает
катастрофу, но не отвечает на вопрос задачи.
Оставляю открытой под п.2 и п.3. Решение по завтрашнему прогону — за владельцем (#2704 п.1).
Поправка к центральному доводу: ноль у верхнего тира — «неприменимо», а не «ни разу не сработал»
В шапке сказано: два верхних тира сопоставления не срабатывали ни разу за всю историю (0 из 49 502), значит 100% домов сматчено слабыми способами. Проверил все три тира отдельно — для двух это верно, для третьего нет.
cadastr_exactиfias_exact— да, ноль по существу.source_exact— ноль по построению. Tier 1 возвращает результат изmatching/houses.py:189-194, не вызывая_upsert_house_source. То есть его метка физически не может попасть в таблицу, по которой велась перепись. Ноль там означает «этот тир в статистику не пишет», а не «этот тир не работает».Разница существенная для вывода задачи: считать третий тир мёртвым нельзя, и «100% сматчено слабыми способами» из этих данных не следует.
Фактическая перепись по 50 228 записям:
Второе: ограничение соседнего замера снято, но обратный вывод не проходит
В #2771 и #2777 разброс объявлений внутри дома мерился только по домам без координат (108 домов). Это ограничение реальное: среди домов с координатами радиус больше 125 м у 733 домов, 22 205 объявлений.
Но читать это как «733 дефекта сопоставления» нельзя — радиус там загрязнён геокодером, а не только сопоставителем. Худший дом всей таблицы (id 12615, радиус 2086.6 км) — это 112 объявлений в одной точке плюс одно с пустым адресом и координатами 59.393 / 24.674, то есть Балтийское море.
Отдельная находка того же разбора: 94 объявления на 47 домах привязаны к дому при пустом адресе. Это самостоятельный дефект — привязка состоялась без того признака, по которому она должна была состояться.
Что это меняет для задачи
Диагноз «дробление из-за слабых тиров» остаётся, но опирается теперь на 58.93% + 18.21%, а не на «100%». И прежде чем усиливать ключ, стоит закрыть привязку при пустом адресе — иначе усиление получит на вход мусор.
Гео-ограждение по-прежнему трогать не надо: 764 из 781 ваших пар оно отвергает по существу, дома действительно далеко друг от друга.
п.2 и п.3 закрыты замером. Перемер дублей на сегодня, PR #2820 (смержен)
Перемер: числа из шапки устарели за четверо суток
Шапка: 653 кластера / 1434 дома / 781 лишняя строка / 6389 объявлений — это замер по
gar_house_guid от 06.08, ключом, который сама же задача и отвергла. Перемер тем ключом,
которым проход реально работает (канон-адрес), 2026-08-10, после схлопывания 821 дома 08.08:
963 лишние строки — это не 963 дубля. Взаимоисключающая разбивка:
То есть 59% «остатка» — это вообще не дубли: дома разнесены на километр, канон-ключ о них
врёт (тот самый класс «Кедровка/Екатеринбург» из шапки, только внутри одного ключа). Из 326
«страж молчит» координаты из объявлений можно поднять у 72; у остальных 254 наблюдения
координат нет нигде — это территория #2771, не эта задача.
ФИАС-проход сегодня сливает 0: 3678 значений
house_fias_id, все различны. Асимметрия«у fias-прохода страж выключен» существует, но не задействована — ни одной строки в журнале.
п.3 — дефект исправлен ДО этой задачи, проверено задним числом
Задача называет правило дефектным: «сортировка ставит дом без объявлений первым».
На актуальном коде это неверно:
listing_cnt DESC NULLS LASTживёт в_KEEPER_ORDERс
1a577fe7(#2674, смержен 06.08 00:11 UTC); в контейнере прода код тот же (прочитан).Проверка по журналу
house_merge_log— прогон 08.08, 821 слияние (первый на исправленномправиле, у обеих сторон лежат снимки):
Опровергнутая предпосылка (моя собственная, по ходу замера): первый прогон дал
«207 худших победителей». Это артефакт базы: я считал, что было у победителя до слияния, через
listings.scraped_at < merged_at, а #2206 двигаетscraped_atпри каждом ре-подтвержденииживого листинга — половина строк победителя «родилась» задним числом. По двум честным базам
(снимок в
listings_snapshotsдо даты слияния; монотонныйlistings.idниже границы батча)получается 0 и 0. Ловушка вписана в код, чтобы следующий не наступил.
п.2 — независимого наблюдения нет ни одного. Это ответ, а не пауза
Проверены все поля
houses, а не предположены:cadastral_numberdadata_enriched_atиhouse_fias_id: это ответ DaData на нашу же строку адреса. Второй кадастр (KNN-подсказка листингов) отвергнут ещё в #2674 — 20.1% значений накрывают >1 здания ГАРhouse_fias_idgar_house_guidzhkh_house_guidWHERE gar_house_guid = <guid>, т.е. это и есть ГАР-guid у 4268 из 4663. Из 194 пар с РАЗНЫМ каноном 193 приходят кадастровым фолбэком (та же KNN-подсказка), и 30 из 31 пары дальше 250 м — тоже онsource+ext_house_id,cian_internal_house_id,yandex_jk_idВывод: ключ не усиливаем. То, что достаёт канон-ключ + страж 250 м, — это потолок,
а не отставание. Гео-ограждение не тронуто, расшивка уже слитого не предлагается.
Что сделано вместо ключа
PR #2820 (смержен): остаток фиксируется числом, которое живёт. Перепись после обоих
проходов пишет в
scrape_runs.countersшесть значений:residual_rows,residual_listings,residual_no_geom,residual_far,residual_cross_fias,residual_mergeable. Разовый замерпротухает быстро — «781» из шапки через четверо суток стал 963.
Корзины намеренно не складываются в один «остаток»: «страж молчит» и «страж отверг» —
противоположные факты, и их сумма читается как долг, которого нет.
residual_mergeable—растяжка на сам проход: прошло все стражи и не слилось, ожидание 0.
Перепись делит с проходом один и тот же префикс кластеризации (
_ranked_cte) — своя копияразъехалась бы с тем, что описывает, невидимо. Падение переписи не роняет слияние.
Прод-сверка ДО мержа (read-only): отрендеренный
_RESIDUAL_SQLна боевой БД дал ровно то,что независимо намерено руками —
963 | 1765 | 8 | 326 | 568 | 61.Критерий post-deploy, записан ДО факта: ближайший прогон расписания (пятница 04:15 UTC) —
в counters появляются шесть
residual_*, при этомresidual_mergeable = 0иresidual_rows ≈ 902 ± 40(963 − 61 сольются, плюс недельный приток).Опровергнутые предпосылки, включая мои прежние
Оно было починено в #2674 за 10 часов до первого из этих комментариев; вторая
формулировка («правок нет после c86a5378») формально верна и вводит в заблуждение,
потому что правка была до. Шапка задачи при этом говорит правду: «исправлено».
неверно: 2648 из 9179. Вывод «адрес — единственный ключ» остаётся, но держится теперь
на том, что все 2648 значений различны, а не на том, что их нет.
стражем на медиане 1084 м, это разные здания.
Со стороны п.2 и п.3 задача закрыта. Открытым остаётся только то, что в неё не входит:
72 строки, которым координаты можно поднять из объявлений (#2771), и 254, у которых наблюдения
координат нет вовсе.