fix(tradein/estimator): сузить bare-street ветку до 3-сегментного district-chain паттерна (#2291)
All checks were successful
CI / changes (pull_request) Successful in 8s
CI Trade-In / changes (pull_request) Successful in 8s
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 1m0s
All checks were successful
CI / changes (pull_request) Successful in 8s
CI Trade-In / changes (pull_request) Successful in 8s
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 1m0s
Deep-review нашёл over-merge риск: bare-street ветка фабриковала уличный токен на голых
2-сегментных адресах без mkr/район-контекста ("ВИЗ, 24" и т.п.) — теперь требует явный
mkr-маркер в более раннем сегменте, ограничивая ветку заявленным 3-сегментным паттерном.
This commit is contained in:
parent
859d4fa317
commit
0de77690e9
2 changed files with 42 additions and 2 deletions
|
|
@ -4987,7 +4987,7 @@ _DEDUP_STREET_TYPE_WORDS_SET = frozenset(_DEDUP_STREET_TYPE_WORDS)
|
|||
|
||||
|
||||
def _bare_street_before_house_segment(s: str) -> tuple[str, str] | None:
|
||||
"""Bare-street ветка (#2291, класс 1): «<имя>, <номер>» без типа/мкр-слова.
|
||||
"""Bare-street ветка (#2291, класс 1): «<мкр-сегмент>, <имя>, <номер>».
|
||||
|
||||
Root cause: `_DEDUP_MKR_SUFFIX_RE` матчит «<имя> м-н/мкр» ГДЕ УГОДНО в
|
||||
строке. Для DomClick-формата «Заречный м-н, Готвальда, 24» — голая улица
|
||||
|
|
@ -4999,6 +4999,17 @@ def _bare_street_before_house_segment(s: str) -> tuple[str, str] | None:
|
|||
Разбивает адрес по запятым; ищет ПЕРВЫЙ сегмент, ЦЕЛИКОМ совпадающий с
|
||||
`_DEDUP_HOUSE_NO_RE` (номер дома). Сегмент НЕПОСРЕДСТВЕННО перед ним — 1-3
|
||||
слова, без мкр-слова/уличного типа/шум-токена — кандидат в bare-улицу.
|
||||
|
||||
#2291 over-merge guard (deep-review, blocking): ветка активируется ТОЛЬКО
|
||||
для 3+ сегментного district-chain паттерна — обязателен ЕЩЁ более ранний
|
||||
сегмент (до кандидата-улицы), который сам содержит мкр/район-слово
|
||||
(`_DEDUP_MKR_WORDS`). Без этого условия голые 2-сегментные адреса без
|
||||
какого-либо mkr-контекста («ВИЗ, 24», «Академический, 24», «ЖК Некий,
|
||||
24» — частый неформальный ЕКБ-шорткат в объявлениях) фабриковали бы
|
||||
уличный токен из названия района/ЖК и рисковали ложным cross-merge двух
|
||||
РАЗНЫХ физлотов. Такие адреса должны вернуть None (решают ветки 1/2/3;
|
||||
итог — безопасный `("", "")`, как и до всей этой ветки).
|
||||
|
||||
Не найдено/не подходит → None (решают ветки 1/2/3, в частности mkr-fallback
|
||||
для «мкр Пионерский, 5», где сегмент перед номером содержит мкр-слово).
|
||||
"""
|
||||
|
|
@ -5010,7 +5021,16 @@ def _bare_street_before_house_segment(s: str) -> tuple[str, str] | None:
|
|||
hm = _DEDUP_HOUSE_NO_RE.fullmatch(house_seg)
|
||||
if hm is None:
|
||||
continue
|
||||
raw_words = segments[idx - 1].strip().split()
|
||||
street_idx = idx - 1
|
||||
earlier_segments = segments[:street_idx]
|
||||
if not earlier_segments or not any(
|
||||
any(w in _DEDUP_MKR_WORDS for w in seg.strip().split()) for seg in earlier_segments
|
||||
):
|
||||
# Нет более раннего сегмента с mkr/район-словом → это не заявленный
|
||||
# 3-сегментный district-chain, а голый 2-сегментный адрес — не
|
||||
# фабрикуем уличный токен, отдаём другим веткам (итог — "", "").
|
||||
continue
|
||||
raw_words = segments[street_idx].strip().split()
|
||||
if not raw_words or len(raw_words) > 3:
|
||||
continue
|
||||
if any(
|
||||
|
|
|
|||
|
|
@ -569,6 +569,26 @@ def test_parse_street_house_bare_street_regression_guards() -> None:
|
|||
assert estimator._parse_street_house("мкр. ЖБИ, улица Сыромолотова") == ("сыромолотова", "")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"addr",
|
||||
[
|
||||
# Deep-review over-merge risk (#2291): голый 2-сегментный адрес БЕЗ
|
||||
# какого-либо mkr/район-контекста — частый неформальный ЕКБ-шорткат в
|
||||
# объявлениях (район/ЖК + номер дома, без слова «улица»/«мкр»/«м-н»).
|
||||
# Bare-street ветка НЕ должна фабриковать уличный токен из района/ЖК —
|
||||
# нет более раннего сегмента с mkr-словом → должно остаться ("", "").
|
||||
"ВИЗ, 24",
|
||||
"Академический, 24",
|
||||
"ЖК Некий, 24",
|
||||
],
|
||||
)
|
||||
def test_parse_street_house_bare_street_requires_earlier_mkr_segment(addr: str) -> None:
|
||||
# Тот же bare-2-сегментный паттерн, что у целевого кейса («<имя>, <номер>»),
|
||||
# но БЕЗ более раннего mkr-сегмента — ветка должна самоограничиться и
|
||||
# вернуть безопасный ("", ""), а не сфабрикованный уличный токен.
|
||||
assert estimator._parse_street_house(addr) == ("", "")
|
||||
|
||||
|
||||
def test_dedup_collapses_domclick_bare_street_mkr_misfire(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
# Класс 1 (#2291) e2e: DomClick «Заречный м-н, Готвальда, 24» раньше
|
||||
# ключевался по району и никогда не сливался с avito/cian, где «готвальда»
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue