fix(estimator): robustness — ratio-tier по финалу, radius-floor, yandex area, expected_sold ≤ asking #1859

Merged
lekss361 merged 4 commits from fix/estimator-robustness-medium3 into main 2026-06-21 05:45:58 +00:00
Owner

Medium-находки аудита «Мера» + дефект, пойманный большим смоком. 4 покоммитных фикса, пороги в settings (флаги, дефолт ≈ безопасное поведение).

Коммиты

  1. 352dfc80 asking_to_sold ratio tier по финальному headline — ratio выбирался по PRE-anchor median, применялся к POST-anchor headline → tier-mismatch. Теперь вызов _get_asking_sold_ratio(anchor_ppm2=финал) ПОСЛЕ corridor-clamp/radius-floor.
  2. b6ea9861 radius-path нижний floor от DKP — anchor-путь имел floor, radius+quarter-index-вниз — нет (асимметричный undershoot). Floor = dkp_low_ppm2 × estimate_radius_floor_factor(0.8) только на radius-пути при наличии dkp_raw. Флаг estimate_radius_floor_enabled(True).
  3. f2cfe66b yandex history skip area≤0 — битые items (area=0/None) больше не сохраняются в house_placement_history (мусор в price_trend).
  4. b2cd2925 expected_sold ≤ asking (ratio cap 1.0)пойман смоком: 3к 27.0M → exp_sold 31.4M > asking (high-tier ratio>1, не клампился). Теперь min(ratio,1.0) на все expected_sold-поля. Флаг estimate_expected_sold_le_asking(True).

Новые settings

estimate_radius_floor_enabled=True, estimate_radius_floor_factor=0.8, estimate_expected_sold_le_asking=True.

Тесты

17 новых (3+4+6+4), ruff clean, полный suite 2121 passed, 0 регрессий (2 pre-existing fail вне затронутого).

Большой смок (на текущем проде, до этого PR)

4 сценария /estimate (anchor/студия/периферия/большая) + rehydrate + PDF(200) + admin (health/pacing/data-quality/runs 422/done) — всё зелёное; analog_tier наполняется по всем уровням. Смок и поймал exp_sold>asking (фикс 4). После мержа+деплоя перегоню дорогой сегмент → exp_sold должен сесть ≤ asking.

Деплой

Backend Python → recreate tradein-backend. Аддитивно, без миграций. NB: деплой-пауза/скрап + rapid-merge (#1839 cumulative-base уже защищает). Cross-ref аудит audits/Mera_Tradein_Estimate_Audit_0620.md.

Medium-находки аудита «Мера» + дефект, пойманный большим смоком. 4 покоммитных фикса, пороги в settings (флаги, дефолт ≈ безопасное поведение). ## Коммиты 1. **`352dfc80` asking_to_sold ratio tier по финальному headline** — ratio выбирался по PRE-anchor median, применялся к POST-anchor headline → tier-mismatch. Теперь вызов `_get_asking_sold_ratio(anchor_ppm2=финал)` ПОСЛЕ corridor-clamp/radius-floor. 2. **`b6ea9861` radius-path нижний floor от DKP** — anchor-путь имел floor, radius+quarter-index-вниз — нет (асимметричный undershoot). Floor = `dkp_low_ppm2 × estimate_radius_floor_factor`(0.8) только на radius-пути при наличии dkp_raw. Флаг `estimate_radius_floor_enabled`(True). 3. **`f2cfe66b` yandex history skip area≤0** — битые items (area=0/None) больше не сохраняются в house_placement_history (мусор в price_trend). 4. **`b2cd2925` expected_sold ≤ asking (ratio cap 1.0)** — **пойман смоком**: 3к 27.0M → exp_sold 31.4M > asking (high-tier ratio>1, не клампился). Теперь `min(ratio,1.0)` на все expected_sold-поля. Флаг `estimate_expected_sold_le_asking`(True). ## Новые settings `estimate_radius_floor_enabled=True`, `estimate_radius_floor_factor=0.8`, `estimate_expected_sold_le_asking=True`. ## Тесты 17 новых (3+4+6+4), ruff clean, полный suite **2121 passed**, 0 регрессий (2 pre-existing fail вне затронутого). ## Большой смок (на текущем проде, до этого PR) 4 сценария /estimate (anchor/студия/периферия/большая) + rehydrate + PDF(200) + admin (health/pacing/data-quality/runs 422/done) — всё зелёное; analog_tier наполняется по всем уровням. Смок и поймал exp_sold>asking (фикс 4). После мержа+деплоя перегоню дорогой сегмент → exp_sold должен сесть ≤ asking. ## Деплой Backend Python → recreate tradein-backend. Аддитивно, без миграций. NB: деплой-пауза/скрап + rapid-merge (#1839 cumulative-base уже защищает). Cross-ref аудит `audits/Mera_Tradein_Estimate_Audit_0620.md`.
lekss361 added 4 commits 2026-06-20 21:36:13 +00:00
_get_asking_sold_ratio теперь вызывается ПОСЛЕ anchor/IMV-blend/quarter-index/
corridor-clamp, получая ФИНАЛЬНЫЙ median_ppm2 для tier-placement (#928 audit).

До фикса: tier резолвился по pre-anchor radius-медиане (~105k), но ratio
применялся к post-anchor headline (~300k) — несовпадение tier'а в premium-
сегменте. После: ratio берётся из того же tier, что и финальный headline.

Graceful: нет ratio → expected_sold_* = None, headline не меняется.
Anchor-путь имеет hard floor от comp_min_ppm2×(1-tol). Radius-путь аналогичной
защиты снизу не имел — quarter-index-вниз или corridor-clamp могли занизить
median неоправданно (asymmetry).

Добавлен floor: если итоговый median_ppm2 < dkp_low_ppm2 × factor → поднять
до floor + лог. Только radius-путь (anchor_tier is None); без dkp_raw → no-op.
За флагами estimate_radius_floor_enabled (default True) и
estimate_radius_floor_factor (default 0.8).
_save_yandex_history_items теперь пропускает items с area_m2 is None или
area_m2 <= 0 (битый парс «0,5 м²» и пр.) перед сохранением в
house_placement_history. Грязь копилась в БД и искажала price_trend.

Estimator защищён NULLIF на уровне SQL, но фильтрация на входе надёжнее.
Лог кол-ва отброшенных (info). Батч не падает из-за одного битого item.
fix(estimator): clamp expected_sold <= asking (ratio cap 1.0) -- smoke 3к exp_sold>asking
All checks were successful
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI / changes (pull_request) Successful in 8s
CI / backend-tests (pull_request) Has been skipped
b2cd2925fd
lekss361 merged commit 810bd056db into main 2026-06-21 05:45:58 +00:00
lekss361 deleted branch fix/estimator-robustness-medium3 2026-06-21 05:45:58 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
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#1859
No description provided.