Issue: #627 User-Visible: no
22 KiB
CODE-REVIEW-627-r3
Материал: b921ba71847df37416bed1c15e3d645953ffa1c9 (рабочая копия уже на нём; git fetch/checkout не выполнялись). Дерево c76d64409884dfb646eb723f3e868003e923cce9. Заход r3, блокирующих циклов израсходовано 1 из 4 (полный трек, лимит 4).
r2 (docs/reviews/CODE-REVIEW-627-r2.md, материал 47d07281b6ce…, дерево e19b817f43f3…) был зелёным и цикла не образовал (#227). r3 существует не потому, что r2 что-то вернул автору, а потому, что автор запушил новый коммит: b921ba71 — ребейз ветки на ушедший вперёд origin/dev (успевший вобрать #642, «диалог «Оптимизировать планы» — свой модуль») с пересборкой бандла и пересчётом потолков. 47d07281 в текущей истории не резолвится (ребейз его осиротил) — по [§2.10] это не находка, а обычное дело; материал ищется по дереву. Дерево, эквивалентное содержимому 47d07281, живо в текущей истории как 70fe860bac6259fc1f32114a6b3fe191fe8d966a (коммит «test(smoke): danger confirmation waits for the composite language gate (#627 r1 M1)», тот же M1-фикс, что и в r2), поэтому дельта раунда объявлена как git diff 70fe860b..b921ba71.
Скоуп
ТЗ #627 (полный трек, из аудита T9 M2-A): не новая функциональность, а бюджетно-техническая работа над уже закрытыми job'ами J4/J6 (docs/SCOPE.md) — держит bundle-budget.mjs честным гейтом ленивых графов онбординга/редактора, без новой видимой поверхности. User-Visible: no на всех трёх коммитах — корректно, ниже подтверждено.
Объявление дельты (git diff 70fe860b..b921ba71 --stat): 74 файла — scripts/bundle-budget.mjs (17 строк: константа потолка + комментарий-причина), scripts/monolith-baseline.json (одно число), и 72 файла механической пересборки (dist/**, custom_components/houseplan/frontend/**, три копии бандла синхронны). src/**/*.ts, test/**, demo/** дельтой не тронуты — подтверждено и git diff --stat, и node scripts/smoke-select.mjs --base 70fe860b --head b921ba71:
Исполняемого frontend-диффа нет (src/**/*.ts не тронут).
Browser-smoke этим диффом не выбираются — это не «пропустить проверки»,
а «выбирать нечего»: смоки проверяют собранную карточку.
Тронуто файлов: 76.
Дельта локальна по содержимому (две строки логики — числовая константа и её обоснование), хотя коммит и называется «ребейз». Тем не менее я разобрал её не по минимуму, а вместе с двумя пробелами доказательств, унаследованными от r1/r2 (см. «Как проверялось»): впервые в истории задачи собранный бандл — совместный продукт #627 и #642 (до этого коммита #642 жил только в origin/dev, 82a48ee0 был выпущен поверх него, но ни разу не гонялся в браузере после реального слияния кода обеих задач в одно дерево), и два смока, тронутых ещё исходным коммитом 82a48ee0 и прямо относящихся к контракту задачи, ни разу не запускались ни в r1, ни в r2. Формально это не входит в дельту r3, но раз я всё равно поднимал браузер для проверки собранного дерева — закрыл оба пробела тем же прогоном; см. ниже.
Как проверялось
Дешёвые гейты подтверждены зелёным Validate на этом самом SHA (run 36025312110, conclusion: success, headSha = b921ba71847df37416bed1c15e3d645953ffa1c9 — проверено напрямую через gh run view --json). Разбивка по джобам:
| Джоб | Результат |
|---|---|
| Классификация изменённых файлов | success |
| Предполёт: документация, провенанс, процесс | success |
| Переиспользование: это дерево уже проверено | success |
| Мутанты по диффу (6/6 шардов) | success |
| Фронтенд: типы, юниты, мутанты, синхрон бандла | success |
| Hassfest / HACS / pytest / geometry parity / browser smokes (3 шарда) / perf-smoke / golden | skipped (workflow_dispatch, не heavy) |
| Доказательство выполненных проверок | success |
Джоб «Фронтенд» содержит npm test → npm run build → bundle-tree.mjs + npm run bundle:budget → npm run lint:unused (в этом порядке, .github/workflows/validate.yml:779-791) — то есть typecheck, юниты, сборка, гейт потолка LAZY_EDITOR_GZIP_CEILING и гейт связности монолита (bundleBytes против scripts/monolith-baseline.json) уже подтверждены на этом точном SHA. Их я не перегонял.
Прогнано лично на b921ba71 (дёшево, для точных чисел в этом документе и потому что новых чисел для CI-подтверждения годится не «похоже», а «совпало»):
| Гейт | Команда | Результат |
|---|---|---|
| Bundle sync (проверка свежести/синхрона копий) | node scripts/bundle-sync.mjs |
git status --short пуст и до, и после — закоммиченный dist/ уже байт-в-байт синхронен с custom_components/** и распакован в demo/srv/assets |
| Bundle budget | npm run bundle:budget |
lazy editor: 228621 B gzip (потолок 229600 B ±2000), lazy onboarding: 27468 B gzip (потолок 28500 B ±2000), initial View: 289418 B gzip (потолок 290400 ±2000) — совпадает с числами коммита b921ba71 дословно |
| Мёртвый код и связность монолита | npm run lint:unused |
monolith: delegates=154 portMembers=348 hostRefs=4869 portPrivates=94 harnessPrivates=101 bundleBytes=2508211 / ok все числа равны базе |
Арифметика коммита проверена построчно:
LAZY_EDITOR_GZIP_CEILING: 229600, полоса 2000 → нижняя граница 227600; при замере 228621 запас сверху 229600−228621=979, запас снизу 228621−227600=1021 — совпадает с текстом комментария вscripts/bundle-budget.mjs:572дословно.monolith-baseline.jsonbundleBytes: базаorigin/dev(0f234f76, тот же коммит, что и merge-base ветки сorigin/dev) —2499182(провереноgit show 0f234f76:scripts/monolith-baseline.json), текущее —2508211, разница+9029— совпадает с текстом коммита («десять новых чанков словарей и записи манифеста»); остальные пять чисел монолита (delegates/portMembers/hostRefs/portPrivates/harnessPrivates) не изменились ни на йоту относительно базыdev— тоже заявлено в коммите и подтверждено прогоном.- Комментарий к
LAZY_EDITOR_GZIP_CEILINGнад константой (строки 559–567 до правки) на промежуточном коммите82a48ee0содержит незаполненные плейсхолдерыXXX(«замер XXX», «Центр оставляет XXX Б сверху и XXX Б до нижней границы») — артефакт промежуточного состояния ветки после первого ребейза наorigin/devс #642, где числа ещё не были пересчитаны. Это не находка:82a48ee0не является вершиной ни одного опубликованного ревью (ни r1, ни r2 его не рецензировали как отдельный SHA — их материал уже был позже осиротевшим40959feb/47d07281), а в материале этого раунда,b921ba71, плейсхолдеры заменены настоящими числами, что я и проверил выше побайтово. Упоминаю, чтобы явно снять вопрос, а не оставить его как тихо замеченную странность.
Смоки. smoke-select для дельты 70fe860b..b921ba71 не выбирает ничего (см. выше) — формально этого достаточно. Тем не менее я поднял браузер (нужно было для проверки живой пересборки бандла) и заодно закрыл два пробела в доказательствах, оставленные r1/r2:
| Смок | Почему запущен | Результат |
|---|---|---|
smoke_lazy_admin_locale.mjs |
Ядро AC4–AC7; первый прогон на дереве, где бандл собран совместно с #642 | OK, все 38 полей true |
smoke_danger_confirmation.mjs |
M1 (r1) / его фикс (r2) — держится ли регрессия закрытой на пересобранном бандле | OK, все 25 полей true, включая {de,fr}GateSettledBeforeAsking |
smoke_optimize_geometry_preflight.mjs |
Тронут 82a48ee0 (добавлено ожидание языкового гейта перед card._editorRuntime.optimizePlans.open() — новый порт из #642); ни r1, ни r2 не упоминают этот файл ни разу (grep -n optimize по обоим документам — пусто), хотя правка именно этого файла явно перечислена в теле коммита b921ba71 («smoke_optimize_geometry_preflight: …, разрешено в коммите задачи») без единой ссылки на прогон |
OK, все 16 полей true — пробел закрыт |
smoke_dialog_segments_i18n.mjs |
Единственный смок, явно названный в ТЗ issue («План автотестов»: «...smoke_dialog_segments_i18n (4 локали × 4 диалога; переключение языка должно ждать гейт)») для риска ровно той же природы, что и M1; тронут 82a48ee0, но ни r1, ни r2 его не упоминают |
OK, все 60 полей true — пробел закрыт |
smoke_color_picker.mjs, smoke_free_walls.mjs, smoke_space_scale_defaults.mjs, smoke_summary_panel.mjs, smoke_toggle_confirmation.mjs, smoke_ux_fixes.mjs |
Ещё 6 смоков получили тот же защитный «дождаться aria-busy» патч в 82a48ee0 (за пределами явного списка ТЗ — самостоятельный аудит автора), ни один не упомянут ни в r1, ни в r2 |
Все 6 — OK, без единого false-поля |
Итого 9 браузерных смоков лично прогнаны на b921ba71, все зелёные без единого красного поля — включая четыре, которые пять раундов до этого (r1: три коммита, r2, теперь r3-до-этого-прогона) молча пропускали.
Чего не проверял
- Индивидуальные прогоны 5 мутантов #627 по
--id(onboarding-loader-skips-namespace-ensureи др.) — на этом SHA не перегонял;src/**в дельте70fe860b..b921ba71не тронут, а мутанты гейтят именноsrc/**. Опираюсь на личный прогон r1 (на уже осиротевшем SHA, но тем же деревеsrc/**) плюс на «Мутанты по диффу (6/6 шардов) — success» в CI наb921ba71— это диффовый прогон относительно доказанного предка, не индивидуальный запуск по--id, но за отсутствием измененийsrc/**он лишь переподтверждает то же дерево, а не проверяет что-то новое. golden:verify, перф-смок,pytest tests_backend, Hassfest/HACS,geometry parity— все skipped в CI (неheavy,workflow_dispatch) и не гейт этой дельты: ни эталонов рендера, ни Python, ни геометрии дифф не касается.- Полный
smoke-select --base origin/dev --head HEAD(а не--base 70fe860b) — не гонял: он воспроизвёл бы ровно то же самое (дельтаorigin/dev..HEADсодержит src-правки #627, уже разобранные в r1), а не что-то специфичное для этого раунда. - Остальные ~250 несвязанных смоков вне плана ТЗ и списков связей — не прогонял, это предрелизная обязанность, не гейт ревью.
- Живой стенд Home Assistant — не поднимал.
Находки
Нет. High 0, Medium 0.
Low-наблюдение, снятое без действия: патч «подождать aria-busy до 250×20мс» теперь инлайново продублирован в 12 файлах demo/smoke_*.mjs (проверено grep -rl "hasAttribute('aria-busy')"), при том что demo/serve.mjs уже экспортирует несколько общих утилит смоков (watchPage, check, checkAll, reportPageErrors, finish) — общий хелпер сюда напрашивается. Не поднимаю до Medium: сам приём (а не его вынесение в хелпер) был явно одобрен r1 как решение M1 («чинится тем же приёмом, что уже применён к девяти другим смокам»), дублирование не в дельте r3 (весь список — из 82a48ee0, уже принятого в r1/r2), и это стиль тестового харнесса, а не продуктовый код.
Что проверено и корректно
| AC | Проверено в r3 | Итог |
|---|---|---|
AC1 (bundle-budget.mjs печатает и гейтит онбординг) |
Не тронут дельтой; CI (Фронтенд job) переподтвердил npm run lint:unused/bundle:budget на этом SHA |
Унаследовано + переподтверждено CI |
| AC2 (числовые потолки и запасы) | Переисполнено лично: npm run bundle:budget на b921ba71 — редактор 228621 ≤ 229600 (запас к полосе 979/1021 Б, >500), онбординг 27468 ≤ 28500 (запас 34526−27468=27058 ≥ 6500, 244433−228621=15812 ≥ 15000), initial View 289418 (было 289457 до задачи — фактически снижение, не рост; в полосе потолка) — причина перецентровки редакторского потолка (#642) записана в комментарии константы дословно с числами |
Доказан заново на текущем SHA |
| AC3 (9 ленивых чанков, владение графами) | Не тронут дельтой (test/i18n-lazy-namespaces.test.mjs, test/bundle-assets.test.mjs не изменились с r1); CI Unit tests зелёные на b921ba71 |
Унаследовано из r1 |
| AC4 (холодное открытие on ru/de/fr, первый кадр на языке) | Лично: smoke_lazy_admin_locale.mjs — OK на пересобранном бандле |
Переисполнено |
| AC5 (live-переключение языка, составной гейт) | Лично: тот же смок + smoke_danger_confirmation.mjs (M1) + smoke_optimize_geometry_preflight.mjs + smoke_dialog_segments_i18n.mjs + 6 доп. смоков с тем же патчем — все OK |
Переисполнено, шире, чем требовала дельта |
| AC6 (отказ обеих попыток → английский только в пространстве) | Не тронут дельтой; smoke_lazy_admin_locale.mjs (поля failure*) — OK в прогоне выше |
Унаследовано + переподтверждено прогоном |
| AC7 (холодный View/en-редактор/Zigbee не тянут лишних чанков) | Не тронут дельтой; те же поля смока — OK | Унаследовано |
| Трейлеры | git show <sha> -s --format='%B' на 82a48ee0/70fe860b/b921ba71 — везде Issue: #627, User-Visible: no |
Корректно |
| Changelog | git diff 70fe860b b921ba71 --stat -- docs/CHANGELOG.md docs/CHANGELOG.ru.md — пусто; верно при User-Visible: no и отсутствии видимых изменений |
Корректно |
| Одно число — один источник | grep -rn "229_600|229600|2508211" scripts test src — по одному вхождению каждое, только в объявлении константы/базы |
Корректно |
Закрытие раунда r2
r2 был зелёным, «Находки: Нет» — закрывать нечего. Таблица приведена для формы, соответствия сокращённому шаблону:
| Находка r2 | Чем закрыта | Где видно |
|---|---|---|
| — | — | — |
Унаследовано из r2
Без повторной проверки в r3 принято из docs/reviews/CODE-REVIEW-627-r2.md (материал 47d07281b6ce… / дерево e19b817f43f3…, вердикт зелёный · заход r2 · High 0 · Medium 0), поскольку src/**, test/**, demo/** в дельте 70fe860b..b921ba71 не тронуты:
- AC3, AC6, AC7 — доказаны в r1, не пересчитывались повторно ни в r2, ни здесь.
- Полный реестр из 7 мутантов #627 (5 новых + 2 с обновлёнными якорями), лично прогнанных r1-ревьюером по
--id, «поймано 1 из 1» каждый. check-docs.mjs --screenshots=warn,check-inputs.mjs --coverage(0),CONTRIBUTING.md/tsconfig.test.json— содержательно не менялись.
Не унаследовано, а переисполнено заново лично в r3 (см. «Как проверялось»): M1-фикс (smoke_danger_confirmation.mjs) и AC4/AC5 — потому что артефакт (собранный бандл) впервые стал совместным продуктом #627+#642, и это первый раз, когда кто-либо гонял браузерные смоки против именно такого дерева.
Вердикт
Зелёный. Дельта раунда (scripts/bundle-budget.mjs, scripts/monolith-baseline.json + механическая пересборка) арифметически честна и подтверждена и CI, и лично. Ни одной находки. Дополнительно: два смока, явно относящихся к контракту задачи (один — по прямому тексту ТЗ, другой — по собственному упоминанию в теле коммита без прогона) и шесть смоков с тем же защитным патчем, ни разу не запускавшихся в r1/r2, лично прогнаны на этом SHA и зелёные — пробел в доказательствах предыдущих раундов закрыт, а не унаследован молча.
Материал раунда
- Ветка:
issue/627-lazy-admin-locales, коммитb921ba71847d— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
c76d64409884dfb646eb723f3e868003e923cce9git log --all --format='%H %T' | grep c76d64409884 - Тело issue:
11ffae080ad26691a4b8dbd32f7736895c0c25a3f0cabe1b09da0e21666e6562 - Вердикт конвейера:
green· High 0