Из девяти вызовов save_listings в pipeline.py три не передавали run_id.
У двух — run_avito_city_sweep:1113 и run_avito_newbuilding_sweep:1754 —
run_id лежал в той же функции (keyword-параметр, под которым идёт
runs.mark_done/heartbeat/is_cancelled) и просто не доезжал до вызова.
Передан.
run_avito_pipeline:570 — оставлен без run_id осознанно, решение записано
в код: у функции нет строки в scrape_runs, продуктовых вызывающих нет
(единственные — тесты), привязывать снимок не к чему.
Писатели вне pipeline.py проверены и тоже помечены: admin /scrape (ручной
скрейп без прогона) и scripts/ingest_domclick_jsonl.py (разовый ingest
файла). Второй и есть главная дыра замера — 129 908 снимков domklik без
run_id, а вовсе не Авито: по источникам заполнение yandex 100%, cian 98.8%,
avito 80.3%, domklik 2.9%. Дыра domklik историческая (ежедневный
run_domclick_city_sweep run_id передаёт), а вот у avito пустые строки
приходят КАЖДЫЙ день (944 за 2026-08-06, 635 за 2026-08-05 — все без run_id).
Бэкфилл 150 515 исторических строк невозможен, проверено:
- привязки снимок→прогон в схеме больше нет;
- по времени неоднозначно: на всех 36 днях с осиротевшими avito-снимками
в сутках было >1 пишущего avito-прогона (до 29);
- observed_at не спасает — ON CONFLICT перезаписывает его последним
писателем дня, а не тем, кто строку создал.
Ложная атрибуция хуже пустоты — бэкфилл не делается.
Refs #2701