# Объявленные пропуски сьюта tradein-mvp/backend.
#
# Пропуск, которого здесь нет, роняет прогон (хук в tests/conftest.py). Смысл: не
# запретить пропуски, а запретить НЕЗАМЕТНЫЕ. Проверка, которая тихо перестала
# исполняться, со временем расходится с кодом, и узнают об этом ровно тогда,
# когда на неё понадобилось опереться (#2722, #2729, #2740).
#
# Формат: один nodeid в строке, без «[параметров]»; `#` — комментарий.
# Прежде чем добавить строку, ответь: почему эту проверку нельзя выполнить ЗДЕСЬ
# и где она выполняется вместо этого. Нет ответа — это не пропуск, а дыра.
#
# Список — НАДмножество сред: в CI Postgres есть (ci-tradein.yml поднимает
# сервис-контейнер и собирает схему из backend/data/sql/), на ноутбуке без БД —
# нет. Запись, чей пропуск не случился, безвредна; пропуск без записи — нет.

# ── Реальный рендер PDF: нужны native-либы WeasyPrint (Pango/cairo/GObject) ────
# Где выполняется: внутри prod-образа — runner-stage tradein-mvp/backend/Dockerfile
# ставит libcairo2 + libpango-1.0-0 + libpangoft2-1.0-0:
#   docker exec tradein-backend python -m pytest -q -m pdf_render tests/test_pdf_real_render.py
# На голом ubuntu-latest в ci-tradein.yml этих либ нет (apt-шага в job'е нет).
tests/test_pdf_real_render.py

# ── Тесты против живой Postgres ───────────────────────────────────────────────
# В CI они ИДУТ (postgres-сервис в ci-tradein.yml, #2745) — записи ниже нужны
# только для прогона на машине без БД. Именно эта группа разъехалась со схемой,
# пока не бежала нигде: #2740 (houses.url стал NOT NULL) и #2744
# (test_gar_flats_loader падал до первого утверждения). Поднять локально:
#   docker run -d -p 5432:5432 -e POSTGRES_DB=tradein -e POSTGRES_USER=tradein \
#     -e POSTGRES_PASSWORD=tradein postgis/postgis:16-3.4
#   psql ... -f backend/data/sql/*.sql   # порядок как в deploy-tradein.yml
tests/tasks/test_backfill_house_coords_from_listings.py::test_real_transfers_agreeing_coords_skips_scattered_and_is_idempotent
tests/tasks/test_cadastral_geo_match.py::test_real_knn_nearest_within_threshold_picked
tests/test_audit_api.py::test_real_accounts_and_analytics_aggregate_inserted_rows
tests/test_gar_flats_loader.py::test_upsert_and_canon_match_populates_gar_flat_count
tests/test_house_dedup_merge.py::test_real_canon_clusterkey_and_geo_guard_merge_semantics
tests/test_house_dedup_merge.py::test_real_fias_pass_cross_guard_and_identity_carryover
tests/test_house_dedup_merge.py::test_real_fias_pass_ignores_geo_guard
tests/test_house_dedup_merge.py::test_real_merge_is_reversible_via_journal
tests/test_house_dedup_merge.py::test_real_merge_repoints_dedups_deletes_and_is_idempotent
tests/test_user_events.py::test_real_record_event_inserts_row
tests/test_3469_showcase_schedule.py::test_live_migration_puts_showcase_into_schedules_and_digest

# Приватность/ретеншн (#2547) — тот же `_live_session()`. Приехали в main
# параллельно с самим списком, поэтому первым же прогоном deploy-лэйна хук их и
# поймал: 4 проверки не исполнились и не были объявлены. Проверено против живой
# БД (схема из backend/data/sql/ по 233 включительно) — 29 passed, тесты живы.
tests/test_data_erasure.py::test_real_erase_by_phone_does_not_match_different_number
tests/test_data_erasure.py::test_real_erase_by_phone_finds_differently_formatted_number
tests/test_data_erasure.py::test_real_erase_by_phone_finds_ru_trunk_prefix_variant
tests/test_purge_expired_trade_in_data.py::test_real_purge_deletes_only_anonymous_expired_estimates

# Payments retention (PR #2754), deep-review MEDIUM finding 2026-08-06 — тот же
# `_live_session()`. Проверяют предполётную проверку purge против реального
# retain_until/payments состояния (здоровая оплаченная строка не поднимает
# тревогу и не блокирует джобу), не только SQL-текст.
tests/test_purge_expired_trade_in_data.py::test_real_preflight_ignores_healthy_paid_row_flags_only_anomaly
tests/test_purge_expired_trade_in_data.py::test_real_purge_not_wedged_by_healthy_paid_row

# Диагноз оборванного прогона (#2764) — тот же `_live_session()`. Проверяет, что
# дефолт mark_banned ('unknown') проходит CHECK-констрейнт из миграции 234:
# на мок-лэйне (deploy-tradein.yml, DSN-заглушка) констрейнта нет вовсе.
tests/test_2764_ban_kind_no_default.py::test_real_default_ban_kind_survives_the_check_constraint

