diff --git a/backend/app/services/forecasting/recommendation.py b/backend/app/services/forecasting/recommendation.py index b38ff480..418d298e 100644 --- a/backend/app/services/forecasting/recommendation.py +++ b/backend/app/services/forecasting/recommendation.py @@ -637,8 +637,9 @@ def _demand_only_overlay( # §9.2 #1593: per-bucket velocity из velocity_by_room (objective_lots # per комнатность). _FORECAST_TO_METRIC_BUCKETS даёт список metric-ключей # для данного forecast_bucket ("80+ м²" = "4"+"5+"). Суммируем ед./мес по - # бакетам. Если velocity_by_room отсутствует ИЛИ все нужные бакеты нулевые - # — fallback на агрегатный base_pace (лучше, чем 0-сигнал). + # бакетам. Честный 0 при известных бакетах — НЕ fallback. Fallback на + # агрегатный base_pace только когда velocity_by_room=None (пустая + # выборка) или bucket неизвестен в _FORECAST_TO_METRIC_BUCKETS. metric_keys = _FORECAST_TO_METRIC_BUCKETS.get(forecast_bucket, []) if vel_by_room is not None and metric_keys: bucket_velocity: float = sum(vel_by_room.get(k, 0.0) for k in metric_keys) diff --git a/backend/app/services/site_finder/market_metrics.py b/backend/app/services/site_finder/market_metrics.py index d7618369..d8e415df 100644 --- a/backend/app/services/site_finder/market_metrics.py +++ b/backend/app/services/site_finder/market_metrics.py @@ -140,6 +140,8 @@ class MarketMetrics: "demand_concentration": _round_or_none(self.demand_concentration, 3), "price_sensitivity": _round_or_none(self.price_sensitivity, 4), "price_sensitivity_source": self.price_sensitivity_source, + # velocity_by_room намеренно не сериализуется: это внутренний + # pipeline-атрибут (потребляется recommendation.py напрямую). } @@ -416,9 +418,10 @@ def compute_market_metrics( # #1593: per-bucket velocity — ед./мес по каждой комнатности. Ключи зеркалят # _room_bucket() ("студия","1","2","3","4","5+"). При has_sample=False нет # смысла делить 0 лотов → None (graceful, зеркало unit_velocity поведения). + # window_months > 0 защищает от ZeroDivisionError (зеркало _monthly_rate()). vel_by_room: dict[str, float] | None = ( {bkt: float(cnt) / float(window_months) for bkt, cnt in sold_by_room.items()} - if has_sample and sold_by_room + if has_sample and sold_by_room and window_months > 0 else None )