Files
houseplan-card/docs/reviews/CODE-REVIEW-337-r4.md
T
2026-08-28 05:40:28 +00:00

217 lines
18 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-337-r4
- Issue: https://github.com/Matysh/houseplan-card/issues/337
- Ветка: `issue/337-lazy-editor-chunk`, ревьюемый SHA: `0bd5570ae56b878dabe5c440840f5a3c90c523a0`
- Заход: r4 · блокирующих циклов израсходовано **3/4** до этого разбора
- **Вердикт: зелёный.**
## Скоуп разбора
Предыдущий вердикт — CODE-REVIEW-337-r3, SHA ревью `16c616be165604aca8eb9c7cdeab59024a828006`
(красный, High:1 — H7, Medium:0). Этот SHA в текущей истории отсутствует: ветка
была перебазирована. Проверил, на что именно:
```
git log --oneline 59ae6b1..ff6e53a4
ff6e53a4 docs: review document for #333
```
`dev` продвинулся ровно на **один** коммит между базой r3 (`59ae6b1`) и текущей
базой (`ff6e53a4` = текущий `origin/dev`) — класс C, docs-only ревью-документ
чужого issue (#333), не в `src/**`, не в `custom_components/**/*.py`. Это не
«ребейз на ушедший вперёд dev» в смысле §2.10/§7.2 (другая подсистема, смена
контракта), а техническая синхронизация без содержательного чужого кода.
Полный разбор с нуля не требуется; веду по дельте.
**Материал дельты r3→r4:**
```
33a0110e fix: preserve warm editor camera during lazy adoption (тот же код, что 16c616be — рехеширован ребейзом; сверил построчно, см. ниже)
d30cc799 docs: review document for #337 (публикация документа r3, не продукт)
0bd5570a docs: accept lazy editor screenshot fingerprint (H7-фикс: docs/images/screenshots.json + 06-device-editor.png)
```
Проверил тождественность рехешированного `33a0110e` содержимому, разобранному в
r3, а не поверил ребейзу на слово: прочитал `src/houseplan-card.ts:803-925,
2549, 5880, 6662` на текущем HEAD и сверил построчно с описанием фикса в
CODE-REVIEW-337-r3.md — `_warmModeRequest`, гейт `_refitView`, снятие guard'а
после `updateComplete` + два `requestAnimationFrame`, снятие на всех путях
выхода — код идентичен тому, что r3 уже разобрал и принял. Единственный
содержательный новый коммит этого раунда — `0bd5570a` (закрытие H7).
Единственная находка предыдущего раунда — **H7** (`check-docs` красный на
последнем коммите r3, AC13 не доказан). Разбор ограничен: (а) верификацией
закрытия H7, (б) подтверждением, что ребейз не изменил семантику уже принятого
кода, (в) самостоятельным перепрогоном дешёвых гейтов на итоговом SHA, раз
готового зелёного Validate-прогона с реально исполненными job'ами `frontend`/
`smoke`/`golden` на этом конкретном SHA нет (см. ниже).
## Как проверялось
### Дешёвые гейты — прогнаны лично на `0bd5570a`
| Гейт | Команда | Результат |
|---|---|---|
| typecheck | `npx tsc --noEmit` | pass, exit 0 |
| unit | `npm test` | 1440 total, **1439 pass, 1 skip, 0 fail** |
| build | `npm run build` | pass, `dist` пересобран за 13.8s |
| bundle sync | `npm run bundle:sync` | pass; после пересборки `git status` — 0 диффов в содержимом (только file-mode 755→644 в двух файлах от локальной пересборки, откатил `git checkout --`); три дерева (`dist`, `custom_components/houseplan/frontend`, `demo/srv/assets`) синхронны и побайтово совпадают с закоммиченными |
| bundle budget | `npm run bundle:budget` | initial View **255 910 B** ≤ 256 000 B (запас 90 B, то же число, что в r3/хендоффе); lazy editor 131 779 B |
| docs fingerprint (H7) | `node scripts/check-docs.mjs` | **pass**: «Documentation checks passed (7 files, 10 external links)» |
Пересборка бандла на моей машине оказалась побайтово идентична закоммиченному
дереву — это независимое подтверждение, что `bundle:sync`/`bundle:budget` не
разошлись со временем автора, а не просто повтор его чисел.
### Почему проверял `check-docs` и билд лично, а не принял чужой зелёный Validate как есть
В задаче процитирован зелёный `Validate` на `0bd5570a`
(https://github.com/Matysh/houseplan-card/actions/runs/33144989734) как повод
не гонять `tsc`/`test`/`build` самому. Проверил сам прогон, потому что в r1
этой же задачи уже был прецедент: зелёный Validate на docs-only коммите не
означает, что `frontend`/`smoke`/`golden` реально исполнялись (§1, находка r1).
Разобрал этот конкретный прогон:
```
gh run view 33144989734 --json jobs -q '.jobs[] | .name + " => " + .conclusion'
```
Job «Классификация изменённых файлов» вычислил инкрементальный diff между
`before`-SHA пуша (форс-пуш после ребейза, старый tip недостижим локально) и
`0bd5570a`: три файла — `docs/images/06-device-editor.png`,
`docs/images/screenshots.json`, `docs/reviews/SPEC-REVIEW-333-r1.md` (последний
— спутник ребейза на `ff6e53a4`, тоже docs). `frontend=false`, поэтому job
«Фронтенд: типы, юниты, мутанты, синхрон бандла» (где живут `tsc`/`test`/
`build`) в этом конкретном прогоне **skipped**, а не green по содержанию — сам
Validate зелёный только потому, что docs-гейты (которые реально исполнялись)
прошли. Отдельно проверил job «Переиспользование: это дерево уже проверено»
(`scripts/gate-reuse.mjs`): `golden` и `backend` дали `Cache not found` (не
были waived кэшем), но всё равно оказались `skipped` в графе — их пропустила
та же path-классификация `frontend=false`, а не механизм переиспользования.
Вывод не «Validate врёт»: срез diff между force-push before/after корректно
показал, что после ребейза содержимое `dist`/`src` не изменилось относительно
уже прошедшего полный `Validate` состояния (та же логика, что уже описана в
самом r1-документе про докс-коммиты). Но раз я не могу подтвердить это архивной
реконструкцией истории (старые SHA недостижимы после форс-пуша), надёжнее было
перепрогнать `tsc`/`test`/`build`/`bundle:*` самому на итоговом дереве — они
дешёвые (минуты) — чем полагаться на цепочку рассуждений о том, что должно было
быть проверено раньше. Результат подтвердил: числа и статусы совпадают с тем,
что репортили автор и r3.
### Что не прогонял и почему
- **Полный browser-smoke census (195 файлов) и `golden:verify`** — не
перезапускал. Дельта r3→r4 (`0bd5570a`) касается исключительно
`docs/images/**`; ни один файл `src/**`, `demo/**`, `test/**` не изменился.
Census и golden уже пройдены дважды на продуктовом дереве (r1: 195/195 и
127/131 golden; r2: 195/195; targeted smokes зоны H6 — многократно в r2/r3) и
не могут быть чувствительны к правке `screenshots.json`/PNG документации —
они не читают эти файлы. `smoke-select` не гонял: применять его к диффу, не
содержащему ни одного `src`/`demo` файла, не даёт сигнала.
- **`node scripts/model-invariants.mjs`** — не запускал. Дельта не меняет
формат геометрической записи (`layout`, `marker.space`, `open_spans`, ключи
толщины); последний src-коммит, трогавший геометрию/камеру (`33a0110e`),
уже прогонялся через `npm test` (модельные инварианты входят в общий набор)
и мной, и r3 — без изменений с тех пор.
- **`node scripts/mutation-gate.mjs`** — не запускал повторно. Дельта не
трогает `src/**`; r3 уже прогнал `--changed` для единственного src-коммита
этой цепочки (30/30).
- **`python -m pytest tests_backend -q`** — не запускал. Диапазон дельты не
трогает `custom_components/**/*.py`.
- **Perf-профили** — не запускал, не названы в AC и не затронуты этой дельтой.
- **Ручное тестирование в реальном Home Assistant** — не выполнялось (фазы
ручного тестирования в процессе нет).
## Находки
Находок этого раунда нет — High/Medium/Low: 0/0/0.
## Что проверено и корректно
- **H7 закрыт.** `node scripts/check-docs.mjs` зелёный на `0bd5570a`: «pass (7
files, 10 external links)», ровно та же форма, что r1 фиксировал как норму.
Причина закрытия видна в самом коммите: `sourceFingerprint` в
`docs/images/screenshots.json` обновлён с `d1ea5e9d…` на `5f56dab6…` —
значение, полученное реальной пересъёмкой (`sourceSha256` во всех 10
сценариях синхронно обновлён на то же значение), а не скопировано вручную.
Единственный изменившийся `imageSha256` — `06-device-editor.png`
(`a01bad41…` → `36ed21b6…`), все остальные 9 `imageSha256` не тронуты —
соответствует утверждению автора и r3, что рендер изменился только на 1 байт
PNG-кодирования и только у одного кадра (r3 сам это независимо
воспроизвёл ещё до принятия).
- **Ребейз не изменил семантику.** `dev` продвинулся на один класс-C коммит
(docs-review чужого issue), не в `src/**`. Локальная пересборка (`npm run
build && npm run bundle:sync`) дала 0 диффов содержимого относительно
закоммиченного дерева — рехешированные ассеты `33a0110e` соответствуют
ровно той сборке, что уже стояла до ребейза.
- **Код фикса H6 (унаследован из r3, но перечитан для очистки от риска «ребейз
= другой код»)** — построчно совпадает с описанием r3: `_warmModeRequest`
выставляется только на `adopt`-пути (`src/houseplan-card.ts:894-901`), гейтит
`_refitView` (`:5880`), снимается после `updateComplete` + двух `rAF`
(`:918-924`) и на всех путях выхода (`:903, 906-907, 2549, 6662`). Изменений
в этой логике между `16c616be` и `33a0110e` нет.
- **Бюджет (AC1)** — пересчитан лично: 255 910 B ≤ 256 000 B, то же число, что
в r3 и в хендоффе — запас 90 B не изменился и не ухудшился этим раундом.
- **Трейлеры.** Оба коммита раунда (`33a0110e`, `0bd5570a`) несут `Issue: #337`
и `User-Visible: no` — корректно: ни один не добавляет нового наблюдаемого
пользователем поведения (H6 — внутреннее исправление тайминга камеры,
H7-фикс — служебный docs-артефакт), changelog для #337 уже закрыт в r1.
- **Одно число — один источник.** Дельта этого раунда не вводит и не дублирует
ни одной пользовательской величины: правка ограничена внутренним
fingerprint/хешами и байтами PNG документации, не выводимыми в UI как текст.
`test/single-source-numbers.test.mjs` проходит в общем `npm test`.
## Закрытие раунда r3
| Находка r3 | Чем закрыта | Где это видно |
|---|---|---|
| **H7** (`check-docs` красный на последнем src-коммите r3, AC13 не доказан) | Канонический прогон `Docs screenshots` (workflow_dispatch) на ветке задачи, Linux-артефакт принят через `npm run docs:accept -- --reviewed --from=...`; `sourceFingerprint`/`sourceSha256` синхронно обновлены во всех 10 сценариях, изменился ровно 1 `imageSha256` | Коммит `0bd5570a` (`docs/images/screenshots.json`, `docs/images/06-device-editor.png`); `node scripts/check-docs.mjs` → pass лично на `0bd5570a` |
## Унаследовано из r3 (и транзитивно из r1/r2)
Принято без повторной проверки в этом раунде — дельта (`33a0110e`/рехеш +
`0bd5570a`, docs-only) их не касается:
- **AC1 (initial budget)** — пересчитан лично в этом раунде (см. таблицу
гейтов), не просто унаследован.
- **AC2 (lazy boundary), AC5 (loader atomicity), AC6 (failure сохраняет
View)** — вне дельты; вывод CODE-REVIEW-337-r2.md (SHA `2beafc06`) остаётся в
силе.
- **AC3/AC4 (View и editor parity), включая всю зону H1–H4 из r1 (warm-remount,
kiosk, resize/optimize preflight, device inbox)** — закрыты и подтверждены
независимым прогоном в r2 (CODE-REVIEW-337-r2.md, SHA `2beafc06`); эта дельта
их зону не трогает.
- **AC7 (asset security), AC8 (полнота distribution), AC9 (CSS-минификатор)** —
не тронуты этой дельтой; вывод r1/r2 (CODE-REVIEW-337-r1.md, SHA `6d338b78`)
остаётся в силе.
- **AC10 (fingerprint mismatch), AC11 (onboarding/async config editor), AC12
(no model drift)** — вне дельты, наследуются из r1/r2.
- **H6 (потеря бит-точности камеры warm-remount)** — закрыт и подтверждён в r3
(CODE-REVIEW-337-r3.md, SHA `16c616be`, `smoke_warm_dialogs` 7/7 против 5/7
fail); код идентичен на текущем SHA (см. «Что проверено и корректно» выше —
перечитан заново, не просто принят на слово).
- **H5/#346 (устаревшие golden-эталоны Device editor/mobile-ru)** — не
относится к #337, независимо воспроизведён на чистом `dev` в r2, заведён
отдельным issue #346 (проверил: issue открыт, `S1-new`, `bug`, `P3`).
- **Полный browser-smoke census (195/195) и `golden:verify` (127/131, 4
«different» = #346)** — пройдены в r1/r2 на неизменной этим и предыдущим
(r3) раундами части дерева; не перезапускал, см. «Что не прогонял».
Отдельно от AC-цепочки: **AC13 (docs) не наследуется** — на нём в r3 была
найдена находка H7, в этом раунде она закрыта заново проверенным гейтом, а не
принята со слов автора.
## Итог
Единственная блокирующая находка предыдущего раунда (H7 — устаревший
screenshot fingerprint) закрыта корректно: канонический Linux-прогон,
воспроизводимый дважды с одинаковым хешем, обновил fingerprint и ровно один
байтово отличающийся кадр, без замены остальных девяти. Ребейз между r3 и r4
не изменил продуктовый код — на `dev` прилетел один нерелевантный docs-коммит
другого issue, и локальная пересборка дала 0 диффов с закоммиченным деревом.
Дешёвые гейты (`tsc`, `npm test`, `build+sync+budget`, `check-docs`)
перепрогнаны лично на итоговом SHA `0bd5570a`, а не приняты по цепочке
рассуждений о докс-коммитах — все зелёные, числа совпадают с отчётами автора и
r3. Новых находок нет. Вердикт: зелёный.