Files
houseplan-card/legacy/reviews/v1.65.0/CODE-REVIEW-203-r1.md
T
Claudeandclaude[bot] 0991c45374 fix(tools): архив переписывает относительные ссылки перенесённых документов (#682)
Ревью #682 r1, Medium: перенос добавляет документу уровень вложенности
(`docs/reviews/X.md` → `legacy/reviews/<тег>/X.md`, `docs/specs/` →
`legacy/specs/`), а относительные ссылки внутри перенесённых документов и в
соседях, ссылавшихся на них, никто не пересчитывал — на `97d19268` 53 битые
ссылки в 46 файлах (заявление «все 26 резолвятся» в `7feb6177` было верно
только до переноса документов ревью). Гейты архив не смотрят.

`reviews-archive.mjs`: `repairLinks` пересчитывает ссылку, если она не
резолвится от нового места, а цель находится от нового или старого места
через карту переносов; битая и до переноса ссылка не трогается. `--apply`
делает это само, `--repair-links=<rev>` — для всех переименований
`<rev>..HEAD`, `--check-links` печатает битые. Этим коммитом
`--repair-links=origin/dev` переписал ровно 53 ссылки в 46 файлах; остались
две прежние «...»-заглушки в CODE-REVIEW-448-r2 (битые и на dev). Тесты:
перенесённый документ, сосед со ссылкой в архив, ТЗ со ссылкой на позже
перенесённое ревью, битая-до-переноса не трогается, в `legacy/` битых нет;
мутант `reviews-archive-links-from-new-place-only`. PROCESS §2.10 и
DEVELOPMENT › Release называют переписывание и `--check-links`.

Issue: #682
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
2026-09-27 22:10:47 +00:00

24 KiB

Код-ревью — issue #203, цикл r1

  • Этап: S7-code-review (PROCESS.md §2.7)
  • Диапазон: git log --oneline origin/dev..HEAD = один коммит 1290927 fix: hide disabled room names (Issue: #203, User-Visible: yes), плюс два уже смёрженных документа ревью ТЗ (84e62dc, 950403d, f7b811a, 009fed9) — без продуктового кода.
  • ТЗ: docs/specs/203-hide-room-names.md, ревью ТЗ зелёное на r2: SPEC-REVIEW-203-r2.md.
  • Issue: #203
  • Ревьюер: Claude (роль «ревьюер кода»), свежая сессия без контекста реализации.

Скоуп ревью

Единственный продуктовый коммит 1290927 на ветке issue/203-hide-room-names поверх origin/dev. Диф: src/houseplan-card.ts, src/space-render.ts, src/styles.ts, scripts/mutation-gate.mjs, demo/smoke_hide_room_names.mjs (новый), demo/smoke_styling_hooks.mjs, docs/CHANGELOG.md, docs/CHANGELOG.ru.md, docs/STYLING-HOOKS.md, docs/TESTING.md, docs/USER-GUIDE.ru.md, docs/UX-MODES.md, docs/images/screenshots.json, три синхронные копии бандла. Сверено построчно с AC1–AC10 из ТЗ и с матрицей видимости §6.1, а также со всеми тремя местами дефекта, названными в SPEC-REVIEW r1/r2 (_renderSvgRoomLabels, staticSvgLabels, iso && !space.bg override).

Как проверялось

Гейт code review соразмерен задаче (PROCESS.md §8, AGENTS.md): диф трогает ровно два renderer-файла и один styling-модуль, поэтому полный набор смоков и performance не запускались — но диф явно меняет видимый результат (удаляет SVG-fallback подписи и CSS-правило), поэтому golden частично проверен диагностическим прогоном, не отложен слепо на бету.

Прогнано лично, в этом сеансе, на актуальном HEAD (1290927):

Гейт Команда Результат
Typecheck npx tsc --noEmit зелёный, без вывода
Unit npm test # tests 912 / # pass 912 / # fail 0
Build + sync 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 зелёный, обе копии побайтово совпадают со свежей сборкой
Targeted smoke (AC1/2/3/4/6) node demo/smoke_hide_room_names.mjs OK, все 13 полей true
Targeted smoke (styling hook AC8) node demo/smoke_styling_hooks.mjs OK, включая новое поле hiddenRoomLabelsAreAbsent: true
Regression (AC5, тронутая поверхность) node demo/smoke_room_cards.mjs OK
Regression (AC5, тронутая поверхность) node demo/smoke_room_link.mjs OK
Regression (AC3, тронутая поверхность) node demo/smoke_isometric_contract.mjs OK
Regression (тронутая поверхность) node demo/smoke_render_parity.mjs OK
Mutation gate, структурная проверка node scripts/mutation-gate.mjs --check все 34 записи реестра ok, включая три новых
Mutation gate, полный прогон мутанта (AC9) node scripts/mutation-gate.mjs --id=hidden-room-names-full-svg-fallback поймано 1 из 1 — смок красный на мутанте
Mutation gate, полный прогон мутанта (AC9) node scripts/mutation-gate.mjs --id=hidden-room-names-compact-svg-fallback поймано 1 из 1
Mutation gate, полный прогон мутанта (AC9) node scripts/mutation-gate.mjs --id=hidden-room-names-iso-override поймано 1 из 1
Golden, диагностика (см. находку Low ниже) node demo/golden/run.mjs --mode=capture --scenario=<id> для 4 сценариев без фона с show_names:false 2 из 4 — passed, 2 из 4 — different (разобрано ниже)

Не прогонялось и почему:

  • npm run golden:verify (полный набор, ~127+ кадров) и python -m pytest tests_backend — диф не трогает custom_components/**/*.py, backend вне скоупа; полный golden:verify дороже, чем того требует диф (два файла рендера), и по AGENTS.md/PROCESS.md §8 полный golden — предрелизный гейт, а не гейт код-ревью. Вместо него — точечная диагностика через golden:capture --scenario=<id> на четырёх сценариях, где !space.bg && show_names:false и есть шанс задеть удалённый fallback (см. ниже).
  • Остальные 122+ browser-смока (demo/smoke_*.mjs) — не относятся к тронутым поверхностям (label rendering, styling hooks, iso, compact card, plan editor); диф не касается wall junctions, openings, sun/light, drag-resize логики напрямую.
  • performance_smoke — в §11 ТЗ явно заявлено «Performance улучшается либо нейтрален… новых проходов/таймеров/network calls нет»; диф только удаляет DOM/SVG узлы и один computed-массив, разбор по коду подтверждает это без профилирования.
  • Мутанты --id= для остальных 31 существующих записей реестра — не относятся к этому дифу, не перепроверялись.

AC — доказательства

AC Как доказан Вердикт
AC1 (flat, нет bg, false → нет .roomlabel/SVG) smoke_hide_room_names.mjs::flatFalseHasNoLabels (исполнено) + мутант hidden-room-names-full-svg-fallback пойман (исполнено) доказано
AC2 (компактная карточка) smoke_hide_room_names.mjs::compactFalseHasNoLabels (исполнено) + мутант hidden-room-names-compact-svg-fallback пойман (исполнено) доказано
AC3 (hidden iso: false не форсирует, true сохраняет) smoke_hide_room_names.mjs::isoFalseHasNoLabels (исполнено) + мутант hidden-room-names-iso-override пойман (исполнено); ветка true не тронута кодом (прочитано: `disp.showNames
AC4 (Plan editor: подпись видна, View снова пуст) smoke_hide_room_names.mjs::planFalseKeepsEditorCard + viewAfterPlanStillHidden (исполнено) доказано
AC5 (true не меняет карточки/метрики/позицию/scale/HA icon) smoke_hide_room_names.mjs::trueState/trueRestoresExistingCard (исполнено) + код true-ветки не менялся (прочитано) + smoke_room_cards.mjs, smoke_room_link.mjs, smoke_render_parity.mjs зелёные (исполнено) доказано
AC6 (live-preview / Save / Cancel round-trip) smoke_hide_room_names.mjs::livePreviewHidesAll/cancelRestoresTrue/reopenReadsFalse (исполнено, через реальный _openSpaceDialog/_saveSpaceDialog) доказано
AC7 (show_borders/fills/Glow/devices/openings/tooltip не меняются) диф не трогает ни одной из этих веток (прочитано полностью — единственные удалённые строки — два render-вызова подписи и CSS .rlabel); дополнительно подтверждено диагностическим golden-прогоном на сценах wall-junctions/junction-patch/corner-split: разница пикселей ограничена ровно текстом подписи, стены/штриховка/заливка визуально идентичны (см. artifacts/golden/diff/*, не коммитится) доказано (частично исполнением golden-диагностики, частично чтением)
AC8 (документация не обещает text.rlabel, честно описывает переключатель) Diff STYLING-HOOKS.md (строка удалена, добавлен breaking-change абзац), USER-GUIDE.ru.md, TESTING.md, UX-MODES.md прочитаны построчно доказано (прочитано)
AC9 (мутант доказывает дефект) Три --id= прогона выше, каждый — «поймано 1 из 1» доказано
AC10 (гейты зелёные) typecheck/unit/build выше, все зелёные доказано

Все десять AC доказаны: девять — исполняемым тестом (смок или мутант, каждый лично прогнан и подтверждён как способный упасть — три мутанта фактически провалили ровно тот смок, который должен), AC7 и AC3(true) — комбинацией чтения кода и точечного исполнения там, где чтения недостаточно для уверенности в отсутствии побочного визуального эффекта.

Проверено и корректно

  • Все три независимых места исходного дефекта (_renderSvgRoomLabels в houseplan-card.ts, staticSvgLabels в space-render.ts, override iso && !space.bg) удалены/обезврежены полностью и по отдельности — не осталось общего пути, который скрыл бы регресс в соседнем renderer. Подтверждено и мутационными тестами (каждый ловится независимо), и grep по src/*.ts — легитимных источников .rlabel/text.rlabel не осталось.
  • CSS .rlabel вычищен из styles.ts вместе с рендер-кодом; неиспользуемый импорт roomCenter в space-render.ts убран корректно — свободная функция roomCenter остаётся используемой внутри space-geometry.ts, метод _roomCenter в houseplan-card.ts остаётся используемым в двух других местах (_snap/жест 13095, 16974) — типизация и сборка это подтверждают, дефекта мёртвого кода нет.
  • Ветка show_names: true не изменена ни в одном из трёх мест — единственная правка третьего места (iso) убирает лишний OR-член (iso && !space.bg), что не меняет исход, когда disp.showNames === true (условие и так истинно). Регресс на true-пути невозможен по построению диффа, что резонно закрывает риск §11 ТЗ («Повторное включение сбросит позицию/scale/metrics») без выделенного мутанта на true-путь.
  • show_borders, room fill, Glow, devices, openings, room hover — диф не касается; ни одна из соответствующих веток рендера не входит в изменённые строки.
  • Трейлеры коммита корректны: Issue: #203, User-Visible: yes, оба changelog (docs/CHANGELOG.md, docs/CHANGELOG.ru.md) правятся в том же коммите 1290927, запись явно называет styling-hook breaking change — ровно то, что рекомендовал снятый Low SPEC-REVIEW r2.
  • docs/UX-MODES.md получил четвёртую строку в таблице «What a space may choose not to draw» — ровно та рекомендация, которая была снята как Low в SPEC-REVIEW r2 без блокировки перехода; выполнена.
  • docs/images/screenshots.json: sourceFingerprint/sourceSha256 пересчитаны и совпадают у всех сценариев — docs-гейт CI (проверка фингерпринта скриншотов против текущего src/**) не будет падать из-за этого коммита.
  • Три копии бандла (dist/, custom_components/houseplan/frontend/, demo/srv/assets/) побайтово совпадают со свежей локальной пересборкой — подтверждено cmp в этом сеансе, не только по словам хендоффа.
  • Скоуп не расширен: non-scope пункты ТЗ (§5 — дефолт show_names для новых пространств #204, tooltip/диалоги, layout-сброс, редизайн карточки) не затронуты диффом.

Находки

Low — новая строка show_names в docs/UX-MODES.md цитирует не тот UI-текст

Файл: docs/UX-MODES.md, добавленная строка таблицы «What a space may choose not to draw»:

| `show_names` — «Показывать названия» | no room name/card is drawn… |

Суть: каждая из трёх уже существующих строк этой таблицы цитирует буквальный текст переключателя из src/i18n/ru.json — «Всегда отображать границы комнат» (space.show_borders), «Скрыть декоративный слой» (space.hide_decor), «Скрыть проёмы» (space.hide_openings); все три совпадают с i18n дословно. Новая строка цитирует «Показывать названия», но фактический UI-текст (src/i18n/ru.json:354) — space.show_names: «Отображать названия комнат (перетаскиваются)». Это не совпадает ни с новой формулировкой, ни (что интереснее) друг с другом: docs/USER-GUIDE.ru.md использует то же неточное «Показывать названия» уже давно, до этого issue — но именно в UX-MODES.md, документе, который сам формулирует правило «canonical subsystem doc», отступление от собственной конвенции таблицы цитировать буквальный UI-текст заметнее.

Почему не блокирует: формулировка не меняет технического смысла строки и не противоречит ни одному AC; расхождение чисто редакционное и не вводит пользователя в заблуждение о поведении. docs/USER-GUIDE.ru.md с тем же текстом существовал до этого issue и не входит в его скоуп починки built-in несостыковки формулировок.

Решение ревьюера: снимается без возврата автору, с записью в этом документе. Рекомендация: при следующей правке этой таблицы (или отдельной docs-гигиене) заменить «Показывать названия» на буквальный текст space.show_names для консистентности со строками-соседями.

Low — два предсуществующих golden-сценария теперь показывают «different» и не названы в хендоффе

Файлы: demo/golden/matrix.mjs (сценарии split-zero-divider-taper-dark, junction-patch-resilience-view-dark, оба mode: 'view', пространство без plan_url/bg, settings.show_names: false — см. demo/golden/harness.mjs строки ~87 и ~157).

Суть: обе фикстуры используют show_names: false без фонового изображения — именно та комбинация, на которой раньше срабатывал удалённый SVG-fallback. Диагностический прогон node demo/golden/run.mjs --mode=capture --scenario=<id> в этом сеансе подтверждает:

  • split-zero-divider-taper-dark: different, 723/783 484 пикселя, diffRatio 0.00092 (порог 0.0005); визуально (см. actual vs diff в этом сеансе, не коммитится) разница — это в точности пропавшие подписи Main room / New room в геометрическом центре комнат, всё остальное (стены, штриховка, заливка) идентично;
  • junction-patch-resilience-view-dark: different, аналогично.
  • Контрольная проверка: те же два сценария на origin/dev (собран в отдельном worktree с симлинком на node_modules) проходят passed без изменений — то есть регрессия golden строго вызвана этим коммитом, а не унаследована.
  • Два других сценария той же категории (wall-junctions-view-dark, isometric-wall-junctions-dark) остались passed — их фикстуры либо не задают show_names: false без фона в той же комбинации, либо разница ниже порога.

Это прямое и корректное следствие починки: старые эталоны фиксировали именно баг (видимую подпись там, где её не должно быть) как «ожидаемое» изображение. Хендофф-комментарий сообщает только общее «Не запускались… полный golden… предрелизным гейтом», не называя, что конкретно эти два кадра точно окажутся different при следующем прогоне golden:verify/golden:capture.

Почему не блокирует: по AGENTS.md/PROCESS.md §8 полный golden — предрелизный гейт, а принятие новых эталонов возможно только через npm run golden:accept -- --reviewed на полном артефакте Linux CI — ни ревьюер, ни автор не может закрыть это на этапе код-ревью локально. Изменение рендер-контракта корректно и предсказано ТЗ (§10.3 требует «reviewed baseline при false не содержит имён» — то есть новые/обновлённые эталоны для этой задачи предполагались как часть релизного цикла, а не этого коммита).

Решение ревьюера: снимается без возврата автору, с записью в этом документе. Рекомендация релиз-менеджеру: при подготовке беты ожидать different ровно на split-zero-divider-taper-dark и junction-patch-resilience-view-dark в задании golden/Validate и принять их через golden:accept -- --reviewed на Linux CI артефакте как ожидаемое следствие фикса — это не повод откатывать исправление и не CI-шум.

Других находок — Low, Medium или High — не выявлено. High: 0, Medium: 0.

Чего не проверял

  • Полный npm run golden:verify (127+ сценариев) — заменён точечной диагностикой golden:capture --scenario=<id> на 4 сценариях, релевантных этому диффу (см. находку выше); остальные сценарии не запускались, диф их не касается.
  • python -m pytest tests_backend -q — диф не трогает custom_components/**/*.py.
  • performance_smoke и любые ручные performance-профили — влияние на перф не заявлено в AC, разобрано по коду (удаление DOM-узлов и одного computed-массива не может регрессировать перф) и по §11 ТЗ, не исполнялось.
  • Полный набор из 127 browser-смоков — не прогонялся; выбраны только таргетные (smoke_hide_room_names, smoke_styling_hooks) и смоки на тронутых поверхностях (smoke_room_cards, smoke_room_link, smoke_isometric_contract, smoke_render_parity).
  • demo/smoke_isometric_live_touch.mjs — упомянут в SPEC-REVIEW r2 как использующий show_names: true, не тронут этим диффом (true-ветка не менялась) и не перепроверялся исполнением в этом цикле; риск низкий, оценен по построению диффа, не по прогону.
  • Остальные 30 существующих записей scripts/mutation-gate.mjs (--id= для каждой) — не относятся к этому дифу.
  • Ручное тестирование в браузере (реальная HA) — фазы ручного тестирования в процессе нет по дизайну (PROCESS.md §2.6); код-ревью и мутационные тесты стоят на её месте.

Вердикт

Все AC1–AC10 доказаны — девять исполняемым тестом (смок и/или мутант, каждый лично прогнан и подтверждён способным упасть), десятый (AC7) комбинацией чтения диффа и точечного golden-исполнения. Три независимых места исходного дефекта закрыты по отдельности, что подтверждено независимым срабатыванием каждого из трёх новых мутантов. Скоуп не расширен, трейлеры и changelog в порядке, три копии бандла синхронны. Единственные две находки — Low, обе не влияют на корректность контракта и не создают продуктовой неопределённости; сняты решением ревьюера с записью и рекомендациями (одна — редакционная правка канонического документа, другая — адресована релиз-менеджеру на этапе беты, а не автору сейчас).

Вердикт: зелёный · цикл r1/4 · High: 0 · Medium: 0