fix(mera/backtest): свежая фикстура не реплеилась, а разрез по сегментам врал по построению #3254

Merged
lekss361 merged 1 commit from fix/3251-backtest-harness-stale-fixture-and-outcome-bucketing into main 2026-08-29 20:11:12 +00:00

1 commit

Author SHA1 Message Date
bot-backend
9516d95277 fix(mera/backtest): свежая фикстура не реплеилась, а разрез по сегментам врал
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 10s
CI Trade-In / browser-tests (pull_request) Has been skipped
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 4m58s
Три связанные правки в харнесе бэктеста.

1. replay_fixture жёстко пинил estimate_dedup_analogs_enabled = False. Это верно
   только для фикстуры, захваченной до #2173, когда дедуп был выключен по
   умолчанию. Любая свежая фикстура при этом становилась нереплеибельной: с
   dedup=True на захвате часть сделок уходит под sufficiency-гейт с
   median_ppm2<=0, ratio_resolver для них не зовётся, а реплей с dedup=False их
   оценивает и падает на «control flow diverged from capture». Теперь значение
   берётся из settings_at_capture; фикстуры без этого поля ведут себя как раньше.

2. Разрез per_segment группирует ошибки по SOLD руб/м2 — по величине, которую
   движок и предсказывает. Корзины отобраны по шуму исхода, отсюда регрессия к
   среднему: даже несмещённый предиктор выглядит завышающим в дешёвых корзинах и
   занижающим в дорогих. На контрольном предикторе без перекоса по построению
   (13074 сделки ЕКБ) этот разрез даёт бизнес -17.04% и элит -30.06% — больше,
   чем наблюдавшийся перекос движка. По этому артефакту уже один раз
   откалибровали estimate_segment_multipliers (#2255). Блок оставлен для
   сравнимости с историей прогонов, но помечен предупреждением в докстринге и в
   печатном выводе.

3. Добавлен per_area_bucket — разрез по площади, независимой от исхода, с
   границами asking_to_sold_ratios (30/44/62/85). Промах конкретного бакета ratio
   виден сразу. Блок аддитивный: area_rows=None у старых вызывающих даёт пустой
   словарь, форма ответа не меняется.

Фикстура заменена на свежую (1600 сделок ЕКБ с 2025-06, 1269 оценённых, захват
после #2620) — прежняя от 2026-07-04 старше перехода ratio на area-бакеты и
показывала точность конфигурации, которой в проде уже нет. Baseline перезахвачен:
n 269 -> 1269, MAPE 12.63 -> 13.90, bias -3.74 -> -0.78, покрытие 86.13%.
Сдвиг метрик — смена измерительной выборки, а не регресс движка.

В каверзы модуля добавлен пункт (d): предсказание идёт из центроида улицы, а не
из адреса дома — в открытом датасете Росреестра нет номера дома, кадастры все
вида 66:41:0000000:0, и 65971 сделка садится в 3137 координат.
2026-08-29 23:05:15 +03:00