feat(ci): красная база получает один перезапуск - #1530
Conversation
Красная `main` замораживает очередь мержа (#1326, #1510) — и правильно делает: мержить поверх сломанной базы бессмысленно. Но выхода из положения у правила не было, когда база красная НЕ ПО ДЕЛУ. Круг замыкался: новый прогон `main` рождается только новым мержем, мерж заморожен, а перезапуск требует `actions:write`, которого у облачной сессии нет — прокси закрывает запись. Оставался клик человека. Замер 08–09.09.2026, две красноты подряд, обе по ОДНОЙ упавшей проверке: `test (macos-latest, 3.12)` после мержа #1516 (следующие три мержа дали зелёные прогоны) и `e2e` после мержа #1518 (весь набор на той же голове прошёл локально целиком). Каждый раз очередь замирала. `scripts/rerun_red_main.py` + `.github/workflows/rerun-red-main.yml` перезапускают упавшие джобы последнего прогона базы ровно при двух условиях, и обе половины обязательны: * упала РОВНО ОДНА проверка. Настоящая поломка почти никогда не роняет одну ячейку матрицы — она валит сборку, линтер или весь ряд ОС; мигание, наоборот, почти всегда одиночное; * попытка РОВНО ОДНА. Второй перезапуск — уже не проверка гипотезы, а добывание зелёного. Не помогло — заморозка остаётся, и очередь двигает PR с меткой `blocker`. Механизм не отменяет правило, а доводит его до конца. Рекурсии нет: перезапуск порождает новый прогон, тот разбудит workflow снова и получит отказ по `run_attempt`. Граница держит цикл сама. След обязателен — итог уходит в summary прогона: «было красным, стало зелёным» без объяснения выглядит как исчезнувшая улика. Closes #1524 Co-Authored-By: Artem Markitanov <86671904+ArtVsMark@users.noreply.github.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wqpt9etxi7Hz6dNyhmYfx1
Co-Authored-By: Artem Markitanov <86671904+ArtVsMark@users.noreply.github.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wqpt9etxi7Hz6dNyhmYfx1
|
Упало тестов: 4 — в джобах:
Прогон: https://github.com/ArtVsMark/Stepik-Python-Grader/actions/runs/34327290449 Сводка обновляется на каждом красном прогоне этого PR ( |
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: Artem Markitanov <86671904+ArtVsMark@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: Artem Markitanov <86671904+ArtVsMark@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: Artem Markitanov <86671904+ArtVsMark@users.noreply.github.com>
Переход #1420 доведён до конца. В обязательных проверках защиты `main` остаётся один `ci-complete`; четырнадцать прежних имён — джобы и ячейки матрицы — убраны из `EXPECTED_CHECKS`. ЗАЧЕМ. Имя ячейки несёт версию Python и флаг эксперимента, то есть меняется от ЧУЖОГО календаря. Выход 3.14 из предрелиза добавил сюда три строки (#1529), выход 3.15 добавил бы ещё три и убрал другие. Каждый такой сдвиг правится в ДВУХ местах сразу — в дереве и во внешней настройке репозитория, — а расходятся они молча: PR начинает ждать проверку, которой больше нет, и ни один прогон об этом не говорит. Ровно это правило 168 и не велит держать в обязательных. ЧТО НЕ ПОТЕРЯНО. Защита от переименования ячейки остаётся: состав выводит `ci_aggregate.expected_checks` из того же `ci.yml`, поэтому поймает её прогон, а не память. Предрелизные ячейки агрегатор отличает сам — по суффиксу `, true)`. ПОЧЕМУ СЕЙЧАС. Порядок перехода менять было нельзя, и он пройден целиком: агрегатор появился (#1456) → владелец добавил его в обязательные, ничего не убирая → PR мержились при нём. Последний шаг доказан на живых случаях, а не обещан: на #1537 и #1540 `ci-complete` зелёный при красных ячейках 3.15, на #1528 и #1530 — красный, потому что там красна обязательная (`windows-latest, 3.13` и `ubuntu-latest, 3.14`). То есть он и пропускает верное, и держит неверное. СМЕНИЛСЯ ПРЕДМЕТ ОДНОЙ ПРОВЕРКИ. `check_matrix_names` держала список в соответствии с матрицей, пока имена перечислялись. Теперь находкой считается ВОЗВРАЩЕНИЕ матричного имени в обязательные: это шаг назад, к состоянию, где каждый выпуск CPython правится дважды. ВЛАДЕЛЬЦУ: те же четырнадцать имён нужно убрать из ruleset, оставив `ci-complete`. Пока они там, ночная сверка назовёт расхождение — «обязательных проверок больше заявленного». Это и есть сигнал доделать, а не поломка гейта. Closes #1420 Claude-Session: https://claude.ai/code/session_01Wqpt9etxi7Hz6dNyhmYfx1 Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Красная
mainзамораживает очередь мержа (#1326, #1510) — и правильноделает: мержить поверх сломанной базы бессмысленно. Но выхода из
положения у правила не было, когда база красная НЕ ПО ДЕЛУ. Круг
замыкался: новый прогон
mainрождается только новым мержем, мержзаморожен, а перезапуск требует
actions:write, которого у облачнойсессии нет — прокси закрывает запись. Оставался клик человека.
Замер 08–09.09.2026, две красноты подряд, обе по ОДНОЙ упавшей
проверке:
test (macos-latest, 3.12)после мержа #1516 (следующие тримержа дали зелёные прогоны) и
e2eпосле мержа #1518 (весь набор натой же голове прошёл локально целиком). Каждый раз очередь замирала.
scripts/rerun_red_main.py+.github/workflows/rerun-red-main.ymlперезапускают упавшие джобы последнего прогона базы ровно при двух
условиях, и обе половины обязательны:
одну ячейку матрицы — она валит сборку, линтер или весь ряд ОС;
мигание, наоборот, почти всегда одиночное;
добывание зелёного.
Не помогло — заморозка остаётся, и очередь двигает PR с меткой
blocker. Механизм не отменяет правило, а доводит его до конца.Рекурсии нет: перезапуск порождает новый прогон, тот разбудит workflow
снова и получит отказ по
run_attempt. Граница держит цикл сама.След обязателен — итог уходит в summary прогона: «было красным, стало
зелёным» без объяснения выглядит как исчезнувшая улика.
Closes #1524
Работа сделана вместе: @ArtVsMark — постановка, решения и приёмка; Claude Code — реализация.