Files
houseplan-card/docs/reviews/CODE-REVIEW-162-r2.md
T
claude[bot] 53f91d974a
Проверка (CI) / Классификация изменённых файлов (push) Successful in 33s
Проверка (CI) / HACS: валидация репозитория (push) Skipped
Проверка (CI) / Hassfest: манифест интеграции (push) Skipped
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Skipped
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 47s
Проверка (CI) / Смоки в браузере (шард 1 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 2 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 3 из 3) (push) Skipped
Проверка (CI) / Смоки: все шарды зелёные (push) Skipped
Проверка (CI) / Golden-кадры против принятых эталонов (push) Skipped
Проверка (CI) / Перф-смок: бюджет времени кадра (push) Skipped
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Skipped
Проверка (CI) / Предполётные проверки: документация, провенанс, процесс (push) Failing after 3m39s
docs: review document for #162
Issue: #162
User-Visible: no
2026-09-03 17:10:17 +00:00

178 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Код-ревью #162 · заход r2
Вердикт: зелёный · заход r2 · блокирующих циклов 1/4 · High: 0 · Medium: 0
## Скоуп раунда
Предыдущий код-ревью (r1) прошёл на HEAD `4032b810` по тексту вердикта, но
фактически ревьюемое дерево включало и `8e2892b9` (CI-фиксы, запушены
2026-09-03 19:42, до публикации вердикта в 19:47) — документ `fe18f80f`
(`docs: review document for #162`) физически является потомком `8e2892b9`
(`git log --format='%h %p' -1 fe18f80f` → `fe18f80f 8e2892b9`). Это
несоответствие SHA в тексте вердикта самому дереву — сам факт не критичен
(правки внутри 8e2892b9 не оспаривались), но найден только чтением git-графа,
а не заявлен явно. Базой для дельты этого раунда взят `8e2892b9`, а не
заявленный `4032b810`, как единственный SHA, действительно совпадающий с
деревом, на котором был вынесен вердикт.
Разбор — по дельте, а не заново: `git diff 8e2892b9..HEAD` (HEAD = `49f69f60`),
две правки-коммита автора (`4b8cf6e0`, `49f69f60`) плюс автоматический
коммит публикации ревью (`fe18f80f`, не код). Дельта закрывает ровно две
находки r1 и не трогает ничего вне их: резолвер маршрутов, серверный
recorder, валидацию config/set, space-deletion, экспорт — не менялись.
## Как проверялось
- Прочитаны оба изменённых участка кода целиком:
`src/houseplan-editor-runtime.ts` (`_vacAutoCalibrate`, `_vacApplyCalibrationProposal`),
`src/editors/vacuum-maps-section.ts` (новый блок «Добавить источник карты»).
- Прослежена цепочка `calibrationTarget()` (`src/vacuum-route-edit.ts:153-163`,
не менялась в этой дельте) → `_vacAutoCalibrate` → `_vacCalConfirm.space` →
`_vacApplyCalibrationProposal` — вручную сверено, что `target.space` есть
`route?.space || dockSpace`, то есть пространство маршрута, а не дока.
- Прогнаны гейты лично (см. раздел «Гейты»), включая точечный прогон нового
мутанта и восьми смоков с прямым совпадением символов дельты.
## Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
| **High** — `_vacApplyCalibrationProposal` коммитил `dev.space` (пространство дока) вместо пространства маршрута при ручной донастройке после high-residual auto-calibration; AC8 нарушался в штатной ветке | `_vacCalConfirm` получил поле `space?: string`; `_vacAutoCalibrate` кладёт в него `target.space` (`src/houseplan-editor-runtime.ts:11035`); `_vacApplyCalibrationProposal` коммитит `proposal.space \|\| dev.space` вместо голого `dev.space` (`src/houseplan-editor-runtime.ts:11055-11056`) | Код: `houseplan-editor-runtime.ts:11029-11035` (запись `space: target.space`) и `:11054-11058` (чтение с фолбэком). Доказательство: `demo/smoke_vacuum_multifloor.mjs:87-104` — новый сценарий «док на f1, маршрут vr2/m2 на garden, высокий residual → ручная подгонка» проверяет `_space === 'garden'` и `_vacFit.routeId === 'vr2'`. Новый мутант `vacuum-manual-fit-after-proposal-uses-the-dock` (`scripts/mutation-gate.mjs`) возвращает `const space = dev.space` — лично прогнан, красный, как обязан (см. «Гейты») |
| **Medium** — §9.3 ТЗ «Добавить источник карты» (отдельная camera на карту) не реализовано; второй сценарий интеграции из тела issue отсутствовал | В `src/editors/vacuum-maps-section.ts` добавлен раскрывающийся блок «Добавить источник карты» (`<details class="vacroute-sources">`), список — кандидаты из `sources.candidates` (тот же `VacSourceResolution`, что и у общего picker + ленивой секции «Все камеры», без дублирующего вычисления), источник без читаемого map id показан неактивным с причиной | Код: `vacuum-maps-section.ts:101-120` (функция `addSource`, список `spare`) и `:212-227` (рендер). Переводы: `vac.route_add_source`, `vac.route_add_source_hint`, `vac.route_source_no_map` добавлены во все 4 языковых файла `src/i18n/support/*.json`, синхронность подтверждена `test/i18n.test.mjs` (счётчик ключей 74→77, тест прогнан в составе `npm test`). Ручной сценарий добавлен в `docs/TESTING.md:84-85` |
Обе находки закрыты по существу, не косметически: High доказан мутантом,
который ловит именно тот регресс, что описан в находке (коммит пространства
дока вместо маршрута); Medium — код читает тот же источник кандидатов, что и
уже проверенный picker, поэтому не вносит второй способ получить тот же
список камер.
## Унаследовано из r1 (без повторной проверки)
Со ссылкой на `docs/reviews/CODE-REVIEW-162-r1.md`, вынесенный на SHA `8e2892b9`
(де-факто; в тексте вердикта ошибочно назван `4032b810`, см. «Скоуп раунда»):
- Резолвер маршрутов и его чистые контракты (`src/vacuum-routes.ts`), включая
6 исходов резолвинга и `adoptLegacyRun` — не изменялись в дельте, доверяю
прежнему прочтению.
- Питоновское зеркало (`custom_components/houseplan/vacuum_routes.py`) и
серверный recorder/GC прогонов (`trails.py`) — не изменялись.
- Валидация `map_routes` на `config/set` и в обоих import-flow, а также
поведение `space-deletion.ts`/`space-reference-repair.ts` — не изменялись.
- Храповик ядровых файлов и ленивый граф (§3.4 ТЗ) — перепроверены заново в
этом раунде отдельным тестом (см. «Гейты»), так как дельта добавляла код
именно в эти файлы; расхождений с r1 не найдено (потолки соблюдены).
- 13 из 15 мутантов (кроме нового `vacuum-manual-fit-after-proposal-uses-the-dock`
и ранее заявленных восьми из спецификации) — не перепрогонялись, так как
защищаемый ими код не в дельте.
- backend-тесты (`pytest tests_backend`, 359 passed по r1) — не перепрогонялись,
дельта не трогает `custom_components/**/*.py` (подтверждено `git diff --stat`).
- Golden/performance — не гонялись ни в r1, ни здесь: вне AC, canonical запуск
остаётся пре-релизным гейтом.
## Находки
Нет. High: 0, Medium: 0.
Побочное наблюдение, не находка: в комментарии автора после `49f69f60`
заявлено «`npm test` 1856/0/1». Мой личный прогон (дважды, стабильно)
даёт 1854 pass / 0 fail / 1 skip (1855 всего). Расхождение на 2 теста не
объясняется дельтой (в ней нет новых `test(...)`, кроме одной изменённой
числовой проверки в `test/i18n.test.mjs`, которая ассертит количество ключей,
а не добавляет тест-кейс). Похоже на опечатку в отчёте, а не на нестабильный
прогон или пропущенные файлы: `fail: 0` в обоих случаях, набор тестов
одинаков. Не блокирует — актуальный результат зафиксирован мной лично и он
зелёный.
## Гейты — что прогнал и результат
- `npx tsc --noEmit` — чисто.
- `npm test` — **1854 pass / 0 fail / 1 skip** (см. наблюдение выше про
расхождение с отчётом автора).
- `npm run build` — собирается; `dist/houseplan-card.js` побайтово совпадает
с `custom_components/houseplan/frontend/houseplan-card.js`; JSON-сверка
`dist/houseplan-assets.json` ↔ `custom_components/.../houseplan-assets.json`
— идентичны. Третья копия (репозиторная `dist/`) — совпадает с только что
собранной, т.е. все копии синхронны.
- `node scripts/check-docs.mjs` — passed (7 файлов, 10 внешних ссылок);
прогнан, так как дельта трогает `src/**`.
- `node --test test/core-file-budget.test.mjs` — 7/7, потолки соблюдены
(`houseplan-card.ts` 13606/13659, `houseplan-editor-runtime.ts`
14320/14323).
- `npm run bundle:budget` — initial View 292978 Б gzip при потолке 294000±2000;
предупреждение про запас < 15000 Б воспроизводится, но это существующий,
учтённый долг (#367, потолок поднят коммитом `51b4cc7e` в этой же ветке до
начала r1), дельта добавила к нему ~7 байт — не новый долг этого раунда.
- `node scripts/smoke-select.mjs --base 8e2892b9 --head HEAD` — 217 смоков в
матрице; 8 «прямых совпадений» по символам дельты (`_vacCalConfirm`,
`_vacFit`, `_commitSpace`, `DevItem`): `smoke_vacuum_multifloor`,
`smoke_vacuum_firstuse`, `smoke_controls`, `smoke_danger_confirm_branches`,
`smoke_device_position_history`, `smoke_editor_gestures`, `smoke_fixed_floor`,
`smoke_vacuum`. Все восемь прогнаны лично — OK.
- `node scripts/mutation-gate.mjs --id=vacuum-manual-fit-after-proposal-uses-the-dock`
— «чистый прогон» OK, мутант краснеет, как обязан (1 из 1 пойман). Остальные
14 мутантов не перегонялись — их код не в дельте (унаследованы из r1).
- `node --test test/single-source-numbers.test.mjs` — 3/3 (уже входит в
`npm test`, прогнан отдельно для явности: дельта добавляет пользователю
видимое число — map id рядом с каждым источником в новом блоке — источник
этого числа один: `host._vacObservedMapId(dev, candidate.entityId)`,
вызывается и для отображения, и для записи маршрута, не кешируется отдельно
для каждого места).
### Что не проверял и почему
- `python -m pytest tests_backend` — не прогонял в этом раунде: дельта не
касается ни одного `custom_components/**/*.py` файла (подтверждено
`git diff --stat 8e2892b9..HEAD`). Результат r1 (359 passed) наследуется.
- `npm run invariants` — не прогонял: дельта не трогает рёбра комнат, записи
толщины, `layout`, `marker.space` или `open_spans`. Поле `route.space`
внутри `marker.vacuum.map_routes[]` — не то же самое, что `marker.space`, и
не является геометрическим ключом решётки.
- `npm run golden:verify` — не прогонял: дельта не меняет геометрию, стили или
слои плана — только текст/поведение диалога в редакторе устройства и текст
предупреждения. Визуальный рендер плана не затронут.
- Полная матрица `demo/smoke_*.mjs` (217 файлов) — не прогонял целиком: дельта
локальна (2 файла кода + переводы), а `scripts/smoke-select.mjs` явно указал
восемь прямых совпадений без «неопределённостей» и без слабых связей,
требующих отдельного решения.
- Остальные 13 из 15 заявленных мутантов — не перепрогонял: они охраняют код,
не входящий в дельту этого раунда (унаследовано из r1, где они уже были
лично прогнаны и покраснели).
- `docs/USER-GUIDE.ru.md` — сверил текст §«Калибровка» (строки 1497-1512):
формулировка уже достаточно общая («каждую карту нужно сопоставить
пространству и откалибровать именно в нём»), не называет конкретные кнопки
и не требует правки под новую «Добавить источник карты».
- Трейлеры `User-Visible: no` на обоих коммитах (`4b8cf6e0`, `49f69f60`)
проверены на соответствие проектной конвенции: во всей ветке этой задачи
только коммиты, впервые вводящие уже отраженную в `docs/CHANGELOG*.md`
возможность, помечены `yes` (`c38501ef`, `ca6ebc30`, `567b4568`); все
доводочные фиксы после них, включая более ранний `4032b810` (та же
категория бага — пространство калибровки), помечены `no`. Обе правки этого
раунда доводят уже анонсированное в «Не выпущено» поведение
(`docs/CHANGELOG.ru.md:16-19` уже обещает «каждую карту можно сопоставить
пространству и откалибровать её именно в этом пространстве» — без уточнения
механизма) до соответствия описанию, а не добавляют новую строку продукта.
Противоречия конвенции не нашёл.
## Итог
Обе находки r1 закрыты по существу и доказаны (одна — мутантом, ловящим
именно описанный регресс; другая — переиспользованием уже проверенного
источника кандидатов без дублирования). Новых находок в дельте нет. Гейты,
соразмерные объёму дельты, зелёные.
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/162-vacuum-map-space-routing`, коммит `49f69f60dbd5` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `60cc4393ee53dac00659790870ee3dcb03ad3248`
```
git log --all --format='%H %T' | grep 60cc4393ee53
```
- ТЗ `docs/specs/162-vacuum-map-space-routing.md`, блоб `a8edcfbe6c37700095f6f8582258eac4fcb58ad9`
```
git log --all --find-object=a8edcfbe6c37700095f6f8582258eac4fcb58ad9 -- docs/specs/162-vacuum-map-space-routing.md
```