fix(forecasting): thread room_bucket velocity into format ranking (#1593) #1696

Merged
lekss361 merged 2 commits from fix/base-pace-room-bucket-1593 into main 2026-06-17 18:08:26 +00:00
Owner

Проблема (#1593)

recommendation.py: base_pace считался без room_bucket, compute_market_metrics не имел per-bucket velocity → ранжирование форматов определялось только macro_coef, per-bucket рекомендации не различались.

Решение

Данные уже были (_query_sales_window использует ROLLUP(rooms_int)sold_by_room). Добавлено поле MarketMetrics.velocity_by_room: dict|None (per-bucket velocity = sold_by_room/window_months; None при отсутствии выборки). _demand_only_overlay берёт bucket_base_pace из него (маппинг _FORECAST_TO_METRIC_BUCKETS, «80+ м²» = «4»+«5+»), fallback на агрегат при None. Остальные 6 callers compute_market_metrics проверены — никто не конструирует MarketMetrics напрямую, не затронуты.

Verify

ruff clean; pytest1246 passed, 1 skipped (+5 тестов: per-bucket values, None-кейсы, ranking определяется velocity не macro_coef, graceful fallback).

Closes #1593

## Проблема (#1593) `recommendation.py`: `base_pace` считался без room_bucket, `compute_market_metrics` не имел per-bucket velocity → ранжирование форматов определялось только `macro_coef`, per-bucket рекомендации не различались. ## Решение Данные уже были (`_query_sales_window` использует `ROLLUP(rooms_int)` → `sold_by_room`). Добавлено поле `MarketMetrics.velocity_by_room: dict|None` (per-bucket velocity = sold_by_room/window_months; None при отсутствии выборки). `_demand_only_overlay` берёт `bucket_base_pace` из него (маппинг `_FORECAST_TO_METRIC_BUCKETS`, «80+ м²» = «4»+«5+»), fallback на агрегат при None. Остальные 6 callers `compute_market_metrics` проверены — никто не конструирует `MarketMetrics` напрямую, не затронуты. ## Verify `ruff` clean; `pytest` → **1246 passed, 1 skipped** (+5 тестов: per-bucket values, None-кейсы, ranking определяется velocity не macro_coef, graceful fallback). Closes #1593
lekss361 added 1 commit 2026-06-17 17:57:03 +00:00
fix(forecasting): thread room_bucket into base_pace/compute_market_metrics for real format ranking (#1593)
Some checks failed
CI / backend-tests (push) Blocked by required conditions
CI / frontend-tests (push) Blocked by required conditions
CI / openapi-codegen-check (push) Blocked by required conditions
CI / changes (push) Successful in 8s
CI / changes (pull_request) Successful in 8s
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 1m42s
CI / backend-tests (pull_request) Has been cancelled
cc6ef80d07
Add `velocity_by_room: dict[str, float] | None` to `MarketMetrics` — per-bucket
unit velocity (ед./мес) derived from the existing `sold_by_room` ROLLUP data that
`_query_sales_window` already returns. No new SQL required.

Thread per-bucket velocity through `_demand_only_overlay` via the new
`_FORECAST_TO_METRIC_BUCKETS` constant that maps each forecast bucket to its
market_metrics room-bucket keys. "80+ м²" sums "4" + "5+" keys. Fallback to
aggregate `unit_velocity` when `velocity_by_room` is None (thin-data path).

Previously `base_pace` was identical for all 5 room-buckets, so §9.4 norm and §9.2
base_pace cancelled out in pace/max_pace and ranking was driven purely by §9.5
macro_coef (segment steepness proxy). Now §9.2 reflects real per-bucket observed
demand from objective_lots.contract_date data.

Callers of `compute_market_metrics` that don't use `velocity_by_room` are unaffected
(the new field is additive to the frozen dataclass). All existing callers verified —
none construct `MarketMetrics` directly except the one production site.
bot-backend added 1 commit 2026-06-17 18:08:05 +00:00
fix(forecasting): wrap long lines, guard window_months=0, correct base_pace fallback comment (#1593 review)
Some checks failed
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / openapi-codegen-check (push) Has been cancelled
CI / changes (push) Has been cancelled
CI / backend-tests (pull_request) Has been cancelled
CI / changes (pull_request) Has been cancelled
CI / openapi-codegen-check (pull_request) Has been cancelled
CI / frontend-tests (pull_request) Has been cancelled
ec0d80c1e9
- Add window_months > 0 guard to vel_by_room dict comprehension (mirrors _monthly_rate)
- Correct outer comment in recommendation.py: honest-zero for known-zero buckets,
  fallback only when velocity_by_room=None or bucket absent from _FORECAST_TO_METRIC_BUCKETS
- Add comment in as_dict() noting velocity_by_room is intentionally not serialized
  (internal pipeline attr consumed directly by recommendation.py)
lekss361 merged commit 96f42cd033 into main 2026-06-17 18:08:26 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1696
No description provided.