diff --git a/backend/tests/services/site_finder/test_supply_layers.py b/backend/tests/services/site_finder/test_supply_layers.py index 054db14f..e9e245fd 100644 --- a/backend/tests/services/site_finder/test_supply_layers.py +++ b/backend/tests/services/site_finder/test_supply_layers.py @@ -229,16 +229,22 @@ class TestLayer1Open: assert "CAST(:districts AS text[])" in sql _assert_no_double_colon_cast(sql) - def test_sql_reads_physflat_view(self) -> None: - # #1964: L1 открытое предложение читает physflat-дедуп view, НЕ сырой - # objective_lots (раздут ~2.91× мульти lot_id/физлот → units_available был - # завышен ~3-4.6× → дефицит-форсайт переоценивал L1). Регресс к - # `FROM objective_lots` → fail. + def test_sql_dedups_physflat_inline(self) -> None: + # Перф-батч #2 (#1953-followup): L1 дедупит INLINE через DISTINCT ON по + # physflat-ключу (последний снапшот), НЕ через v_objective_lots_latest + # (view = оптимизационный барьер → full-scan 1.76M, ~6с). Анти-регресс + # #1964 сохранён: чтение СЫРОГО objective_lots БЕЗ дедупа раздуло бы + # units_available ~2.91× (мульти lot_id/физлот) — поэтому требуем DISTINCT ON. db = _mock_db([]) compute_layer1_open(db, district="Автовокзал") sql = _executed_sql(db) - assert "v_objective_lots_latest" in sql, "L1 должен читать physflat-дедуп view" - assert "FROM objective_lots " not in sql, "L1 не должен читать сырой objective_lots" + norm = " ".join(sql.split()) + assert "DISTINCT ON" in norm, "L1 должен physflat-дедупить (анти-инфляция #1964)" + for col in ("project_name", "corpus_name", "section", "floor", "lot_number"): + assert col in norm, f"physflat-ключ DISTINCT ON должен включать {col}" + assert "snapshot_date DESC" in norm, "дедуп к последнему снапшоту физлота" + assert "FROM objective_lots" in norm, "L1 читает сырой objective_lots (inline-дедуп)" + assert "v_objective_lots_latest" not in sql, "view = full-scan, должен быть inline" def test_params(self) -> None: db = _mock_db([])