tradein/scraper: длинная серия неудач замолкает навсегда, а прогон, оборванный после частичного сбора, отчитывается успешным #2670

Closed
opened 2026-08-05 18:50:21 +00:00 by bot-backend · 4 comments
Collaborator

Два следствия одного устройства проверки честности статуса, найдены при ревью PR #2667. Оба — тот же класс, что и сегодняшняя серия: механизм есть, но срабатывает не тогда, когда нужно.

1. Постоянно сломанный источник перестаёт о себе напоминать

Алерт по подряд идущим неудачам срабатывает на точной серии из трёх: три последних прогона неуспешны и четвёртый успешен. Как только серия становится длиннее, алерт замолкает — навсегда, повторного напоминания нет.

Пока источники падали вперемешку с успехами, это работало: серия рвалась, алерт взводился заново. Но после #2667 длинная непрерывная серия бана становится ожидаемым состоянием Домклика — до починки прокси (#2638). То есть про сломанный источник придёт ровно одно сообщение, а дальше тишина, неотличимая от «всё хорошо».

Это ровно та ловушка, из-за которой #2574 месяц выглядела как «всё собирается».

Чем чинить: повторное напоминание с разрежением (например раз в сутки, потом раз в неделю), либо отдельная сводка «источники, которые не собирают дольше N дней». Второе честнее — оно отвечает на вопрос «что у нас сейчас сломано», а не «что сломалось только что».

2. Оборванный после частичного сбора прогон считается успешным

Проверка честного статуса разбирает два случая: блок (теперь banned) и ноль лотов при ошибках (failed). Всё остальное — «успешно».

Значит прогон, который собрал часть комнатных бакетов и оборвался по таймауту или исключению, попадает в «успешно». Он ровно так же неполон, как заблокированный, но отчитается зелёным — и его неполнота уедет дальше в данные молча.

На проде такого пока не случалось (строк с ошибками при ненулевом сборе нет), поэтому это профилактика, а не инцидент. Но форма ровно та же, что у уже случившегося: у Домклика гейт требовал одновременно блока и нуля лотов, а блок никогда не давал ноль — и 13 блоков из 13 ушли в «успешно».

Чем чинить: сравнивать собранное с ожидаемым охватом (сколько бакетов из скольких пройдено), а не с нулём. Прогон, прошедший 3 бакета из 6, не «успешен», даже если лоты есть.

Общее

Оба пункта об одном: успех определяется как «не поймали известную ошибку», а не как «сделали то, что собирались». Первое определение всегда будет пропускать новые способы не сделать работу.

Связано: #2657, #2625, #2574, #1968.

Два следствия одного устройства проверки честности статуса, найдены при ревью PR #2667. Оба — тот же класс, что и сегодняшняя серия: механизм есть, но срабатывает не тогда, когда нужно. ## 1. Постоянно сломанный источник перестаёт о себе напоминать Алерт по подряд идущим неудачам срабатывает на **точной серии из трёх**: три последних прогона неуспешны и четвёртый успешен. Как только серия становится длиннее, алерт замолкает — **навсегда**, повторного напоминания нет. Пока источники падали вперемешку с успехами, это работало: серия рвалась, алерт взводился заново. Но после #2667 длинная непрерывная серия бана становится **ожидаемым состоянием** Домклика — до починки прокси (#2638). То есть про сломанный источник придёт ровно одно сообщение, а дальше тишина, неотличимая от «всё хорошо». Это ровно та ловушка, из-за которой #2574 месяц выглядела как «всё собирается». Чем чинить: повторное напоминание с разрежением (например раз в сутки, потом раз в неделю), либо отдельная сводка «источники, которые не собирают дольше N дней». Второе честнее — оно отвечает на вопрос «что у нас сейчас сломано», а не «что сломалось только что». ## 2. Оборванный после частичного сбора прогон считается успешным Проверка честного статуса разбирает два случая: блок (теперь `banned`) и ноль лотов при ошибках (`failed`). Всё остальное — «успешно». Значит прогон, который собрал часть комнатных бакетов и оборвался по таймауту или исключению, попадает в «успешно». Он ровно так же неполон, как заблокированный, но отчитается зелёным — и его неполнота уедет дальше в данные молча. На проде такого пока не случалось (строк с ошибками при ненулевом сборе нет), поэтому это профилактика, а не инцидент. Но форма ровно та же, что у уже случившегося: у Домклика гейт требовал одновременно блока **и** нуля лотов, а блок никогда не давал ноль — и 13 блоков из 13 ушли в «успешно». Чем чинить: сравнивать собранное с ожидаемым охватом (сколько бакетов из скольких пройдено), а не с нулём. Прогон, прошедший 3 бакета из 6, не «успешен», даже если лоты есть. ## Общее Оба пункта об одном: **успех определяется как «не поймали известную ошибку»**, а не как «сделали то, что собирались». Первое определение всегда будет пропускать новые способы не сделать работу. Связано: #2657, #2625, #2574, #1968.
Author
Collaborator

