fix(estimator): anchor low-confidence gate (#audit-1)
Якорь с confidence=low ИЛИ (n<gate_min_n И FSD>gate_max_fsd) не заменяет headline — fallback на radius-median. Дефолты (min_n=3, max_fsd=0.20) не режут здоровые якоря (n≥4, FSD<0.15 проходят). За флагом estimate_sb_low_conf_gate_enabled (дефолт True). Логируется с причиной.
This commit is contained in:
parent
a425f2f200
commit
55c7bc2c72
2 changed files with 51 additions and 0 deletions
|
|
@ -134,6 +134,35 @@ class Settings(BaseSettings):
|
|||
asking_to_sold_haircut: float = 0.05 # дефолтная asking→sold скидка (banded по ppm²)
|
||||
estimate_fsd_k: float = 1.65 # множитель FSD → полуширина диапазона
|
||||
|
||||
# ── #audit-1: anchor low-confidence gate ─────────────────────────────────
|
||||
# Якорь с низкой уверенностью (confidence="low" ИЛИ n < min_n И FSD > max_fsd)
|
||||
# НЕ заменяет headline — fallback на radius-median. Дефолты подобраны так, что
|
||||
# здоровые якоря (n≥4 с FSD<0.15) проходят без изменений.
|
||||
# estimate_sb_gate_min_n=3 : при n<3 И FSD>max_fsd гейт срабатывает
|
||||
# estimate_sb_gate_max_fsd=0.20: FSD>0.20 при малом n → ненадёжный якорь
|
||||
# Отдельный флаг: False → точно старое поведение (гейта нет).
|
||||
estimate_sb_low_conf_gate_enabled: bool = True
|
||||
estimate_sb_gate_min_n: int = 3
|
||||
estimate_sb_gate_max_fsd: float = 0.20
|
||||
|
||||
# ── #audit-3: price_trend freshness filter ────────────────────────────────
|
||||
# Исключать items старше N месяцев из price_trend (house_placement_history).
|
||||
# Дефолт 6 (консервативно); аудит предложил 3 — конфигурируемо.
|
||||
estimate_price_trend_max_age_months: int = 6
|
||||
|
||||
# ── #audit-4: MAD-clip after similarity-weighting ─────────────────────────
|
||||
# True = clip происходит ПОСЛЕ similarity-weighting (на взвешенных ppm²).
|
||||
# False = clip ДО weighting (старое поведение). Дефолт True.
|
||||
estimate_sb_clip_after_weight: bool = True
|
||||
|
||||
# ── #audit-5: data-age guards ─────────────────────────────────────────────
|
||||
# sber_index_max_age_days: максимальный допустимый возраст последнего месяца
|
||||
# СберИндекс-серии (дней). Если latest месяц старее — логируем warning.
|
||||
sber_index_max_age_days: int = 35
|
||||
# avito_imv_thin_market_threshold: если market_count < порога — IMV-оценка
|
||||
# на тонком рынке (thin_market=True в AvitoImvSummary) + warning.
|
||||
avito_imv_thin_market_threshold: int = 10
|
||||
|
||||
# ── #764: per-cadastral-quarter price index correction ───────────────────
|
||||
# Gap-correction: квартальный индекс применяется ТОЛЬКО в pure-radius пути
|
||||
# (когда same-building anchor и IMV-blend не сработали). Корректирует РАЗРЫВ
|
||||
|
|
|
|||
|
|
@ -2321,6 +2321,28 @@ async def estimate_quality(
|
|||
int(gate_threshold),
|
||||
)
|
||||
anchor = None
|
||||
# #audit-1: low-confidence gate — якорь с низкой уверенностью или малым n
|
||||
# при высоком FSD НЕ заменяет headline; fallback на radius-median.
|
||||
# Tier A (n≥4, FSD<0.15) проходит без изменений при дефолтных порогах.
|
||||
if anchor is not None and settings.estimate_sb_low_conf_gate_enabled:
|
||||
gate_low = anchor["confidence"] == "low"
|
||||
gate_thin = (
|
||||
anchor["n"] < settings.estimate_sb_gate_min_n
|
||||
and anchor["fsd"] > settings.estimate_sb_gate_max_fsd
|
||||
)
|
||||
if gate_low or gate_thin:
|
||||
logger.info(
|
||||
"sb_anchor low-conf gate #audit-1: tier=%s n=%d fsd=%.3f conf=%s"
|
||||
" → suppressed (gate_low=%s gate_thin=%s) → radius fallback",
|
||||
anchor_tier,
|
||||
anchor["n"],
|
||||
anchor["fsd"],
|
||||
anchor["confidence"],
|
||||
gate_low,
|
||||
gate_thin,
|
||||
)
|
||||
anchor = None
|
||||
anchor_tier = None
|
||||
if anchor is not None:
|
||||
# #694: якорь мутирует headline — UI-аналоги должны отражать ЭТИ комплы.
|
||||
anchor_comps_used = comps
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue