Files
2026-10-01 14:55:10 +00:00

16 KiB
Raw Permalink Blame History

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 — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: 0d71ae29c68313fe4be018c5026ec20ccb600cc8
    git log --all --format='%H %T' | grep 0d71ae29c683
    
  • Тело issue: e2d6161bb012959bb539ad49b1ed92bdc86fdc4cb703235caab7bca18258dc38
  • Вердикт конвейера: green · High 0 · маршрут fix