Files
houseplan-card/docs/reviews/CODE-REVIEW-329-r3.md
T
claude[bot] 2c4b505f1a
Проверка (CI) / Процесс: process.yml идентичен в main и dev (push) Successful in 2m48s
Проверка (CI) / Провенанс коммитов: трейлеры и эталоны (push) Successful in 2m31s
Проверка (CI) / Процессный гейт: диапазон, трейлеры, статусы issue (push) Successful in 2m30s
Проверка (CI) / Классификация изменённых файлов (push) Successful in 36s
Проверка (CI) / HACS: валидация репозитория (push) Skipped
Проверка (CI) / Hassfest: манифест интеграции (push) Skipped
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Skipped
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 38s
Проверка (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 47s
docs: review document for #329
Issue: #329
User-Visible: no
2026-08-27 21:49:59 +00:00

158 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CODE-REVIEW-329-r3
Этап: code · заход r3 · блокирующих циклов израсходовано 2 из 4
## Скоуп раунда
Предыдущий вердикт (code r2, `226`-й комментарий issue) — красный,
единственная находка **r2-H1**: мутант `junction-limit-backend-raw-baseline`
в `scripts/mutation-gate.mjs` был добавлен с `guard: 'python3 -m pytest
tests_backend/test_junction_limits.py -q'`, в обход конвенции ВСЕХ прочих
бэкенд-мутантов реестра (`node scripts/backend-test-guard.mjs <pattern>
<file>`), из-за чего `test/mutation-gate.test.mjs` красился на CI.
Вердикт r2 получен на SHA `26c6e870` (Matysh: «Актуальный HEAD ветки для
ревью — `26c6e870`», непосредственно перед вердиктом). Автор закрыл
находку коммитом `273b0d5e`, текущий HEAD.
Дельта этого раунда:
```
git diff 26c6e870..HEAD --stat (без docs/reviews/*)
scripts/mutation-gate.mjs | 4 ++--
test/mutation-gate.test.mjs | 6 +-----
2 files changed, 3 insertions(+), 7 deletions(-)
```
Дельта не затрагивает `src/**`, бэкенд-продакшен-код, геометрию, документацию
пользователя — только реестр мутантов и его контрактный тест. Это ровно то,
что запрошено находкой r2-H1, без побочных правок. Разбор по дельте признан
достаточным: изменение локально, не является ребейзом, не меняет контракт
поведения продукта и по объёму несопоставимо мало относительно исходной
задачи (две строки правки guard + возврат теста к исходному виду).
## Что проверено (дельта)
1. **Форма guard соответствует конвенции.** Новый guard —
`node scripts/backend-test-guard.mjs
test_legacy_baseline_is_judged_after_the_same_migration
tests_backend/test_junction_limits.py` — совпадает по форме со всеми
остальными записями реестра, использующими бэкенд-хелпер (проверено
`grep -n "backend-test-guard" scripts/mutation-gate.mjs` — 16 вхождений,
новое неотличимо от прочих).
2. **Контракт теста возвращён к исходному виду.**
`test/mutation-gate.test.mjs` снова требует, чтобы guard называл `.mjs`
(убрана временная ветка `.py`, убран комментарий-объяснение, который её
оправдывал). `grep` подтвердил: других мутантов, называющих `.py`
напрямую (в обход хелпера), в реестре нет — правка не откроет дыру для
будущих аналогичных случаев.
3. **Мутант по-прежнему ловит регрессию.** Прогнан НЕ ТОЛЬКО `--check`
(проверяет только уникальность якоря патча), а полный цикл конкретного
мутанта:
`node scripts/mutation-gate.mjs --id=junction-limit-backend-raw-baseline`
→
```
ok чистый прогон: node scripts/backend-test-guard.mjs test_legacy_baseline_is_judged_after_the_same_migration tests_backend/test_junction_limits.py
ok junction-limit-backend-raw-baseline: тест покраснел, как обязан
поймано 1 из 1
```
То есть подтверждено обеими половинами: код без мутации проходит целевой
тест, а с применённым патчем (`migrated = config` вместо прогона через
`commit_wall_segment_model`) целевой тест красится. Это и есть доказательство
«тест умеет падать» для данной находки.
4. **pytest напрямую.** `python3 -m pytest tests_backend/test_junction_limits.py -q`
→ `8 passed`. (pytest в песочнице ревью отсутствовал изначально, установлен
`pip3 install --user pytest` — тот же шаг, что r2 констатировал как разовую
особенность окружения, не продукта.)
5. **`npm test`** → `# tests 1391 / # pass 1390 / # fail 0 / # skipped 1`,
совпадает с итогом, который автор указал в коммите `273b0d5e`.
6. **`npx tsc --noEmit`** — чисто (дельта не трогает `.ts`, но прогнан по
правилу «всегда»).
7. **`npm run build`** — собрался, `dist/houseplan-card.js` создан.
Сверка бандла: `cmp dist/houseplan-card.js
custom_components/houseplan/frontend/houseplan-card.js` — совпадает
побайтово. Третья копия, `demo/srv/assets/houseplan-card.js`, в дереве
отсутствует (она untracked рабочая копия demo-стенда, `bundle-sync.mjs`
создаёт её по требованию) — отсутствие ожидаемо и не связано с этой
правкой, дельта фронтенд не трогает.
8. **`node scripts/check-docs.mjs`** → `Documentation checks passed (7 files,
10 external links)`. Формально необязателен (дельта не в `src/**`), прогнан
по инерции — зелёный.
9. **`node scripts/smoke-select.mjs --base 26c6e870 --head HEAD`** →
«Исполняемого frontend-диффа нет (`src/**/*.ts` не тронут). Browser-smoke
этим диффом не выбираются — выбирать нечего». Полный прогон смоков не
делал — инструмент прямо говорит, что выбирать нечего, а не «неопределённость».
## Закрытие раунда r2
| Находка | Чем закрыта | Где это видно |
|---|---|---|
| r2-H1: guard бэкенд-мутанта в обход конвенции `.mjs`-хелпера, контрактный тест красный на CI | `scripts/mutation-gate.mjs`: guard мутанта `junction-limit-backend-raw-baseline` переписан на `node scripts/backend-test-guard.mjs test_legacy_baseline_is_judged_after_the_same_migration tests_backend/test_junction_limits.py`; `test/mutation-gate.test.mjs`: контракт `every guard command points at a file that exists` возвращён к проверке только `.mjs`, временная ветка для `.py` и оправдывающий её комментарий убраны | Коммит `273b0d5e`; `npm test` 1390/0 (было 1389 passed/1 failed на `0824e510`); точечный прогон `node scripts/mutation-gate.mjs --id=junction-limit-backend-raw-baseline` — «поймано 1 из 1» |
## Унаследовано из r2 (и, транзитивно, из r1)
Без повторной проверки исполнением приняты — дельта r3 их не касается кодом,
которого они доказывают:
- **H1 (бэкенд мигрирует обе стороны перед сравнением)** — доказано в r1,
подтверждено закрытым в r2 тестом `test_legacy_baseline_is_judged_after_the_same_migration`
и мутантом. Документ: `docs/reviews/CODE-REVIEW-329-r2.md`, раздел
«Закрытие раунда r1», SHA `26c6e870`.
- **M1 (мёртвый код `apexCaps`/`clipPolygonOutsideCap`/`degenerateApexCaps`
удалён)** — `docs/reviews/CODE-REVIEW-329-r2.md`, SHA `26c6e870`.
- **M2/M3 (дубль раздела USER-GUIDE устранён, канал Resize описан верно)** —
там же, SHA `26c6e870`.
- **M4 (AC10, Optimize не создаёт новых нарушений, доказан двумя юнитами)** —
там же, SHA `26c6e870`.
- **Остальные AC (П1–П5 юниты и границы, §4 честная вершина + golden, AC5a/b,
AC7a через реальный pointer-жест, AC7b, паритет AC9, скоуп применения AC8)** —
впервые проверены и признаны корректными в `docs/reviews/CODE-REVIEW-329-r1.md`,
подтверждены неизменными в r2 (дельта r1→r2 их не трогала за вычетом
перечисленных выше M1–M4 и H1); дельта r2→r3 тем более их не трогает
(единственные изменённые файлы — `scripts/mutation-gate.mjs` и
`test/mutation-gate.test.mjs`, не пересекающиеся с производственным кодом
junction-limits, рендером или бэкендом). Документ: `docs/reviews/CODE-REVIEW-329-r1.md`,
SHA `e1df015d`; golden/invariants/мутанты для этих AC — из отчёта r1
(«что прогнано»).
- **Полный HA-harness backend не прогоняется** — унаследованный пробел
окружения, констатирован ещё в r1 (недоступны `homeassistant`/`voluptuous`),
подтверждён в r2, в r3 не переоценивался — дельта его не касается.
## Чего не проверял в этом раунде и почему
- **`npm run golden:verify`** — не прогонял. Дельта не трогает рендер,
геометрию, стили, слои; полная матрица (~80 сцен) уже прогнана и зелёная
в r2 на коде, который в r3 не менялся.
- **`npm run invariants`** — не прогонял. Дельта не трогает рёбра комнат,
записи толщины, `layout`, `marker.space`, `open_spans` — инварианты модели
здесь неприменимы.
- **Браузерные смоки** — не прогонял ни одного. `smoke-select.mjs` для
диапазона `26c6e870..HEAD` прямо сообщает «выбирать нечего»: единственные
изменённые файлы — `scripts/mutation-gate.mjs` и `test/mutation-gate.test.mjs`,
оба вне `src/**`, ни один смок такой диапазон не оценивает даже как слабую
связь.
- **`python -m pytest tests_backend -q` (полный набор)** — прогнал только
файл `test_junction_limits.py`, целевой для находки; полный бэкенд-набор
не запускал, так как дельта не трогает бэкенд-продакшен-код (только тест
и реестр мутантов на фронтенде/CI), а `test_junction_limits.py` — тот файл,
контракт которого проверяет закрытие r2-H1.
- **Performance-профили** — не прогонял, в AC не названы и дельта их не
задевает.
- **Полный `.github/workflows/mutation-gate.yml` (пересборка бандла на
каждого мутанта)** — не прогонял; это предрелизный гейт (PROCESS.md §8),
несоразмерен точечной правке одной записи реестра. Точечный прогон именно
этого мутанта сделан отдельно (см. выше) и достаточен как доказательство.
## Вывод
Единственная находка r2 (High) закрыта по существу и подтверждена
исполнением: guard мутанта следует конвенции, контракт реестра не ослаблен,
мутант по-прежнему доказанно ловит регрессию H1 (1/1), `npm test` и
`pytest tests_backend/test_junction_limits.py` зелёные. Новых находок delta
не создаёт — правка изолирована в тестовой инфраструктуре, не пересекается
с продакшен-кодом или пользовательским поведением. Trailer коммита
(`Issue: #329`, `User-Visible: no`) корректен для чисто тестового изменения;
changelog не тронут — верно, правок не требовалось.
Вердикт: зелёный.