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

18 KiB
Raw Permalink Blame History

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. Новых находок нет. Вердикт: зелёный.