16 KiB
CODE-REVIEW-746-r1
Issue: #746 · трек: show · заход: r1 · блокирующих циклов израсходовано 0 из 2
Материал: aa0b60e75498d052625886d1cdc23190566f9bde (ветка issue/746-room-fill-alpha,
один коммит поверх dev 653d94ef, ребейз-без-изменения-кода зафиксирован автором
в комментарии issue от 2026-10-01T14:27:02Z)
Validate на этом SHA: https://github.com/Matysh/houseplan-card/actions/runs/36876972490 — success
Скоуп
Баг: .room { transition: 0.12s } анимирует цвет и fill-opacity/stroke-opacity
независимо, видимая непрозрачность — их произведение. Состояния без заливки
(overlay, yard, outlined, picked) держали альфу в цвете (rgba(...),
*-opacity по умолчанию 1), а .styled — наоборот, непрозрачный цвет плюс
fill-opacity: var(--room-fill-op). При переходе между половинами одна растёт,
другая падает, и продукт в середине пути больше обоих концов: комнаты вспыхивали
серым при открытии «Настроек пространства» на этаже без заливки и темнели при
входе/выходе из редактора плана на закрашенном этаже.
Правка приводит четыре состояния .room (overlay, yard, outlined, picked)
к той же записи, что уже была у .styled: непрозрачный цвет + явная
fill-opacity/stroke-opacity, transparent — только вместе с нулевой
*-opacity. Сам переход, .styled и переменные --room-* не тронуты.
Поверхность одна — блок правил .room в src/styles/plan.styles.ts;
houseplan-space-card берёт те же стили реэкспортом (src/styles.ts), отдельной
правки не требует — проверено чтением: src/styles.ts:10,19 подключает
planStyles без переопределения .room.*.
Диапазон git diff origin/dev...HEAD: src/styles/plan.styles.ts (+24/-4),
новый demo/smoke_room_fill_transitions.mjs, docs/CHANGELOG.md,
docs/CHANGELOG.ru.md, docs/STYLING-HOOKS.md — один коммит, трейлеры
Issue: #746 и User-Visible: yes на месте, оба changelog в том же коммите.
Критерии §5 (трек show) — все пройдены
- complexity — issue оценивает сложность 2/10; правка — точечная замена записи прозрачности в 4 блоках CSS-правил, без новой логики.
- surfaces — одна поверхность: правила
.roomв одном файле стилей, переиспользуемые всеми рендерами плана. - migration — нет миграции конфига; риск для пользовательских правил
card-mod (правило, задающее только
fillбезfill-opacity, станет невидимым) явно описан в issue, в обоих CHANGELOG и в STYLING-HOOKS.md — не обойдён молчанием. - ux-contract — видимое поведение в покое не меняется (доказано пофреймово, см. ниже); исправляется переходный артефакт, а не контракт.
- perf-touch — чистый CSS, без touch-поверхности; perf-смок в Validate зелёный (не требовался AC, но прогнался сам).
- undocumented — ожидаемое поведение зафиксировано самим issue (таблица
AC с точными числами) и теперь — в
docs/STYLING-HOOKS.md§3.2 (новый абзац, ссылка на §3.3 «Everything generated» корректна).
Маршрут: fix (вердикт зелёный, reclassify неприменим).
Как проверялось
| Гейт | Статус | Как |
|---|---|---|
tsc --noEmit, npm test, npm run build + сверка бандла |
не перегонял | зелёный Validate на точном SHA aa0b60e7 (run 36876972490), "Фронтенд: типы, юниты, мутанты, синхрон бандла" — success |
golden:verify |
не перегонял сам, приняты результаты CI | тот же Validate, job "Golden-кадры против принятых эталонов" — success (ci:golden выставлена и отработала) |
| Смоки (полная матрица, 3 шарда) | не перегонял всю матрицу | тот же Validate, все три шарда "Смоки в браузере" — success; лог шарда 1 содержит ok smoke_room_fill_transitions — сам смок задачи выполнялся в CI и прошёл |
demo/smoke_room_fill_transitions.mjs |
прогнал сам, дважды | см. ниже — независимая проверка автотеста на red/green |
scripts/smoke-select.mjs --base origin/dev --head HEAD |
прогнал | 「НЕОПРЕДЕЛЁННОСТЬ» — диффа в src/styles/plan.styles.ts символьная связь с смоками не выводится автоматически (CSS-правила, не функции); решение по AC1 issue и ручной проверке ниже |
| pytest / Hassfest / HACS / мутанты по диффу / геометрия TS-Python | не прогонял | нет правок Python/конфига/геометрии — неприменимо, в Validate эти джобы skipped |
| Мутанты (реестр) | не прогонял и не обязан | трек show, §10.4: мутанты на разработке не гоняются ни на одном треке |
Чего не проверял: полную матрицу golden и смоков заново (доверяю
зелёному Validate на точном материале — свежесть подтверждена #343); ручное
тестирование в браузере сверх смока (нет штатного гейта, Chromium не
запускал для этого — только для перепрогона смока, который сам headless);
поведение .radarsetup .room — явно вне скоупа в issue («Не-скоуп»).
Независимая проверка AC1/AC2 (смок умеет падать)
Защитный AC — здесь это обязательная таблица «чем доказан · чем краснеет»:
| AC | Чем доказан | Чем краснеет |
|---|---|---|
| AC1: видимая непрозрачность заливки/обводки ни в одной точке перехода не превышает больший из концов более чем на 0.005 | demo/smoke_room_fill_transitions.mjs, прогнан мной на aa0b60e7: OK, все проверки (fillOvershoot/strokeOvershoot ≤ tolerance) зелёные для 4 путей + контроль |
Я откатил патч src/styles/plan.styles.ts до состояния origin/dev (git apply -R), пересобрал бандл и перепрогнал тот же смок: FAILED (6), с точными числами из issue — openSettings fill/stroke 0 → 0.2413 → 0, cancelSettings fill 0.18 → 0.3049 → 0 и stroke 0 → 0.2418 → 0, enterPlanEditor fill 0.18 → 0.3172 → 0.06, leavePlanEditor fill 0.06 → 0.314 → 0.18. Совпадает с цифрами issue (0.241/0.305/0.317/0.314) и отчётом автора. Тест действительно умеет падать именно на дефекте из issue, не на постороннем |
AC2: кадр в покое не меняется (overlay, styled, outlined, picked, yard) |
Тот же смок, секция rest: цвет и видимая непрозрачность по пяти состояниям совпадают с таблицей REST, зашитой в смок как ожидание дев-поведения; плюс Golden CI на точном SHA — success |
На отклонение кадра покоя красит сам смок (check по каждому состоянию и каналу) — отдельно не провоцировал, т.к. правка кода не трогает значения styled/рест-часть overlay и т.д.; разбор по коду подтверждает: изменились только порядок/форма записи (hex→rgb + отдельная opacity), числовое произведение то же (проверено чтением, не исполнением, для каждой из 4 строк диффа — см. ниже) |
После обеих проверок рабочая копия и dist/ возвращены ровно к материалу
ревью (git checkout -- dist/, git clean -fd dist/, git status чист,
git rev-parse HEAD = aa0b60e75498d052625886d1cdc23190566f9bde).
Разбор по коду (проверено чтением, не исполнением)
Для каждого изменённого блока: произведение «альфа цвета × *-opacity» в покое не меняется, а при переходе оба сомножителя теперь монотонны от 0 (или от другого конца) к цели, поэтому продукт двух неубывающих/невозрастающих кривых ограничен большим из концов — перелёта быть не может:
.room.overlay: былоfill: transparent(альфа 0,fill-opacityпо умолчанию 1) → сталоfill: transparent; fill-opacity: 0— продукт 0 в обоих случаях, при переходе к.styledоба множителя (альфа цвета и opacity) растут от 0 монотонно → продукт ограничен произведением конечных значений, перелёта нет. Симметрично дляstroke..room.yard: былоfill: rgba(75, 140, 90, 0.14)(продукт 0.14) → сталоfill: rgb(75, 140, 90); fill-opacity: 0.14(продукт 0.14) — рест не меняется, подтверждено прогоном (rest.yard.fill = ["rgb(75, 140, 90)", 0.14])..room.outlined:rgba(62,166,255,0.06)/0.55→rgb(...); fill-opacity: 0.06/stroke-opacity: 0.55— рест не меняется (подтверждено прогоном)..room.picked:rgba(255,193,77,0.25)→rgb(...); fill-opacity: 0.25;stroke: #ffc14d(уже непрозрачный) получил явныйstroke-opacity: 1— без визуального эффекта в покое, что и наблюдается (rest.picked.stroke = ["rgb(255, 193, 77)", 1]).
Побочный эффект, который автор сам назвал в отчёте и я подтвердил чтением:
у .room.overlay:hover/.room.yard:hover (наведение на незакрашенную
комнату) теперь обе половины (stroke и stroke-opacity) идут от 0 к 1
вместо одной — начало затухания визуально чуть мягче, монотонность
сохраняется, перелёта нет. Не находка: раскрыто в отчёте автора, не меняет
контракт, не заявлено как AC.
Проверка «одно число — один источник»
Числа 0.14 / 0.06 / 0.55 / 0.25 (видимые альфы yard/outlined/picked)
встречаются только в src/styles/plan.styles.ts — их единственный источник.
Поиском (grep по RGB-триплетам 75,140,90 / 62,166,255 / 255,193,77
вне plan.styles.ts) второго места с тем же числом не нашлось; совпадение в
src/styles/devices.styles.ts:379 (rgba(62, 166, 255, 0.22)) — другой
компонент (устройство), другое число (0.22), не дублирует величину задачи.
demo/smoke_merge_highlight.mjs сверяет только подстроку цвета
(includes('255, 193, 77')), а не альфу — совместимость с переходом на
rgb(...) + отдельный fill-opacity подтверждена прогоном CI (шард 1:
смок зелёный).
Что проверено и корректно
- Диапазон диффа
origin/dev...HEAD— ровно заявленное в ТЗ:.room.overlay,.yard,.outlined,.picked;.styledи переменные--room-*не тронуты (построчная сверка). houseplan-space-cardподтверждённо берёт те же стили без дублирования правил.- Трейлеры
Issue: #746,User-Visible: yesна коммите; оба CHANGELOG правлены в том же коммите, текст совпадает с AC3 issue дословно (RU и EN). docs/STYLING-HOOKS.mdполучил абзац, фиксирующий новый инвариант как контракт — ссылка на §3.3 «Everything generated» для самих величин корректна (значения остаются негарантированными, инвариант записи — гарантирован).- Смок умеет падать именно на дефекте issue (см. раздел выше) — не ложно положительный.
- CI на точном SHA материала: Validate, Golden, вся матрица смоков (включая новый) — зелёные.
- Метки issue соответствуют треку и объёму:
track:show,ci:golden,S7-code-review. - Риски (невидимость для правил card-mod без явной
*-opacity, более мягкое начало hover-замирания) названы автором и подтверждены разбором, задокументированы в CHANGELOG/STYLING-HOOKS — не висящие Medium.
Находки
Нет. High: 0, Medium: 0 (ни в скоупе, ни вне скоупа).
Вердикт
Зелёный. AC1 и AC2 доказаны автотестом, тест проверен на способность падать лично (red на отменённом патче с теми же числами, что в issue), AC3 (гейт/CHANGELOG) выполнен. Побочных дефектов не найдено, риски раскрыты и задокументированы.
Материал раунда
- Ветка:
issue/746-room-fill-alpha, коммитaa0b60e75498— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
0d71ae29c68313fe4be018c5026ec20ccb600cc8git log --all --format='%H %T' | grep 0d71ae29c683 - Тело issue:
e2d6161bb012959bb539ad49b1ed92bdc86fdc4cb703235caab7bca18258dc38 - Вердикт конвейера:
green· High 0 · маршрутfix