Прод-прогон 5210 оборвался по ratio-критерию — 14 блоков из 20, ровно порог 0.7 —
и отчитался строкой «ABORT -- 1 consecutive blocks». Число верное: последняя серия
в тот момент действительно равнялась единице (19-я попытка успех, 20-я блок).
Величина не та. Читатель лога видит цифру, по которой обрыва быть не могло, и идёт
искать несуществующий баг в брейкере.
Причина: #3184 заменил критерий обрыва на долю в скользящем окне, а текст лога
остался от прежнего критерия «N подряд» — то есть ровно та же болезнь, которую
#3178 лечил у соседней строки (литерал «IP rate-limited» вместо измеренной причины).
- BlockRatioBreaker.abort_reason() возвращает "ratio" / "safety_net" / None;
should_abort() выражен через него, поведение не меняется.
- abort_explanation() даёт текст с той величиной, по которой обрыв и произошёл:
доля печатает «доля блоков 14/20 в окне (порог 70%)», safety-net — «5 блоков
подряд без единого успеха (снапшот 5 короче окна 20)».
- counters["abort_reason"] — чтобы причина обрыва читалась SQL-запросом по
scrape_runs, а не грепом контейнера. Ключа нет, если прогон не обрывался.
Тесты (проверено мутацией источника — на прежнем сообщении оба падают):
- ratio-обрыв на раскладке прогона 5210 (серия на обрыве = 1) требует «14/20»
в логе и отсутствия слова consecutive;
- safety-net требует «5 блоков подряд» и отсутствия «доля блоков» — без этого
зеркала первый тест проходил бы и у сообщения, всегда печатающего долю;
- прогон без обрыва (13/20) не пишет abort_reason в counters.
Refs #3184, #3178