source_url записывается только при вставке — колонка не способна залечиться сама (решение не очевидно, поэтому не чинил) #2842

Open
opened 2026-08-12 15:46:16 +00:00 by bot-backend · 1 comment
Collaborator

Побочная находка из #2838 / #2840. Живого дефекта сегодня нет — завожу не для срочной правки, а чтобы рассуждение не пропало: оно стоило разбора двум агентам, а решение неочевидно и требует выбора.

Механизм

listings.source_url пишется только при вставке. Его нет:

  • в ON CONFLICT DO UPDATE (packages/scraper-kit/src/scraper_kit/base.py),
  • в reconcile-UPDATE там же.

Следствие: если продюсер однажды запишет неверный адрес, повторные встречи того же объявления его не исправят, сколько бы раз свип его ни переобошёл.

Чем это уже стоило

Ровно так и вышло. Починка продюсера (#2235) вылечила только новые строки. Миграция 164 вылечила только те легаси-строки, чей адрес делили несколько строк — она искала дубли URL, а не непарсимые адреса. Строки с уникальной ссылкой на карточку застройщика не попали никуда и прожили так до 12.08:

3535 объявлений Яндекса вели на сайты застройщиков
     (macroserver.ru 912, macro.sbercrm.com 440, akademicheskiy.org 356,
      na100.pro 331, strana.com 318, ten-stroy.ru 189, хвост из 25)
из них живых (is_active)                        3522
свип переобошёл 511 из них 11.08 — и не починил
второй потребитель (yandex_address_backfill)    1777 из 5545 ходили не туда

При этом строки были обогатимы всё время: у всех 3535 в source_id лежал числовой offerId, живая проба боевым трактом дала 6 из 6 → HTTP 200 и разбор успешен. Их просто тянули по неверному адресу, а счётчик честно показывал «обогащено 0» и назывался unenrichable_pending — замер верный, ярлык неверный.

Вылечено миграцией 257 (#2840): непарсимых 0 из 17 970, у второго потребителя 0 из 1777. Но вылечено разово.

Почему я не стал чинить

Очевидная правка — добавить source_url в ON CONFLICT DO UPDATEможет быть вредна. Тогда каждая новая встреча объявления перетирала бы адрес, и худшее наблюдение победило бы лучшее: сегодня канонический адрес защищён именно тем, что его не трогают. Это ровно тот случай, где «сделать колонку обновляемой» и «сделать колонку правильной» — разные вещи.

Варианты, между которыми надо выбрать:

  1. Оставить как есть, лечить миграциями по мере обнаружения — дёшево, но каждый следующий случай проживёт месяцами, потому что признака у него нет.
  2. Обновлять по условию: перезаписывать, только если новый адрес канонический, а старый нет. Монотонно, перетирания хорошего плохим не будет.
  3. Сторож вместо правки: регулярно считать долю непарсимых адресов по каждому источнику и показывать её. Не чинит, но лишает дефект возможности прожить незамеченным.

Мой голос за 2 + 3: второе делает колонку самолечащейся без риска деградации, третье закрывает остальные источники, где такой же дефект пока просто не искали.

Что стоит проверить до выбора

Это рассуждение проверено только на Яндексе. У Авито, Циана и Домклика та же вставка и тот же reconcile — доля непарсимых адресов у них не измерялась ни разу. Прежде чем чинить, стоит спросить у прода то же самое по каждому источнику: ноль там будет означать «неприменимо», а не «проверено».

Связано: #2838 (очередь научилась адресовать по source_id), #2840 (разовое лечение колонки + таблица отката yandex_source_url_backfill_257), #2674 (эпик «код есть, срабатываний нет»).

Побочная находка из #2838 / #2840. **Живого дефекта сегодня нет** — завожу не для срочной правки, а чтобы рассуждение не пропало: оно стоило разбора двум агентам, а решение неочевидно и требует выбора. ## Механизм `listings.source_url` пишется **только при вставке**. Его нет: - в `ON CONFLICT DO UPDATE` (`packages/scraper-kit/src/scraper_kit/base.py`), - в reconcile-UPDATE там же. Следствие: если продюсер однажды запишет неверный адрес, повторные встречи того же объявления его **не исправят**, сколько бы раз свип его ни переобошёл. ## Чем это уже стоило Ровно так и вышло. Починка продюсера (#2235) вылечила только новые строки. Миграция 164 вылечила только те легаси-строки, чей адрес **делили** несколько строк — она искала дубли URL, а не непарсимые адреса. Строки с уникальной ссылкой на карточку застройщика не попали никуда и прожили так до 12.08: ``` 3535 объявлений Яндекса вели на сайты застройщиков (macroserver.ru 912, macro.sbercrm.com 440, akademicheskiy.org 356, na100.pro 331, strana.com 318, ten-stroy.ru 189, хвост из 25) из них живых (is_active) 3522 свип переобошёл 511 из них 11.08 — и не починил второй потребитель (yandex_address_backfill) 1777 из 5545 ходили не туда ``` При этом строки были **обогатимы всё время**: у всех 3535 в `source_id` лежал числовой offerId, живая проба боевым трактом дала 6 из 6 → HTTP 200 и разбор успешен. Их просто тянули по неверному адресу, а счётчик честно показывал «обогащено 0» и назывался `unenrichable_pending` — замер верный, ярлык неверный. Вылечено миграцией 257 (#2840): непарсимых 0 из 17 970, у второго потребителя 0 из 1777. Но вылечено **разово**. ## Почему я не стал чинить Очевидная правка — добавить `source_url` в `ON CONFLICT DO UPDATE` — **может быть вредна**. Тогда каждая новая встреча объявления перетирала бы адрес, и худшее наблюдение победило бы лучшее: сегодня канонический адрес защищён именно тем, что его не трогают. Это ровно тот случай, где «сделать колонку обновляемой» и «сделать колонку правильной» — разные вещи. Варианты, между которыми надо выбрать: 1. Оставить как есть, лечить миграциями по мере обнаружения — дёшево, но каждый следующий случай проживёт месяцами, потому что признака у него нет. 2. Обновлять по условию: перезаписывать, только если новый адрес канонический, а старый нет. Монотонно, перетирания хорошего плохим не будет. 3. Сторож вместо правки: регулярно считать долю непарсимых адресов по каждому источнику и показывать её. Не чинит, но лишает дефект возможности прожить незамеченным. Мой голос за **2 + 3**: второе делает колонку самолечащейся без риска деградации, третье закрывает остальные источники, где такой же дефект пока просто не искали. ## Что стоит проверить до выбора Это рассуждение проверено **только на Яндексе**. У Авито, Циана и Домклика та же вставка и тот же reconcile — доля непарсимых адресов у них не измерялась ни разу. Прежде чем чинить, стоит спросить у прода то же самое по каждому источнику: ноль там будет означать «неприменимо», а не «проверено». Связано: #2838 (очередь научилась адресовать по `source_id`), #2840 (разовое лечение колонки + таблица отката `yandex_source_url_backfill_257`), #2674 (эпик «код есть, срабатываний нет»).
Author
Collaborator

Проверил остальные источники — дефекта у них нет

Выше я написал, что рассуждение проверено только на Яндексе и по остальным источникам надо спросить у прода. Спросил (12.08, после миграции 257):

источник объявлений ссылка ведёт на чужой домен без ссылки
avito 51 135 0 0
cian 22 901 0 0
yandex 17 970 0 0
domklik 6 779 0 0
n1 382 0 0

Природа этих нулей — «неприменимо», а не «заблокировано выше по потоку»: продюсеры остальных площадок собирают адрес из полей самой площадки, у них нет пути записать чужую ссылку. У Яндекса он был — карточка новостройки на выдаче ведёт на сайт застройщика, и продюсер брал её как есть.

Значит область дефекта — один источник, и он вылечен. Пункт 3 предложения (сторож по всем источникам) от этого ослабевает: сторожить нечего, кроме Яндекса, а у Яндекса продюсер починен ещё в #2235.

Остаётся пункт 2 — обновлять по условию «новый канонический, старый нет». Но и он теперь не срочный: без второго источника порчи колонке неоткуда испортиться.

Итог: чинить сейчас нечего. Задачу оставляю открытой как записанное рассуждение, а не как работу.

Отдельно: я чуть не завёл несуществующий дефект

Первый мой запрос показал у Домклика 6779 из 6779 «чужой домен». Это была опечатка в моём же запросе: источник в базе называется domklik, а домен у него domclick.ru — сопоставление по имени источника не сработало и свалилось в запасную ветку. Все 6779 ведут на ekaterinburg.domclick.ru и domclick.ru, то есть на свою площадку.

Чего это стоило бы: «100% объявлений Домклика ведут не туда» — число крупное, картинка правдоподобная (у Яндекса же нашлось), и следующий читатель пошёл бы чинить пустоту. Поймалось только тем, что 6779 из 6779 — слишком ровно для настоящей порчи: настоящая почти никогда не бывает поголовной.

Признак на будущее: доля ровно 0% или ровно 100% чаще означает дефект измерителя, чем измеряемого.

## Проверил остальные источники — дефекта у них нет Выше я написал, что рассуждение проверено только на Яндексе и по остальным источникам надо спросить у прода. Спросил (12.08, после миграции 257): | источник | объявлений | ссылка ведёт на чужой домен | без ссылки | |---|---:|---:|---:| | avito | 51 135 | **0** | 0 | | cian | 22 901 | **0** | 0 | | yandex | 17 970 | **0** | 0 | | domklik | 6 779 | **0** | 0 | | n1 | 382 | **0** | 0 | Природа этих нулей — **«неприменимо»**, а не «заблокировано выше по потоку»: продюсеры остальных площадок собирают адрес из полей самой площадки, у них нет пути записать чужую ссылку. У Яндекса он был — карточка новостройки на выдаче ведёт на сайт застройщика, и продюсер брал её как есть. Значит область дефекта — **один источник, и он вылечен**. Пункт 3 предложения (сторож по всем источникам) от этого ослабевает: сторожить нечего, кроме Яндекса, а у Яндекса продюсер починен ещё в #2235. Остаётся пункт 2 — обновлять по условию «новый канонический, старый нет». Но и он теперь не срочный: без второго источника порчи колонке неоткуда испортиться. **Итог: чинить сейчас нечего.** Задачу оставляю открытой как записанное рассуждение, а не как работу. ## Отдельно: я чуть не завёл несуществующий дефект Первый мой запрос показал у Домклика **6779 из 6779 «чужой домен»**. Это была опечатка в моём же запросе: источник в базе называется `domklik`, а домен у него `domclick.ru` — сопоставление по имени источника не сработало и свалилось в запасную ветку. Все 6779 ведут на `ekaterinburg.domclick.ru` и `domclick.ru`, то есть на свою площадку. Чего это стоило бы: «100% объявлений Домклика ведут не туда» — число крупное, картинка правдоподобная (у Яндекса же нашлось), и следующий читатель пошёл бы чинить пустоту. Поймалось только тем, что 6779 из 6779 — слишком ровно для настоящей порчи: настоящая почти никогда не бывает поголовной. **Признак на будущее:** доля ровно 0% или ровно 100% чаще означает дефект измерителя, чем измеряемого.
lekss361 added the
needs-discussion
priority/p3
scope/backend
scrapers
tech-debt
tradein
labels 2026-08-16 10:25:23 +00:00
Sign in to join this conversation.
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#2842
No description provided.