13 KiB
CODE-REVIEW-472-r2
Issue: #472 — «Полный мутационный прогон по расписанию падал дважды подряд без
реакции: у отказа нет адресата». Лёгкий трек (small). Код-ревью, заход r2,
блокирующих циклов израсходовано 1 из 2.
Материал раунда
- SHA материала:
57a4a0ed69d01f0e1bf710f44f287cdc32c1e8fd(git rev-parse HEAD) - Предыдущий заход (r1):
docs/reviews/CODE-REVIEW-472-r1.md, вердикт — жёлтый, найдена M1 (SHA отчёта берётся изgithub.sha, а дляscheduleэто вершинаmain, неdev), проверено наdec6c03e89af48f570bf60994b99aeacba0cb966. - Этот SHA (
dec6c03e…) сегодня недостижим ни из одной ветки/тега — провереноgit cat-file -t dec6c03e(объект не найден) иgit log --all. Ветка была ещё раз приведена кdevконвейером между r1 и r2 (тот же механизм, что уже осиротилa8ea3b8aмежду исходной реализацией и r1 — «material-anchors», PROCESS.md §7.2). Восстановил доверие к преемственности не по названию SHA, а по содержимому: коммитe76f3909(«ci: отчёт об отказе расписания мутантов…», текущий предок делты) даёт побайтово тот жеgit diff --stat, что зафиксирован в «Скоуп диффа» CODE-REVIEW-472-r1.md (105/28/177/34/99/49 строк по тем же шести файлам) — содержимое, прорецензированное в r1, и содержимое подe76f3909— один и тот же текст, просто с новым SHA после ребейза. Дельта раунда — ровно один коммит поверх этого дерева:57a4a0ed ci: SHA отчёта mutation-gate — от чекаута dev, не github.sha (#472 r1)— единственный коммит послеd77d1953(публикация документа r1).
- Трейлеры дельты:
Issue: #472,User-Visible: no— верно, диапазон CI-only, changelog не тронут. - Зелёного
Validateна57a4a0edнет (см. системное примечание к заходу) — дешёвые гейты прогнаны мной, см. ниже.
Дельта раунда
.github/workflows/mutation-gate.yml | 5 ++++-
test/mutation-gate.test.mjs | 8 ++++++++
2 files changed, 12 insertions(+), 1 deletion(-)
- SHA: ${{ github.sha }}
run: |
+ # SHA — того дерева, которое чекаутили и гоняли (dev), а не
+ # github.sha: для расписания это вершина default-ветки main, и отчёт
+ # называл бы «dev @ <SHA main>» (ревью r1). Образец — process.yml.
+ SHA=$(git rev-parse HEAD)
mkdir -p artifacts
node scripts/mutation-gate-report.mjs \
--logs=artifacts/mutation-logs --shards=4 \
--run-url="$RUN_URL" --ref=dev --sha="$SHA" \
плюс новый контрактный тест #472 r1: SHA отчёта — от чекаута dev, а не github.sha.
Диапазон не тронул ничего за пределами mutation-gate.yml и одного тестового
файла: ни src/**, ни custom_components/**/*.py, ни другие workflow.
Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
M1 — SHA в отчёте брался из github.sha (вершина main для schedule), а не из чекаутнутого dev |
Строка env: SHA: ${{ github.sha }} убрана из блока env; вместо неё в теле шага SHA=$(git rev-parse HEAD), выполняется после actions/checkout@v7 с ref: dev (проверено чтением: шаг checkout идёт раньше в том же job report, mutation-gate.yml:124-153) |
.github/workflows/mutation-gate.yml, шаг «Собрать отчёт» job report; подтверждено исполнением — новый тест «17 pass» при фиксе, и я вручную откатил строку на ${{ github.sha }} в рабочей копии: тест падает (17 pass / 1 fail), значит утверждение теста небутафорское |
| L1 — поиск открытого issue по заголовку (кириллица) не проверен вживую против реального GitHub API | Не код-находка, а решение: автор явно принял риск («Low — принято, понаблюдаем на первом реальном отказе») — сам r1-документ и автор согласились, что это не блокирует и альтернативы без сетевого доступа нет | Комментарий автора в issue от 12:17:55Z: «L1 — принято, понаблюдаем на первом реальном отказе»; изменений кода не требовалось и не вносилось |
Оба закрытия проверены не по заявлению автора: M1 — исполнением теста в обе стороны (падает без фикса, проходит с фиксом), L1 — это принятый риск с явной записью, а не пропуск.
Унаследовано из r1
Всё, чего не касается делта (весь диапазон, кроме env: SHA и одного нового
теста), наследуется из docs/reviews/CODE-REVIEW-472-r1.md (SHA материала
dec6c03e, содержимое эквивалентно текущему e76f3909 — см. сверку diff-stat
выше) без повторной проверки:
- AC1 (concurrency-группы
schedule/workflow_dispatchразные) — контрактный тест + чтение. - AC2 (лог шарда — артефакт,
if: always(),PIPESTATUS/pipefailсохраняет код выхода) — контрактный тест + чтение. - AC3 (сбор
escaped/redGuards/unparsed, дедуп, статусmissing) — 8 юнитов + 3 мутанта задачи, каждый прогнан индивидуально «поймано 1 из 1» на реальном исполнении (изолированный git-worktree). - AC4 (заголовок с маркером, тело — прогон/SHA/
--id=) — юнит; замечание r1 (SHA неверный) устранено делтой этого раунда, сама структура тела не менялась. - AC4b (отдельные разделы
redGuards/unparsed, ни один не превращается в--id=) — юниты + мутантmutation-report-red-guard-as-mutant, прогнан индивидуально. - AC5 (job
report: толькоscheduleи не-успех, праваcontents/actions/issuesполностью) — контрактный тест + чтение. - AC6 (повторный отказ — комментарий, не второе issue) — контрактный тест на порядок вызовов
gh+jq-фильтр воспроизведён локально на фикстуре автором ревью r1. - AC7 (нет Telegram-секретов — не отказ) — контрактный тест + чтение условного шага.
- AC8 (
mutation-gate.ymlпод сверкойmain/devнаравне сprocess.yml) — контрактный тест + чтениеvalidate.yml. - Плюмбинг артефактов (
upload-artifact→download-artifact→ путь, который читаетmutation-gate-report.mjs) — прослежен логически в r1. - Откат («Одним коммитом») — не менялся этой делтой.
Эти пункты дельта не задевает: делта — это одна переменная окружения и один тест поверх неизменного контракта. Причин перепроверять AC1-AC3, AC5-AC8 нет — код, который их доказывает, не тронут.
Гейты этого раунда
| Гейт | Команда | Результат |
|---|---|---|
| typecheck | npx tsc --noEmit |
зелёный, 0 ошибок |
| unit (полный набор) | npm test |
2107 тестов, pass 2106, fail 0, skipped 1 |
| unit (точечно, дельта) | node --test test/mutation-gate.test.mjs |
18/18 pass; при ручном откате SHA=$(git rev-parse HEAD) → SHA=${{ github.sha }} — 17 pass / 1 fail (новый тест ловит регресс) |
| build + сверка 3 копий бандла | npm run build (tsc+rollup), затем node scripts/bundle-sync.mjs |
build зелёный; bundle-sync не оставил diff в custom_components/houseplan/frontend и demo/srv/assets — три копии уже совпадали |
| provenance | node scripts/validate-commit-provenance.mjs 57a4a0ed~1..57a4a0ed |
exit 0 |
| smoke-select | node scripts/smoke-select.mjs --base origin/dev --head HEAD |
«Исполняемого frontend-диффа нет… смоки этим диффом не выбираются», тронуто файлов: 7 — браузерные смоки не нужны |
Диапазон origin/dev..HEAD (не только делта раунда) не трогает src/** —
check-docs, no-new-any, golden, backend pytest, model-invariants,
perf-профили и полный (255) мутационный прогон неприменимы по тем же причинам,
что и в r1 (см. «Чего не проверял» там); делта этого раунда их тем более не
касается.
Что проверено и корректно
- M1 закрыта корректно:
SHA=$(git rev-parse HEAD)выполняется послеcheckout … ref: devв том же job — вычисленное значение соответствует дереву, которое реально гоняли мутанты, а не вершинеmain. - Новый тест умеет падать: проверено вручную откатом строки в рабочей копии (17/18 → 1 fail), а не «Verified» без исполнения.
- Трейлеры дельты (
Issue: #472,User-Visible: no) верны; changelog не тронут — корректно для CI-only правки. - Дешёвые гейты (typecheck/unit/build+3 копии бандла/provenance) зелёные на
57a4a0ed. - Унаследованные AC1-AC8+AC4b не задеты делтой — перепроверка не требовалась.
Чего не проверял
- Живое поведение
gh issue list --searchпротив реального API (L1) — не проверялось ни в r1, ни сейчас: принятый риск, не в скоупе делты. - Полный (255) мутационный прогон — предрелизный гейт, не гейт ревью.
check-docs, golden, backend pytest, browser-smokes, perf-профили — diff не трогаетsrc/**/Python/визуал/perf-путь;smoke-selectподтверждает отсутствие исполняемого frontend-диффа.- Зеркалирование
mutation-gate.ymlвmainпосле мержа — ручной постмерж-шаг вне этого коммита, как отмечено в r1.
Вердикт
Зелёный. Единственная находка r1 (M1) закрыта по существу и подтверждена исполнением (тест падает без фикса, проходит с фиксом); L1 — принятый автором риск без кода. Дельта раунда минимальна и не затрагивает ничего, что требовало бы переоткрытия AC1-AC8. Дешёвые гейты зелёные.
Материал раунда
- Ветка:
issue/472-mutation-gate-report, коммит57a4a0ed69d0— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
f6df55ea4b6305533915ed7682917d70322708e3git log --all --format='%H %T' | grep f6df55ea4b63