mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
15 KiB
15 KiB
Код-ревью issue #200 — r1
- Issue: #200
- ТЗ: docs/specs/200-room-label-parity.md
- ТЗ-ревью: SPEC-REVIEW-200-r1.md — зелёный
- Диапазон:
origin/dev..HEAD(детач наorigin/issue/200-room-label-parity), коммиты4089c91,bf83246,cd029a0,88a2877 - Продуктовая реализация:
cd029a0(Issue: #200,User-Visible: yes) - Сопутствующий коммит:
88a2877(обновление docs-скриншотов,User-Visible: no)
Вердикт
Зелёный · цикл r1/4 · High: 0 · Medium: 0
Скоуп проверки
Только код-ревью реализации (cd029a0, 88a2877) против принятого ТЗ.
ТЗ и его ревью не пересматривались повторно. Проверялись:
- продуктовый код
src/houseplan-card.ts,src/styles.ts; - тесты/гейты:
demo/smoke_room_link.mjs,demo/golden/{harness,matrix}.mjs,test/golden-matrix.test.mjs,scripts/mutation-gate.mjs; - документация:
docs/TESTING.md,docs/CHANGELOG.md,docs/CHANGELOG.ru.md,docs/USER-GUIDE.ru.md(на предмет противоречий), сгенерированные бандлы и docs-скриншоты.
Как проверялось — гейты
| Гейт | Команда | Результат |
|---|---|---|
| Typecheck | npx tsc --noEmit |
зелёный |
| Unit | npm test |
909 passed, 0 failed |
| Build + 3 копии бандла | npm run build && cmp dist/houseplan-card.js custom_components/houseplan/frontend/houseplan-card.js && cmp dist/houseplan-card.js demo/srv/assets/houseplan-card.js |
зелёный, все три идентичны |
| Целевой smoke (AC1, AC2, AC3, AC4, AC5, AC6 частично) | node demo/smoke_room_link.mjs |
зелёный; во всех 4 комбинациях DPR×theme nameDeltas/metricDeltas = [0,0,0,0] |
| Mutation gate, якоря | node scripts/mutation-gate.mjs --check |
зелёный, все 30 мутантов (включая 2 новых) применяются ровно один раз |
| Mutation gate, мутант 1 (AC9) | node scripts/mutation-gate.mjs --id=plan-room-area-icon-hidden |
чистый прогон зелёный, на мутанте demo/smoke_room_link.mjs упал, как обязано |
| Mutation gate, мутант 2 (AC9) | node scripts/mutation-gate.mjs --id=plan-room-area-icon-navigates |
чистый прогон зелёный, на мутанте demo/smoke_room_link.mjs упал, как обязано |
| Соседний smoke (AC6, regression) | node demo/smoke_room_cards.mjs |
зелёный — handles/gear/scale/placeholder-cases не задеты |
| Соседний smoke (AC3, pointer routing regression) | node demo/smoke_card_tool_conflict.mjs |
зелёный — маршрутизация клика/pointerdown между инструментом и карточкой не сломана |
| Визуальный результат | npm run golden:verify |
все существующие сценарии — passed; 4 новых (room-label-parity-*) — missing-baseline (ожидаемо, см. ниже) |
| Офлайн process-gate | node scripts/process-gate.mjs |
«гейт пройден, предупреждений 0» |
| CI-провенанс (по ссылкам автора) | gh api .../jobs/96101891192 → job smoke на SHA cd029a0 |
success; run 32263084569 на SHA 88a2877 → docs/provenance/process-gate все success |
Полный browser-smoke набор (127 файлов), python -m pytest tests_backend и
performance-профили не гонялись локально:
- backend/Python не тронуты (diff не содержит
custom_components/**/*.py) — прогон бэкенд-тестов не нужен; - полный smoke-набор избыточен: диапазон изменений — рендер и event-routing
одной подсистемы (room-label), целевой smoke плюс два смежных
(
room_cards,card_tool_conflict) покрывают затронутую поверхность; Linux CIsmoke-job на этом же SHA (см. таблицу) прошёл целиком; - performance profiles не названы в AC; риск в ТЗ (§11 спека) обоснован как
пренебрежимый (не добавляются timers/subscriptions/network calls), и
performance_smoke-job Linux CI на SHAcd029a0зелёный (проверено черезgh api, не процитировано автором явно, но подтверждает отсутствие регрессии).
AC — как каждый доказан
| AC | Доказательство | Итог |
|---|---|---|
| AC1 | smoke_room_link.mjs: view-link-per-area-room, plan-keeps-links — счётчик .rlgo равен числу комнат с area в обоих режимах, во всех 4 комбинациях DPR×theme |
доказано автотестом, тест умеет падать (мутант plan-room-area-icon-hidden) |
| AC2 | smoke_room_link.mjs: view-navigates — перехват history.pushState, URL содержит /config/areas/area/ |
доказано автотестом |
| AC3 | smoke_room_link.mjs: plan-does-not-navigate (клик по иконке + реальный pointer-drag не меняют route/режим) и plan-icon-drags-label (drag, начатый на иконке через page.mouse, меняет layout.rl_<id>) |
доказано автотестом, тест умеет падать (мутант plan-room-area-icon-navigates) |
| AC4 | smoke_room_link.mjs: core-name-parity/core-metrics-parity, допуск ≤0,5 CSS px — фактические дельты 0 во всех комбинациях |
доказано автотестом, оба мутанта дополнительно валят именно этот AC |
| AC5 | Тот же smoke прогнан в light/dark при DPR 1 и 2 (theme-applied подтверждает применение темы); plan-controls-preserved проверяет, что .rlhandle×4 и кнопка настроек не входят в core-измерение |
доказано автотестом; golden-review см. ниже |
| AC6 | Диагностика по коду: код, отвечающий за room.unnamed-placeholder (`r.name |
|
| AC7 | docs/CHANGELOG.md/docs/CHANGELOG.ru.md и docs/TESTING.md правлены в том же коммите cd029a0, что и поведение |
проверено чтением diff |
| AC8 | Таблица гейтов выше — все зелёные до постановки S7-code-review |
доказано |
| AC9 | Два новых entries в scripts/mutation-gate.mjs, guard node demo/smoke_room_link.mjs; лично прогнаны --id=plan-room-area-icon-hidden и --id=plan-room-area-icon-navigates — оба: чистый прогон зелёный, на мутанте guard красный |
доказано выполнением, не только чтением реестра |
Что проверено и корректно
- Механизм фикса.
.rlgoтеперь рендерится всегда, когдаr.areaистинен (showAreaLink = !!r.area), а не только вне_markup. Интерактивность (title,@click,@pointerdown-stopPropagation) остаётся только приareaLinkInteractive = !this._markup, то есть в Planpointerdownс иконки не глушится и всплывает в.roomlabel, где его подхватывает уже существующий_labelDown()— drag с иконки использует тот же threshold, pointer capture и сохранение layout, что и drag с текста. Реализует ровно Q1/AC3 контракт из ТЗ. - Геометрический инвариант (AC4/AC5). Новый приватный метод
_roomLabelReferenceViewWidth()(houseplan-card.ts:5011) активен только приthis._markup(то есть только в Plan editor — Devices/Background editors и View не задеты, что соответствует non-scope ТЗ) и вычисляет «гипотетическую» View-ширину через уже существующий_viewForModeTarget(), подставляяstage.clientHeight + editorchrome.heightвместо фактической высоты stage. Через новую CSS-переменную--rl-icon-size(src/styles.ts:876) это значение становится базовымfont-sizeдля.roomlabel, от которого черезemнаследуются.rlname(897) и.rlmetrics(975,0.75em) — то есть правится не только размер иконки, а вся core-карточка целиком, что и требует AC4. В View/Devices/Background_roomLabelReferenceViewWidthвозвращаетview.wбез изменений — визуальный результат этих режимов побайтово не меняется, что подтверждаетgolden:verify: все прежние сценарии (включаяgeometry-*,lighting-*) осталисьpassedбез единого diff. - Числовой smoke (расширенный
demo/smoke_room_link.mjs) измеряет bounding box.rlname/.rlmetricsотносительно центра.roomlabel(а не viewport), что соответствует решению владельца Q2 — chrome/stage-высота не участвует в сравнении. Проверено выполнением: дельты действительно 0, а не «в пределах допуска, но не ноль» — запас на реальных условиях больше требуемого. - Mutation gate. Оба обязательных по ТЗ (§10.3) мутанта зарегистрированы и лично проверены на способность красить guard в красный — это снимает главный риск процесса («зелёный тест, который ничего не проверяет»).
- Трейлеры и changelog.
cd029a0:Issue: #200,User-Visible: yes, оба changelog правлены в этом же коммите.88a2877:User-Visible: no, документация без поведенческих изменений. - i18n. Diff не содержит правок
src/i18n/*.json— соответствует ТЗ («новых строк и переводов нет»); в Plan иконка не получает новыйtitle/role, что и обещано в §8 ТЗ. docs/USER-GUIDE.ru.mdне содержит формулировок, противоречащих новому поведению (искал по «зон», «rlgo», «перейти к комнате» — совпадений с описанием этого взаимодействия нет).
Находки
Нет находок High или Medium. Одна Low, снимается без цикла:
- Low. CSS-переменная
--rl-icon-size(src/styles.ts:876,houseplan-card.ts:15820) по имени выглядит как «размер только значка», но фактически задаёт базовыйfont-sizeвсей.roomlabel-карточки — и имени, и значка, и (через каскадem).rlmetrics. Название сбивает при будущем чтении кода рядом с уже существующим--icon-size/--dev-size, которые влияют только на маркеры устройств. Функционально не является дефектом: поведение проверено численно и совпадает с контрактом AC4/AC5. Снимаю с записью — переименование не меняет наблюдаемое поведение и не стоит отдельного цикла ревью.
Чего не проверял
- Полный browser-smoke набор (127 файлов) — прогнаны только целевой
(
smoke_room_link) и два смежных по поверхности (smoke_room_cards,smoke_card_tool_conflict); остальные не относятся к затронутому коду. python -m pytest tests_backend— backend/Python не тронуты этим diff’ом.- Golden baseline acceptance — 4 новых сценария
room-label-parity-*не имеют эталона (missing-baselineвgolden:verify), что ожидаемо и соответствует процессу: эталоны принимаются толькоnpm run golden:accept -- --reviewedна полном Linux CI артефакте перед бетой, не в issue-ветке. Визуально просмотрел сгенерированныеartifacts/golden/actual/room-label- parity-{view,plan}-{light,dark}.png— состав и выравнивание карточки совпадают между View и Plan в обеих темах, дополнительных дефектов не увидел. - Ручной тест на реальном touch-устройстве — вне контракта задачи (Plan
editor — best effort по
docs/TOUCH-SUPPORT.md); pointer-маршрутизация для touch не отличается от мыши на уровне событий, проверено чтением. - Performance-профили (
performance_smoke) не гонялись локально; риск в ТЗ назван пренебрежимым и подтверждается зелёнымperformance_smoke-job на SHAcd029a0в CI (обнаружено черезgh api, не было процитировано автором в хендоффе).