fix(tradein/sql): окно 23→0 вместо 23→24 — миграция не применялась
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 9s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 4m21s

CI поймал то, что статические проверки пропустили: пять строк получили
window_start_hour=23, window_end_hour=24, а констрейнт из 052_ требует
BETWEEN 0 AND 23. Весь INSERT падал, миграция не применялась.

Час 23 заворачивается в 0 — планировщик поддерживает окна через полночь
явно (window_end_hour <= window_start_hour → cross-midnight).

Тест test_migration_262_windows_are_one_hour и пропустил ошибку: он
требовал end == start + 1, что для 23 даёт ровно 24. Теперь сверяет
(start + 1) % 24, плюс отдельная проверка на диапазон 0..23 — то есть
на то самое условие прод-констрейнта.

Проверено сухим прогоном на боевой схеме: BEGIN → миграция → ROLLBACK,
psql exit 0, число строк не изменилось.
This commit is contained in:
bot-backend 2026-08-13 22:01:49 +03:00
parent 76116f8869
commit 609768a3bd
2 changed files with 25 additions and 6 deletions

View file

@ -280,7 +280,7 @@ VALUES
'avito_city_sweep_verkhnyaya_tura',
false,
23,
24,
0,
((CURRENT_DATE + INTERVAL '1 day') + make_interval(hours => 23)) AT TIME ZONE 'UTC',
'{"pages_per_anchor": 3, "detail_top_n": 0, "request_delay_sec": 7.0, "enrich_houses": true, "radius_m": 3000, "interval_days": 3, "city": "verkhnyaya_tura"}'::jsonb
),
@ -427,7 +427,7 @@ VALUES
'cian_city_sweep_sysert',
false,
23,
24,
0,
((CURRENT_DATE + INTERVAL '1 day') + make_interval(hours => 23)) AT TIME ZONE 'UTC',
'{"pages_per_anchor": 3, "request_delay_sec": 5, "radius_m": 3000, "detail_top_n": 10, "enrich_houses": true, "interval_days": 3, "city": "sysert"}'::jsonb
),
@ -555,7 +555,7 @@ VALUES
'cian_city_sweep_lesnoy',
false,
23,
24,
0,
((CURRENT_DATE + INTERVAL '1 day') + make_interval(hours => 23)) AT TIME ZONE 'UTC',
'{"pages_per_anchor": 3, "request_delay_sec": 5, "radius_m": 3000, "detail_top_n": 10, "enrich_houses": true, "interval_days": 3, "city": "lesnoy"}'::jsonb
),
@ -766,7 +766,7 @@ VALUES
'yandex_city_sweep_degtyarsk',
false,
23,
24,
0,
((CURRENT_DATE + INTERVAL '1 day') + make_interval(hours => 23)) AT TIME ZONE 'UTC',
'{"pages_per_anchor": 3, "request_delay_sec": 9, "radius_m": 25000, "interval_days": 3, "city": "degtyarsk"}'::jsonb
),
@ -910,7 +910,7 @@ VALUES
'yandex_city_sweep_verkhnyaya_tura',
false,
23,
24,
0,
((CURRENT_DATE + INTERVAL '1 day') + make_interval(hours => 23)) AT TIME ZONE 'UTC',
'{"pages_per_anchor": 3, "request_delay_sec": 9, "radius_m": 25000, "interval_days": 3, "city": "verkhnyaya_tura"}'::jsonb
),

View file

@ -393,8 +393,27 @@ def _row_windows(path: Path) -> list[tuple[str, str, int, int]]:
def test_migration_262_windows_are_one_hour() -> None:
"""Окно ровно на час. Час 23 заворачивается в 0 (cross-midnight) — scheduler
это поддерживает явно (`window_end_hour <= window_start_hour` окно через
полночь, см. scraper_kit.orchestration.scheduler)."""
for provider, slug, start, end in _row_windows(_MIGRATION_262):
assert end == start + 1, f"{provider}_{slug}: window [{start},{end}) не 1-часовое"
expected = (start + 1) % 24
assert (
end == expected
), f"{provider}_{slug}: window [{start},{end}) не 1-часовое (ожидали end={expected})"
def test_migration_262_window_hours_satisfy_db_check_constraint() -> None:
"""Оба часа обязаны попадать в 0..23 — иначе миграция не применится вовсе.
Регресс: первая версия давала start=23, end=24 у пяти строк. Проверка
«end == start + 1» это пропускала, а прод-констрейнт `window_end_range`
(052_scrape_schedules.sql: CHECK (window_end_hour BETWEEN 0 AND 23))
нет, и весь INSERT падал в CI на реальном postgres.
"""
for provider, slug, start, end in _row_windows(_MIGRATION_262):
assert 0 <= start <= 23, f"{provider}_{slug}: window_start_hour={start} вне 0..23"
assert 0 <= end <= 23, f"{provider}_{slug}: window_end_hour={end} вне 0..23"
def test_migration_262_windows_avoid_ekb_and_wave1_occupied_hours() -> None: