17 KiB
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— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
7af77c0d963b8047d83c3ede78cb57df7ca00881git log --all --format='%H %T' | grep 7af77c0d963b - Тело issue:
2cb0efd54b1cd5a5a4f8733121da3241c0cb7b0f2b2376759717d163f0b496dd - Вердикт конвейера:
green· High 0