Files
houseplan-card/docs/reviews/CODE-REVIEW-602-r2.md
T
2026-09-20 21:46:00 +00:00

129 lines
16 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-602-r2
Issue: #602 · Этап: code · Заход: r2 · блокирующих циклов израсходовано 1 из 4
Материал: `e1fa2591a4cc7cb5a86ee43183353eb3b9783984` (issue/602-dialog-polish), рабочая копия ревью — на этом SHA, `git status` чист на всём протяжении разбора.
## Скоуп раунда
Предыдущий заход (r1, материал `c69d73f1`, документ `docs/reviews/CODE-REVIEW-602-r1.md`)
дал единственную находку — Medium в скоупе: `npm run golden:verify` был красным (8 из 173
сцен `different`), а AC15/план тестирования ТЗ требуют его зелёным. Всё остальное (AC1–AC14,
AC16, трейлеры, i18n, отдельно проверенный риск с авто-раскрытием radar-формы) r1 закрыл без
замечаний.
Дельта этого раунда — **строго** `git diff c69d73f1..e1fa2591`:
- `demo/golden/baselines/baselines-index.json` — обновлены хэши и метаданные приёмки;
- 8 PNG-файлов эталонов (ровно те 8 сцен, что r1 назвал `different`);
- `docs/reviews/CODE-REVIEW-602-r1.md` — публикация документа r1 (добавлен конвейером,
не автором; не несёт функциональных изменений).
`src/**`, `test/**`, `demo/smoke_*`, локали, `docs/USER-GUIDE*`, `docs/CHANGELOG*` в дельте
не тронуты. Это ровно то действие, которое r1 назвал единственным недостающим шагом (принятие
эталонов на канонической Linux-сборке с трейлерами `Release:`/`Baseline-Reviewed:`) — не
рефакторинг, не смена контракта, не задета новая подсистема. По PROCESS.md §2.9 разбор
сужен до дельты; полный повторный прогон всех AC1–AC16 не требуется, так как ни один из них
не зависит от кода, тронутого дельтой.
## Как проверялось
| Гейт | Статус | Как проверено |
|---|---|---|
| `typecheck`/`npm test`/`npm run build` + сверка 3 копий бандла | зелёный, не перегонял | Validate на точном материале `e1fa2591` — [прогон 35539075873](https://github.com/Matysh/houseplan-card/actions/runs/35539075873), `conclusion: success`, `headSha` совпадает (проверено `gh run list --commit e1fa2591…`). Дельта раунда не трогает `src/**`, пересчитывать нечего. |
| `node scripts/check-docs.mjs --strict` | не перегонял, не применимо | Дельта не трогает `src/**`/`docs/images/**`; отпечаток документации не мог измениться этим коммитом (уже был зелёным на `c69d73f1`, см. r1). |
| `npm run golden:verify` (закрытие Medium r1) | **зелёный**, проверено на канонических CI-прогонах, не перегонял локально | Два независимых прогона на точных SHA дают причинно-следственную пару: (1) [прогон 35538133817](https://github.com/Matysh/houseplan-card/actions/runs/35538133817) на материале `8ca877c9` (код идентичен `c69d73f1`, только + документ r1) — `conclusion: failure`, это тот самый диагностический Linux-снимок, из которого взяты 8 кадров; (2) [прогон 35539075873](https://github.com/Matysh/houseplan-card/actions/runs/35539075873) на материале ревью `e1fa2591` — job «Golden-кадры против принятых эталонов» `conclusion: success` (не skip — проверено `gh api .../check-runs`, это полный, а не dedup-прогон). Разница между (1) и (2) — ровно принятие 8 эталонов, ничего больше. |
| Целостность принятых эталонов | зелёный, проверил сам | Пересчитал SHA-256 всех 8 принятых PNG в рабочей копии и сверил с записями `baselines-index.json` — совпадают побайтово для всех 8 (`device-dialog-desktop-en/de`, `device-dialog-mobile-ru`, `device-help-popover-light-ru`, `settings-help-zoom-200-en-light/ru-dark`, `device-ripple-color-popover-mobile-ru`, `space-room-color-popover-desktop-ru`). Ни один файл вне этого списка не изменился (`git diff c69d73f1..e1fa2591 --stat` — 10 файлов, из них 8 названы явно). |
| Провенанс и allowlist приёмки | зелёный, проверил чтением `demo/golden/accept.mjs` | Скрипт (не тронут этой дельтой, инфраструктура доверенная и ранее не была предметом замечаний) отказывается писать эталоны без `--reviewed`, проверяет `buildFingerprint === sourceFingerprint(ROOT)` (гарантия, что кадры сняты именно с этого исходника), считает «свидетелей» — необъявленные сцены, совпавшие байт-в-байт (#355) — и отказывает при их нехватке (`floor`). В принятом индексе `witnesses.count: 104` при `floor: 10` — с большим запасом, то есть посторонний дрейф вне 8 объявленных сцен инструментом исключён. `foreignCapture.reason` в индексе прямым текстом фиксирует «съёмка на Linux CI, приёмка на Windows автора после визуальной проверки» — это осознанный, задокументированный путь, а не сокрытие. |
| Трейлеры коммита `e1fa2591` | зелёный, проверил сам | `git show -s --format=%B`: `Issue: #602`, `User-Visible: no`, `Release: v1.77.0-beta.3` (совпадает с `package.json` `version`), `Baseline-Reviewed: …/runs/35538133817` — ровно то, что требует `scripts/validate-commit-provenance.mjs:64-77` для коммитов, трогающих `demo/golden/baselines/*.{png,json}`, и ровно то, что r1 указал как «что нужно». |
| Мутанты по диффу (6/6 шардов) | зелёный, не перегонял | Тот же прогон 35539075873 — все 6 шардов `success`; дельта раунда не содержит логики, которую могли бы поймать мутанты (только бинарные эталоны и JSON-метаданные). |
| Смоки (`demo/smoke_*.mjs`) | не гонял, не применимо | Дельта не трогает ни один smoke-файл и ни один файл, который smoke-и импортируют (`src/**`, `dist/**`) — `scripts/smoke-select.mjs` не даёт новых кандидатов относительно уже проверенного в r1 диапазона. Полный набор смоков r1 уже прогнал сам на функциональном коде (746147d0/c69d73f1), эта дельта его не меняет — наследуется. |
| `npm run invariants`, `python -m pytest tests_backend`, performance-профили | не гонял | Дельта не трогает геометрию/`custom_components/**/*.py`/перф-пути — то же основание, что и в r1, не изменилось. |
## Находки
Нет. Единственная находка r1 закрыта именно тем действием, которое r1 предписал; новых
находок дельта не создаёт (дельта не содержит логики — только данные эталонов, их индекс и
публикацию документа предыдущего раунда).
## Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
| Medium: `npm run golden:verify` красный на материале ревью (8/173 `different`: `device-dialog-desktop-en/de`, `device-dialog-mobile-ru`, `device-help-popover-light-ru`, `settings-help-zoom-200-en-light/ru-dark`, `device-ripple-color-popover-mobile-ru`, `space-room-color-popover-desktop-ru`), обещанный тестовый артефакт (принятые baseline-кадры) отсутствовал | Коммит `e1fa2591`: принятие ровно этих 8 эталонов через `accept.mjs --reviewed` на артефакте канонического Linux-прогона 35538133817, с трейлерами `Release:`/`Baseline-Reviewed:`, как и требовало r1 дословно («Что нужно») | `git diff c69d73f1..e1fa2591 -- demo/golden/baselines` — те же 8 id, ни одного лишнего; `gh api .../35539075873/check-runs` → job golden `success` (не skip); хэши PNG совпадают с индексом (см. таблицу выше) |
Побочное наблюдение без действия: документ r1 в прозе назвал общее число сцен «150»
(«8 из 150 сцен different»), тогда как в самом индексе на материале r1 (`c69d73f1`) их уже
было 173, и это же число совпадает с явным `GOLDEN_SCENARIOS.length` и с «165 сохранены без
изменений» из комментария автора (165+8=173). Похоже на опечатку в тексте документа r1, а не
на ошибку разбора — состав 8 названных сцен и итоговое решение («нужен `golden:accept`») от
этого не меняются, поэтому не поднимаю как находку.
## Унаследовано из r1
Без повторной проверки в этом раунде — дельта их не задевает, основание см. в
`docs/reviews/CODE-REVIEW-602-r1.md` на SHA `c69d73f1f26b3277fde938a4eb08195c561e46ba`:
- AC1/AC8 — лишние подписи/заголовок убраны, синхронно по 4 локалям;
- AC2 — центрирование тумблера (`top: 50%`/`translateY(-50%)`), защитный AC подтверждён
мутацией руками;
- AC3/AC5 — числовые поля не обрезаются/не перекрывают слайдер (grid-раскладка `.hpf-range`);
- AC4 — подписи шкалы совпадают с концами трека (`84px` единый резерв);
- AC6/AC7/AC14 — однострочные футеры, mobile icon-only, confirm в одну строку на
320/360/560;
- AC9 — climate-toggle перенесён после «Additional actions»;
- AC10 — нейтральный `dialog.unsaved` убран из всех 4 диалогов и локалей;
- AC11–AC13 — единая toggle-секция радара, восстановление черновика Off→On, защитный AC
подтверждён мутацией руками; `savedUnsupported`/`virtual`-ветки структурно не тронуты;
- AC16 — оба changelog и `docs/USER-GUIDE*` правлены в коммите `746147d0` с `User-Visible: yes`;
- трейлеры `746147d0`/`c69d73f1` — корректны;
- отдельно проверенный и закрытый риск: авто-раскрытие radar-формы для распознанного, но
ещё не сохранённого устройства — унаследованное (не из диффа #602) и задокументированное
в `docs/USER-GUIDE.md` поведение, не регрессия;
- соответствие `docs/SCOPE.md` (J4/J6) и `docs/TOUCH-SUPPORT.md` — оценено в ревью ТЗ (зелёный
вердикт spec r2) и не пересматривается на этапе кода без изменения контракта.
Ни один из этих пунктов дельта `c69d73f1..e1fa2591` не задевает (она не содержит `src/**`).
## Чего не проверял
- **`npm test`/`npm run typecheck`/`npm run build` — не перегонял.** Дешёвые гейты зелёные на
точном SHA `e1fa2591` (Validate 35539075873), дельта раунда их не меняет.
- **`node scripts/check-docs.mjs --strict`** — не перегонял, дельта не трогает `src/**`/
`docs/images/**`.
- **Полная матрица `demo/smoke_*.mjs`** — не гонял; дельта не содержит кода, который смоки
исполняют, `smoke-select` не даёт новых кандидатов сверх уже проверенных в r1.
- **`npm run invariants`, `python -m pytest tests_backend`, performance-профили** — не гонял,
как и в r1: дельта не касается геометрии, `custom_components/**/*.py` или перф-путей.
- **Локальный повторный прогон `npm run golden:verify`** — не гонял руками (нет причины: два
канонических Linux-прогона на нужных SHA уже дают прямую причинно-следственную пару
«до фикса красный → после фикса зелёный», это сильнее локального дубля на этой же машине).
- **Ручная проверка в браузере HA** — не проводилась (среды HA нет), как и в r1.
## Материал раунда
- SHA: `e1fa2591a4cc7cb5a86ee43183353eb3b9783984` (`issue/602-dialog-polish`)
- Дерево материала: идентично рабочей копии на момент вывода вердикта (`git status --short`
пуст непосредственно перед выводом)
- ТЗ: тело issue #602, зелёный вердикт спецификации r2
- Предыдущий код-ревью: `docs/reviews/CODE-REVIEW-602-r1.md`, материал `c69d73f1`, вердикт
жёлтый · High 0 · Medium 1
## Вердикт
Зелёный. Единственная Medium-находка r1 закрыта именно предписанным действием, дельта раунда
не содержит функционального кода и не создаёт новых находок.
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/602-dialog-polish`, коммит `e1fa2591a4cc` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `eed53eb273f319a3cf3c49bf42d1625feca21672`
```
git log --all --format='%H %T' | grep eed53eb273f3
```
- Тело issue: `8f8081ec29db1c104189682530643bde421d91127170b2c635107c595950a5a9`
- Вердикт конвейера: `green` · High 0