gendesign/backend/tests/services/site_finder
Light1YT e67cb721bf fix(objective): physflat-dedup current-state consumers + honest n_sold window (#1964)
objective_lots — current-state UPSERT (UNIQUE objective_lot_id, 5 snapshot_date),
но Объектив присваивает ОДНОМУ физлоту (project,corpus,section,floor,lot_number)
несколько lot_id за пере-листинги → таблица раздута ~2.91× (прод: 1.75M квартир-
строк vs 603k физлотов). История — в отдельной objective_lots_history (не трогаем).

STEP 1: миграция 175 — VIEW v_objective_lots_latest (DISTINCT ON physflat-ключ,
последний снапшот). ol.* стабилен (51==51 колонок). DRY-RUN на проде: 603 049
квартир vs 1 753 283 raw.

STEP 2: репойнт current-state консьюмеров objective_lots → v_objective_lots_latest:
- supply_layers._L1_OPEN_SQL (L1 открытое предложение → дефицит-форсайт; прод:
  Юго-Западный комфорт 58 606 → 12 620)
- competitors._SOLD_COUNT_SQL (+ комментарий: COUNT(DISTINCT lot_id) СОХРАНЁН для
  fan-out-защиты маппинга, не COUNT(*) — view гарантирует physflat-дедуп, DISTINCT
  гарантирует mapping-fan-out-safety)
- parcels.py obj_pricing CTE (карточка конкурента units_sold/available)
- special_indices._ARTIFICIAL_DEMAND_SQL
- parcels.py district price block + geo-radius median (sample_size/n)
- concepts._OBJECTIVE_MEDIAN_SQL (гейт n≥10)
- landing KPI3 (% квартир с ценой)
- admin_scrape coverage: `lots` оставлен сырым (ETL-fidelity vs SQLite), добавлен
  `lots_physflat`
#1959 inline-дедуп в market_metrics НЕ рефакторим — добавлен комментарий об общем
physflat-ключе с view.

STEP 3: report_assembler._deal_count теперь = unit_velocity × window_months
(оконные продажи), НЕ кумулятивный n_sold. confidence_engine помечает фактор
«за 6 мес» и гейтит порогами окна (high≥50) — кумулятив (прод EKB ~380 921) делал
гейт бессмысленным и подпись лживой; оконное (~24 876 за 6 мес) честно.

Тесты: +guard'ы (L1/sold-count читают view, deal_count оконный). 963 passed.
2026-06-28 04:27:43 +05:00
..
test_best_layouts.py fix(best-layouts): per-object latest snapshot for supply (#1956) 2026-06-27 23:24:28 +05:00
test_competitor_relevance.py feat(site-finder): per-competitor relevance_weight (#949 PR B) (#1000) 2026-06-02 19:45:38 +00:00
test_competitors_parking.py feat(site-finder): domrf→cad geom-match + parking_ratio конкурентов (#96) (#1327) 2026-06-14 14:49:28 +00:00
test_developer_attribution.py feat(site-finder): детерминированная атрибуция застройщика в analyze (#1088) 2026-06-13 16:13:45 +05:00
test_district_resolver.py feat(forecast): resolve admin district -> micro set in §9.x market/supply/sales filters 2026-06-05 07:03:37 +05:00
test_future_supply.py feat(forecasting): §9.x→§22 orchestrator + fix supply-side district resolution (3a) 2026-06-05 08:21:04 +05:00
test_locations.py fix(site_finder): make Location demand_index city-relative (#948) 2026-06-08 13:58:12 +05:00
test_macro.py fix(#945): indicator-aware default region in macro reader + document debt data-quality 2026-06-04 11:49:41 +05:00
test_market_metrics.py fix(forecast): посегментный+дедуплицированный индекс дефицита (#1959) 2026-06-27 22:50:58 +05:00
test_own_portfolio.py feat(site-finder): own-portfolio data source for §25.3 cannibalization (#1169 PR1) 2026-06-08 16:21:53 +05:00
test_parcel_financial.py feat(financial): ground-floor нежилое (office/commercial) tranche 2026-06-25 11:40:01 +00:00
test_pat_subzones.py fix(sf): робастный путь к koltsovo JSON в pat-loader (#1155) 2026-06-07 15:34:10 +00:00
test_premises_lookup.py feat(site-finder): per-building помещения/машино-места + parking_ratio (on-demand MVP, #96) 2026-06-14 18:48:16 +05:00
test_riasurt_lookup.py feat(site-finder): РИАСУРТ Свердл 14-layer harvest client+schema+task for ЕКБ agglomeration (#108) 2026-06-17 21:49:04 +03:00
test_supply_layers.py fix(objective): physflat-dedup current-state consumers + honest n_sold window (#1964) 2026-06-28 04:27:43 +05:00