domrf_kn_objects is a snapshot dimension (UNIQUE (obj_id, snapshot_date), ~8 snapshots/obj_id). _SUPPLY_BATCH_SQL joined flats to ALL object-snapshot rows (no o.snapshot_date filter), counting each flat ~8.5x → supply_units_in_radius inflated ~8.5x, sold_pct_of_supply deflated ~8.5x, is_oversold under-fired (all user-facing, best_layouts.py:571-611; sold_pct=deals/supply is a raw ratio so no canceling). Fix: dedup objects to one row per obj_id (latest-snapshot coords) via DISTINCT ON in an objects-first MATERIALIZED CTE, then join domrf_kn_flats via idx_kn_flats_obj. units now = one count per flat (prod cross-check at radius 1.5km: units == count(*) == count(DISTINCT f.id) == 9612 for 65 objects; correction factor 8.56x at 1.5km, 9.13x at 1.0km). This also aligns the supply denominator with the deals numerator (_COMPETITORS_IN_RADIUS_SQL already uses DISTINCT ON latest snapshot). Perf bonus: objects-first avoids the parallel seq scan of the ~376k-row flats snapshot. radius 1.5km / snapshot 2026-05-17: 240ms/~28k buffers/6712 disk reads -> 49ms/1554 buffers/0 disk reads (~5x). Tests: add SQL-text fan-out guard (DISTINCT ON + MATERIALIZED, no bare flats->objects join); update stale EXPLAIN mirror in test_phantom_columns. USER-FACING: best-layouts supply/sold_pct/is_oversold/sell-out-months shift ~8.5x toward correct (frontend BestLayoutsBlock only; ТЗ recommendation + PDF unchanged — they derive from sum_deals, not supply). Deep-reviewed (APPROVE). |
||
|---|---|---|
| .. | ||
| analysis_runs | ||
| analytics | ||
| cadastre | ||
| chat | ||
| etl | ||
| exporters | ||
| forecasting | ||
| generative | ||
| llm | ||
| photos | ||
| scrapers | ||
| site_finder | ||
| __init__.py | ||
| analytics_queries.py | ||
| analytics_refresh.py | ||
| forecast_request_cache.py | ||
| insights.py | ||
| job_settings.py | ||
| objective_etl.py | ||
| objective_sync_config.py | ||
| own_projects.py | ||
| weather_cache.py | ||