fix(tradein/estimator): min-width floor ±12% на ценовой диапазон (#2209) #2230

Merged
lekss361 merged 1 commit from fix/tradein-range-min-width-floor into main 2026-07-02 21:21:29 +00:00
Owner

Summary

  • При n=1 аналоге Q1==Q3==median → диапазон схлопывался в ноль ширины (ложная точность юзеру). Добавлен RANGE_MIN_HALFWIDTH_PCT = 0.12 + чистая _apply_range_floor, применяемая последней в спайне (после IMV-blend/quarter-index/corridor/hedonic) к обоим диапазонам — headline asking и expected_sold — вокруг их точек.
  • Floor только расширяет (уже-широкий не тронут); точка (median/expected_sold) и confidence не меняются; low клампится ≥0; не может триггернуть manual_review wide-range (max ratio floor'а 1.273 < порога 1.9).
  • Калибровка ±12%: живой бэктест 2026-07-02 (n=276) — MAPE low-conf 14.8%, медианная отн. ширина 0.743; floor затрагивает только вырожденно-узкий хвост.

Backtest-гейт (ценовое изменение)

Frozen baseline байт-идентичен до/после (replay фикстуры 277 сделок проверен): expected_sold-диапазон строится калиброванным PI-бэндом (rel-width 0.743 ≫ floor 0.24) — floor на нём честный no-op; кусает только вырожденный asking-хвост (n=1..2), который replay не скорит. Bias/MAPE не сдвинулись вовсе (точка не тронута — инвариант брифа выполнен). backtest_baseline.json не потребовал регенерации, CI-регресс-гейт зелёный.

Как проверено

  • Полный локальный pytest: 2983 passed, 6 skipped, 1 deselected (включая 10 новых floor-тестов + frozen gate + roundtrip).
  • code-reviewer: APPROVE без minor — порядок floor-последним подтверждён grep'ом всех downstream реассайнов (персист/DTO/PDF только читают); тест floor-после-IMV-blend доказывает порядок; 0 удалённых строк (никакого попутного рефакторинга).
  • Побочный UX-выигрыш: PDF-бар диапазона теперь рендерится и при бывшем n=1 (range_high > range_low).

Refs #2209

## Summary - При n=1 аналоге Q1==Q3==median → диапазон схлопывался в **ноль ширины** (ложная точность юзеру). Добавлен `RANGE_MIN_HALFWIDTH_PCT = 0.12` + чистая `_apply_range_floor`, применяемая **последней** в спайне (после IMV-blend/quarter-index/corridor/hedonic) к обоим диапазонам — headline asking и expected_sold — вокруг их точек. - Floor **только расширяет** (уже-широкий не тронут); точка (median/expected_sold) и confidence не меняются; low клампится ≥0; не может триггернуть manual_review wide-range (max ratio floor'а 1.273 < порога 1.9). - Калибровка ±12%: живой бэктест 2026-07-02 (n=276) — MAPE low-conf 14.8%, медианная отн. ширина 0.743; floor затрагивает только вырожденно-узкий хвост. ## Backtest-гейт (ценовое изменение) **Frozen baseline байт-идентичен до/после** (replay фикстуры 277 сделок проверен): expected_sold-диапазон строится калиброванным PI-бэндом (rel-width 0.743 ≫ floor 0.24) — floor на нём честный no-op; кусает только вырожденный asking-хвост (n=1..2), который replay не скорит. **Bias/MAPE не сдвинулись вовсе** (точка не тронута — инвариант брифа выполнен). `backtest_baseline.json` не потребовал регенерации, CI-регресс-гейт зелёный. ## Как проверено - Полный локальный pytest: **2983 passed, 6 skipped, 1 deselected** (включая 10 новых floor-тестов + frozen gate + roundtrip). - code-reviewer: ✅ APPROVE без minor — порядок floor-последним подтверждён grep'ом всех downstream реассайнов (персист/DTO/PDF только читают); тест floor-после-IMV-blend доказывает порядок; 0 удалённых строк (никакого попутного рефакторинга). - Побочный UX-выигрыш: PDF-бар диапазона теперь рендерится и при бывшем n=1 (range_high > range_low). Refs #2209
lekss361 added 1 commit 2026-07-02 21:08:28 +00:00
fix(tradein/estimator): min-width floor ±12% на ценовой диапазон (#2209)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 7s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 1m43s
a6f073ba9a
При n=1 аналоге q1==q3==median → asking-диапазон (Q1..Q3 ₽/м²) схлопывался в
ноль ширины: юзеру уходил «диапазон» из одной точки с ложной точностью.
RANGE_MIN_HALFWIDTH_PCT=0.12 + чистая _apply_range_floor, применяемая
ПОСЛЕДНЕЙ в спайне к обоим диапазонам (headline asking + expected_sold)
вокруг их точек. Floor ТОЛЬКО расширяет; точку и confidence не трогает;
не может триггернуть manual_review wide-range (1.273 < 1.9).

Frozen backtest baseline БАЙТ-ИДЕНТИЧЕН до/после (replay проверен):
expected_sold-диапазон строится калиброванным PI-бэндом (rel-width 0.743,
кратно шире floor 0.24) — floor на нём no-op; кусает только вырожденный
asking-хвост (n=1..2), который replay не скорит. Bias/MAPE не сдвинуты.
+10 юнит-тестов (включая доказательство порядка floor-после-IMV-blend).

Refs #2209
lekss361 merged commit 9f28092356 into main 2026-07-02 21:21:29 +00:00
lekss361 deleted branch fix/tradein-range-min-width-floor 2026-07-02 21:21:29 +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#2230
No description provided.