Проверка на проде 2026-08-07: код доехал, механизм ни разу не сработал — ЖДЁТ ПРОГОНА

Оба пункта в живом контейнере (проверено вызовом внутри tradein-scraper, а не по релизу):

STREAK_ALERT_MAX_PERIOD = 16 · STREAK_SCAN_LIMIT = 500
лестница вех при пороге 3: 3, 6, 12, 24, 48, 96, 144, 192
DomClickScraper.buckets_completed — есть
ветка «пройдено N бакетов из M → mark_failed» — есть

п.2 виден в данных. Счётчики охвата появились у прогонов с 06.08: domclick_city_sweep
id 3348 (07.08 03:34) — buckets_completed 0 / buckets_total 6, статус failed. У прогонов
до правки (3264, 3192, 3115 …) этих ключей нет вовсе. Сама ветка «частичный охват» ещё не
срабатывала — на проде такого случая не было, задача сама называет п.2 профилактикой.

п.1 поведенчески не проверен: сработать было не на чем. Стрики ≥ 3 сейчас ровно два, и
оба у источников, которые с момента правки не бегали:

avito_full_load              стрик 31   следующий прогон 2026-08-10 14:16 UTC
avito_full_load_exhaustive   стрик  5   следующий прогон 2026-08-09 14:02 UTC