# Гейт номеров миграций (#2683) сверяется с origin/main и точкой ветвления. Где
# git-эталона нет — прогон внутри prod-образа, экспорт исходников без .git —
# проверять не с чем, и тест это ГОВОРИТ вслух вместо тихого зелёного.
# В CI пропуска не бывает: при CI/GITHUB_ACTIONS та же ветка делает pytest.fail
# (отсутствие эталона в пайплайне — сломанный гейт, а не «нечего проверять»),
# а ci-tradein.yml/deploy-tradein.yml берут checkout с fetch-depth: 0 — при нём
# checkout сам приносит refs/remotes/origin/*, отдельный git fetch не нужен и
# из job-контейнера всё равно не проходит (run 6977, connection refused).
tests/test_migration_numbering.py::test_applied_migration_is_not_renamed_or_deleted
tests/test_migration_numbering.py::test_new_migration_takes_a_free_number
# Повтор застрявших transient_error (#2674, PR #2843) — тот же `_live_session()`.
# Проверяют ВЫБОРКУ очереди на живой схеме (кто попал в пакет прогона), а не текст
# SQL: на мок-лэйне deploy-tradein.yml БД нет вовсе. В ci-tradein.yml они бегут
# по-настоящему (Postgres + схема из data/sql) — там прогон и был красным на
# origin/main и зелёным на ветке. Статическая половина файла
# (test_retry_queue_is_not_bound_to_only_status) БД не требует и идёт в обоих лэйнах.
tests/test_house_imv_retry_stuck.py::test_explicit_only_status_still_takes_exhausted_houses
tests/test_house_imv_retry_stuck.py::test_stuck_transient_house_returns_to_the_queue_by_itself
tests/test_house_imv_retry_stuck.py::test_transient_attempts_counter_only_counts_transient

# MAJOR-1 fix, coverage probe (#2894, независимый ревью) — тот же `live_session` fixture
# (self-skip через `_live_db_available()`, живёт только при реальном Postgres DSN).
# Проверяет, что novostroyki-строка / geo_precision='city'-строка / price_rub=0-строка
# физически не попадают в когорту (не только SQL-текст, который проверяется отдельным
# статическим тестом test_cohort_sql_excludes_* в этом же файле, идущим на обоих лэйнах).
tests/test_coverage_probe_endpoint.py::test_major1_cohort_excludes_novostroyki_and_city_precision_live

# MAJOR-2 поведенческий пин (повторная проверка #2894) — та же `live_session` fixture.
# Ловит мутацию «убрать FILTER у percentile_cont, оставив у count(*)», которую
# текстовый тест test_max_age_outlier_days_passed_to_sql пропускал (подстрока
# `days_on_market <= :max_age_days` встречается в SQL дважды). На мок-лэйне
# (deploy-tradein.yml, DSN-заглушка) реальной БД нет — self-skip.
tests/test_coverage_probe_endpoint.py::test_max_age_outlier_excluded_from_median_live

# #2992 — гейт неизменной строки в апсертах listings / listing_sources. Шесть live-тестов
# идут через реальный save_listings / upsert_listing_source на живом Postgres и меряют,
# переписана ли строка, по ctid (save_listings коммитит — транзакционные счётчики
# бесполезны). Без БД — skip; в CI Trade-In идут на postgres-сервисе (#2745). Свои
# строки t2992-* тесты удаляют явно в finally.
tests/test_2992_upsert_unchanged_gate.py::test_unchanged_rescrape_same_day_does_not_update_the_row
tests/test_2992_upsert_unchanged_gate.py::test_changed_price_still_updates
tests/test_2992_upsert_unchanged_gate.py::test_coalesce_backfill_still_updates
tests/test_2992_upsert_unchanged_gate.py::test_next_day_rescrape_updates_even_if_unchanged
tests/test_2992_upsert_unchanged_gate.py::test_skipped_row_still_yields_listing_id_for_downstream
tests/test_2992_upsert_unchanged_gate.py::test_listing_sources_unchanged_rescrape_same_day_does_not_update
# #3036 — house-поля с детальной страницы Авито → houses (fill-only). Live-тест ходит в
# настоящую БД (в CI она есть, #2745), локально без TEST_DATABASE_URL пропускается. Строки
# t3036-* тест удаляет в finally.
tests/test_3036_detail_house_params_to_houses.py::test_live_fill_only_then_keep_then_unlinked_untouched

# PR-A LATERAL-поиск предшественника в поле переобхода (#2659 продолжение) — тот же
# `_live_session()`. Три live-теста вставляют синтетическую историю снимков (в т.ч.
# с дырами) в ОДНОЙ транзакции и проверяют результат JOIN LATERAL/equality-join
# прямым SELECT'ом в той же транзакции — cleanup через rollback (без commit), явный
# DELETE не нужен. Без БД — skip; в CI Trade-In идут на postgres-сервисе (#2745).
tests/test_revisit_floor_lateral_lookup.py::test_lateral_ignores_gaps_and_matches_dense_daily_history
tests/test_revisit_floor_lateral_lookup.py::test_equality_join_loses_gapped_pairs_and_gives_a_smaller_floor
tests/test_revisit_floor_lateral_lookup.py::test_missing_history_before_anchor_still_yields_no_floor_via_lateral

# Эрозия признаков продавца (#3063, PR #3067) — тот же `_live_session()`.
# Проверяют ПОВЕДЕНИЕ апсерта на живой схеме: что бедный re-scrape не обнуляет
# is_homeowner/is_pro_seller/phones/sale_type (COALESCE держит), и обратное — что
# настоящая смена признака всё ещё перезаписывает (COALESCE не сделал поля
# write-once). SQL-текст проверяется отдельно статической половиной того же файла
# (test_field_is_coalesce_protected_in_set + test_unchanged_gate_mirrors_the_set_clause),
# она идёт на ОБОИХ лэйнах. В ci-tradein.yml эти два бегут по-настоящему
# (postgres-сервис) — там прогон и был зелёным; в deploy-tradein.yml БД нет вовсе.
tests/test_3063_seller_fields_not_eroded.py::test_poor_rescrape_does_not_erase_seller_fields
tests/test_3063_seller_fields_not_eroded.py::test_real_change_still_overwrites
