Files
houseplan-card/docs/reviews/CODE-REVIEW-526-r1.md
T
2026-09-11 07:32:32 +00:00

17 KiB
Raw Blame History

CODE-REVIEW-526-r1

Issue: #526 — стилевой минификатор ни разу не работал Материал: git log --oneline origin/dev..HEAD / git diff origin/dev...HEAD, ровно bde05697d1bd758a944523371cb8ecc2da302b8b (рабочая копия на нём, git status чист) Заход: r1 · блокирующих циклов израсходовано 0/4 Вердикт: зелёный


Скоуп

Три коммита поверх origin/dev:

коммит класс что User-Visible
0a0a9f0f A/B/C (продукт+гейты+доки) CSS_TAG распознаёт css + пробел/перенос/таб + бэктик вместо строгого css\`` — и в отсеве transform, и во внутреннем сканере minifyStaticCssTemplates; потолок INITIAL_VIEW_GZIP_CEILING300 700 → 288 300; юниты AC1/AC2/AC4; новый смокdemo/smoke_css_minifier_semantics.mjs(AC3); два мутанта вscripts/mutation-gate.mjs; changelog RU+EN, docs/DEVELOPMENT.md`; три копии бандла yes
b9e40aeb B синтаксическая правка: якорь мутанта с переносом строки собирается из экранированных частей (реальный \n, вставленный в JS-строку, ломал модуль, и --check красил тихо) no
bde05697 C обновлён отпечаток скриншотов документации после включения минификации (docs:accept --identical, все 11 кадров попиксельно совпали) no

Ветка issue/526-css-minifier-tag, история после ребейза на dev с исправлением #528 (не относящийся к #526 мутант о тени маркера, снятый отдельной задачей) — содержимое #526 при ребейзе не менялось, что и проверено ниже прогонами на текущем SHA.

Затронутые файлы совпадают с ТЗ: scripts/css-template-minifier.mjs, scripts/bundle-budget.mjs, scripts/mutation-gate.mjs, test/bundle-assets.test.mjs, demo/smoke_css_minifier_semantics.mjs, docs/CHANGELOG.md, docs/CHANGELOG.ru.md, docs/DEVELOPMENT.md, docs/images/screenshots.json, плюс сгенерированные dist/** и custom_components/houseplan/frontend/** (класс D, коммитится вместе с продуктовой правкой — допустимо).

src/** в диффе нет ни одной строки — исправление живёт целиком в build-тулинге.

Как проверялось

Дешёвые гейты подтверждены Validate на этом SHA (успешный прогон, ссылка в постановке задачи) — tsc --noEmit, npm test, npm run build не перегонял по этой причине сам по себе, но фактически пересобрал бандл ниже как часть проверки трёх копий, и это попутно повторило typecheck+build.

Гейты, которые прогнал сам (все ниже — реальные команды с реальным выводом, не пересказ хендоффа):

Гейт Команда Результат
Пересборка + три копии бандла npm run bundle:sync → git status --porcelain сборка 19.5 с, дерево осталось чистым — dist / custom_components/.../frontend / demo/srv/assets идентичны закоммиченным
Юниты минификатора node --test test/bundle-assets.test.mjs 29/29 pass
no-new-any node scripts/no-new-any.mjs --base origin/dev --head HEAD «Новых any нет» (0 добавленных строк в src/**/*.ts — диффа там и нет)
Документация/скриншоты node scripts/check-docs.mjs «Documentation checks passed (7 files, 12 external links)»
Бюджет бандла node scripts/bundle-budget.mjs initial View: 287284 B gzip (потолок 288300 ±2000, budget 301066, headroom 13782); только предупреждение о низком запасе (< 15000 Б) — ожидаемо, не отказ
Полная golden-матрица (AC5) npm run golden:verify 100/100 passed, код возврата 0, ни одного mismatch — я запустил её сам, так как автор не смог из-за лимита команды в песочнице (178 с)
Смок AC3 node demo/smoke_css_minifier_semantics.mjs filesCompared: 6, rulesCompared: 1049, everyRuleIdentical: true, savedBytes: 54921 → OK
Смоки, упомянутые в хендоффе как относящиеся к ребейзу/#528 node demo/smoke_marker_shadow_transitions.mjs, node demo/smoke_align_guides.mjs, node demo/smoke_space_switch_transitions.mjs все OK
Выбор смоков по диффу node scripts/smoke-select.mjs --base origin/dev --head HEAD «Исполняемого frontend-диффа нет (src/**/*.ts не тронут). Browser-smoke этим диффом не выбираются — это не «пропустить проверки», а «выбирать нечего»»
process-gate node scripts/process-gate.mjs origin/dev..HEAD «гейт пройден, предупреждений 0» (проверка 8 требует --issues, офлайн не гонял — не нужна для вердикта)
Мутанты (точечно) node scripts/mutation-gate.mjs --id=css-minifier-skips-typescript-output и --id=css-minifier-eats-required-space оба «поймано 1 из 1»; --check для обоих — ok, якоря уникальны

Не прогонял и почему:

  • python -m pytest tests_backend — диффом не тронут ни один custom_components/**/*.py.
  • Performance-профили (large-house-isometric-v1, large-house-interaction-v1) — диффом не тронуты src/iso-*, src/live-*, src/render-*, houseplan-render-lifecycle.ts, houseplan-card.ts; scripts/smoke-select.mjs/классификатор гейта тоже подтверждают отсутствие frontend-диффа.
  • Полный npx tsc --noEmit отдельной командой — покрыт: он часть npm run build, прогнанного через bundle:sync выше, и часть green Validate на этом же SHA.
  • Полный набор demo/smoke_*.mjs — не запускал: smoke-select.mjs явно говорит «выбирать нечего» (диффа в src/** нет), а вручную прогнал ровно те четыре, что упомянуты в истории задачи (новый AC3-смок плюс три, задетые соседним #528/ребейзом).

Находки

Нет ни одной блокирующей (High) находки.

Low, снимаю без возврата. AC1 в ТЗ формулирует три исключения из распознавания тега: something.css\``, mycss`и «строка'css`'внутри кавычек». Тестtest/bundle-assets.test.mjs (#526 AC1) проверяет только первые два — третий случай нигде не тестируется. Проверил чтением и руками: и текущий код (новый CSS_TAGregex), и кодdevдо этой задачи (тот жеcode.indexOf('css`', cursor)) на самом деле **не** оставляют такую строку нетронутой — оба воспринимают предшествующую кавычку как «не-словесный» разделитель и пытаются искать закрывающий бэктик дальше по файлу (в вырожденном случае бросают unclosed css template). Это не регрессия этой задачи: поведение идентично dev, K2 («поведение минификатора не меняется») формально соблюдён, и в src/**такой строки-ловушки нет ни разу (провереноgrep -rn "css`" src/`). Снимаю как Low: ТЗ переоценило существующее поведение, тест честно проверяет то, что реально гарантировано, а несуществующий сегодня риск не стоит цикла ревью.

