18 KiB
CODE-REVIEW-179-r2
- Issue: https://github.com/Matysh/houseplan-card/issues/179
- ТЗ:
docs/specs/179-device-icons-redesign.md(зелёное SPEC-REVIEW r2) - Диапазон:
origin/dev..HEAD— ровно один коммит,9daa2e9(«fix: align device compatibility guards and vacuum puck»).origin/devуже стоит на6fdb7dc— весь материал из CODE-REVIEW-179-r1 (зелёный,48bcdafи далее) туда слит; r2 проверяет только delta сверху. - Ревьюер: Claude (свежая сессия, без контекста реализации r1/r2)
- Вердикт: зелёный · цикл r2/4 · High: 0 · Medium: 0
Скоуп
Автор объяснил в комментарии к issue: r1 был зелёным и слит, но параллельный
полный smoke-прогон нашёл 7 существующих guard-смоков, которые ещё читали
старую подложку .dev напрямую (до редизайна 48bcdaf фон/бордер маркера были
на самом .dev, после — на дочерних .device-core/.device-shell). При их
актуализации всплыл реальный, а не тестовый, дефект: живой vacpuck пылесоса не
получил обновлённую тему пакета (light/dark core, обводка, тень), хотя
действующий (до-#179) контракт «пылесос выглядит как базовая иконка устройства,
только круглая и меньше» — docs/USER-GUIDE.ru.md и комментарий в
src/styles.ts («owner's wording: «иконка похожа на иконку базы, только
круглая и чуть меньше»») — привязывает его вид к базовому маркеру. Редизайн
базового маркера изменил это «оригинал», а vacpuck не подтянулся — это пробел
именно в объёме #179, не посторонняя находка.
Диапазон (git diff --stat origin/dev...HEAD, 16 файлов) состоит из:
src/houseplan-card.ts,src/styles.ts— применение существующегоdeviceThemeClass()к.vacpuckи его CSS-блока (core/stroke/shadow теперь зеркалят.device-shell/.device-coreиз r1, а не старые--hp-bg/--hp-line/--shadow-1токены);- 7 demo-смоков (
smoke_cover_no_plate,smoke_cover_plate_precedence,smoke_hidden_flag,smoke_icon_scale,smoke_infinite_canvas,smoke_motion_sense,smoke_vacuum) — assertions переориентированы на новую DOM-структуру и текущие тайминги/значения (например, длительность continuous pulse2.4s → 3.6s— уже принятая r1 величина, эти смоки её просто не знали); - 3 сгенерированных копии бандла (
dist/,custom_components/.../frontend/,demo/srv/assets/) — класс D, следствие правки styles/houseplan-card; 1 doc-скриншот (docs/images/06-device-display-preview.png) иdocs/images/screenshots.json(весьsourceFingerprintпересчитан, как и ожидается при любой правкеsrc/); оба changelog. - Посторонних правок вне этого плана не найдено.
Как проверялось
| Гейт | Команда | Результат |
|---|---|---|
| Typecheck | npx tsc --noEmit |
green |
| Unit | npm test |
930 tests, 930 pass, 0 fail, 0 skip |
| Build + bundle parity | npm run build && cmp (все 3 копии) |
green, побайтово идентичны — прогонялось дважды (до и после mutation-gate), оба раза чисто |
| Docs fingerprint | node scripts/check-docs.mjs --external |
green, 7 files, 10 external links |
| Process gate (офлайн) | node scripts/process-gate.mjs |
green, диапазон = 1 коммит, 0 предупреждений |
| 7 целевых compatibility-смоков (ровно то, что чинит коммит) | node demo/smoke_cover_no_plate.mjs, smoke_cover_plate_precedence.mjs, smoke_hidden_flag.mjs, smoke_icon_scale.mjs, smoke_infinite_canvas.mjs, smoke_motion_sense.mjs, smoke_vacuum.mjs |
все 7 green, лично прогнаны |
| Регрессия mutation-guards из r1 (тот же styles.ts) | node scripts/mutation-gate.mjs --id=device-unavailable-hover-restored / --id=device-marker-lqi-low-boundary-shifted / --id=device-long-value-ellipsis-restored / --id=device-keyboard-bypasses-click-path |
все 4: чистый прогон зелёный, мутант красный — гейты пережили этот диф без деградации |
--check реестра мутаций |
node scripts/mutation-gate.mjs --check |
все 20 патчей, включая 4 device-, ложатся ровно один раз |
Гейты НЕ прогонялись, и почему:
- Полный
node scripts/mutation-gate.mjs(без--id) и полный browser-smoke набор (127 файлов) — диф касается ровно одной подсистемы (device marker + vacpuck) и её уже известного набора зависимых смоков; все 7 задетых смоков прогнаны лично, полный набор — предрелизный гейт (PROCESS.md §8). npm run golden:verify— grep поdemo/golden/не нашёл ни одного сценария, завязанного на vacpuck; визуальный риск ограничен цветами core/shell, которые дословно совпадают с уже принятым в r1 (golden-проверенным) пакетом.device-shell/.device-core(тот жеborder: 1px solid #BCBCBCи тот жеbox-shadow: 0 1px 2px rgb(37 40 45/12%), 0 4px 8px -1.07px rgb(37 40 45/18%)— сверено построчно, см. ниже). Полный набор — предрелизный гейт.python -m pytest tests_backend -q— Python-код не тронут.- Performance-профили — диф не добавляет новых подписок/наблюдателей (только CSS custom properties и класс-строка), числового бюджета в AC для этого фикса не названо; предрелизный гейт.
- Мутационная проверка вручную (временный откат
deviceThemeClass()на.vacpuckвsrc/houseplan-card.tsи повторный прогонsmoke_vacuum.mjs) была задумана, но заблокирована системой разрешений — ревьюеру запрещено редактировать продуктовый код (роль в PROCESS.md §6: «Ревьюер кода… Не имеет права: править продуктовый код»). Вместо этого проверено чтением: иsmoke_cover_no_plate.mjs, иsmoke_vacuum.mjsсверяют точныеgetComputedStyle(...).backgroundColor/.borderTopColorсо значениями, которые совпадают только при наличии обеих правок (тема + пакетный shell/shadow) — вернуть старые токены (var(--hp-bg),var(--shadow-1)) сломало бы именно эти сравнения, не давая тесту пройти «случайно».
Находки
Нет High и Medium. Два Low, оба решены на месте без правки кода (запись ниже).
- Low-1 (снят). Формальный трейс:
docs/specs/179-device-icons-redesign.mdне упоминает vacpuck ни в одном AC — эта правка не была частью исходного ТЗ. Не поднимаю как Medium «вне скоупа», потому что решение задокументировано самим владельцем в комментарии issue («реальный пробел… vacpuck оставался на старых theme colors») и находится внутри той же поверхности, что и #179 (единственная причина, по которой vacpuck вообще имеет цветовой контракт — «выглядит как базовая иконка», а базовую иконку поменял именно #179). Формальной правки ТЗ (новый AC15) не внесено — при следующей правке этого маркера стоит дописать его в §8 ТЗ, но блокировать r2 из-за отсутствия строки в уже принятом документе не за что: issue как канонический источник (PROCESS.md, преамбула) фиксирует то же решение. - Low-2 (снят). RU changelog («Живой маркер робота-пылесоса использует те
же цвета темы, обводку и тень») не использует уже устоявшийся в
docs/USER-GUIDE.ru.mdтермин «puck» (там прямо: «живой puck», «движущийся puck», строки 649/828/879/1153). EN-версия термин использует верно («The live vacuum puck…»). Смысл фразы не искажён и путаницы у пользователя не создаёт, поэтому не блокирую; для единообразия в следующей правке лучше сказать «живой puck пылесоса».
Проверено и корректно
- Тема vacpuck.
.vacpuckтеперь объявляет--vac-core-bg/--vac-core-fgчерезlight-dark(#fff, #252525)с явным переопределением.vacpuck.theme-light/.vacpuck.theme-dark— тот же паттерн (тот жеlight-dark()fallback + классовое переопределение), что уже принят и проверен для.devв r1 (--device-core-bg/--device-core-fg,src/styles.ts:1867-1868); новой техники CSS не введено.deviceThemeClass()— не новая функция, тот же хелпер изsrc/device-face.ts, который уже применяется к.devво всех трёх поверхностях (houseplan-card.ts,hp-device-preview.ts,space-render.ts); здесь просто добавлен четвёртый вызов на vacpuck. проверено чтением + smoke (smoke_vacuum.mjsgreen, лично прогнан). - Border/shadow parity.
.vacpuck:border: 1px solid #BCBCBCиbox-shadow: 0 1px 2px rgb(37 40 45/12%), 0 4px 8px -1.07px rgb(37 40 45/18%)— построчно идентичны.device-shell(src/styles.ts:1912,1915-1917), сверено дословно. Владельческий контракт «vacpuck = уменьшенная базовая иконка» соблюден для нового пакета так же, как соблюдался для старого. проверено чтением. - 7 compatibility-смоков. Прочитаны целиком (не только diff): новые
assertions измеряют то же самое, что старые (нейтральный/жёлтый/оранжевый
фон, unlocked-amber, geometry без ellipsis, границы пульсации), но через
корректный текущий DOM (
.device-core/.device-shellвместо.dev— с r1 фон и бордер физически переехали на дочерние элементы, поэтому старые селекторы стали мимо цели, а не «менее строгими»). В одном месте строгость даже выросла:smoke_cover_no_plate.mjsтеперь дополнительно проверяетcolor === 'rgb(0, 0, 0)'у закрытого замка (AC4 r1: чёрный glyph), чего раньше не было. Убранная «-2px» компенсация границы вsmoke_icon_scale.mjs/smoke_infinite_canvas.mjsсоответствует факту:.device-core(src/styles.ts:1951-1966) не имеет собственногоborder— бордер только на.device-shell, значит вычитать пиксель больше не нужно. Ни одна проверка не смягчена до тавтологии (typeof x === 'string'и т.п.) — все сравнивают конкретныеgetComputedStyle-значения. лично прогнаны, все 7 green. - Отсутствие побочных правок.
git diff --statограничен файлами из описания коммита; секьюрный lock-инвариант (docs/SCOPE.mdCR-1) в этом диффе не затронут (правка не касаетсяlockState/_clickDevice/resolveToggleIntent) — подтверждено чтением, отдельный прогонsmoke_lock_*не требовался, т.к. эти файлы не входят в diff. проверено чтением. - Регрессия r1-мутаций. Все 4 mutation-guard, введённые в r1
(
device-unavailable-hover-restored,device-marker-lqi-low-boundary-shifted,device-long-value-ellipsis-restored,device-keyboard-bypasses-click-path), лично прогнаны заново на новом HEAD — чистый код зелёный, мутант красный для каждого. Правка.vacpuckне задела их поведение. лично прогнано, мутация подтверждена исполнением. - Freshness/parity.
npm run buildдважды (до и после mutation-gate) давал побайтово идентичные три копии бандла — сборка не расходится с тем, что закоммичено, и mutation-gate корректно восстанавливает файлы после себя (git statusпуст после каждого прогона).check-docs.mjs --externalзелёный — screenshot fingerprint (docs/images/screenshots.json) актуален относительно новогоsrc/. лично прогнано. - Трейлеры и процесс. Единственный коммит
9daa2e9несётIssue: #179иUser-Visible: yes; оба changelog правятся в этом же коммите (RU и EN), соответствует правилу «правки в оба changelog в том же коммите».process-gate.mjs(офлайн) — 0 предупреждений на диапазоне из 1 коммита.
Чего не проверял
- Полный
golden:verify, полный browser-smoke набор (127), полный mutation-gate без--id,performance_smoke,pytest tests_backend— предрелизный гейт по PROCESS.md §8, диф не расширяет их необходимость (обосновано выше по каждому пункту). - Мутационную проверку самой правки
.vacpuckне выполнил исполнением (запрещено редактировать продуктовый код в роли ревьюера) — заменено разбором точных значений в assertions (см. «Как проверялось»). - Визуальную приёмку
docs/images/06-device-display-preview.pngглазами не делал — доверился зелёномуcheck-docs.mjs --external(фингерпринт подтверждает, что скриншот пересобран из текущего кода, а не устарел); единственный байт разницы в размере файла для полноценной ревизии PNG не даёт повода подозревать регрессию.
Итог
Единственный коммит диапазона (9daa2e9) — точечный compatibility-фикс внутри
уже принятого объёма #179: обновляет 7 существующих guard-смоков под новую DOM-
структуру маркера из r1 и приводит vacpuck в соответствие с той же темой/пакетом
shell, что уже получил основной маркер. Оба изменения проверены построчным
сравнением с уже отревьюенными в r1 значениями (не с нуля), все 7 задетых
смоков и 4 унаследованных mutation-guard лично прогнаны и зелёные. Секьюрный
lock-инвариант не затронут. High: 0, Medium: 0; два Low сняты с записью
(отсутствие формального AC15 в ТЗ — компенсировано решением владельца в issue;
RU-терминология «маркер» вместо устоявшегося «puck» — не искажает смысл).
Задача уходит в очередь на пре-релиз.