fix(tradein): sync n_analogs to anchor count when anchor drives headline (#695) #739

Merged
bot-reviewer merged 1 commit from fix/695-n-analogs-anchor into main 2026-05-30 15:25:35 +00:00
2 changed files with 28 additions and 0 deletions
Showing only changes of commit d688d24a12 - Show all commits

View file

@ -1818,6 +1818,14 @@ async def estimate_quality(
f"Оценка построена по {anchor['n']} аналогам из {tier_label}"
f"{' (топ-уровень в доме)' if anchor['used_uplift'] else ''}."
) + repair_note
# #695 (QA fixup): когда якорь подменяет headline и список аналогов на
# комплы дома, n_analogs ДОЛЖЕН считаться по anchor-популяции, а не по
# радиусу (listings_clean). Иначе все UI-счётчики («Аналогов N»,
# «Показано N из M», «по N аналогам», гистограмма) расходятся: radius=4 vs
# anchor=5 → артефакт «Показано 5 из 4». anchor['n'] = число комплов, на
# которых построена оценка (= показываемый analogs, capped 10). Для anchor-
# пути это и есть «полное число найденных» по контракту n_analogs (#698).
n_analogs = anchor["n"]
# ── #651: IMV / Yandex BLEND (killer accuracy fix) — SECONDARY, Tier D only ──
# Радиусная медиана системно занижает премиум/видовые квартиры (нет class/

View file

@ -947,3 +947,23 @@ def test_explanation_radius_path_keeps_base_text() -> None:
exp = est.confidence_explanation or ""
assert "Найдено" in exp
assert "Оценка построена по" not in exp # якорной фразы нет на чистом радиусе
# ── #695 QA fixup: n_analogs синхронизируется с anchor-популяцией (radius≠anchor) ──
def test_anchor_n_analogs_syncs_to_anchor_count() -> None:
"""#695 QA-fail: anchor подменяет headline+список на комплы дома, но n_analogs
раньше оставался радиусным «Показано 5 из 4». radius=5 anchor=3 намеренно;
n_analogs ДОЛЖЕН стать 3 (anchor), согласуясь с «по 3 аналогам» в explanation."""
radius = [_make_listing(price_per_m2=200_000.0) for _ in range(5)]
est = _run_estimate(anchor_comps=_SB_COMPS_PREMIUM, anchor_tier="A", radius_analogs=radius)
assert est.n_analogs == 3 # = len(_SB_COMPS_PREMIUM), НЕ 5 (радиус)
assert "по 3 аналогам" in (est.confidence_explanation or "")
def test_radius_path_n_analogs_unchanged() -> None:
"""#695 контроль: без якоря n_analogs = радиусный счёт (поведение не меняется)."""
radius = [_make_listing(price_per_m2=200_000.0) for _ in range(5)]
est = _run_estimate(anchor_comps=[], anchor_tier=None, radius_analogs=radius)
assert est.n_analogs == 5