[tradein][estimator] Gate перед flip tier_aware_ratio_enabled ON — backtest + golden-regression (#928/#934 follow-up) #936

Closed
opened 2026-05-31 21:23:02 +00:00 by bot-reviewer · 2 comments
Collaborator

Follow-up из PR #934 (merged, Closes #928) — ppm²-tier segmentation залит dark (flag OFF).

НЕ включать tier_aware_ratio_enabled=True на проде до прохождения gate

PR #934 ships byte-identical при flag OFF. Перед флипом ON нужен Step-5 backtest (из тела #934, секция «Gate before flag-flip»):

  1. Brusnika EKB-2485: expected_sold ≥ 3.35M с flag ON (была 3.16M, −9% vs ~3.47M buyout; tier low ratio 0.911 → ожидается ≈3.57M).
  2. Golden-regression: все 53 кейса из research/TradeIn_Valuation_Golden_Dataset_May29 §6 — headline median byte-identical pre/post флипа (headline не должен меняться, меняется только expected_sold).
  3. Held-out ДКП-проверка mid/high тиров — их sold-side НЕ покрыт asking-priced golden-сетом; нужна отдельная сверка против реальных ДКП.
  4. M3 ревизия: tier-placement сейчас по pre-anchor median_ppm2, а не по same-building Tukey anchor (#928 spec). Перепроверить/поправить до флипа.

DoD

Все 4 пункта зелёные → flip tier_aware_ratio_enabled=True в .env.runtime отдельным change + post-flip QA estimate-эндпоинта. Если регрессия headline ≠ 0 на любом golden-кейсе → НЕ флипать, разбираться.

Refs #928, #934, #794, #920 (СберИндекс backtest — связанный estimator-gate).

Follow-up из PR #934 (merged, `Closes #928`) — ppm²-tier segmentation залит **dark (flag OFF)**. ## НЕ включать `tier_aware_ratio_enabled=True` на проде до прохождения gate PR #934 ships byte-identical при flag OFF. Перед флипом ON нужен Step-5 backtest (из тела #934, секция «Gate before flag-flip»): 1. **Brusnika EKB-2485**: `expected_sold ≥ 3.35M` с flag ON (была 3.16M, −9% vs ~3.47M buyout; tier low ratio 0.911 → ожидается ≈3.57M). 2. **Golden-regression**: все 53 кейса из `research/TradeIn_Valuation_Golden_Dataset_May29` §6 — headline median **byte-identical** pre/post флипа (headline не должен меняться, меняется только `expected_sold`). 3. **Held-out ДКП-проверка mid/high тиров** — их sold-side НЕ покрыт asking-priced golden-сетом; нужна отдельная сверка против реальных ДКП. 4. **M3 ревизия**: tier-placement сейчас по pre-anchor `median_ppm2`, а не по same-building Tukey anchor (#928 spec). Перепроверить/поправить до флипа. ## DoD Все 4 пункта зелёные → flip `tier_aware_ratio_enabled=True` в `.env.runtime` отдельным change + post-flip QA estimate-эндпоинта. Если регрессия headline ≠ 0 на любом golden-кейсе → НЕ флипать, разбираться. Refs #928, #934, #794, #920 (СберИндекс backtest — связанный estimator-gate).
bot-reviewer added the
priority/p2
scope/backend
status/ready
tradein
labels 2026-05-31 21:23:12 +00:00
Owner

Held-out ДКП backtest — gate NOT passed, flag must stay OFF

Прогнал held-out backtest на проде (read-only, in-container, 642/700 матчей recent rosreestr ДКП, radius 1500m, per-deal Tukey asking-median через estimator pure-funcs). Сравнение pred_sold vs реальная ДКП-цена, по тирам (placement по asking-anchor, как в проде).

SHIPPED tier-ratios (то, что включил бы флаг) — РЕГРЕССИЯ

tier RAW asking GLOBAL per-rooms (сейчас, flag OFF) TIER shipped (flag ON)
low bias +24.3% MAPE 26.7% −4.2% / 15.9% +6.5% / 17.2%
mid +29.4% / 31.0% +3.8% / 15.8% +23.0% / 25.6%
high +44.0% / 45.5% +9.2% / 22.0% +29.1% / 34.2%
all +30.5% / 32.3% +3.3% / 17.2% +19.5% / 24.6%

Включение флага ухудшило бы bias с +3.3% → +19.5% (систематическая ПЕРЕоценка expected_sold) на ВСЕХ тирах, включая low.

Root cause: derivation tier-ratio band-conditioned (артефакт)

Миграция 098 считает median(sold в полосе)/median(asking в полосе), где полоса = asking-терцили. Обе стороны заклиплены в одну ppm²-полосу → ratio схлопывается к ~1.0 (shipped: rb=2 low 0.888 / mid 0.978 / high 1.017). Это НЕ asking→sold коэффициент — это within-band median-alignment. Применение ~0.9–1.0 вместо реального ~0.75 → +20% переоценка.

Правильная деривация (OOS, fit even-id → eval odd-id, ratio = median(sold)/median(asking-anchor) по тиру)

fit: global=0.75, low=0.851, mid=0.76, high=0.712 (правильный порядок: дешёвое продаётся near-ask, премиум −29% от ask — экономически осмысленно, ОБРАТНЫЙ порядок к shipped).

tier GLOBAL(fit) TIER(fit, correct)
low −6.8% / 17.0% +5.8% / 16.3%
mid −3.6% / 16.9% −2.3% / 16.9%
high +9.2% / 18.9% +3.6% / 19.8%

Корректный тиринг даёт лишь маржинальный выигрыш (high-tier bias 9.2%→3.6%, MAPE ~flat), НЕ оправдывает текущую реализацию.

Выводы / действия

  1. НЕ флипать tier_aware_ratio_enabled — shipped derivation регрессирует. Флаг остаётся OFF (демо-safe, dark merge корректен).
  2. Текущий global per-rooms ratio уже хорошо калиброван к ДКП (+3.3% bias) — исходная посылка #928 «expected_sold систематически занижен» на широкой ДКП-популяции НЕ подтверждается.
  3. Brusnika gap (3.16M vs 3.47M «выкуп») — вероятно ДКП-registered vs девелоперский buyout-offer, не баг ratio. Гнаться за 3.47M подняло бы переоценку реальных регистраций.
  4. Если тиринг продолжать — переписать деривацию на median(sold)/median(asking-anchor) per (rooms×tier), fit на отдельном окне, eval OOS; выигрыш всё равно маржинальный (high-tier). Иначе — закрыть #928-feature как not-worth-it, оставить global per-rooms.

Backtest read-only, прод не изменён, флаг OFF.

## Held-out ДКП backtest — gate NOT passed, flag must stay OFF Прогнал held-out backtest на проде (read-only, in-container, 642/700 матчей recent rosreestr ДКП, radius 1500m, per-deal Tukey asking-median через estimator pure-funcs). Сравнение pred_sold vs реальная ДКП-цена, по тирам (placement по asking-anchor, как в проде). ### SHIPPED tier-ratios (то, что включил бы флаг) — РЕГРЕССИЯ | tier | RAW asking | GLOBAL per-rooms (сейчас, flag OFF) | TIER shipped (flag ON) | |---|---|---|---| | low | bias +24.3% MAPE 26.7% | **−4.2% / 15.9%** | +6.5% / 17.2% | | mid | +29.4% / 31.0% | **+3.8% / 15.8%** | +23.0% / 25.6% | | high | +44.0% / 45.5% | **+9.2% / 22.0%** | +29.1% / 34.2% | | **all** | +30.5% / 32.3% | **+3.3% / 17.2%** | **+19.5% / 24.6%** | Включение флага ухудшило бы bias с **+3.3% → +19.5%** (систематическая ПЕРЕоценка expected_sold) на ВСЕХ тирах, включая low. ### Root cause: derivation tier-ratio band-conditioned (артефакт) Миграция 098 считает `median(sold в полосе)/median(asking в полосе)`, где полоса = asking-терцили. Обе стороны заклиплены в одну ppm²-полосу → ratio схлопывается к ~1.0 (shipped: rb=2 low 0.888 / mid 0.978 / high 1.017). Это НЕ asking→sold коэффициент — это within-band median-alignment. Применение ~0.9–1.0 вместо реального ~0.75 → +20% переоценка. ### Правильная деривация (OOS, fit even-id → eval odd-id, ratio = median(sold)/median(asking-anchor) по тиру) fit: global=0.75, **low=0.851, mid=0.76, high=0.712** (правильный порядок: дешёвое продаётся near-ask, премиум −29% от ask — экономически осмысленно, ОБРАТНЫЙ порядок к shipped). | tier | GLOBAL(fit) | TIER(fit, correct) | |---|---|---| | low | −6.8% / 17.0% | +5.8% / 16.3% | | mid | −3.6% / 16.9% | −2.3% / 16.9% | | high | +9.2% / 18.9% | **+3.6%** / 19.8% | Корректный тиринг даёт лишь **маржинальный** выигрыш (high-tier bias 9.2%→3.6%, MAPE ~flat), НЕ оправдывает текущую реализацию. ### Выводы / действия 1. **НЕ флипать `tier_aware_ratio_enabled`** — shipped derivation регрессирует. Флаг остаётся OFF (демо-safe, dark merge корректен). 2. Текущий global per-rooms ratio **уже хорошо калиброван** к ДКП (+3.3% bias) — исходная посылка #928 «expected_sold систематически занижен» на широкой ДКП-популяции НЕ подтверждается. 3. Brusnika gap (3.16M vs 3.47M «выкуп») — вероятно **ДКП-registered vs девелоперский buyout-offer**, не баг ratio. Гнаться за 3.47M подняло бы переоценку реальных регистраций. 4. Если тиринг продолжать — переписать деривацию на `median(sold)/median(asking-anchor)` per (rooms×tier), fit на отдельном окне, eval OOS; выигрыш всё равно маржинальный (high-tier). Иначе — закрыть #928-feature как not-worth-it, оставить global per-rooms. Backtest read-only, прод не изменён, флаг OFF.
Collaborator

Гейт уже пройден (2026-06-01) — re-run не нужен. Per vault decisions/Decision_Tradein_Ppm2_Tier_Asking_Sold_Ratio.md:

Прогнан held-out backtest на проде (642 реальных rosreestr ДКП, radius 1500m, estimator pure-funcs, read-only). Вывод: включение tier_aware_ratio_enabled УХУДШИЛО бы точность, НЕ улучшило → флаг остаётся OFF постоянно. Brusnika-кейс (1 точка, ≥3.35M) ввёл в заблуждение vs 642-точечный backtest — sold-сторона калибрована на ДКП и уже корректна на global per-rooms.

То есть DoD-гейт разрешён отрицательно: флипать НЕ надо, код остаётся dark (flag OFF), прод на global per-rooms ratio. Step-5 backtest выполнен, held-out проверка mid/high покрыта 642-точечной выборкой (не только Brusnika asking-golden).

Закрываю как resolved (решение зафиксировано в волте; флаг намеренно OFF, не tracking-долг). Если захочешь пере-проверить на свежих ДКП позже — scripts/backtest_estimator.py --holdout-split --sample N.

Гейт уже пройден (2026-06-01) — re-run не нужен. Per vault `decisions/Decision_Tradein_Ppm2_Tier_Asking_Sold_Ratio.md`: > Прогнан held-out backtest на проде (**642 реальных rosreestr ДКП**, radius 1500m, estimator pure-funcs, read-only). **Вывод: включение `tier_aware_ratio_enabled` УХУДШИЛО бы точность, НЕ улучшило** → флаг остаётся **OFF постоянно**. Brusnika-кейс (1 точка, ≥3.35M) ввёл в заблуждение vs 642-точечный backtest — sold-сторона калибрована на ДКП и уже корректна на global per-rooms. То есть DoD-гейт разрешён отрицательно: **флипать НЕ надо**, код остаётся dark (flag OFF), прод на global per-rooms ratio. Step-5 backtest выполнен, held-out проверка mid/high покрыта 642-точечной выборкой (не только Brusnika asking-golden). Закрываю как resolved (решение зафиксировано в волте; флаг намеренно OFF, не tracking-долг). Если захочешь пере-проверить на свежих ДКП позже — `scripts/backtest_estimator.py --holdout-split --sample N`.
Sign in to join this conversation.
No milestone
No project
No assignees
3 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#936
No description provided.