Issue: #649 User-Visible: no
25 KiB
CODE-REVIEW-649-r2
Issue: #649 · 2.5D, этап 6: объёмные иконки-плитки с тенью, мягкий свет по солнцу, слой декора без изменений, режим из experimental в General settings.
Материал: git log --oneline origin/dev..HEAD / git diff origin/dev...HEAD,
ровно на SHA 106fdc096d5dd7de55d22a88c3a0a2b894b83b49 (рабочая копия уже на
нём; ветку не переключал, git fetch/pull/checkout на другой коммит не
выполнял).
106fdc09 fix(2.5D): prove the sun beam is cut by bodies; review r1 lows (#649)
e1f1c7d9 docs: review document for #649
2ed05031 test(mutants): stage3-w12 guard follows the renamed #649 contract test
e5ab4659 feat: 2.5D stage 6 — public setting, raised tiles, soft sun, theme-free walls (#649)
164 файла в фиче + 73 файла в делте раунда. Трейлеры на всех трёх рабочих
коммитах корректны: Issue: #649 везде; User-Visible: yes на e5ab4659
(оба changelog в том же коммите — docs/CHANGELOG.md/.ru.md, +12/+12 строк);
User-Visible: no на 2ed05031 (гейт мутанта) и на 106fdc09 (делта этого
раунда — см. ниже, почему верно). Заход r2 код-ревью; ТЗ (r2 в теле issue) уже
прошло зелёное SPEC-REVIEW-649-r2.
SHA материала r1 не резолвится. de4521823ba69c390fda4c0534e52e24a63cc66a
(коммит) и дерево 571541905136a48c1729755f6d7877e5ac6aece4 из блока
«Материал раунда» документа r1 отсутствуют в git log --all этого клона (не
shallow — git rev-parse --is-shallow-repository → false, 3576 коммитов на
origin/dev). Это не находка (§2.10: «SHA не резолвится — обычное дело»): у
текущего e5ab4659 тот же commit message, тот же автор/дата инструмента, тот
же родитель (origin/dev tip) и почти идентичная статистика диффа (164 файла,
+5569/−3766 против заявленных в r1 +5570/−3767 — расхождение в одну строку в
обе стороны, не содержательное). Это типичная механика конвейера: ветка
ребейзится на актуальный origin/dev перед каждым раундом, что меняет все SHA
ниже точки ребейза без изменения содержимого. Дельта раунда — ровно то, что
показывает git diff e5ab4659..106fdc09 (коммит 2ed05031 между ними не
трогает продуктовый код, только чинит протухший guard мутанта — унаследован
как есть). Объём разбора: по дельте (§2.10), она полностью локальна — один
новый коммит 106fdc09, который сам называет себя ответом на r1 («review r1
lows»).
Скоуп
Без изменений с r1 (см. docs/reviews/CODE-REVIEW-649-r1.md → «Скоуп»).
Предмет ЭТОГО раунда — единственный новый коммит 106fdc09: закрывает
Medium-находку r1 (M1, обрезка 2.5D-луча барьерами не была доказана тестом) и
пять из шести Low (L1, L3, L4, L5, L6; L2 была снята самим r1 без правки кода
как опечатка хендоффа — здесь закрывать нечего).
Как проверялось (объём по дельте, §2.10)
- Прочитан документ и вердикт предыдущего раунда:
docs/reviews/CODE-REVIEW-649-r1.md— жёлтый, High 0, Medium 1 (M1), Low 6 (L2 снята r1 сразу). - Объявлена дельта:
git diff e5ab4659..106fdc09— 73 файла (в основном пересобранный бандл), содержательно:src/iso-sun.tsне тронут (толькоtest/,demo/,scripts/mutation-registry.mjs,src/iso-tiles.ts,src/houseplan-card.tsкомментарий,docs/DEVELOPMENT.md,docs/ARCHITECTURE.md,demo/benchmark_large_house.mjs). Полный текст диффа коммита106fdc09прочитан построчно. - Для M1 — прочитан
src/iso-sun.ts:82-122(computeIsoSunBeams), подтверждено, чтоdirectionalOccluders(input.occluders, away, travel)(строка 112) — ровно то место, которое M1 называл риском (перепутанный знак направления/длина). Новый юнитtest/iso-stage6.test.mjs(тест «AC7 the 2.5D beam is cut…») ставит колонну на пути луча и проверяет три точки (перед колонной светло, за колонной темно, рядом с тенью снова светло) плюс площадь тени. - Мутационное доказательство выполнено исполнением, не чтением. Для всех
трёх новых мутантов (
iso-sun-occluders-toward-sun,iso-sun-occluders-ignored,iso-sun-card-drops-occluders) я вручную применил патч изscripts/mutation-registry.mjs, прогнал именно тот guard, что записан в реестре, убедился в красном результате, затем откатил файл и для двух из них (те, что требуют бандл) пересобрал (npm run bundle:sync) и подтвердилgit statusчист — см. таблицу ниже, результаты все реальные прогоны этой сессии. - Для L3 (
src/iso-tiles.ts:109-117,isoTileStateCss) вручную пересчитана специфичность CSS: новые правила.dev.theme-dark.${state}(3 класса) и.dev.theme-dark.${state}.iso-floor-light(4 класса) перебивают старые.dev.${state}(2) /.dev.${state}.iso-floor-light(3) по специфичности независимо от порядка — правки корректны структурно, не только текстуально. Также перепроверено (как и в r1), что для всех 6ISO_STATE_BODIESisoEdgeColorсегодня возвращает одно и то же значение независимо отtheme, потому что ни один не тёмный (luma·255<70) и ни один не «near-white» в 0..1-шкале (luma>0.98) — значит фикс сегодня не меняет видимый результат ни для одного реального состояния, что и объясняетUser-Visible: no. - Для L1 прочитаны все 4 места, названные в r1 (
docs/DEVELOPMENT.md:231,docs/ARCHITECTURE.md:31,src/houseplan-card.ts:627,demo/benchmark_large_house.mjs:145) — все четыре переписаны, проверено, что переписанный текст не противоречит соседним абзацам того же файла (docs/DEVELOPMENT.md:249-251,docs/ARCHITECTURE.md:86-88,src/houseplan-card.ts:~2305), и что не осталось других вхождений «experimental/alpha-only/opt-in alpha» применительно именно к 2.5D/Stage 4 (grep -n alphaпо трём файлам — только легитимные несвязанные употребления: общийhp_alpha/Labs-инфраструктура и цветовая альфа). - Для L4/L5/L6 прочитаны новые ассерты
demo/smoke_iso_tiles.mjsи сверены с CSS-правилами, на которые они опираются (специфичность.dev.theme-dark/.oplock/.virtual .device-shell-frame,iso-overlays?.devices.get(d.id)опциональная цепочка для L6) — все три были задокументированы в r1 как «проверено чтением, корректно, но без теста»; теперь тест есть и я лично прогнал его (все ассертыtrue). - Прогнаны реально (не приняты по Validate) — таблица ниже.
Гейты — что прогнано и с каким результатом
| Гейт | Прогнан | Результат |
|---|---|---|
Validate на 106fdc09 |
нет, зачтён по ссылке (условие задачи) | success, https://github.com/Matysh/houseplan-card/actions/runs/36161723663 |
npx tsc -p tsconfig.test.json + node scripts/fix-test-build.mjs |
да | 0 ошибок |
npm run bundle:sync (tsc --noEmit && rollup -c + bundle-tree sync) |
да, дважды (baseline и после отката мутанта) | чисто оба раза, git status --porcelain пуст после отката — закоммиченные dist/**, custom_components/.../frontend, demo/srv/assets побайтово совпадают со свежей сборкой на этом SHA |
node --test test/iso-stage6.test.mjs (весь файл, 10 тестов) |
да | OK, 10/10 pass |
node --test --test-name-pattern="AC7 the 2.5D beam is cut" test/iso-stage6.test.mjs на немутированном коде |
да | OK |
Мутант iso-sun-occluders-toward-sun (away→toSun) применён к src/iso-sun.ts, тот же guard |
да | красный — AssertionError: between the window and the body the floor stays lit, ожидалось true, получено false |
Мутант iso-sun-occluders-ignored (доп. условие elevation > 90) применён, тот же guard |
да | красный — AssertionError: behind the body, away from the sun, the floor is in shadow |
Мутант iso-sun-card-drops-occluders (occluders: [] в houseplan-card.ts) применён, пересобран, node demo/smoke_iso_sun.mjs |
да | красный — bodyCutsTheBeam: expected true, got false; после отката и пересборки git status снова чист |
node demo/smoke_iso_sun.mjs на немутированном коде |
да | OK, все 20 проверок true, включая новые bodyCutsTheBeam, beamBackWithoutBody |
node demo/smoke_iso_tiles.mjs на немутированном коде |
да | OK, все 39 проверок true, включая новые alarmBeatsHover, alarmBeatsSelected, virtualNoDashedRing, noBordersKeepsTiles, noBordersKeepsShadows |
node scripts/check-docs.mjs --external --screenshots=warn (режим обычного пуша, classify-changes.mjs/validate.yml) |
да | OK, 7 файлов, 12 внешних ссылок; один WARN про устаревший фингерпринт скриншотов — унаследован, предрелизный гейт (#479), делта его не касается |
node scripts/smoke-select.mjs --base 2ed05031 --head HEAD (скоуп ровно делты раунда) |
да | НЕОПРЕДЕЛЁННОСТЬ — дифф исполняемый, но инструмент не находит символьной связи (делта — 2 файла src/**, изменения в основном текстовые/CSS-generation внутри уже покрытых функций); решение — см. ниже |
node scripts/smoke-select.mjs --base origin/dev --head HEAD (полный охват фичи, как в r1) |
да | те же 78 прямых совпадений, что в r1 (делта раунда их не меняет) — решение r1 унаследовано без повтора |
python -m pytest tests_backend |
нет | делта раунда не трогает ни одного .py-файла (git show 106fdc09 --stat — 0 совпадений custom_components/.*\.py); гейт неприменим к этой делте |
npm run golden:verify |
нет | делта User-Visible: no, ни одна золотая сцена не задета |
npm run invariants |
нет | делта не меняет каноническую геометрию (только презентационные occluders/CSS-эмиссию) |
Полный npm test |
нет, принят по Validate на этом SHA | — |
Решение по smoke-select --base 2ed05031 --head HEAD (НЕОПРЕДЕЛЁННОСТЬ).
Инструмент не связал делту ни с одним смоком символьно (изменения в
iso-sun.ts не тронуты вовсе — только новый юнит-тест их покрывает; изменения
в iso-tiles.ts — две дополнительные CSS-строки внутри уже существующей
функции). Это не разрешение ничего не прогонять (по инструкции промпта): я сам
выбрал и прогнал smoke_iso_sun.mjs и smoke_iso_tiles.mjs — ровно те смоки,
что физически упражняют изменённые функции (computeIsoSunBeams,
isoTileStateCss) через реальный рендер в браузере, и лично воспроизвёл
падение всех трёх новых мутантов на них. Остальные ~275 смоков матрицы не
запускал: делта не трогает ничего вне iso-sun.ts/iso-tiles.ts/тестов/доков.
Находки
Нет ни High, ни Medium, ни Low. Делта раунда полностью и по существу закрывает M1 (доказано исполнением: тест и три мутанта, все три реально покраснели) и пять Low из шести (L1, L3, L4, L5, L6); L2 была снята ещё в r1.
Закрытие раунда r1
| Находка | Чем закрыта | Где это видно |
|---|---|---|
M1 (Medium) — обрезка 2.5D-луча барьерами (физические тела, Solid-перегородки) нигде не доказана тестом; названный риск — перепутанный знак направления или длина экструзии в directionalOccluders(input.occluders, away, travel) |
Новый юнит test/iso-stage6.test.mjs («AC7 the 2.5D beam is cut…», колонна на пути луча: лит перед ней, тень за ней, лит рядом) + новые ассерты demo/smoke_iso_sun.mjs (bodyCutsTheBeam, beamBackWithoutBody, Solid-перегородка в реальном рендере) + три мутанта реестра (iso-sun-occluders-toward-sun, iso-sun-occluders-ignored, iso-sun-card-drops-occluders). Все три лично применены и подтверждены красными в этой сессии (см. таблицу гейтов) |
test/iso-stage6.test.mjs:151-179; demo/smoke_iso_sun.mjs:99-130; scripts/mutation-registry.mjs:3526-3546; код неизменён — src/iso-sun.ts:111-114 |
| L1 — устаревшие «alpha/hidden»-формулировки рядом с исправленным текстом | Переписаны все 4 места, проверено на противоречие соседним абзацам | docs/DEVELOPMENT.md:231-232, docs/ARCHITECTURE.md:31, src/houseplan-card.ts:627, demo/benchmark_large_house.mjs:145 |
| L2 — опечатка числа в хендоффе (не код) | Была снята уже в r1 без правки; в этом раунде править нечего | — |
L3 — isoTileStateCss() не различал тему для торца состояний |
Добавлены .dev.theme-dark.${state} / ...iso-floor-light со своим вызовом edge(body,'dark',...), специфичность выше старых правил (проверено пересчётом), покрыто новым ассертом юнита |
src/iso-tiles.ts:113-116; test/iso-stage6.test.mjs:68-70 |
| L4 — «Alert > чистый Hover» и «Alert > чистый Selected» не проверялись отдельно | Два новых прогона: реальный mouse.move + alarm без селекта/фокуса; sel+alarm без hover/focus |
demo/smoke_iso_tiles.mjs:197-200,207-221 |
L5 — нет теста на .dev.virtual (Q1: без пунктира) |
Новый ассерт virtualNoDashedRing на .device-shell-frame с классом .virtual |
demo/smoke_iso_tiles.mjs:201-203,222 |
L6 — плитки/тени без стен (show_borders:false) не покрыты тестом |
Новые ассерты noBordersKeepsTiles/noBordersKeepsShadows через реальный setServerConfig |
demo/smoke_iso_tiles.mjs:224-238 |
Унаследовано из r1
Без повторной проверки, документ docs/reviews/CODE-REVIEW-649-r1.md,
материал — фактическое содержимое e5ab4659/2ed05031 (идентично по
существу тому, что рецензировалось в r1 под старыми SHA e59c89df/de452182,
см. обоснование выше — ребейз без изменения содержимого):
- AC1 (Flat неизменен,
test/styles-split.test.mjs, единственный вызовfurniturePlanScreenScale), AC2 (геометрия/торец плитки), AC3 (коллизии ×1.12), AC4 (тень, таблица параметров), AC5 (рамки/приоритет — базовая часть, за вычетом закрытых сейчас L4-пар), AC6 (forced-colors), AC7 (формула луча, градиенты, стопы, ворота видимости — за вычетом закрытого сейчас M1), AC8 (мебель,stroke-width), AC9 (тема не красит стены), AC10/AC11 (settings.volumetric_view, alpha-вход убран, backend-валидация), AC12 (макеты, side-by-side), Golden/матрица, мутационный реестр (16 старых мутантов), бюджет бандла — все приняты по документу r1 без повторного прогона в этом раунде, т.к. делта106fdc09их не касается. python -m pytest tests_backendне прогонялся ни в r1 (нетpytestв песочнице), ни сейчас (делта не трогает Python) — тот же непокрытый гейт, не расширившийся.- ~70 «слабых» совпадений
smoke-select --base origin/dev— решение r1 не прогонять сохраняется без изменений (делта их не касается).
Проверено и корректно
- M1 закрыта доказательством через исполнение, а не только чтением: юнит и
смок падают именно там, где ожидается (перед барьером — светло, за ним —
тень, рядом — снова светло; площадь луча уменьшается минимум на 20×50
плановых единиц), и все три мутанта реестра лично воспроизведены красными,
затем код и бандл возвращены в состояние
HEAD(git statusчист). - L3 — фикс специфичностно корректен (новые селекторы объективно перебивают
старые) и сегодня не меняет видимый результат ни для одного из 6
ISO_STATE_BODIES(пересчитано вручную по порогамluma<70/luma>0.98), что подтверждает трейлерUser-Visible: no. - L1 — все 4 места переписаны без противоречий с соседним текстом; других
вхождений «2.5D как alpha/hidden/opt-in» в кодовой базе не осталось
(
grepпо изменённым и смежным файлам). - L4/L5/L6 — только новые тесты поверх неизменного, уже корректного (по выводу r1) поведения; лично прогнаны, все зелёные.
- Три-way синхронизация бандла (
dist/**,custom_components/.../frontend,demo/srv/assets) чиста на106fdc09— подтверждено дважды: один раз как есть, один раз после применения и отката мутантаiso-sun-card-drops-occluders. - Монолит
src/houseplan-card.ts— 12880 строк, без изменений (правка L1 в нём — замена текста комментария в тех же строках, не добавление). - Трейлеры всех трёх коммитов раунда корректны;
User-Visible: noна106fdc09обоснован построчно (доп. тесты + одна текстуально верная, но сегодня недостижимая ветка CSS).
Чего не проверял
python -m pytest tests_backend— делта не трогаетcustom_components/**/*.py(0 совпадений в статистике коммита); не гейт этой делты.npm run golden:verify/npm run invariants— делтаUser-Visible: no, не меняет золотые сцены и не трогает каноническую геометрию модели.- Полный
npm testи полныйValidate(мутанты) — приняты по зелёному прогону на этом самом SHA (ссылка в задаче); перегонял только те тесты и мутанты, что относятся к делте раунда. - ~275 смоков вне
smoke_iso_sun.mjs/smoke_iso_tiles.mjs—smoke-selectс базой ровно на делту (2ed05031..HEAD) не нашёл символьной связи (НЕОПРЕДЕЛЁННОСТЬ) ни с одним из них, и содержательно делта не выходит за пределыiso-sun.ts/iso-tiles.ts/тестов/документации; полный прогон матрицы против всей фичи (78 прямых совпаденийorigin/dev..HEAD) унаследован из r1 без повтора. - Реальный экран/планшет, Safari — как и в r1, недоступны в песочнице.
Вывод
High: 0. Medium: 0. Low: 0. Делта раунда (106fdc09) полностью закрывает
единственную блокирующую находку r1 (M1) доказательством через исполнение — я
лично применил все три новых мутанта реестра и подтвердил, что юнит и смок
падают именно так, как заявлено в because, а не просто прочитал код на
доверие. Пять Low из шести получили тесты или точечные правки без побочных
эффектов (L3 пересчитан на отсутствие видимого изменения сегодня — трейлер
User-Visible: no корректен); L2 была снята ещё в r1. Дельта локальна и
изолирована (src/iso-sun.ts не изменён вовсе, src/iso-tiles.ts — 2 строки,
остальное — тесты/доки/бандл), новых находок не внесла.
Вердикт: зелёный · заход r2 · блокирующих циклов 1/4 · High: 0 · Medium: 0
Материал раунда
- Ветка:
issue/649-25d-stage6, коммит106fdc096d5d— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
77286175d538a146863d0b2f80a63e9ffa20af96git log --all --format='%H %T' | grep 77286175d538 - Тело issue:
e7d94f185bc9a5d2d7e168933579903e54c88a9819347cb49f0f7c35db60a9e7 - Вердикт конвейера:
green· High 0