|
Some checks failed
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Failing after 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
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
ВНИМАНИЕ: миграция 189 УДАЛЯЕТ строки на проде (см. «Что удаляется»). _UPSERT_NO_ACT_SQL заканчивается ON CONFLICT DO NOTHING, а единственный подходящий констрейнт — uq_land_reservation_cad_act UNIQUE (cad_num, act_number) с обычной NULL-семантикой. В Postgres NULL != NULL, поэтому у записей БЕЗ номера акта конфликт не наступает никогда: DO NOTHING не срабатывает, каждый недельный прогон вставляет копию. То есть ON CONFLICT здесь был декорацией. Замер прода 20.08.2026: строк всего 297 из них act_number IS NULL 297 (все) групп (cad_num, doc_url) с дублями 27 максимум копий одной записи 11 лишних строк 270 (91% таблицы) Что удаляется: копии сверх первой (минимальный id) в каждой группе. Это порождение бага, а не пользовательские данные: таблица — кэш OCR-разбора PDF с сайта, пересобираемый прогоном таски. Проверено, что ключ подходит: ни у одного cad_num нет более одного doc_url (max = 1), дубли внутри групп — точные копии. Прецеденты NULLS NOT DISTINCT в репо: м.110, м.125, м.140, м.158. Prod = PG16.4. Документация приведена к реальности. Docstring обещал python-дедуп по (cad_num, doc_url) и «двухшаговый UPSERT ниже» — ни того, ни другого в коде не было. Комментарий у варианта B был честнее, но его оценка «rare, data audit OK» не подтвердилась: 91% таблицы. Отложенный там вариант (уникальный индекс на NULL) и реализован этой миграцией. Тест репетирует миграцию на ВРЕМЕННОЙ копии, засеянной как прод (11 копий одной записи + соседний участок): исполняет РЕАЛЬНЫЕ выражения из файла, проверяет 12 строк → 2 и что повторная вставка стала no-op. Плюс фальсификация: со СТАРЫМ констрейнтом дубль обязан появиться — без неё зелёный тест неотличим от «оно и так работало». Плюс два контроля: записи С номером акта дедуплицировались и раньше, разные участки не схлопываются. Первая версия репетиции упала на ADD CONSTRAINT — я разбивал миграцию по «;» и молча выбрасывал куски, начинающиеся с комментария, вместе с DELETE. Это ровно то, что репетиция и должна ловить; разбор исправлен. Прогоны: tests/sql (живой Postgres) 6 passed rc=0; -k "izyatie or reservation" 76 passed rc=0. Шесть nodeid в skip_allowlist.txt — нужен Postgres, в CI идут. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| api | ||
| fixtures | ||
| integration | ||
| ops | ||
| scrapers | ||
| scripts | ||
| services | ||
| smoke | ||
| sql | ||
| support | ||
| workers | ||
| __init__.py | ||
| _sentry_wiring_probe.py | ||
| conftest.py | ||
| skip_allowlist.txt | ||
| test_2464c_photos_session_release.py | ||
| test_2464c_timeout_guard_returns.py | ||
| test_admin_weight_profiles.py | ||
| test_app_logging.py | ||
| test_audit_middleware.py | ||
| test_auth_db.py | ||
| test_auth_session_guard.py | ||
| test_auth_session_service.py | ||
| test_concepts_stub.py | ||
| test_connection_capacity_loaders.py | ||
| test_eesk_reserve_loader.py | ||
| test_eias_heat_loader.py | ||
| test_ekb_geoportal_client.py | ||
| test_ekgas_outlet_loader.py | ||
| test_gas_grs_loader.py | ||
| test_gate_verdict.py | ||
| test_gisogd66_loader.py | ||
| test_health.py | ||
| test_layout_signature.py | ||
| test_layout_tz_html.py | ||
| test_layout_tz_pdf.py | ||
| test_network_obremenenie.py | ||
| test_network_zone_humanize.py | ||
| test_noise_loader.py | ||
| test_nspd_client.py | ||
| test_nspd_sync.py | ||
| test_ors_client.py | ||
| test_osm_tp_geocoder.py | ||
| test_osrm_client_local.py | ||
| test_ping.py | ||
| test_poi_score.py | ||
| test_quarter_dump_lookup.py | ||
| test_rbac.py | ||
| test_riasurt_sverdl_client.py | ||
| test_saturation.py | ||
| test_sentry_init.py | ||
| test_skip_guard_loud.py | ||
| test_utility_infrastructure_loader.py | ||
| test_velocity.py | ||
| test_weight_profiles.py | ||