Что проверено и корректно

  • AC1 (unit). Прогнал test/bundle-assets.test.mjs — тег с пробелом/переносом/табуляцией распознаётся, mycss\``/lit.css`/styles$css`не считаются тегом. Тест умеет падать: то же выражение на кодеdev (code.indexOf('css`', cursor)) для css `с пробелом возвращаетnull` — воспроизвёл вручную на копии старого файла.

  • AC2 (unit). cssTemplateMinifier().transform на скомпилированном TS-выводе (тег с пробелом) возвращает изменённый код без комментария; на .js и на коде без тега — null. Проверено тем же прогоном теста.

  • AC3 (smoke). demo/smoke_css_minifier_semantics.mjs сравнивает CSSOM исходного и минифицированного текста в CSSStyleSheet для 6 файлов, 1049 правил, расхождений 0. Прогнал сам, число правил и экономия (54 921 Б сырого текста) совпадают с цифрами хендоффа. Отклонение от буквального текста ТЗ («посимвольно») задокументировано автором явно (сравнение нормализует ровно объявленную минификатором политику пробелов — коллапс пробелов, пробел у ,/:/(/) — и ничего сверх; съеденный комбинатор или пробел в calc() остаются расхождением, что и ловит мутант css-minifier-eats-required-space). Причина отклонения реальна: браузер хранит значение CSS custom property текстом как есть, посимвольное сравнение cssText было недостижимо не по вине минификатора. Названо честно, а не тихо — принимаю.

  • AC4 (unit, защитный). Тест берёт реальные фразы из комментариев src/styles/*.ts (≥20 штук по ≥40 символов) и требует их отсутствия во всём dist/**. Прогнан в составе полного набора теста — зелёный.

  • AC5 (golden). npm run golden:verify — 100/100, код возврата 0. Прогнал сам, автор честно указал, что не смог из-за лимита команды в своей песочнице.

  • AC6. Потолок 300 700 → 288 300 с записью в комментарии bundle-budget.mjs; node scripts/bundle-budget.mjs зелёный, только некритичное предупреждение о низком запасе (< 15 000 Б) — это существующий долг #367/#474, не новый дефект этой задачи. Тесты #438 * (test/bundle-assets.test.mjs) зелёные.

  • AC7 (защитный, таблица «чем краснеет»):

    AC чем доказан чем краснеет
    AC1/AC2/AC4 (общий отсев) node --test test/bundle-assets.test.mjs (тест-паттерн #526 AC4|#526 AC2 внутри мутанта) мутант css-minifier-skips-typescript-output (возврат transform к code.includes('css\')) — прогнал сам: поймано 1 из 1`
    AC3 (семантика) node demo/smoke_css_minifier_semantics.mjs мутант css-minifier-eats-required-space (перестаёт восстанавливать значащий пробел в minifyCssText) — прогнал сам: поймано 1 из 1

    Второй мутант в ТЗ не заявлен явно (AC7 называет только отсев), но добавлен автором сверх минимума и обоснован правильно: без него смок AC3 остался бы недоказанной защитой (описан код, но не проверено, что он может покраснеть). Оба анкера прошли --check (найдены ровно один раз каждый).

  • AC8. docs/CHANGELOG.md и docs/CHANGELOG.ru.md — записи о −12,8 КБ на холодной загрузке, число совпадает с фактом; docs/DEVELOPMENT.md — раздел про то, что плагин видит вывод TypeScript, а не исходник. Все три файла в одном коммите (0a0a9f0f) с User-Visible: yes — проверено чтением git show --stat.

  • Синтаксическая правка мутанта (b9e40aeb) — реальный баг: буквальный перенос строки внутри JS-строкового литерала ломал модуль. Проверил, что текущий якорь (собранный через конкатенацию с \n) синтаксически валиден и находится в файле ровно один раз (--check → ok).

  • Ребейз на #528 — задеваемая соседняя подсистема (маркеры/переходы) не относится к скоупу #526; сам факт ребейза не «другой код» по смыслу §7.2, так как содержимое #526 не изменилось — перепроверил прогоном smoke_space_switch_transitions.mjs (OK) и полного test/bundle-assets.test.mjs (29/29) на текущем SHA.

  • «Одно число — один источник»: изменение не выводит пользователю никакого числа ни в интерфейсе, ни дважды — это чисто build-time экономия байт, отображаемая только в changelog. Неприменимо.

  • Touch: не задействован — правка не касается ни одного интерактивного пути.

  • i18n/бэкенд/геометрия: не затронуты, проверено по диффу — в src/**, custom_components/**/*.py, файлах геометрии (layout, marker.space, стены) изменений нет.

  • Процесс: node scripts/process-gate.mjs origin/dev..HEAD — «гейт пройден, предупреждений 0»; трейлеры Issue: #526 и User-Visible: на месте во всех трёх коммитах; имя ветки соответствует.

Чего не проверял

  • python -m pytest tests_backend — нет диффа в Python.
  • Performance-смоки (glow/isometric/interaction профили) — нет диффа в src/iso-*/src/live-*/src/render-*/houseplan-render-lifecycle.ts/houseplan-card.ts, и smoke-select.mjs/process-gate это подтверждают.
  • Полный список из ~сотни demo/smoke_*.mjs — не относится к диффу за пределами src/**; выбор инструментом дал пустой список, вручную добавил только те четыре, что фигурируют в истории задачи.
  • Проверка 8 process-gate.mjs (--issues, статус issue через GitHub API) — офлайн-режим; реальный рубеж — это ревью, а не она.

Материал раунда

  • Ветка: issue/526-css-minifier-tag, коммит bde05697d1bd — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: 7af77c0d963b8047d83c3ede78cb57df7ca00881
    git log --all --format='%H %T' | grep 7af77c0d963b
    
  • Тело issue: 2cb0efd54b1cd5a5a4f8733121da3241c0cb7b0f2b2376759717d163f0b496dd
  • Вердикт конвейера: green · High 0