feat(tradein/estimator): manual_review recommendation flag (#2002) #2019

Merged
lekss361 merged 1 commit from feat/tradein-manual-review into main 2026-06-27 18:17:24 +00:00
Owner

Summary

Recommends a human valuation (no auto-offer) when the auto-estimate is risky — closes the identification→action loop (#2002 #4). Consumes the shipped premium_building flag (#2006) + value/confidence/range signals. Metadata only — no pricing change (regression baseline byte-identical).

estimate_quality computes manual_review_recommended: bool + manual_review_reasons: list[str] via a pure helper, triggered (when estimate_manual_review_enabled) by any of:

  • premium_building → "премиальный дом — премия зависит от отделки/вида (не в данных сделок)"
  • expected_sold_price ≥ 20M₽ (estimate_manual_review_high_value_rub) → "высокая стоимость"
  • confidence == "low" → "низкая уверенность оценки"
  • asking-IQR range_high/range_low ≥ 1.9 (estimate_manual_review_wide_range_ratio) → "широкий диапазон цены"

Exposed on AggregatedEstimate (manual_review_recommended, manual_review_reasons), defaults False/[].

Design note (reviewer-relevant): the wide-range trigger reads the asking-IQR range_*_rub, NOT expected_sold_range_* — the calibrated PI band is a fixed ×[0.649,1.392] (ratio ≈2.14 ≥ 1.9) so it would fire on nearly every estimate; the asking-IQR reflects real comp dispersion.

Test plan

  • regression gate byte-identical (pure flag, pricing untouched)
  • tests/test_estimator_manual_review.py — 16 tests (each trigger isolated, 4-reason combined, all-clear, threshold boundaries, div-guard ×4, disabled-flag, recommended == bool(reasons) invariant, serialization)
  • full suite 2574 passed / 2 skipped (1 pre-existing unrelated test_search_cache_hit)
  • ruff strict clean

Follow-up (#2002)

Frontend surfaces manual_review_recommended + reasons (banner / disable auto-offer); premium-building curation (class labels + false-positive demotion) enriches the premium_building input.

Refs #2002

## Summary Recommends a **human valuation** (no auto-offer) when the auto-estimate is risky — closes the identification→action loop (#2002 #4). Consumes the shipped `premium_building` flag (#2006) + value/confidence/range signals. **Metadata only — no pricing change** (regression baseline byte-identical). `estimate_quality` computes `manual_review_recommended: bool` + `manual_review_reasons: list[str]` via a pure helper, triggered (when `estimate_manual_review_enabled`) by any of: - `premium_building` → "премиальный дом — премия зависит от отделки/вида (не в данных сделок)" - `expected_sold_price ≥ 20M₽` (`estimate_manual_review_high_value_rub`) → "высокая стоимость" - `confidence == "low"` → "низкая уверенность оценки" - asking-IQR `range_high/range_low ≥ 1.9` (`estimate_manual_review_wide_range_ratio`) → "широкий диапазон цены" Exposed on `AggregatedEstimate` (`manual_review_recommended`, `manual_review_reasons`), defaults `False`/`[]`. **Design note (reviewer-relevant):** the wide-range trigger reads the **asking-IQR** `range_*_rub`, NOT `expected_sold_range_*` — the calibrated PI band is a fixed ×[0.649,1.392] (ratio ≈2.14 ≥ 1.9) so it would fire on nearly every estimate; the asking-IQR reflects real comp dispersion. ## Test plan - [x] regression gate **byte-identical** (pure flag, pricing untouched) - [x] `tests/test_estimator_manual_review.py` — 16 tests (each trigger isolated, 4-reason combined, all-clear, threshold boundaries, div-guard ×4, disabled-flag, `recommended == bool(reasons)` invariant, serialization) - [x] full suite **2574 passed / 2 skipped** (1 pre-existing unrelated `test_search_cache_hit`) - [x] ruff strict clean ## Follow-up (#2002) Frontend surfaces `manual_review_recommended` + reasons (banner / disable auto-offer); premium-building curation (class labels + false-positive demotion) enriches the `premium_building` input. Refs #2002
lekss361 added 1 commit 2026-06-27 18:17:14 +00:00
feat(tradein/estimator): manual_review recommendation flag (#2002)
All checks were successful
CI / changes (pull_request) Successful in 8s
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
07834b59a1
Производный ФЛАГ manual_review_recommended + RU-причины: помечает оценки,
которые НЕ стоит авто-оффэрить (нужна ручная оценка человеком). Триггеры:
премиальный дом, высокая стоимость (>=20 млн), низкая уверенность,
широкий asking-диапазон (range_high/range_low >= 1.9). За флагом
estimate_manual_review_enabled.

Чисто метаданные — НЕ трогает median/expected_sold/ranges, regression-gate
остаётся byte-identical (зелёный). Pure helper _manual_review + unit-тесты.
lekss361 merged commit 275e7e9618 into main 2026-06-27 18:17:24 +00:00
lekss361 deleted branch feat/tradein-manual-review 2026-06-27 18:17:25 +00:00
lekss361 added the
priority/p2
scope/backend
tradein
labels 2026-06-27 18:17:25 +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#2019
No description provided.