fix(tradein/estimate): домовой IMV-якорь приводится к базису ремонта квартиры (#2677) #2816

Merged
bot-backend merged 1 commit from fix/2677-house-anchor-renovation into main 2026-08-12 20:17:11 +00:00
Collaborator

Что чинится

median_price к моменту blend'а уже домножен на _repair_coefficient («требует ремонта» −6 %, «хороший» +5 %, «евро» +10 %), а домовой якорь из house_imv_evaluations запрошен у Avito с одним ремонтом (renovation_type). Порог anchor > median×1.15 и сам blend клали два разных базиса на одну шкалу.

Для клиента с «требует ремонта» это означало: порог фактически ×1.081 вместо ×1.15 (срабатывает чаще), а сработавший blend с весом 0.5 возвращал половину его −6 % обратно вверх. Однонаправленный якорь наполовину отменял поправку на ремонт.

Правка не трогает калибровку: якорь домножается ровно на тот коэффициент, который код уже применил к медиане — coef(ремонт клиента) / coef(ремонт строки якоря). Это не заявка на верность самих коэффициентов (_REPAIR_COEF — рыночная эвристика с покрытием ~2 %, см. предупреждение в коде), а починка расхождения базисов.

Карточка Avito в ответе остаётся сырой — чужое число мы не правим. Пересчитанный якорь уходит только в blend, и пояснение это называет («…приведённой к состоянию ремонта квартиры»).

ДЕНЕЖНЫЙ ЭФФЕКТ (до мержа)

Замер на проде 2026-08-10, 1061 персистированная оценка, прогнан тем же кодом, что и прод: match_house_readonly_fetch_house_imv_anchor_apply_imv_blend в контейнере tradein-backend, только SELECT + rollback.

Реализованный эффект сегодня — 0 ₽. Blend не сработал ни разу: 0 маркеров «скорректирована по оценке Avito IMV» в confidence_explanation на 1061 строку.

Канал измерения показать срабатывание способен — в той же колонке лежат 174 заметки про ремонт, 269 про «того же дома» и 456 про «ближайшее окружение», то есть дописывание в explanation доезжает до БД.

Разложение нуля:

ступень из 1061
оценка резолвится в дом (match_house_readonly) 674
у дома есть band-совместимая строка house_imv_evaluations 240
якорь превышает median×1.15 19
blend реально выполнился 0 — все 19 гасит гейт anchor_tier is None выше по потоку (Tier D only)

Контрфакт на этих 19 (что было бы, дойди они до blend'а) — старый код против базис-согласованного:

ремонт клиента оценок Δ медианы Δ ₽
needs_repair 9 (4 разных дома) −3.3 … −9.8 %, медиана −7.9 % −4 131 046
good 1 +9.6 % +474 641
остальные 9 0 % (якорь cosmetic, ремонт клиента standard/неизвестен → k = 1.0) 0

Распределение anchor / median по 236 оценкам с якорем: min 0.233 · p25 0.764 · median 0.911 · p75 1.043 · max 1.910. Якорь чаще НИЖЕ нашей медианы — потому однонаправленный вверх blend и редок.

Проверка направления на заведомо известных объектах

Правка для «требует ремонта» понижает оценку — не тот случай, когда приятный результат подозрителен. Но проверил обе стороны:

дом 184767, ул. Софьи Перовской 119 (2-комн. 42.9 м², «требует ремонта», Δ −9.8 %)

  • старый код: 100 411 ₽/м²
  • с правкой: 90 566 ₽/м²
  • факт: 143 ДКП-сделки за 18 мес, по 2-комнатным ~43–53 м² медиана ≈ 91 300 ₽/м²; 22 активных объявления, медиана 94 859 ₽/м²

Правка попадает в медиану сделок, старый код на 10 % выше неё. Ближе к правде.

дом 6767, ул. Гаршина 3/2 (1-комн. 32.3 м², «хороший ремонт», Δ +9.6 %) — случай, где правка ПОВЫШАЕТ

  • старый код: 153 629 ₽/м²
  • с правкой: 168 324 ₽/м²
  • факт: 19 ДКП-сделок, p25 134 865 / медиана 155 660 / p75 165 479 ₽/м²; 45 объявлений, медиана 156 452 ₽/м²

Здесь новое число выходит выше p75 сделок дома, то есть по этому объекту правка от медианы уходит. Оправдание «квартира с хорошим ремонтом и должна быть в верхней части дома» — это история, а не измерение; честно: повышающая половина правки на известных объектах не подтверждена, она опирается на те же непроверенные _REPAIR_COEF, что и вся поправка на ремонт. n = 2 объекта.

Что осознанно НЕ сделано

  • Однонаправленность blend'а не тронута. «Только вверх» — задокументированное продуктовое решение (config.py: «ОДНОНАПРАВЛЕННО: только повышаем (баг — занижение)»), а не дефект в смысле #2677. Симметризация двигает цену у всех и требует решения владельца.
  • Гейт anchor_tier is None не тронут. Именно он держит реализованный эффект на нуле; это существующий дизайн (blend — фолбэк Tier D).
  • Пункт 2 issue «выбирать строку, близкую по ремонту» невыполним и проверен: house_imv_eval_house_uniq_idx UNIQUE (house_id) — строка на дом ровно одна, выбирать не из чего. Реализован второй вариант из того же пункта — «корректировать якорь отношением коэффициентов ремонта».

Тест

tradein-mvp/backend/tests/test_2677_house_anchor_repair_basis.py — 6 тестов, все 6 красные на origin/main и падают на цифрах, а не на импорте (_anchor_repair_factor импортируется внутри тестов намеренно, чтобы сквозные кейсы дошли до выполнения):

FAILED test_needs_repair_client_not_lifted_by_cosmetic_anchor
    assert 6170000 == 5640000
FAILED test_euro_anchor_not_applied_raw_to_unknown_repair_client
    assert 6500000 == 6000000
FAILED test_blend_still_fires_and_reports_the_rebased_anchor
    assert 7820000 == 7520000
FAILED test_anchor_query_selects_renovation_type
FAILED test_repair_factor_is_ratio_of_the_same_coefficients
FAILED test_repair_factor_unknown_anchor_renovation_falls_back_to_standard_basis
6 failed in 0.39s

На ветке: 6 passed. Полный прогон tradein-backend: 4103 passed, 18 skipped.

Test plan

  • красный прогон на origin/main (цифрами, выше)
  • зелёный на ветке + полный сьют 4103 passed
  • ruff 0.7.4 (версия pre-commit) check + format
  • прод-верификация — критерий записан ДО факта, см. ниже

Прод-верификация: критерий приёмки, записан ДО мержа

Реализованный эффект сегодня 0 ₽, поэтому «число на проде сразу после деплоя» невозможно — проверять нечего, пока держит гейт Tier D. Критерий, фиксируемый заранее:

Дата проверки: 2026-09-10 (месяц после мержа).

  1. SELECT count(*) FROM trade_in_estimates WHERE created_at > '<дата мержа>' AND confidence_explanation LIKE '%скорректирована по оценке Avito IMV%' — сколько blend'ов реально произошло.
  2. Если > 0: у каждой такой оценки с repair_state IS NOT NULL в логах backend обязана быть строка imv_anchor repair-basis #2677: renovation=… k=… с k != 1.0. Отсутствие строки при непустом repair_state и renovation_type != 'cosmetic' = правка не доехала.
  3. Если = 0 — правка по-прежнему профилактическая, и это НЕ «проверено», а «повода сработать не было»; тогда проверять снова после того, как снимут гейт anchor_tier is None либо house_imv_evaluations наберёт >100 строк с renovation_type != 'cosmetic' (сегодня их 6 из 2674).

Refs #2677

## Что чинится `median_price` к моменту blend'а уже домножен на `_repair_coefficient` («требует ремонта» −6 %, «хороший» +5 %, «евро» +10 %), а домовой якорь из `house_imv_evaluations` запрошен у Avito с **одним** ремонтом (`renovation_type`). Порог `anchor > median×1.15` и сам blend клали два разных базиса на одну шкалу. Для клиента с «требует ремонта» это означало: порог фактически ×1.081 вместо ×1.15 (срабатывает чаще), а сработавший blend с весом 0.5 возвращал половину его −6 % обратно вверх. Однонаправленный якорь наполовину отменял поправку на ремонт. Правка **не трогает калибровку**: якорь домножается ровно на тот коэффициент, который код уже применил к медиане — `coef(ремонт клиента) / coef(ремонт строки якоря)`. Это не заявка на верность самих коэффициентов (`_REPAIR_COEF` — рыночная эвристика с покрытием ~2 %, см. предупреждение в коде), а починка расхождения базисов. Карточка Avito в ответе остаётся **сырой** — чужое число мы не правим. Пересчитанный якорь уходит только в blend, и пояснение это называет («…приведённой к состоянию ремонта квартиры»). ## ДЕНЕЖНЫЙ ЭФФЕКТ (до мержа) Замер на проде 2026-08-10, 1061 персистированная оценка, прогнан **тем же кодом**, что и прод: `match_house_readonly` → `_fetch_house_imv_anchor` → `_apply_imv_blend` в контейнере `tradein-backend`, только SELECT + rollback. **Реализованный эффект сегодня — 0 ₽.** Blend не сработал ни разу: 0 маркеров `«скорректирована по оценке Avito IMV»` в `confidence_explanation` на 1061 строку. Канал измерения показать срабатывание **способен** — в той же колонке лежат 174 заметки про ремонт, 269 про «того же дома» и 456 про «ближайшее окружение», то есть дописывание в `explanation` доезжает до БД. Разложение нуля: | ступень | из 1061 | |---|---| | оценка резолвится в дом (`match_house_readonly`) | 674 | | у дома есть band-совместимая строка `house_imv_evaluations` | 240 | | якорь превышает `median×1.15` | 19 | | **blend реально выполнился** | **0** — все 19 гасит гейт `anchor_tier is None` выше по потоку (Tier D only) | Контрфакт на этих 19 (что было бы, дойди они до blend'а) — старый код против базис-согласованного: | ремонт клиента | оценок | Δ медианы | Δ ₽ | |---|---|---|---| | `needs_repair` | 9 (4 разных дома) | −3.3 … −9.8 %, медиана −7.9 % | −4 131 046 | | `good` | 1 | +9.6 % | +474 641 | | остальные | 9 | 0 % (якорь `cosmetic`, ремонт клиента `standard`/неизвестен → k = 1.0) | 0 | Распределение `anchor / median` по 236 оценкам с якорем: min 0.233 · p25 0.764 · **median 0.911** · p75 1.043 · max 1.910. Якорь чаще НИЖЕ нашей медианы — потому однонаправленный вверх blend и редок. ## Проверка направления на заведомо известных объектах Правка для «требует ремонта» **понижает** оценку — не тот случай, когда приятный результат подозрителен. Но проверил обе стороны: **дом 184767, ул. Софьи Перовской 119** (2-комн. 42.9 м², «требует ремонта», Δ −9.8 %) - старый код: 100 411 ₽/м² - с правкой: 90 566 ₽/м² - факт: 143 ДКП-сделки за 18 мес, по 2-комнатным ~43–53 м² медиана **≈ 91 300 ₽/м²**; 22 активных объявления, медиана 94 859 ₽/м² Правка попадает в медиану сделок, старый код на 10 % выше неё. **Ближе к правде.** **дом 6767, ул. Гаршина 3/2** (1-комн. 32.3 м², «хороший ремонт», Δ +9.6 %) — случай, где правка ПОВЫШАЕТ - старый код: 153 629 ₽/м² - с правкой: 168 324 ₽/м² - факт: 19 ДКП-сделок, p25 134 865 / медиана 155 660 / p75 165 479 ₽/м²; 45 объявлений, медиана 156 452 ₽/м² Здесь новое число выходит **выше p75 сделок дома**, то есть по этому объекту правка от медианы уходит. Оправдание «квартира с хорошим ремонтом и должна быть в верхней части дома» — это история, а не измерение; честно: **повышающая половина правки на известных объектах не подтверждена**, она опирается на те же непроверенные `_REPAIR_COEF`, что и вся поправка на ремонт. n = 2 объекта. ## Что осознанно НЕ сделано - **Однонаправленность blend'а не тронута.** «Только вверх» — задокументированное продуктовое решение (`config.py`: «ОДНОНАПРАВЛЕННО: только повышаем (баг — занижение)»), а не дефект в смысле #2677. Симметризация двигает цену у всех и требует решения владельца. - **Гейт `anchor_tier is None` не тронут.** Именно он держит реализованный эффект на нуле; это существующий дизайн (blend — фолбэк Tier D). - **Пункт 2 issue «выбирать строку, близкую по ремонту» невыполним** и проверен: `house_imv_eval_house_uniq_idx UNIQUE (house_id)` — строка на дом ровно одна, выбирать не из чего. Реализован второй вариант из того же пункта — «корректировать якорь отношением коэффициентов ремонта». ## Тест `tradein-mvp/backend/tests/test_2677_house_anchor_repair_basis.py` — 6 тестов, **все 6 красные на `origin/main`** и падают на цифрах, а не на импорте (`_anchor_repair_factor` импортируется внутри тестов намеренно, чтобы сквозные кейсы дошли до выполнения): ``` FAILED test_needs_repair_client_not_lifted_by_cosmetic_anchor assert 6170000 == 5640000 FAILED test_euro_anchor_not_applied_raw_to_unknown_repair_client assert 6500000 == 6000000 FAILED test_blend_still_fires_and_reports_the_rebased_anchor assert 7820000 == 7520000 FAILED test_anchor_query_selects_renovation_type FAILED test_repair_factor_is_ratio_of_the_same_coefficients FAILED test_repair_factor_unknown_anchor_renovation_falls_back_to_standard_basis 6 failed in 0.39s ``` На ветке: `6 passed`. Полный прогон tradein-backend: `4103 passed, 18 skipped`. ## Test plan - [x] красный прогон на `origin/main` (цифрами, выше) - [x] зелёный на ветке + полный сьют 4103 passed - [x] ruff 0.7.4 (версия pre-commit) check + format - [ ] прод-верификация — критерий записан ДО факта, см. ниже ## Прод-верификация: критерий приёмки, записан ДО мержа Реализованный эффект сегодня 0 ₽, поэтому «число на проде сразу после деплоя» невозможно — проверять нечего, пока держит гейт Tier D. Критерий, фиксируемый заранее: **Дата проверки: 2026-09-10 (месяц после мержа).** 1. `SELECT count(*) FROM trade_in_estimates WHERE created_at > '<дата мержа>' AND confidence_explanation LIKE '%скорректирована по оценке Avito IMV%'` — сколько blend'ов реально произошло. 2. Если > 0: у каждой такой оценки с `repair_state IS NOT NULL` в логах backend обязана быть строка `imv_anchor repair-basis #2677: renovation=… k=…` с `k != 1.0`. **Отсутствие строки при непустом `repair_state` и `renovation_type != 'cosmetic'` = правка не доехала.** 3. Если = 0 — правка по-прежнему профилактическая, и это НЕ «проверено», а «повода сработать не было»; тогда проверять снова после того, как снимут гейт `anchor_tier is None` либо `house_imv_evaluations` наберёт >100 строк с `renovation_type != 'cosmetic'` (сегодня их 6 из 2674). Refs #2677
bot-backend added 1 commit 2026-08-10 09:38:00 +00:00
fix(tradein/estimate): домовой IMV-якорь приводится к базису ремонта квартиры
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 9s
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 3m55s
1ec37a793b
median_price к моменту blend'а уже домножен на _repair_coefficient («требует
ремонта» −6%, «евро» +10%), а домовой якорь из house_imv_evaluations запрошен
у Avito с ОДНИМ ремонтом (renovation_type). Порог anchor > median×1.15 и сам
blend клали два разных базиса на одну шкалу: у клиента с «требует ремонта»
порог фактически падал до ×1.081, а сработавший blend возвращал половину его
−6% обратно вверх — то есть однонаправленный якорь наполовину отменял
поправку на ремонт.

Правка не трогает калибровку: якорь домножается ровно на тот коэффициент,
который код УЖЕ применил к медиане (coef(ремонт клиента) / coef(ремонт строки
якоря)). Карточка Avito остаётся сырой — чужое число мы не правим; в blend
уходит пересчитанное, и пояснение это называет.

Замер на проде (1061 персистированная оценка, 2026-08-10, тем же кодом:
match_house_readonly → _fetch_house_imv_anchor → _apply_imv_blend):
- реализованный эффект СЕГОДНЯ 0 ₽ — blend не сработал ни разу (0 маркеров
  в confidence_explanation при 174 repair-заметках и 725 anchor-заметках
  в той же колонке, то есть канал показать срабатывание способен);
- 674/1061 оценок резолвятся в дом, 240 получают домовой якорь, порог
  пересекают 19 — все они гасятся гейтом anchor_tier is None выше по потоку;
- на этих 19 старый код против базис-согласованного: 9 оценок «требует
  ремонта» −3.3…−9.8 % (−4.13 млн ₽ суммарно), 1 оценка «хороший ремонт»
  +9.6 % (+0.47 млн ₽).

Однонаправленность blend'а НЕ трогаю — это отдельное продуктовое решение
(config: «ОДНОНАПРАВЛЕННО: только повышаем»), не дефект в смысле #2677.

Refs #2677
Author
Collaborator

Независимая перепроверка этого PR из другой ветки (#2674, PR #2852) — выводы подтверждаю, метод у вас сильнее моего.

Я пришёл к той же правке независимо (отношение _REPAIR_COEF, приведение якоря к базису ремонта клиента, сырая карточка Avito не трогается) и снял свой дубль. Совпало по числам без сговора:

ваш замер (10.08, 1061 оценка) мой (12.08, 1081 оценка)
распределение anchor / median p25 0.764 · медиана 0.911 · p75 1.043 · max 1.910 p25 0.763 · медиана 0.911 · p75 1.043 · max 1.910
оценок с band-совместимым якорем 240 224
реализованный эффект блендa сегодня 0 ₽, 0 маркеров в confidence_explanation 0 строк с «Avito IMV» на 1081 (канал живой: 183 строки про ремонт)

Где я ошибся, а вы нет: я оценивал anchor_tier по тексту объяснения («того же дома») и насчитал 127 Tier-D с якорем / 14 пересекающих порог. Вы прогнали тот же код в контейнере и показали, что все пересекающие порог гасит гейт anchor_tier is None. Текстовый прокси не видит Tier B/C — ваша цифра верная.

Три довода в пользу мержа, которых в описании нет:

  1. Гейт эры/свежести как альтернатива — отклонён замером. Все 224 band-совместимые строки на проде дореформенные; свежих 47 не хватает ни на одну оценку. Гейт не отсёк бы плохое, а выключил бы механизм.
  2. Массовая переоценка вашу правку не заменяет. 1628 из 2633 домов уже в imv_status='ok', батч берёт только pending/transient_error (там 7144 дома при ~25/прогон ≈ 286 суток) — для них обновление не «через 300 суток», а никогда. И даже идеально свежая строка спрошена в модальном ремонте ДОМА, а не в ремонте клиента: базисы всё равно разные.
  3. _REPAIR_COEF подтверждается данными. Парное сравнение ppm² внутри дома (база standard, прод 12.08): needs_repair 0.946 при коэффициенте 0.94, good 1.039 при 1.05, excellent 1.113 при 1.10 (61 / 289 / 84 домов-пар). Ваша оговорка «это не заявка на верность коэффициентов» корректна, но по факту они попадают в измеренное.

Смежное, если будете трогать этот участок: докстринг _fetch_house_imv_anchor по-прежнему обещает «популирована (~2951 домов, fresh)» — неправда по обоим пунктам (2680 строк, 2633 старше 40 суток). Чиню отдельно в #2852, конфликт возможен на 3-5 строках докстринга — мержьте этот PR первым, я перебазируюсь.

(правка предыдущего комментария: в нём shell съел обратные кавычки — содержание то же)

Независимая перепроверка этого PR из другой ветки (#2674, PR #2852) — **выводы подтверждаю, метод у вас сильнее моего.** Я пришёл к той же правке независимо (отношение `_REPAIR_COEF`, приведение якоря к базису ремонта клиента, сырая карточка Avito не трогается) и снял свой дубль. Совпало по числам без сговора: | | ваш замер (10.08, 1061 оценка) | мой (12.08, 1081 оценка) | |---|---|---| | распределение `anchor / median` | p25 0.764 · медиана **0.911** · p75 1.043 · max 1.910 | p25 0.763 · медиана **0.911** · p75 1.043 · max 1.910 | | оценок с band-совместимым якорем | 240 | 224 | | реализованный эффект блендa сегодня | 0 ₽, 0 маркеров в `confidence_explanation` | 0 строк с «Avito IMV» на 1081 (канал живой: 183 строки про ремонт) | Где я ошибся, а вы нет: я оценивал `anchor_tier` по тексту объяснения («того же дома») и насчитал 127 Tier-D с якорем / 14 пересекающих порог. Вы прогнали **тот же код в контейнере** и показали, что все пересекающие порог гасит гейт `anchor_tier is None`. Текстовый прокси не видит Tier B/C — ваша цифра верная. Три довода в пользу мержа, которых в описании нет: 1. **Гейт эры/свежести как альтернатива — отклонён замером.** Все 224 band-совместимые строки на проде дореформенные; свежих 47 не хватает ни на одну оценку. Гейт не отсёк бы плохое, а выключил бы механизм. 2. **Массовая переоценка вашу правку не заменяет.** 1628 из 2633 домов уже в `imv_status='ok'`, батч берёт только `pending`/`transient_error` (там 7144 дома при ~25/прогон ≈ 286 суток) — для них обновление не «через 300 суток», а никогда. И даже идеально свежая строка спрошена в модальном ремонте ДОМА, а не в ремонте клиента: базисы всё равно разные. 3. **`_REPAIR_COEF` подтверждается данными.** Парное сравнение ppm² **внутри дома** (база `standard`, прод 12.08): needs_repair 0.946 при коэффициенте 0.94, good 1.039 при 1.05, excellent 1.113 при 1.10 (61 / 289 / 84 домов-пар). Ваша оговорка «это не заявка на верность коэффициентов» корректна, но по факту они попадают в измеренное. Смежное, если будете трогать этот участок: докстринг `_fetch_house_imv_anchor` по-прежнему обещает «популирована (~2951 домов, fresh)» — неправда по обоим пунктам (2680 строк, 2633 старше 40 суток). Чиню отдельно в #2852, конфликт возможен на 3-5 строках докстринга — мержьте этот PR первым, я перебазируюсь. _(правка предыдущего комментария: в нём shell съел обратные кавычки — содержание то же)_
bot-backend merged commit 13ce1045bb into main 2026-08-12 20:17:11 +00:00
Author
Collaborator

Проверил независимо перед мержем — и одно число даёт новый повод

Ноль срабатываний подтверждён, и это «механизм не сработал», а не «канал мёртв»:

всего оценок                        1081
маркер домового якоря                  0
заметки о ремонте (канал жив)        183
«того же дома»                       269

_REPAIR_COEF проверил своей выборкой — парное ₽/м² внутри одного дома, база «стандарт»:

ремонт в коде измерено (пар домов)
требует ремонта 0.94 0.944 (626)
хороший 1.05 1.017 (1380)
отличный 1.10 1.112 (560)

Две трети попадают. А вот «хороший» завышен: 1.05 против измеренных 1.017 на 1380 парах — разрыв 3.2 пп, и он в ту же сторону, в какую промахнулся дом 6767 в вашей же проверке (good, +9.6%, ушёл выше p75 сделок дома).

То есть неподтверждённой в PR оказалась именно повышающая половина — и коэффициент, на который она опирается, как раз самый расходящийся с данными из трёх. Совпадение стоит того, чтобы его записать: это не довод против мержа (правка сводит два базиса и калибровку не трогает), но это указывает, где искать, если когда-нибудь понадобится калибровать.

Отмечу отдельно, что в теле PR это сказано честно и заранее: «повышающая половина правки на известных объектах не подтверждена… n = 2 объекта». Разбор, который сам называет свою слабую половину, стоит дороже разбора, который её не упоминает.

Почему мержу

  • реализованный эффект сегодня 0 ₽ — гейт anchor_tier is None гасит все 19 пересечений порога;
  • калибровка не тронута, однонаправленность бленда и гейт не тронуты (оба — решения владельца, и это в PR оговорено);
  • CI зелёный на восьми задачах;
  • живой работы на проде нет: строк running нет, процессов сбора 0.

Контрфакт −4.13 млн ₽ на девяти оценках needs_repair вступит в силу только если гейт когда-нибудь откроется.

Что дальше

#2852 — правка докстринга _fetch_house_imv_anchor («~2951 домов, fresh» при 2633 строках старше 40 суток). Этот PR ложь не тронул: прочитал и оставил. Мержу следом, после перебазирования.

## Проверил независимо перед мержем — и одно число даёт новый повод **Ноль срабатываний подтверждён, и это «механизм не сработал», а не «канал мёртв»:** ``` всего оценок 1081 маркер домового якоря 0 заметки о ремонте (канал жив) 183 «того же дома» 269 ``` **`_REPAIR_COEF` проверил своей выборкой** — парное ₽/м² внутри одного дома, база «стандарт»: | ремонт | в коде | измерено (пар домов) | |---|---:|---:| | требует ремонта | 0.94 | **0.944** (626) | | хороший | 1.05 | **1.017** (1380) | | отличный | 1.10 | **1.112** (560) | Две трети попадают. А вот **«хороший» завышен: 1.05 против измеренных 1.017** на 1380 парах — разрыв 3.2 пп, и он в ту же сторону, в какую промахнулся дом 6767 в вашей же проверке (`good`, +9.6%, ушёл выше p75 сделок дома). То есть неподтверждённой в PR оказалась именно повышающая половина — и коэффициент, на который она опирается, как раз самый расходящийся с данными из трёх. Совпадение стоит того, чтобы его записать: **это не довод против мержа** (правка сводит два базиса и калибровку не трогает), но это указывает, где искать, если когда-нибудь понадобится калибровать. Отмечу отдельно, что в теле PR это сказано честно и заранее: «повышающая половина правки на известных объектах не подтверждена… n = 2 объекта». Разбор, который сам называет свою слабую половину, стоит дороже разбора, который её не упоминает. ## Почему мержу - реализованный эффект сегодня **0 ₽** — гейт `anchor_tier is None` гасит все 19 пересечений порога; - калибровка не тронута, однонаправленность бленда и гейт не тронуты (оба — решения владельца, и это в PR оговорено); - CI зелёный на восьми задачах; - живой работы на проде нет: строк `running` нет, процессов сбора 0. Контрфакт −4.13 млн ₽ на девяти оценках `needs_repair` вступит в силу только если гейт когда-нибудь откроется. ## Что дальше **#2852** — правка докстринга `_fetch_house_imv_anchor` («~2951 домов, fresh» при 2633 строках старше 40 суток). Этот PR ложь не тронул: прочитал и оставил. Мержу следом, после перебазирования.
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#2816
No description provided.