В GlitchTip за всё время ни одного события вида has N consecutive failed/banned runs
(искал по подстроке consecutive — нашлись только per-run ABORT'ы, это другой сторож).

Критерий приёмки (записан ДО факта)

2026-08-09, avito_full_load_exhaustive. Если прогон снова неуспешен, стрик станет 6
это веха лестницы, и в проекте trade-in GlitchTip обязано появиться событие с текстом
Scraper source 'avito_full_load_exhaustive' has 6 consecutive failed/banned runs.
Появится — п.1 подтверждён живым срабатыванием. Не появится — сторож не работает.

2026-08-10, avito_full_load: стрик 31 → 32, вехи там нет, события быть не должно
это встречная проверка, что лестница не выродилась в спам.

Две оговорки, которые стоит знать заранее

  1. Разрежение на длинных стриках грубее, чем кажется. Вехи идут 24 → 48, промежуточных нет.
    avito_full_load со стриком 31 при недельном такте получит следующее напоминание на 48-й
    неудаче — это 17 недель. Формально «замолкает навсегда» вылечено, практически для
    недельных источников напоминание приходит раз в четыре месяца. Второй вариант из задачи
    («сводка: источники, которые не собирают дольше N дней»), который вы называли более честным,
    не сделан — и именно он закрывал бы этот случай.
  2. Напоминание уходит в никуда. Получателей в GlitchTip 0, правил 0, отправлено 0 (#2673).
    Даже подтверждённое срабатывание 09.08 будет означать «событие записано», а не «кто-то узнал».
## Проверка на проде 2026-08-07: код доехал, механизм ни разу не сработал — ЖДЁТ ПРОГОНА **Оба пункта в живом контейнере** (проверено вызовом внутри `tradein-scraper`, а не по релизу): ``` STREAK_ALERT_MAX_PERIOD = 16 · STREAK_SCAN_LIMIT = 500 лестница вех при пороге 3: 3, 6, 12, 24, 48, 96, 144, 192 DomClickScraper.buckets_completed — есть ветка «пройдено N бакетов из M → mark_failed» — есть ``` **п.2 виден в данных.** Счётчики охвата появились у прогонов с 06.08: `domclick_city_sweep` id 3348 (07.08 03:34) — `buckets_completed 0 / buckets_total 6`, статус `failed`. У прогонов до правки (3264, 3192, 3115 …) этих ключей нет вовсе. Сама ветка «частичный охват» ещё не срабатывала — на проде такого случая не было, задача сама называет п.2 профилактикой. **п.1 поведенчески не проверен: сработать было не на чем.** Стрики ≥ 3 сейчас ровно два, и оба у источников, которые с момента правки не бегали: ``` avito_full_load стрик 31 следующий прогон 2026-08-10 14:16 UTC avito_full_load_exhaustive стрик 5 следующий прогон 2026-08-09 14:02 UTC ``` В GlitchTip за всё время **ни одного** события вида `has N consecutive failed/banned runs` (искал по подстроке `consecutive` — нашлись только per-run ABORT'ы, это другой сторож). ## Критерий приёмки (записан ДО факта) **2026-08-09, `avito_full_load_exhaustive`.** Если прогон снова неуспешен, стрик станет **6** — это веха лестницы, и в проекте `trade-in` GlitchTip обязано появиться событие с текстом `Scraper source 'avito_full_load_exhaustive' has 6 consecutive failed/banned runs`. Появится — п.1 подтверждён живым срабатыванием. Не появится — сторож не работает. **2026-08-10, `avito_full_load`:** стрик 31 → 32, вехи там нет, события быть **не должно** — это встречная проверка, что лестница не выродилась в спам. ## Две оговорки, которые стоит знать заранее 1. **Разрежение на длинных стриках грубее, чем кажется.** Вехи идут 24 → 48, промежуточных нет. `avito_full_load` со стриком 31 при недельном такте получит следующее напоминание на 48-й неудаче — это **17 недель**. Формально «замолкает навсегда» вылечено, практически для недельных источников напоминание приходит раз в четыре месяца. Второй вариант из задачи («сводка: источники, которые не собирают дольше N дней»), который вы называли более честным, не сделан — и именно он закрывал бы этот случай. 2. **Напоминание уходит в никуда.** Получателей в GlitchTip 0, правил 0, отправлено 0 (#2673). Даже подтверждённое срабатывание 09.08 будет означать «событие записано», а не «кто-то узнал».
Author
Collaborator

Остаток закрыт сводкой, а не уплотнением вех — PR #2806 (смержен 2026-08-10 08:29 UTC)

Разбор 07.08 предлагал два выхода: уплотнить лестницу либо ограничить её по времени. Прод-данные 2026-08-10 отвергают оба.

Шесть источников не имели успешного прогона дольше 3× своего такта:

источник стрик сут. без успеха когда напомнит лестница
avito_full_load_exhaustive 0 49.5 никогда: 5 банов подряд обнулил cancelled 09.08 (деплой убил бегущий прогон)
cian_history_backfill 0 42.1 никогда: завершённых прогонов нет с 30.06; единственная строка за 42 дня — skipped (cian_cookies_expired)
avito_full_load 31 37.7 веха 48 при interval_days=7 → +17 прогонов ≈ 119 суток
avito_detail_backfill 5 5.2 веха 6 → завтра
domclick_city_sweep 5 5.1 веха 6 → завтра
domclick_detail_backfill 4 5.0 веха 6 → послезавтра

Из трёх худших редкие вехи виноваты только в одном случае. У двух других стрик равен нулю: лестница шагает по подряд идущим завершённым failed/banned, а «замолчал» там означает «перестал производить завершённые прогоны» либо «серию обнулило не-провальное завершение». Уплотнять нечего, таймить тоже нечего — ограничение «не реже раза в неделю» без стрика не срабатывает по той же причине.

Поэтому сделан второй вариант из исходной задачи, тот, который вы называли более честным: раз в сутки одно событие со списком источников, у которых max(finished_at) при status='done' старше 3× interval_days их расписания. Порог и сортировка — в тактах, а не в сутках: 24 суток без сбора у 28-суточного rosreestr_quarter_poll норма, у суточного domclick_city_sweep авария.

Лестница оставлена как есть. Она отвечает на другой вопрос — «что сломалось только что» — и после сводки её редкие вехи перестают быть проблемой: avito_full_load теперь называется каждые сутки, а не раз в 119.

Что попутно опровергнуто

  1. Критерий приёмки от 07.08 не сработал не потому, что сторож сломан. 09.08 avito_full_load_exhaustive завершился cancelled (14:02 → 17:00), а не banned, — стрик обнулился с 5 до 0, вехи 6 не случилось. Ожидаемого события в GlitchTip нет, и это НЕ отказ механизма; это третий способ замолчать, которого разбор не предполагал.
  2. Шапка scraper_kit/orchestration/scheduler.py врала: «боевой рантайм по-прежнему крутит старый app.services.scheduler». Эта ветка удалена в #2397 Part C, прод (python -m app.scheduler_main) крутит именно kit-loop. Строка пережила собственную правду и посылала правку сторожей не в тот файл — исправлена в том же PR.

Критерий приёмки (записан ДО факта)

2026-08-11, в первые сутки после деплоя в логе tradein-scraper обязана появиться ровно одна строка scheduler: N источников не собирают дольше 3× своего такта, и в ней обязаны быть названы cian_history_backfill и avito_full_load_exhaustive — те двое, у кого стрик 0. Нет строки → сводка не работает. Есть, но без этих двоих → порог посчитан не тем тактом. Встречная проверка: rosreestr_quarter_poll (такт 28 сут, 24 сут без сбора) в списке быть не должен.

Оговорка #2673 в силе: получателей в GlitchTip 0, сводка означает «событие записано», а не «кто-то узнал».

## Остаток закрыт сводкой, а не уплотнением вех — PR #2806 (смержен 2026-08-10 08:29 UTC) Разбор 07.08 предлагал два выхода: уплотнить лестницу либо ограничить её по времени. **Прод-данные 2026-08-10 отвергают оба.** Шесть источников не имели успешного прогона дольше 3× своего такта: | источник | стрик | сут. без успеха | когда напомнит лестница | |---|---|---|---| | `avito_full_load_exhaustive` | **0** | 49.5 | никогда: 5 банов подряд обнулил `cancelled` 09.08 (деплой убил бегущий прогон) | | `cian_history_backfill` | **0** | 42.1 | никогда: завершённых прогонов нет с 30.06; единственная строка за 42 дня — `skipped` (cian_cookies_expired) | | `avito_full_load` | 31 | 37.7 | веха 48 при `interval_days=7` → +17 прогонов ≈ **119 суток** | | `avito_detail_backfill` | 5 | 5.2 | веха 6 → завтра | | `domclick_city_sweep` | 5 | 5.1 | веха 6 → завтра | | `domclick_detail_backfill` | 4 | 5.0 | веха 6 → послезавтра | Из трёх худших **редкие вехи виноваты только в одном случае**. У двух других стрик равен нулю: лестница шагает по подряд идущим завершённым `failed`/`banned`, а «замолчал» там означает «перестал производить завершённые прогоны» либо «серию обнулило не-провальное завершение». Уплотнять нечего, таймить тоже нечего — ограничение «не реже раза в неделю» без стрика не срабатывает по той же причине. Поэтому сделан второй вариант из исходной задачи, тот, который вы называли более честным: раз в сутки одно событие со списком источников, у которых `max(finished_at) при status='done'` старше `3× interval_days` их расписания. Порог и сортировка — в тактах, а не в сутках: 24 суток без сбора у 28-суточного `rosreestr_quarter_poll` норма, у суточного `domclick_city_sweep` авария. **Лестница оставлена как есть.** Она отвечает на другой вопрос — «что сломалось только что» — и после сводки её редкие вехи перестают быть проблемой: `avito_full_load` теперь называется каждые сутки, а не раз в 119. ### Что попутно опровергнуто 1. **Критерий приёмки от 07.08 не сработал не потому, что сторож сломан.** 09.08 `avito_full_load_exhaustive` завершился `cancelled` (14:02 → 17:00), а не `banned`, — стрик обнулился с 5 до 0, вехи 6 не случилось. Ожидаемого события в GlitchTip нет, и это НЕ отказ механизма; это третий способ замолчать, которого разбор не предполагал. 2. **Шапка `scraper_kit/orchestration/scheduler.py` врала**: «боевой рантайм по-прежнему крутит старый `app.services.scheduler`». Эта ветка удалена в #2397 Part C, прод (`python -m app.scheduler_main`) крутит именно kit-loop. Строка пережила собственную правду и посылала правку сторожей не в тот файл — исправлена в том же PR. ### Критерий приёмки (записан ДО факта) **2026-08-11, в первые сутки после деплоя** в логе `tradein-scraper` обязана появиться ровно одна строка `scheduler: N источников не собирают дольше 3× своего такта`, и в ней обязаны быть названы `cian_history_backfill` и `avito_full_load_exhaustive` — те двое, у кого стрик 0. Нет строки → сводка не работает. Есть, но без этих двоих → порог посчитан не тем тактом. Встречная проверка: `rosreestr_quarter_poll` (такт 28 сут, 24 сут без сбора) в списке быть **не должен**. Оговорка #2673 в силе: получателей в GlitchTip 0, сводка означает «событие записано», а не «кто-то узнал».
Author
Collaborator

Прод-проверка 2026-08-10: критерий выполнен, на сутки раньше срока

Критерий записан ДО факта (см. описание PR #2806): в первые сутки после деплоя в логе tradein-scraper — ровно одна строка сводки, и в ней обязаны быть названы двое со стриком 0. Сводка сработала на первом же тике после деплоя:

2026-08-10 08:37:09,702 ERROR scraper_kit.orchestration.scheduler:
scheduler: 6 источников не собирают дольше 3× своего такта —
cian_history_backfill 42.1d/1d, avito_full_load_exhaustive 49.5d/7d, avito_full_load 37.7d/7d,
avito_detail_backfill 5.2d/1d, domclick_city_sweep 5.1d/1d, domclick_detail_backfill 5.0d/1d (#2670)
  • cian_history_backfill (стрик 0, 42.1 сут) и avito_full_load_exhaustive (стрик 0, 49.5 сут) названы — те двое, которых лестница не увидит никогда;
  • rosreestr_quarter_poll (такт 28 сут, 24 сут без сбора) в списке отсутствует — встречная проверка пройдена, порог считается в тактах, а не в сутках;
  • шесть источников и все шесть чисел совпали с прогнозом, посчитанным SQL-ом до правки, — сводка меряет то же, что мерил я руками.

Код проверен в живом контейнере, не по релизу: hasattr(scheduler, "emit_stale_digest") == True, STALE_DIGEST_INTERVAL_FACTOR == 3.

Известный потолок подтвердился ровно в предсказанном виде: за сегодня два выпуска — 08:37:09 и 08:58:43, по одному на пересоздание контейнера (деплой PR #2806 и деплой соседнего PR #2809). Это то самое «рестарт даёт лишний выпуск», помеченное # ponytail: в коде. Один лишний выпуск в сутки на деплой — принятая цена за отсутствие таблицы состояния.

## Прод-проверка 2026-08-10: критерий выполнен, на сутки раньше срока Критерий записан ДО факта (см. описание PR #2806): в первые сутки после деплоя в логе `tradein-scraper` — ровно одна строка сводки, и в ней обязаны быть названы двое со стриком 0. Сводка сработала на первом же тике после деплоя: ``` 2026-08-10 08:37:09,702 ERROR scraper_kit.orchestration.scheduler: scheduler: 6 источников не собирают дольше 3× своего такта — cian_history_backfill 42.1d/1d, avito_full_load_exhaustive 49.5d/7d, avito_full_load 37.7d/7d, avito_detail_backfill 5.2d/1d, domclick_city_sweep 5.1d/1d, domclick_detail_backfill 5.0d/1d (#2670) ``` - `cian_history_backfill` (стрик 0, 42.1 сут) и `avito_full_load_exhaustive` (стрик 0, 49.5 сут) названы — те двое, которых лестница не увидит никогда; - `rosreestr_quarter_poll` (такт 28 сут, 24 сут без сбора) в списке отсутствует — встречная проверка пройдена, порог считается в тактах, а не в сутках; - шесть источников и все шесть чисел совпали с прогнозом, посчитанным SQL-ом до правки, — сводка меряет то же, что мерил я руками. Код проверен в живом контейнере, не по релизу: `hasattr(scheduler, "emit_stale_digest") == True`, `STALE_DIGEST_INTERVAL_FACTOR == 3`. **Известный потолок подтвердился ровно в предсказанном виде:** за сегодня два выпуска — 08:37:09 и 08:58:43, по одному на пересоздание контейнера (деплой PR #2806 и деплой соседнего PR #2809). Это то самое «рестарт даёт лишний выпуск», помеченное `# ponytail:` в коде. Один лишний выпуск в сутки на деплой — принятая цена за отсутствие таблицы состояния.
Author
Collaborator

Прод 12.08: сводка живая, оба пункта разрешены — закрываю

п.1 (сломанный источник перестаёт напоминать) — работает, второе подтверждение. Сводка выпущена сегодня, на первом тике после пересоздания контейнера (старт 12:24:14 → выпуск 12:24:47 UTC):

2026-08-12 12:24:47,331 ERROR scraper_kit.orchestration.scheduler:
scheduler: 5 источников не собирают дольше 3× своего такта —
avito_full_load_exhaustive 51.7d/7d, avito_detail_backfill 7.3d/1d,
domclick_city_sweep 7.3d/1d, domclick_detail_backfill 7.2d/1d,
avito_full_load 39.9d/7d (#2670)

Список изменился с 10.08 осмысленно, а не случайно: было шесть, стало пять — cian_history_backfill ушёл, потому что 11.08 и 12.08 отработал done (listings_succeeded 100 в обоих). Сводка не просто печатается, она реагирует на выздоровление источника. Встречная проверка держится: rosreestr_quarter_poll (такт 28 сут) в списке по-прежнему нет. Код живой: emit_stale_digest есть, STALE_DIGEST_INTERVAL_FACTOR == 3 (проверено внутри контейнера).

Оговорка про суточный такт, чтобы не выдавать за большее: подтвердить его по логам нельзя — docker logs живёт от последнего пересоздания контейнера, а деплои идут чаще суток. Наблюдаемо: каждый запуск даёт ровно один выпуск, и содержимое совпадает с независимым SQL-замером. Это тот самый известный потолок, помеченный # ponytail: в коде.

п.2 (оборванный после частичного сбора прогон считается успешным) — механизм на месте, случая не было. Счётчики охвата пишутся у всех прогонов с бакетами:

run дата статус buckets lots
3751 12.08 banned 0/6 59
3675 11.08 banned 0/6 58
3594 10.08 banned 0/6 372
3502 / 3420 / 3348 07-09.08 failed 0/6 0

Строк с частичным охватом (0 < completed < total) на проде нет ни одной. Ноль имеет причину — повода не было: задача сама называет п.2 профилактикой, и за неделю случай «оборвался после частичного сбора, но без блока» не наступил. Ветка при этом достижима — pipeline.py:3946, elif 0 < counters.buckets_completed < counters.buckets_total: — и покрыта tests/test_2670_streak_and_partial_coverage.py. Ждать её живого срабатывания бессрочно смысла нет.

Оговорка #2673 (получателей в GlitchTip 0) остаётся в силе и живёт в своей задаче: сводка означает «событие записано», а не «кто-то узнал».

## Прод 12.08: сводка живая, оба пункта разрешены — закрываю **п.1 (сломанный источник перестаёт напоминать) — работает, второе подтверждение.** Сводка выпущена сегодня, на первом тике после пересоздания контейнера (старт 12:24:14 → выпуск 12:24:47 UTC): ``` 2026-08-12 12:24:47,331 ERROR scraper_kit.orchestration.scheduler: scheduler: 5 источников не собирают дольше 3× своего такта — avito_full_load_exhaustive 51.7d/7d, avito_detail_backfill 7.3d/1d, domclick_city_sweep 7.3d/1d, domclick_detail_backfill 7.2d/1d, avito_full_load 39.9d/7d (#2670) ``` Список изменился с 10.08 осмысленно, а не случайно: было шесть, стало пять — **`cian_history_backfill` ушёл**, потому что 11.08 и 12.08 отработал `done` (listings_succeeded 100 в обоих). Сводка не просто печатается, она реагирует на выздоровление источника. Встречная проверка держится: `rosreestr_quarter_poll` (такт 28 сут) в списке по-прежнему нет. Код живой: `emit_stale_digest` есть, `STALE_DIGEST_INTERVAL_FACTOR == 3` (проверено внутри контейнера). Оговорка про суточный такт, чтобы не выдавать за большее: подтвердить его по логам нельзя — `docker logs` живёт от последнего пересоздания контейнера, а деплои идут чаще суток. Наблюдаемо: каждый запуск даёт ровно один выпуск, и содержимое совпадает с независимым SQL-замером. Это тот самый известный потолок, помеченный `# ponytail:` в коде. **п.2 (оборванный после частичного сбора прогон считается успешным) — механизм на месте, случая не было.** Счётчики охвата пишутся у всех прогонов с бакетами: | run | дата | статус | buckets | lots | |---|---|---|---|---:| | 3751 | 12.08 | banned | 0/6 | 59 | | 3675 | 11.08 | banned | 0/6 | 58 | | 3594 | 10.08 | banned | 0/6 | 372 | | 3502 / 3420 / 3348 | 07-09.08 | failed | 0/6 | 0 | Строк с частичным охватом (`0 < completed < total`) на проде нет ни одной. Ноль имеет причину — **повода не было**: задача сама называет п.2 профилактикой, и за неделю случай «оборвался после частичного сбора, но без блока» не наступил. Ветка при этом достижима — `pipeline.py:3946`, `elif 0 < counters.buckets_completed < counters.buckets_total:` — и покрыта `tests/test_2670_streak_and_partial_coverage.py`. Ждать её живого срабатывания бессрочно смысла нет. Оговорка #2673 (получателей в GlitchTip 0) остаётся в силе и живёт в своей задаче: сводка означает «событие записано», а не «кто-то узнал».
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#2670
No description provided.