Files
houseplan-card/legacy/reviews/v1.65.0/CODE-REVIEW-200-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

15 KiB
Raw Blame History

Код-ревью 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 CI smoke-job на этом же SHA (см. таблицу) прошёл целиком;
  • performance profiles не названы в AC; риск в ТЗ (§11 спека) обоснован как пренебрежимый (не добавляются timers/subscriptions/network calls), и performance_smoke-job Linux CI на SHA cd029a0 зелёный (проверено через 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, то есть в Plan pointerdown с иконки не глушится и всплывает в .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 на SHA cd029a0 в CI (обнаружено через gh api, не было процитировано автором в хендоффе).