ci: full mutation gate runs nightly, outside the development and release cycle

The full registry run proves that tests can fail, not that the product
works; 4 of its 5 runs since 02.09 were manual dispatches tied to
releases. Owner decision 09.09: a daily schedule (01:00 UTC, before the
02:30 nightly Validate), failures reported as an issue by the existing
#472 job, no place in the development or release flow. Docs and the
workflow comments say so; the test pins the daily cron.

Issue: #513
User-Visible: no
This commit is contained in:
Codex
2026-09-09 20:49:08 +03:00
parent 9b65d4bcf7
commit 61905bacdc
4 changed files with 24 additions and 13 deletions
+12 -10
View File
@@ -5,11 +5,12 @@ name: Мутационный гейт
# оставшийся зелёным на сломанном коде, ничего не защищает — он лишь выглядит
# защитой, и это хуже его отсутствия.
#
# Прогон дорогой, поэтому он не входит в Validate и не идёт на каждый push.
# Его место — перед стабильным релизом (PROCESS.md §8) и раз в неделю по
# расписанию, чтобы дрейф тестов не копился до релиза. Дешёвая половина —
# «якоря патчей живы, guard-файлы существуют» — идёт с обычными юнитами:
# test/mutation-gate.test.mjs.
# Прогон дорогой и проверяет не продукт, а тесты, поэтому он не входит ни в
# Validate, ни в цикл разработки, ни в релизный гейт (#513, решение владельца
# 09.09): каждую ночь по расписанию, отказ — issue с отчётом (#472).
# Мутанты, задетые диффом, конвейер ревью гоняет отдельно на кандидате (#510).
# Дешёвая половина — «якоря патчей живы, guard-файлы существуют» — идёт с
# обычными юнитами: test/mutation-gate.test.mjs.
#
# #332: бандл собирается только мутантам с браузерным гвардом (guardNeedsBundle),
# компиляция тестов в worktree стартует с тёплого test-build (инкрементальный
@@ -25,14 +26,15 @@ on:
required: false
default: dev
schedule:
# Понедельник, 05:20 UTC — до начала рабочего дня владельца.
- cron: '20 5 * * 1'
# Каждую ночь, 01:00 UTC (04:00 MSK) — после суток правок и до ночного
# полного Validate (nightly.yml, 02:30 UTC), чтобы не делить раннеры (#513).
- cron: '0 1 * * *'
permissions:
contents: read
# Группа зависит от события (#472). Прежде она была одна на всё, и ручной
# запуск перед релизом отменял идущий по расписанию — так 24.08 погиб
# запуск (отладка гейта) отменял идущий по расписанию — так 24.08 погиб
# еженедельный прогон, а отменённый в списке выглядит «не красным». Поймать
# отмену изнутри нельзя: вместе с прогоном отменяются и не начавшиеся job,
# включая любой репортёр. Значит отмену надо не ловить, а не допускать.
@@ -111,8 +113,8 @@ jobs:
if-no-files-found: warn
retention-days: 30
# Адресат у отказа (#472). Только по расписанию: ручные прогоны перед
# релизом падают по замыслу, их результат владелец смотрит сам — issue на
# Адресат у отказа (#472). Только по расписанию: ручной dispatch остаётся
# для отладки самого гейта, его результат смотрят в прогоне — issue на
# каждый такой отказ был бы шумом, который снова перестанут читать.
#
# Права job-уровня ЗАМЕНЯЮТ права workflow, а не дополняют (прецедент —
+3 -1
View File
@@ -30,7 +30,9 @@
Проверка: `node scripts/mutation-gate.mjs --check` — якоря патчей живы;
полный прогон — workflow `mutation-gate.yml` (четыре чересполосных шарда,
`--shard=i/4`), перед стабильным релизом и по понедельникам. Дешёвая половина
`--shard=i/4`) каждую ночь по расписанию (01:00 UTC); в цикле разработки и в
релизном гейте он не участвует — проверяет тесты, а не продукт; отказ сам
заводит issue с отчётом (#472, #513). Дешёвая половина
идёт с юнитами: `test/mutation-gate.test.mjs`. Локально для дельты задачи —
`node scripts/mutation-gate.mjs --changed origin/dev..HEAD`: гоняются только
мутанты, чьи patch-файлы или **входы гарда** задеты диффом (#332, #475, #492).
+3 -2
View File
@@ -22,8 +22,9 @@
// worktree → патч → сборка бандла → бандл в demo/srv/assets → тест. Тест,
// оставшийся зелёным, — это провал гейта, а не успех теста.
//
// Прогон дорогой (пересборка бандла на мутанта), поэтому его место — перед
// стабильным релизом (.github/workflows/mutation-gate.yml), не на каждой бете.
// Прогон дорогой (пересборка бандла на мутанта) и проверяет тесты, а не
// продукт, поэтому его место — ночное расписание (.github/workflows/
// mutation-gate.yml, #513), вне цикла разработки и релиза; отказ — issue.
// Дешёвая часть — «патчи применимы, guard-файлы существуют» — живёт в
// test/mutation-gate.test.mjs и идёт с обычными юнитами: реестр, отставший от
// кода, хуже отсутствующего, потому что выглядит защитой.
+6
View File
@@ -260,6 +260,12 @@ const validateWorkflowText = readWorkflowFile(
new URL('../.github/workflows/validate.yml', import.meta.url), 'utf8',
);
test('#513 AC1: полный мутационный прогон идёт каждую ночь, не раз в неделю и не перед релизом', () => {
assert.match(mutationWorkflow, /- cron: '0 1 \* \* \*'/, 'ежедневно 01:00 UTC');
assert.ok(!/cron: '[^']*\* [0-6]'/.test(mutationWorkflow), 'недельного расписания (день недели) быть не должно');
assert.ok(!mutationWorkflow.includes('перед стабильным релизом'), 'полный прогон — не шаг релиза');
});
test('#472 AC1: у расписания и ручного запуска разные concurrency-группы', () => {
assert.match(mutationWorkflow, /group: mutation-gate-\$\{\{ github\.event_name \}\}/);
});