# CODE-REVIEW-513-r1 Заход: r1 · блокирующих циклов израсходовано 0 из 2 ## Материал - Диапазон: `git log --oneline origin/dev..HEAD` → один коммит, `61905bacdc5a9f08cd70562d7a43b50b8ad88c4a` («ci: full mutation gate runs nightly, outside the development and release cycle»), рабочая копия уже на нём. - Диффстат (`git diff origin/dev...HEAD --stat`): ``` .github/workflows/mutation-gate.yml | 22 ++++++++++++---------- docs/TESTING.md | 4 +++- scripts/mutation-gate.mjs | 5 +++-- test/mutation-gate.test.mjs | 6 ++++++ 4 files changed, 24 insertions(+), 13 deletions(-) ``` - Трейлеры коммита: `Issue: #513`, `User-Visible: no` — оба присутствуют, формат верный. `User-Visible: no` соответствует факту: правка не меняет ни UX, ни модель данных, ни конфиг — только расписание CI-джобы и тексты комментариев/доков. Правок `docs/CHANGELOG.md`/`docs/CHANGELOG.ru.md` нет, что и требуется при `User-Visible: no`. - Метка `small` — ТЗ в теле issue, файла в `docs/specs/` нет и не должно быть. Соответствует. ## Скоуп Issue #513: полный мутационный прогон (`mutation-gate.yml`) проверяет не продукт, а способность тестов падать; решение владельца 09.09 — гонять его ежедневно ночью по расписанию, вне цикла разработки и вне релизного гейта, отказ заводит issue отчётом (механизм #472). Диффу соответствует ровно эта формулировка: правка не трогает продуктовый код, `src/**` не затронут. Соответствие docs/SCOPE.md: изменение процессное (CI-гигиена), напрямую не служит ни одной строке Core user jobs, но и не обязано — это класс C (инфраструктура тестирования), допустимый вне рамки job-листа по той же логике, что и остальной тестовый/CI-аппарат проекта. ## Как проверялось 1. Прочитал тело issue #513 и хендофф-комментарий (Codex, 09.09) через `gh issue view 513 --json body,comments,labels`. 2. Прочитал полный `git diff origin/dev...HEAD` — четыре файла, все правки по существу совпадают с ТЗ пункт за пунктом (см. ниже разбор по AC). 3. Проверил трейлеры коммита (`git log -1 --format=%B`). 4. Прогнал `node --test test/mutation-gate.test.mjs` — 42/42 зелёных (хендофф заявляет «44/44»; расхождение в счётчике не влияет на содержание, тесты не переименованы и не удалены относительно dev — не считаю это находкой, только фиксирую расхождение с заявленным числом). 5. Проверил дисциплину «тест умеет падать»: временно откатил cron в `.github/workflows/mutation-gate.yml` на старое недельное расписание (`'20 5 * * 1'`) и перезапустил `test/mutation-gate.test.mjs` — новый тест `#513 AC1` действительно падает (`not ok 14`), остальные тесты не затронуты. Файл восстановлен `cp` из бэкапа, `git status --short` после восстановления — пусто, рабочее дерево чистое. 6. Проверил AC2 отдельно: `if: always() && github.event_name == 'schedule' && ...` в report-job (`.github/workflows/mutation-gate.yml:125`) не менялся этим диффом и остаётся верным — ручной dispatch по-прежнему не заводит issue. 7. Проверил отсутствие коллизии по времени с ночным Validate: `nightly.yml` cron `'30 2 * * *'` (02:30 UTC) против нового `'0 1 * * *'` (01:00 UTC) в `mutation-gate.yml` — разнесены на 1.5 часа, как заявлено в комментарии коммита. 8. Проверил AC3 («ни один документ процесса не называет полный мутационный прогон шагом разработки или релиза») не только на изменённых файлах, а поиском по всему дереву: `grep -rn "предрелизный гейт"`, `grep -rn "мутацион"` по `*.md`/`*.mjs`/`*.yml`, поиск остатков старого cron `'20 5 * * 1'` и фразы «по понедельникам». Здесь нашлась находка — см. ниже. 9. Проверил `docs/specs/README.md` (ТЗ пункт 3 называет этот файл в списке документации к правке) — файл не содержит вообще ни одного упоминания мутационного гейта ни до, ни после дельты; менять там было нечего, это не пропуск, а пункт ТЗ, применимый только если бы там было устаревшее упоминание. ## Находки ### Medium (в скоупе) — `scripts/pre-push-gate.mjs` продолжает называть полный мутационный реестр предрелизным гейтом `scripts/pre-push-gate.mjs:22-24` (комментарий) и `scripts/pre-push-gate.mjs:182-183` (текст, который печатается разработчику при каждом локальном прогоне перед push) буквально утверждают: ``` * HA-харнесс и весь мутационный реестр — предрелизный гейт; здесь только то, ... console.log(' · golden, полная матрица смоков, HA-харнесс, весь мутационный реестр —' + ' предрелизный гейт, не этот набор'); ``` Это прямо противоречит решению владельца и AC3 этой задачи: полный мутационный реестр (`mutation-gate.yml`, шардированный прогон) с этим диффом явно выведен и из цикла разработки, и из релизного гейта — он живёт только по ночному расписанию, отвязанно от push и релиза (см. новые комментарии в самом `mutation-gate.yml` и `docs/TESTING.md`). А `pre-push-gate.mjs` — это именно инструмент цикла разработки (запускается разработчиком перед push) и именно документ процесса в духе AC3: он объясняет, какие гейты куда относятся. После этой правки он продолжает говорить каждому разработчику, что «весь мутационный реестр» нужно гонять «перед стабильным релизом» — а это больше не так. **Воспроизведение:** `node scripts/pre-push-gate.mjs` (или просто чтение файла) — строка 183 напечатает утверждение, которое прямо противоречит новому тексту `docs/TESTING.md:33-34` («в цикле разработки и в релизном гейте он не участвует») и новому комментарию `scripts/mutation-gate.mjs` («вне цикла разработки и релиза»). **Почему это Medium, а не High:** ничего не ломается технически — CI не краснеет, тесты не врут о своём результате, само поведение гейтов (cron, report-job) реализовано верно и проверяется тестом. Это стилистически- информационный дефект: неверная строка в выводе локального скрипта и в его шапке-комментарии, который непосредственно относится к предмету задачи и буквально противоречит её AC3 («ни один документ процесса не называет полный мутационный прогон шагом разработки или релиза»). Это тот случай, который задача была обязана закрыть, но не закрыла — правка тривиальна (переформулировать две строки), поэтому это годится чинить прямо в этой задаче, а не заводить отдельный issue (Medium в скоупе, PROCESS.md §12). **Предложение по правке (не мной вносится, для автора):** заменить «HA-харнесс и весь мутационный реестр — предрелизный гейт» на формулировку, согласованную с новым текстом `docs/TESTING.md`/`mutation-gate.mjs` — например, «HA-харнесс — предрелизный гейт, весь мутационный реестр — ночное расписание вне цикла разработки и релиза (#513)» — в обоих местах (комментарий и `console.log`). ## Разбор по AC - **AC1** (cron ежедневный `0 1 * * *`, тест краснеет при смене на недельное). Выполнен. `mutation-gate.yml:29` → `- cron: '0 1 * * *'`. Тест `test/mutation-gate.test.mjs:263` пинит этот cron и явно запрещает day-of-week компонент и фразу «перед стабильным релизом». Тест умеет падать — проверено экспериментально (см. «Как проверялось», п.5). - **AC2** (report-job заводит/дописывает issue только для schedule-прогонов). Выполнен, без изменений в этом диффе — условие `github.event_name == 'schedule'` на месте (`.github/workflows/mutation-gate.yml:125`), покрыто существующим тестом `#472 AC1`/сопутствующими (не переписывался этой задачей, дельта его не касается). - **AC3** (ни один документ процесса не называет полный прогон шагом разработки или релиза). **Не выполнен полностью** — см. находку выше: `scripts/pre-push-gate.mjs` продолжает называть весь мутационный реестр «предрелизным гейтом» в комментарии и в фактическом выводе скрипта. `docs/TESTING.md`, `scripts/mutation-gate.mjs` (шапка) и `.github/workflows/mutation-gate.yml` (комментарии) — исправлены верно. - **AC4** (`User-Visible: no`; UX/i18n/модель данных не затронуты). Выполнен — диффу не затрагивает `src/**`, только CI/доки/тест; трейлер коммита соответствует. ## Что проверено и корректно - Cron не пересекается по времени с ночным Validate (1.5 часа разницы). - `workflow_dispatch` по-прежнему доступен для отладки самого гейта, но report-job на него не реагирует — issue не заводится на ручных прогонах, как и требовалось. - Текст `docs/TESTING.md` и шапка `scripts/mutation-gate.mjs` согласованы друг с другом и с новым поведением workflow. - Мутанты по диффу (#510, локальный `--changed`) — не путаются с полным ночным прогоном, это разные механизмы, задача их не смешивает. - Класс изменений (C: workflow/доки/тест) соответствует фактическому диффу, `git diff --stat` не содержит правок продуктового кода. ## Чего не проверял и почему - `npx tsc --noEmit`, `npm test` (полный), `npm run build` со сверкой трёх копий бандла — **не прогонял отдельно**. Validate на этом же SHA (`61905bac`) зелёный (ссылка в задаче на прогон), diff не трогает `src/**`, поэтому дельта с этим прогоном нулевая по тем поверхностям, которые эти гейты проверяют. - `node scripts/check-docs.mjs` — не прогонял: diff не трогает `src/**` (только `.github/workflows`, `docs/TESTING.md`, `scripts/mutation-gate.mjs`, `test/mutation-gate.test.mjs`), отпечаток скриншотов документации не мог устареть от этой правки. - `npm run invariants` / инварианты модели — не применимо: диффу не затрагивает геометрию, рёбра, `layout`, `marker.space`, `open_spans`. - Браузерные смоки `demo/smoke_*.mjs` — не прогонял и не выбирал через `scripts/smoke-select.mjs`: diff не трогает ни один файл, от которого зависит рендер или демо-сервер; выборка тривиально пуста по составу diff'а (workflow/CI-доки/тест одного скрипта). - `npm run golden:verify` — не применимо, визуал не менялся. - `python -m pytest tests_backend` — не применимо, `custom_components/**/*.py` не тронут. - Performance-профили — не применимо, в AC не названы и чувствительный код не тронут. - Полный `node scripts/mutation-gate.mjs` (без `--changed`) — не прогонял: это дорогой прогон (~37 мин, ~100 job-мин), сама задача выводит его из цикла разработки и ревью; локально прогнал только дешёвую часть — `test/mutation-gate.test.mjs` (см. «Как проверялось»). - «Одно число — один источник»: неприменимо, диффу не добавляет и не меняет ни одной пользовательски видимой величины (только CI-расписание и текст документации/комментариев). ## Вердикт Жёлтый. AC1, AC2, AC4 выполнены и подтверждены (тест краснеет на мутации, report-job условие корректно, User-Visible верен). AC3 не закрыт полностью: `scripts/pre-push-gate.mjs` остаётся документом процесса, который прямо противоречит принятому в этой же задаче решению — Medium в скоупе, чинится в этой же задаче без нового issue. --- ## Материал раунда - Ветка: `issue/513-mutation-gate-nightly`, коммит `61905bacdc5a` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала: `0ff88d8c67bc15b1170c5a0164b6d94f15af2bfe` ``` git log --all --format='%H %T' | grep 0ff88d8c67bc ``` - Вердикт конвейера: `yellow` · High 0