mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-30 19:58:50 +00:00
docs: review document for #475
Проверка (CI) / Предполётные проверки: документация, провенанс, процесс (push) Failing after 1m16s
Проверка (CI) / Классификация изменённых файлов (push) Successful in 34s
Проверка (CI) / HACS: валидация репозитория (push) Skipped
Проверка (CI) / Hassfest: манифест интеграции (push) Skipped
Проверка (CI) / Мутанты по диффу: затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Skipped
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 1m11s
Проверка (CI) / Смоки в браузере (шард 1 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 2 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 3 из 3) (push) Skipped
Проверка (CI) / Смоки: все шарды зелёные (push) Skipped
Проверка (CI) / Golden-кадры против принятых эталонов (push) Skipped
Проверка (CI) / Перф-смок: бюджет времени кадра (push) Skipped
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Skipped
Проверка (CI) / Предполётные проверки: документация, провенанс, процесс (push) Failing after 1m16s
Проверка (CI) / Классификация изменённых файлов (push) Successful in 34s
Проверка (CI) / HACS: валидация репозитория (push) Skipped
Проверка (CI) / Hassfest: манифест интеграции (push) Skipped
Проверка (CI) / Мутанты по диффу: затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Skipped
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 1m11s
Проверка (CI) / Смоки в браузере (шард 1 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 2 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 3 из 3) (push) Skipped
Проверка (CI) / Смоки: все шарды зелёные (push) Skipped
Проверка (CI) / Golden-кадры против принятых эталонов (push) Skipped
Проверка (CI) / Перф-смок: бюджет времени кадра (push) Skipped
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Skipped
Issue: #475 User-Visible: no
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
# CODE-REVIEW-475-r2
|
||||
|
||||
Issue: #475 · «mutation-gate --check не отличает живого свидетеля от мёртвого»
|
||||
Трек: `small` (лёгкий) · Этап: код-ревью · Заход: r2 · блокирующих циклов 0/2
|
||||
|
||||
**Разбор — полный, не по дельте.** Ветка приведена конвейером к `dev` до
|
||||
ревью: поверх позиции r1 (`3ed8c920`) легло 5 коммитов `dev`, итог —
|
||||
`0540901c`. После ребейза это другой код (§7.2): полный разбор обязателен, а
|
||||
не сокращение по дельте §2.10, хотя раунд формально второй. Проверено: сами
|
||||
5 коммитов `dev` (`isometric overlay plates`, ревью #471/#472, обновление
|
||||
скриншотов) не пересекаются ни по одному файлу с диапазоном задачи
|
||||
(`git diff origin/dev...HEAD` — 5 файлов, все из диапазона `origin/dev..HEAD`
|
||||
для этой ветки, см. «Скоуп») — риск скрытого конфликта, ради которого
|
||||
предписан полный разбор, не материализовался, но раздел «Унаследовано»
|
||||
всё равно фиксирует это явно, а не тихо.
|
||||
|
||||
## Скоуп
|
||||
|
||||
`git diff origin/dev...HEAD` — 5 файлов, класс B (issue переиспользован,
|
||||
класса A нет ни одного файла):
|
||||
|
||||
- `.github/workflows/validate.yml` — выход `mutants` у job `changes`, третий
|
||||
дизъюнкт в триггере `changed_mutants`, сама job (уже существовала с r1,
|
||||
фикс только про триггер);
|
||||
- `scripts/mutation-gate.mjs` — `guardFiles()`, расширенный
|
||||
`selectChangedMutants()`, 2 мутанта (без изменений с r1);
|
||||
- `test/mutation-gate.test.mjs` — AC1–AC3, AC5–AC7; AC7 переписан (фикс r1);
|
||||
- `test/validate-workflow.test.mjs` — контракт на YAML (AC4), дополнен
|
||||
проверкой третьего дизъюнкта и классификатора `mutants` (фикс r1);
|
||||
- `docs/reviews/CODE-REVIEW-475-r1.md` — артефакт предыдущего раунда,
|
||||
контенту не рецензируется повторно.
|
||||
|
||||
## Как проверялось
|
||||
|
||||
Зелёного Validate на `0540901c` нет — прогон не найден, гейты прогнаны
|
||||
самостоятельно. Объём соразмерен классу B без правок в `src/**` (issue #127,
|
||||
PROCESS.md §8):
|
||||
|
||||
| Гейт | Команда | Результат |
|
||||
|---|---|---|
|
||||
| Typecheck | `npx tsc --noEmit` | зелёный |
|
||||
| Юниты | `npm test` | **2083 pass / 0 fail / 1 skip** |
|
||||
| Юниты по затронутым файлам отдельно | `node --test test/mutation-gate.test.mjs` · `node --test test/validate-workflow.test.mjs` | 17/17 и 11/11 pass, все `#475 AC*`-тесты и новый `AC4`-тест зелёные |
|
||||
| Сборка + синхрон бандла | `npm run build` → `cmp dist/houseplan-card.js custom_components/houseplan/frontend/houseplan-card.js` | зелёный, байт-в-байт; `git status` после сборки чист — правка не задевает `src/**`, бандл не изменился |
|
||||
| Новый код не добавляет `any` | `node scripts/no-new-any.mjs --base origin/dev --head HEAD` | «добавленных строк в `src/**/*.ts`: 0» — diff не касается `src/**` |
|
||||
| Отбор браузерных смоков | `node scripts/smoke-select.mjs --base origin/dev --head HEAD` | «Browser-smoke этим диффом не выбираются… src/**/*.ts не тронут» |
|
||||
| Реестр мутантов применим | `node scripts/mutation-gate.mjs --check` | **509/509 `ok`**, включая оба новых мутанта, дублей якоря нет |
|
||||
| Мутант `changed-selection-ignores-guard-files` | `node scripts/mutation-gate.mjs --id=changed-selection-ignores-guard-files` | чистый прогон ok → патч красит тест: «поймано 1 из 1» |
|
||||
| Мутант `changed-selection-matches-any-token` | `node scripts/mutation-gate.mjs --id=changed-selection-matches-any-token` | то же, «поймано 1 из 1» |
|
||||
| Самоприменение отбора к своему же диффу | `node scripts/mutation-gate.mjs --changed=origin/dev..HEAD` | «файлов в диффе 5, мутантов затронуто 4 из 509»: оба новых #475-мутанта плюс два не связанных с задачей (`workflow-scan-hardcodes-the-list`, `typing-gate-stops-running` — патчат тот же `validate.yml`); механизм отбирает сам себя корректно |
|
||||
| AC7 напрямую по реальному реестру | `node -e "...MUTANTS.filter(patch.file==='.../frontend_registration.py')..."` | ровно 4 id, включая `frontend-reload-notice-forgets-persisted-flag` — тот самый пропущенный в Low r1 |
|
||||
| Процессный гейт | `node scripts/process-gate.mjs --range fc5973c2..HEAD` | «гейт пройден, предупреждений 0»; ветка `issue/475-changed-mutants-on-push`, трейлеры `Issue:`/`User-Visible: no` на всех 3 коммитах диапазона |
|
||||
|
||||
**Не прогонялось и почему:**
|
||||
|
||||
- `python -m pytest tests_backend -q` — окружения ревью `.venv-backend`/`pytest`
|
||||
не содержит (`pip show pytest` → not found), задокументированное ограничение
|
||||
(AGENTS.md «Environments», PROCESS.md «Backend»), не следствие задачи.
|
||||
Диф не трогает ни один `.py`-файл продукта; самоприменение отбора наткнулось
|
||||
на ту же нехватку pytest на **чужом** мутанте (`typing-gate-stops-running`,
|
||||
не из #475) — это подтверждает ограничение среды, а не пробел задачи.
|
||||
Оба мутанта #475 проверены индивидуально через `--id=`, их гварды — `node --test`,
|
||||
pytest не требуют.
|
||||
- `check-docs.mjs`, `golden:verify`, `model-invariants`, performance-профили,
|
||||
`single-source-numbers` — diff не трогает `src/**`, визуал, геометрию или
|
||||
пользовательские числа; неприменимо, не пропуск.
|
||||
|
||||
## Находки
|
||||
|
||||
Блокирующих находок нет.
|
||||
|
||||
**Low, снят без правки (новый, не из r1):** `AGENTS.md:398-400` перечисляет
|
||||
«Gate jobs, matching the actual `validate.yml`» поимённо (`docs`, `provenance`,
|
||||
`process-gate`, `hacs`, `hassfest`, `frontend`, `smoke`, `golden`,
|
||||
`performance_smoke`, `backend`) и не включает новую `changed_mutants`, хотя
|
||||
она блокирующая (без `continue-on-error`, проверено `test/validate-workflow.test.mjs`).
|
||||
Проверено чтением `scripts/release-gate.mjs:9` (`classifyValidateRuns`) —
|
||||
критерий готовности релиза читает **общий вывод workflow-прогона** Validate
|
||||
через GitHub Actions API, а не имена отдельных job; красная `changed_mutants`
|
||||
красит весь прогон и блокирует релиз тем же путём, что и остальные job из
|
||||
списка. AC4 («job… входит в итоговый check») выполнен по факту — список в
|
||||
AGENTS.md чисто описательный для человека и не читается никаким скриптом
|
||||
(проверено: `grep -rn "Gate jobs, matching"` вне `AGENTS.md` пусто, синхронности
|
||||
с кодом никто не проверяет). Обновление списка не входило в DoD ТЗ (документация
|
||||
класса C не предмет этой задачи), и его отсутствие не создаёт функционального
|
||||
дефекта — только неполноту одного предложения в другом документе. Снимаю без
|
||||
правки.
|
||||
|
||||
## Проверка AC — таблица «чем доказан / чем краснеет»
|
||||
|
||||
| AC | Доказано | Чем | Чем краснеет |
|
||||
|---|---|---|---|
|
||||
| AC1 | unit | `test/mutation-gate.test.mjs` `#475 AC1` | не защитный AC (сравнение множества) |
|
||||
| AC2 | unit + мутант | `#475 AC2` | `changed-selection-ignores-guard-files`: «поймано 1 из 1» (прогнано лично) |
|
||||
| AC3 | unit + мутант | `#475 AC3` | `changed-selection-matches-any-token`: «поймано 1 из 1» (прогнано лично) |
|
||||
| AC4 | unit (YAML-контракт) + чтение | `test/validate-workflow.test.mjs` (новый тест `#475 AC4`) + чтение `validate.yml:411-465` | не защитный AC (расположение/текст job) — обычное сравнение ожидаемого текста с фактическим; тест прогнан лично, зелёный |
|
||||
| AC5 | unit + чтение | `#475 AC5` + `guardNeedsBundle` вызывается только для отобранных (чтение, не исполнение полного CI) | не защитный AC — расположение раннего выхода |
|
||||
| AC6 | unit | `#475 AC6`, реальный реестр | не защитный AC — сравнение множества id |
|
||||
| AC7 | unit (полный, фикс r1) + независимая проверка | `#475 AC7` (теперь фильтр по `patch.file`, не по префиксу id) + прямой запрос к `MUTANTS` (см. таблицу гейтов) | не защитный AC — сравнение множества id, но полнота множества (4, не 3) проверена мной по факту, а не на слово |
|
||||
|
||||
## Закрытие раунда r1
|
||||
|
||||
| Находка r1 | Чем закрыта | Где видно |
|
||||
|---|---|---|
|
||||
| **Medium** — триггер `changed_mutants` не покрывал изменение `scripts/mutation-gate.mjs` (третий дизъюнкт контракта §2 отсутствовал и в `if:`, и в контрактном тесте) | Классификатор получил выход `mutants` по точному пути `^scripts/mutation-gate\.mjs$`; триггер job — `frontend \|\| backend \|\| mutants`; все 3 fallback-ветки полного прогона выставляют `mutants=true` | `validate.yml:185,241,265,275,287,414` (прочитано построчно) + `test/validate-workflow.test.mjs` тест `#475 AC4` (прогнан лично, зелёный, проверяет все три места) |
|
||||
| **Low** — тест AC7 фильтровал бэкенд-мутанты по префиксу id (`frontend-registration-*`) и пропускал 4-й (`frontend-reload-notice-forgets-persisted-flag`), хотя код отбирал все 4 | Тест переписан на фильтр по `patch.file === 'custom_components/houseplan/frontend_registration.py'`, что автоматически включает все 4 | `test/mutation-gate.test.mjs` тест `#475 AC7` (прогнан лично) + независимый запрос к `MUTANTS` в этом раунде подтвердил ровно 4 id, включая четвёртый |
|
||||
|
||||
Обе находки закрыты кодом, а не заявлением автора — обе перепроверены
|
||||
самостоятельным прогоном/чтением в этом раунде.
|
||||
|
||||
## Унаследовано из r1
|
||||
|
||||
Формально не применимо в смысле «сокращения объёма» — разбор в этом раунде
|
||||
полный (см. причину в шапке документа), каждый AC1–AC7 и обе находки r1
|
||||
перепроверены заново на `0540901c`, а не приняты на слово. Из документа
|
||||
`docs/reviews/CODE-REVIEW-475-r1.md` (SHA материала `c0207af4`) взяты без
|
||||
повторного вывода только два факта, не подлежащие пересмотру кодом: перечень
|
||||
файлов диапазона (сверен заново и совпал) и формулировки самих находок
|
||||
(процитированы дословно в разделе «Закрытие раунда r1» — их текст не
|
||||
переизобретается, а их **закрытие** доказано отдельно). Спор о продуктовом
|
||||
контракте (что должен покрывать триггер) на этапе ТЗ решён в
|
||||
`SPEC-REVIEW-475-r1`/`r2` (жёлтый → зелёный) — это другой этап (§2.4, а не
|
||||
§2.7) и не переоткрывается здесь; код-ревью проверяло только соответствие
|
||||
уже принятому контракту, а не сам контракт.
|
||||
|
||||
## Что проверено и корректно
|
||||
|
||||
- `guardFiles()` — только токены `[\w./-]+\.(mjs|py)`, не начинающиеся с `-`,
|
||||
существующие в репозитории; проверено на `--test-name-pattern="magnet
|
||||
presses|x.mjs"` (юнит `#475 AC3`, прогнан лично) — фрагмент шаблона
|
||||
`presses|x.mjs"` корректно не считается файлом гарда (несуществующий
|
||||
символ `|` вне допустимого набора).
|
||||
- `selectChangedMutants(mutants, changedFiles, exists)` обратно совместима:
|
||||
вызов без третьего параметра (как в CLI, `mutation-gate.mjs:6891`)
|
||||
использует дефолтный `existsSync` внутри `guardFiles`; старый тест `#332`
|
||||
(шардирование) по-прежнему проходит без правок сигнатуры.
|
||||
- Мутанты #475 верно устроены: якорь `changed-selection-ignores-guard-files`
|
||||
собран из двух конкатенированных строк ровно затем, чтобы `--check` не
|
||||
находил его дважды (в коде и в определении) — подтверждено: `--check` даёт
|
||||
`ok`, дублей нет, реестр 507 → 509.
|
||||
- База диапазона в `changed_mutants` (`PROVEN_BASE`/`BEFORE_SHA`/
|
||||
`merge-base`-фолбэк) побайтово идентична уже работающему блоку в job
|
||||
`frontend` (гейт «новый код не добавляет any», #387/#388) — не новая
|
||||
логика, а переиспользованная; сверено построчно чтением обоих мест.
|
||||
- Установка Python и Chromium в `changed_mutants` дословно повторяет шаги
|
||||
`mutation-gate.yml` (checkout → setup-node → npm ci → setup-python 3.14 →
|
||||
`pip install -r tests_backend/requirements.txt` → кэш Playwright →
|
||||
установка при промахе) — сверено построчно.
|
||||
- Триггер `mutants` — точный путь (`^scripts/mutation-gate\.mjs$`), не
|
||||
расширяет отбор ложно на соседние файлы; регресса для уже принятых
|
||||
`frontend`/`backend`-веток нет — они лишь дополнены третьим условием
|
||||
через `||`, не заменены.
|
||||
- Трейлеры всех 3 коммитов диапазона (`Issue: #475`, `User-Visible: no`) —
|
||||
корректны для инфраструктурной правки без пользовательского эффекта;
|
||||
changelog не тронут, что верно при `User-Visible: no`; `process-gate.mjs`
|
||||
подтверждает нулём предупреждений.
|
||||
- Ни один другой файл репозитория не вызывает `selectChangedMutants`/
|
||||
`guardFiles` — изменение сигнатуры не создаёт риска регрессии на стороне
|
||||
вызывающего кода (проверено `grep` по `*.mjs`/`*.ts`).
|
||||
|
||||
## Чего не проверял
|
||||
|
||||
- Полный `pytest tests_backend` (среда без `.venv-backend`) — см. «Как
|
||||
проверялось». Ограничение среды, не задачи.
|
||||
- Поведение `changed_mutants` job живьём в GitHub Actions (реальный запуск
|
||||
runner, кэш Playwright, реальный `github.event.before` на push-событии) —
|
||||
логика веток `EVENT_NAME`/`REF`/`PROVEN_BASE` проверена чтением и сверкой
|
||||
с идентичным уже работающим кодом job `frontend`, не отдельным прогоном
|
||||
workflow (это доступно только через реальный CI прогон на push, вне
|
||||
ревью).
|
||||
- Полноту списка «Gate jobs» в `AGENTS.md` как автоматизированного контракта
|
||||
— там нет читающего его скрипта; см. Low.
|
||||
|
||||
## Вердикт
|
||||
|
||||
Зелёный. Обе находки r1 (Medium и Low) закрыты и проверены самостоятельно, а
|
||||
не на слово автора. Новых High/Medium находок нет. Единственная новая
|
||||
находка — Low вне блокирующего порога, снята без правки с объяснением, почему
|
||||
функционального дефекта нет. Полный разбор всех AC подтверждает, что задача
|
||||
решает заявленный сценарий: разрыв «неделя–релиз» для отбора мутантов по
|
||||
диффу закрыт, включая триггер по правке самого реестра и по бэкенд-мутантам.
|
||||
|
||||
---
|
||||
|
||||
## Материал раунда
|
||||
|
||||
- Ветка: `issue/475-changed-mutants-on-push`, вершина `0540901cda486724a65ebcd9c4cb4f6d36bde906`.
|
||||
- Диапазон разбора: `origin/dev..HEAD` (`fc5973c2..0540901c`), 3 коммита задачи.
|
||||
- Предыдущий заход: `docs/reviews/CODE-REVIEW-475-r1.md`, SHA материала `c0207af4` (осиротевший после ребейза — ожидаемо, §2.10).
|
||||
|
||||
---
|
||||
|
||||
<!-- material-anchors: сгенерировано конвейером (#414) -->
|
||||
|
||||
## Материал раунда
|
||||
|
||||
- Ветка: `issue/475-changed-mutants-on-push`, коммит `3ed8c9204473` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
|
||||
- Дерево материала: `12506be1e214ea1080a510d34089b505127c22bb`
|
||||
```
|
||||
git log --all --format='%H %T' | grep 12506be1e214
|
||||
```
|
||||
Reference in New Issue
Block a user