Skip to content

feat(ci): красная база получает один перезапуск - #1530

Merged
ArtVsMark merged 6 commits into
mainfrom
agent/red-main-gets-one-rerun
Oct 1, 2026
Merged

ArtVsMark merged 6 commits into
mainfrom
agent/red-main-gets-one-rerun

Conversation

@ArtVsMark

Copy link
Copy Markdown
Owner

Красная 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 — реализация.

claude and others added 2 commits September 9, 2026 05:35
Красная `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
@ArtVsMark ArtVsMark added the merge-when-green Согласие смержить без автора: авто-мерж включится, как позеленеет label Sep 9, 2026
@ArtVsMark
ArtVsMark enabled auto-merge (squash) September 9, 2026 06:16
@claude claude Bot added area/ci CI/CD и скрипты (.github/, scripts/) enhancement New feature or request labels Sep 9, 2026
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Упало тестов: 4 — в джобах: macos-latest-3.15, ubuntu-latest-3.14, ubuntu-latest-3.15, windows-latest-3.15.

  • macos-latest-3.15 — tests/test_glossary_draft_pipeline.py::test_run_check_bundled_ratchet
    failure: AssertionError: Примеры этих карточек разошлись с ожиданиями:

    сообщение целиком
        bytearray.title: ждали 'bytearray(b"They\\\'Re Here")', получили 'bytearray(b"They\'Re Here")'
        typing.TypeVarTuple: ждали 'typing.Unpack[Ts]', получили 'typing.Unpack[~Ts]'
        typing.no_type_check_decorator: ImportError: cannot import name 'no_type_check_decorator' from 'typing' (/Library/Frameworks/Python.framework/Versions/3.15/lib/python3.15/typing.py)
    assert not [('bytearray.title', 'ждали \'bytearray(b"They\\\\\\\'Re Here")\', получили \'bytearray(b"They\\\'Re Here")\''), ('typ...no_type_check_decorator' from 'typing' (/Library/Frameworks/Python.framework/Versions/3.15/lib/python3.15/typing.py)")]
    
  • ubuntu-latest-3.14 — tests/test_missing_queue_sqlite.py::test_concurrent_creation_of_a_missing_queue_loses_nothing
    failure: AssertionError: воркеры завершились с ненулевым кодом:

    сообщение целиком
      воркер 1: код 1
      Traceback (most recent call last):
        File "/home/runner/work/Stepik-Python-Grader/Stepik-Python-Grader/src/stepik_grader/glossary/json_provider.py", line 582, in append_missing_entries
          _ensure_queue_db(path)
          ~~~~~~~~~~~~~~~~^^^^^^
        File "/home/runner/work/Stepik-Python-Grader/Stepik-Python-Grader/src/stepik_grader/glossary/json_provider.py", line 511, in _ensure_queue_db
          with contextlib.closing(_connect_queue(path)) as conn:
                                  ~~~~~~~~~~~~~~^^^^^^
        File "/home/runner/work/Stepik-Python-Grader/Stepik-Python-Grader/src/stepik_grader/glossary/json_provider.py", line 291, in _connect_queue
          conn = db.connect(path, migrate=_queue_migrate)
        File "/home/runner/work/Stepik-Python-Grader/Stepik-Python-Grader/src/stepik_grader/db.py", line 137, in connect
          migrate(conn)
          ~~~~~~~^^^^^^
        File "/home/runner/work/Stepik-Python-Grader/Stepik-Python-Grader/src/stepik_grader/glossary/json_provider.py", line 281, in _queue_migrate
          db.apply_schema(conn, version=_QUEUE_SCHEMA_VERSION, ddl=_QUEUE_SCHEMA_V1)
          ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/home/runner/work/Stepik-Python-Grader/Stepik-Python-Grader/src/stepik_grader/db.py", line 241, in apply_schema
          with exclusive_transaction(conn):
               ~~~~~~~~~~~~~~~~~~~~~^^^^^^
        File "/opt/hostedtoolcache/Python/3.14.7/x64/lib/python3.14/contextlib.py", line 148, in __exit__
          next(self.gen)
          ~~~~^^^^^^^^^^
        File "/home/runner/work/Stepik-Python-Grader/Stepik-Python-Grader/src/stepik_grader/db.py", line 179, in exclusive_transaction
          conn.execute("COMMIT")
          ~~~~~~~~~~~~^^^^^^^^^^
      sqlite3.OperationalError: disk I/O error
    
      The above exception was the direct cause of the following exception:
    
      Traceback (most recent call last):
    …и ещё 11 строк(и).
    
  • ubuntu-latest-3.15 — tests/test_glossary_draft_pipeline.py::test_run_check_bundled_ratchet
    failure: AssertionError: Примеры этих карточек разошлись с ожиданиями:

    сообщение целиком
        bytearray.title: ждали 'bytearray(b"They\\\'Re Here")', получили 'bytearray(b"They\'Re Here")'
        typing.TypeVarTuple: ждали 'typing.Unpack[Ts]', получили 'typing.Unpack[~Ts]'
        typing.no_type_check_decorator: ImportError: cannot import name 'no_type_check_decorator' from 'typing' (/opt/hostedtoolcache/Python/3.15.0-rc.2/x64/lib/python3.15/typing.py)
    assert not [('bytearray.title', 'ждали \'bytearray(b"They\\\\\\\'Re Here")\', получили \'bytearray(b"They\\\'Re Here")\''), ('typ... name 'no_type_check_decorator' from 'typing' (/opt/hostedtoolcache/Python/3.15.0-rc.2/x64/lib/python3.15/typing.py)")]
    
  • windows-latest-3.15 — tests/test_glossary_draft_pipeline.py::test_run_check_bundled_ratchet
    failure: AssertionError: Примеры этих карточек разошлись с ожиданиями:

    сообщение целиком
        bytearray.title: ждали 'bytearray(b"They\\\'Re Here")', получили 'bytearray(b"They\'Re Here")'
        typing.TypeVarTuple: ждали 'typing.Unpack[Ts]', получили 'typing.Unpack[~Ts]'
        typing.no_type_check_decorator: ImportError: cannot import name 'no_type_check_decorator' from 'typing' (C:\hostedtoolcache\windows\Python\3.15.0-rc.2\x64\Lib\typing.py)
    assert not [('bytearray.title', 'ждали \'bytearray(b"They\\\\\\\'Re Here")\', получили \'bytearray(b"They\\\'Re Here")\''), ('typ...ame 'no_type_check_decorator' from 'typing' (C:\\hostedtoolcache\\windows\\Python\\3.15.0-rc.2\\x64\\Lib\\typing.py)")]
    

Прогон: https://github.com/ArtVsMark/Stepik-Python-Grader/actions/runs/34327290449


Сводка обновляется на каждом красном прогоне этого PR (scripts/report_failed_tests.py, issue #1382).

@ArtVsMark ArtVsMark added queue-frozen Заморозка конвейера: база красная, согласие вернётся само and removed merge-when-green Согласие смержить без автора: авто-мерж включится, как позеленеет labels Sep 9, 2026
@ArtVsMark
ArtVsMark disabled auto-merge September 9, 2026 14:10
@ArtVsMark ArtVsMark added merge-when-green Согласие смержить без автора: авто-мерж включится, как позеленеет and removed queue-frozen Заморозка конвейера: база красная, согласие вернётся само labels Sep 9, 2026
@ArtVsMark
ArtVsMark enabled auto-merge (squash) September 9, 2026 17:59
@ArtVsMark ArtVsMark added queue-frozen Заморозка конвейера: база красная, согласие вернётся само and removed merge-when-green Согласие смержить без автора: авто-мерж включится, как позеленеет labels Sep 13, 2026
@ArtVsMark
ArtVsMark disabled auto-merge September 13, 2026 11:21
@ArtVsMark ArtVsMark added merge-when-green Согласие смержить без автора: авто-мерж включится, как позеленеет and removed queue-frozen Заморозка конвейера: база красная, согласие вернётся само labels Sep 13, 2026
@ArtVsMark
ArtVsMark enabled auto-merge (squash) September 13, 2026 12:43
@ArtVsMark ArtVsMark added queue-frozen Заморозка конвейера: база красная, согласие вернётся само and removed merge-when-green Согласие смержить без автора: авто-мерж включится, как позеленеет labels Sep 16, 2026
@ArtVsMark
ArtVsMark disabled auto-merge September 16, 2026 09:55
@ArtVsMark ArtVsMark added merge-when-green Согласие смержить без автора: авто-мерж включится, как позеленеет and removed queue-frozen Заморозка конвейера: база красная, согласие вернётся само labels Sep 17, 2026
@ArtVsMark
ArtVsMark enabled auto-merge (squash) September 17, 2026 10:26
@ArtVsMark ArtVsMark added queue-frozen Заморозка конвейера: база красная, согласие вернётся само and removed merge-when-green Согласие смержить без автора: авто-мерж включится, как позеленеет labels Sep 18, 2026
@ArtVsMark
ArtVsMark disabled auto-merge September 18, 2026 11:11
@ArtVsMark ArtVsMark added merge-when-green Согласие смержить без автора: авто-мерж включится, как позеленеет and removed queue-frozen Заморозка конвейера: база красная, согласие вернётся само labels Sep 19, 2026
@ArtVsMark
ArtVsMark enabled auto-merge (squash) September 19, 2026 11:33
@ArtVsMark ArtVsMark added queue-frozen Заморозка конвейера: база красная, согласие вернётся само and removed merge-when-green Согласие смержить без автора: авто-мерж включится, как позеленеет labels Sep 21, 2026
@ArtVsMark
ArtVsMark disabled auto-merge September 21, 2026 11:06
@ArtVsMark ArtVsMark added merge-when-green Согласие смержить без автора: авто-мерж включится, как позеленеет and removed queue-frozen Заморозка конвейера: база красная, согласие вернётся само labels Sep 22, 2026
@ArtVsMark
ArtVsMark enabled auto-merge (squash) September 22, 2026 09:56
@ArtVsMark ArtVsMark added queue-frozen Заморозка конвейера: база красная, согласие вернётся само and removed merge-when-green Согласие смержить без автора: авто-мерж включится, как позеленеет labels Sep 25, 2026
@ArtVsMark
ArtVsMark disabled auto-merge September 25, 2026 18:35
@ArtVsMark
ArtVsMark disabled auto-merge September 25, 2026 18:35
@ArtVsMark
ArtVsMark enabled auto-merge (squash) September 25, 2026 18:35
@ArtVsMark
ArtVsMark disabled auto-merge September 25, 2026 18:35
@ArtVsMark ArtVsMark added merge-when-green Согласие смержить без автора: авто-мерж включится, как позеленеет and removed queue-frozen Заморозка конвейера: база красная, согласие вернётся само labels Sep 26, 2026
@ArtVsMark
ArtVsMark enabled auto-merge (squash) September 26, 2026 10:16
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>
@ArtVsMark
ArtVsMark merged commit baf26e5 into main Oct 1, 2026
22 checks passed
@ArtVsMark
ArtVsMark deleted the agent/red-main-gets-one-rerun branch October 1, 2026 15:36
ArtVsMark added a commit that referenced this pull request Oct 1, 2026
Переход #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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/ci CI/CD и скрипты (.github/, scripts/) enhancement New feature or request merge-when-green Согласие смержить без автора: авто-мерж включится, как позеленеет

Projects

None yet

2 participants