mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
@@ -0,0 +1,150 @@
|
|||||||
|
# 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(-)
|
||||||
|
```
|
||||||
|
|
||||||
|
```diff
|
||||||
|
- 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. Дешёвые гейты зелёные.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- material-anchors: сгенерировано конвейером (#414) -->
|
||||||
|
|
||||||
|
## Материал раунда
|
||||||
|
|
||||||
|
- Ветка: `issue/472-mutation-gate-report`, коммит `57a4a0ed69d0` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
|
||||||
|
- Дерево материала: `f6df55ea4b6305533915ed7682917d70322708e3`
|
||||||
|
```
|
||||||
|
git log --all --format='%H %T' | grep f6df55ea4b63
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user