18 KiB
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…), все остальные 9imageSha256не тронуты — соответствует утверждению автора и 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_dialogs7/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. Новых находок нет. Вердикт: зелёный.