docs(tradein/estimator): докстринг домового IMV-якоря говорит правду о таблице (#2674) #2852

Merged
bot-backend merged 1 commit from fix/house-imv-anchor-era into main 2026-08-12 20:29:29 +00:00
Collaborator

Что это

Докстринг-фикс, один файл, исполняемого кода не касается. Перебазирован на origin/main уже с влитым #2816.

Изначально в этой ветке была своя правка базиса ремонта — оказалась дублем открытого тогда #2816, снята. Осталось то, чего не сделал ни один PR.

Что чинится

_fetch_house_imv_anchor обещал: «house_imv_evaluations популирована (~2951 домов, fresh)». Неправда по обоим пунктам. Утверждение пережило #2816: тот дописал ниже блок про renovation_type, а ложь строкой выше прочитал и оставил — ровно тот сценарий, ради которого докстринги и правят отдельно.

Замер 2026-08-12, прод:

строк 2680, по одной на дом (UNIQUE(house_id)ORDER BY в запросе выбирает из ≤1 кандидата, а не ранжирует)
старше 40 суток 2633 (98.2%), из них 2366 — один прогон 24.05
свежих (после фикса параметров 06.08) 47
ремонт: литерал 'cosmetic' vs мода по объявлениям дома совпал 972 (36.9%) · разошёлся 1217 (46.2%) · моды нет 444
тип дома vs houses.house_type верно 901 · неверно 74 (46 раз «панель» вместо «монолита») · неизвестно 1658

Два решения, отвергнутые замером — записаны, чтобы не предлагали заново

Гейт эры/свежести. Band-совместимая строка есть у 224 оценок из 1081, и все 224 дореформенные. Свежих 47 не хватает ни на одну. Гейт не отсёк бы плохое, а выключил бы механизм.

Массовая переоценка. 1628 из 2633 домов уже в imv_status='ok', батч берёт только pending/transient_error — для них обновление не «через 300 суток», а никогда; впереди 7144 дома при ~25/прогон ≈ 286 суток. И корень не в свежести: строка, спрошенная в модальном ремонте ДОМА, всё равно не в базисе ремонта клиента — это #2677/#2816.

Test plan

  • pytest tests/ на перебазированной ветке — 4327 passed, 21 skipped
  • test_2677_house_anchor_repair_basis.py + test_estimator_imv_blend.py + test_backtest_regression_gate.py — 24 passed
  • CI зелёный на d823ba10; ruff check чисто
  • пульс перед мержем: scrape_runs status='running' — 0 строк, процессов скрейпера 0

Refs #2674, #2677

## Что это Докстринг-фикс, один файл, исполняемого кода не касается. Перебазирован на `origin/main` уже с влитым #2816. Изначально в этой ветке была своя правка базиса ремонта — оказалась дублем открытого тогда **#2816**, снята. Осталось то, чего не сделал ни один PR. ## Что чинится `_fetch_house_imv_anchor` обещал: «`house_imv_evaluations` популирована (~2951 домов, **fresh**)». Неправда по обоим пунктам. Утверждение **пережило #2816**: тот дописал ниже блок про `renovation_type`, а ложь строкой выше прочитал и оставил — ровно тот сценарий, ради которого докстринги и правят отдельно. Замер 2026-08-12, прод: | | | |---|---| | строк | 2680, по одной на дом (`UNIQUE(house_id)` → `ORDER BY` в запросе выбирает из ≤1 кандидата, а не ранжирует) | | старше 40 суток | **2633 (98.2%)**, из них 2366 — один прогон 24.05 | | свежих (после фикса параметров 06.08) | **47** | | ремонт: литерал `'cosmetic'` vs мода по объявлениям дома | совпал 972 (36.9%) · разошёлся 1217 (46.2%) · моды нет 444 | | тип дома vs `houses.house_type` | верно 901 · **неверно 74** (46 раз «панель» вместо «монолита») · неизвестно 1658 | ## Два решения, отвергнутые замером — записаны, чтобы не предлагали заново **Гейт эры/свежести.** Band-совместимая строка есть у **224** оценок из 1081, и **все 224 дореформенные**. Свежих 47 не хватает ни на одну. Гейт не отсёк бы плохое, а выключил бы механизм. **Массовая переоценка.** 1628 из 2633 домов уже в `imv_status='ok'`, батч берёт только `pending`/`transient_error` — для них обновление не «через 300 суток», а никогда; впереди 7144 дома при ~25/прогон ≈ 286 суток. И корень не в свежести: строка, спрошенная в модальном ремонте ДОМА, всё равно не в базисе ремонта клиента — это #2677/#2816. ## Test plan - [x] `pytest tests/` на перебазированной ветке — **4327 passed, 21 skipped** - [x] `test_2677_house_anchor_repair_basis.py` + `test_estimator_imv_blend.py` + `test_backtest_regression_gate.py` — 24 passed - [x] CI зелёный на `d823ba10`; `ruff check` чисто - [x] пульс перед мержем: `scrape_runs status='running'` — 0 строк, процессов скрейпера 0 Refs #2674, #2677
bot-backend added 1 commit 2026-08-12 20:05:24 +00:00
fix(tradein/estimator): домовой IMV-якорь и медиана сравниваются в одной базе ремонта (#2674)
All checks were successful
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 4m29s
CI Trade-In / changes (pull_request) Successful in 12s
CI / changes (pull_request) Successful in 13s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
81980da4d4
Порог блендa `anchor > median × 1.15` сравнивал два числа в РАЗНЫХ базах.
`median_price` к этому моменту уже умножена на `_repair_coefficient(repair_state)`
(блок 4b), то есть описывает квартиру С РЕМОНТОМ ЦЕЛИ. Якорь — цена квартиры в том
классе отделки, в котором строку спросили у Авито: 2633 из 2680 строк
house_imv_evaluations спрошены с литералом renovation_type='cosmetic' (до фикса
параметров 06.08), свежие 47 — в модальном ремонте ДОМА. Ни то, ни другое не есть
ремонт цели.

Знак ошибки детерминирован ремонтом цели, и это видно на проде (1081 оценка,
из них 127 Tier-D с band-совместимым якорем):
  - цель needs_repair: медиана ×0.94, якорь нет → порог берётся «на халяву».
    6 из 14 живых блендов — такие; 5 из 6 после приведения к общей базе исчезают.
  - цель good/excellent (23 оценки): медиана ×1.05/×1.10 → порог недостижим,
    бленд не срабатывал НИ РАЗУ.

Множитель — отношение уже существующих `_REPAIR_COEF`, обратное отображение
вокабуляра Авито — существующий `_IMV_REPAIR_MAP`. Второй таблицы не заводим.
Незнакомый/пустой класс с любой стороны → 1.0 (прежнее поведение). Сводка
AvitoImvSummary продолжает показывать СЫРУЮ цифру Авито — она так и подписана.

`_REPAIR_COEF` проверен данными (прод 2026-08-12, парное сравнение ppm² ВНУТРИ
дома, база standard): needs_repair 0.946 при коэффициенте 0.94, good 1.039 при
1.05, excellent 1.113 при 1.10 (61/289/84 домов-пар) — эвристика попадает
в измеренное, отдельный множитель не нужен.

Гейт «не брать дореформенные строки» рассмотрен и ОТКЛОНЁН замером: он снимает
якорь у 224 оценок из 224 (все 224 сидят на дореформенных строках), чтобы убрать
5 ложных срабатываний — 14 блендов и +16.6 млн ₽ коррекции превращаются в 0.
Массовая переоценка тоже не чинит дефект: даже при идеально свежих строках,
спрошенных в модальном ремонте дома, бленд у целей good/excellent срабатывает
2 раза из 23 вместо 0 — база всё равно не та.

Докстринг `_fetch_house_imv_anchor` обещал «~2951 домов, fresh» — неправда по
обоим пунктам. Заменён на замер с датой: 2680 строк, 2633 (98.2%) старше 40 суток,
2366 — один прогон 24.05; естественное обновление их не чинит, потому что 1628 из
2633 домов уже в imv_status='ok', а батч выбирает pending/transient_error, где
сейчас 7144 дома при темпе ~25/прогон.

Тесты двусторонние: на origin/main цель excellent даёт 6 600 000 вместо 7 425 000
(бленд подавлен), цель needs_repair — 6 120 000 вместо 5 640 000 (ложный бленд).

Refs #2674
Light1YT added 1 commit 2026-08-12 20:09:18 +00:00
docs(tradein/estimator): докстринг якоря говорит правду о таблице, а код-фикс отдан #2816 (#2674)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 10s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 4m21s
CI Trade-In / browser-tests (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
95e3b209ce
Правка ремонта якоря, добавленная первым коммитом ветки, — дубль уже открытого
PR #2816 (`_anchor_repair_factor`, #2677, открыт 10.08, mergeable). Свой код снят,
чтобы не мержить одно и то же дважды; независимая перепроверка чисел #2816 —
в описании PR.

Остаётся то, чего не чинит ни один открытый PR: докстринг `_fetch_house_imv_anchor`
обещал «house_imv_evaluations популирована (~2951 домов, fresh)». Неправда по обоим
пунктам, и #2816 её тоже не тронул — прочитал и оставил. Заменено на замер с датой:
2680 строк, 2633 (98.2%) старше 40 суток, 2366 — один прогон 24.05, свежих 47;
дореформенные спрошены с литералом renovation_type='cosmetic' (мода дома совпала
у 972, разошлась у 1217) и с дефолтом house_type='panel' (тип разошёлся у 74).

Плюс записаны два отвергнутых замером решения, чтобы их не предлагали заново:
гейт эры снимает якорь у 224 оценок из 224 (все band-совместимые строки на проде —
дореформенные), массовая переоценка упирается в 1628 домов уже в imv_status='ok'
при очереди 7144 и темпе ~25/прогон, и корень всё равно не в свежести.

Refs #2674, #2677
bot-backend changed title from fix(tradein/estimator): домовой IMV-якорь и медиана — в одной базе ремонта (#2674) to docs(tradein/estimator): докстринг домового IMV-якоря говорит правду о таблице (#2674) 2026-08-12 20:09:52 +00:00
Light1YT force-pushed fix/house-imv-anchor-era from 95e3b209ce to d823ba10c1 2026-08-12 20:21:51 +00:00 Compare
bot-backend merged commit bcc4f2c29e into main 2026-08-12 20:29:29 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 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#2852
No description provided.