Files
houseplan-card/docs/reviews/CODE-REVIEW-472-r2.md
T
2026-09-06 12:37:04 +00:00

13 KiB
Raw Blame History

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 — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: f6df55ea4b6305533915ed7682917d70322708e3
    git log --all --format='%H %T' | grep f6df55ea4b63