Files
houseplan-card/docs/reviews/SPEC-REVIEW-448-r1.md
T
2026-09-04 16:20:34 +03:00

182 lines
16 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.
# SPEC-REVIEW-448-r1
- Issue: [#448](https://github.com/Matysh/houseplan-card/issues/448) — Labs: единый бессрочный переключатель `hp_alpha` для экспериментальных функций
- ТЗ: `docs/specs/448-alpha-switch.md` (SHA `aa72704a`)
- Трек: полный (лёгкий явно отклонён аналитикой: «меняются долговременный compatibility-контракт и несколько runtime/test/documentation поверхностей»)
- Этап: `S4-spec-review` · заход r1 · блокирующих циклов израсходовано 0 из 4 (до этого вердикта)
- Ревьюер ≠ автор ТЗ (Codex); эта сессия не участвовала в написании ТЗ.
## Скоуп
Диапазон, вынесенный на ревью, — только документация: `git diff origin/dev...HEAD`
даёт два файла, `docs/specs/448-alpha-switch.md` (новый, 260 строк) и одну
строку в `docs/specs/README.md` (реестр ссылок issue↔ТЗ). Продуктовый код не
менялся — верно для стадии `S4-spec-review`, где менять `src/**`/
`custom_components/**` запрещено правилом №1 до `S5-ready`. Коммит `aa72704a`
несёт трейлеры `Issue: #448` и `User-Visible: no` — корректно, поведение ещё не
изменилось.
Задача продолжает прямо одобренное узкое 2.5D-исключение из `docs/SCOPE.md`
(единственный прецедент `#89`) и служит J1: она не строит новую функцию, а
чинит контракт включения уже принятого Stage 1/2 изометрического View,
испорченный version-expiry в `src/labs.ts`. Из «не-скоуп» разделов SCOPE.md
задача не задевает ничего — доступ к experimental-переключателю остаётся
скрытым, публичного 3-D запуска и новых редакторов ТЗ не вводит.
## Как проверялось
1. Прочитаны `docs/SCOPE.md`, `AGENTS.md`, `PROCESS.md` (§1–§10.4 включительно).
2. Прочитаны тело issue #448 и все три комментария (аналитика, вопросы
владельцу, решения владельца со ссылкой на ТЗ).
3. Прочитан канонический `docs/ISOMETRIC.md` (текущий контракт `iso`/Labs,
which `hp_alpha` заменяет) и `docs/UX-MODES.md` (раздел Kiosk mode) —
подсистема, которую задевает пункт «full-card View и kiosk gate».
4. Прочитан действующий `src/labs.ts` целиком и потребители Labs в
`src/houseplan-card.ts` (grep по `iso|Labs|labs`, ~40 точек использования:
`_labsIso`, `_desiredProjection`, `_setProjection`, `_effectiveProjection`,
projection-toggle кнопка, `noteLabsRender`) — чтобы отличить утверждения ТЗ
о текущем поведении от догадок.
5. Сверены i18n-ключи `view.flat`/`view.volumetric` в `src/i18n/{ru,en}.json`
с прозой ТЗ («Плоский / 3-D»).
6. Проверено `docs/CONFIG-COMPATIBILITY.md` (сфера действия — persisted-поля
схемы плана, не browser-local Labs storage) — подтверждено, что раздел
«Модель данных и миграция» ТЗ корректно объявляет её вне применимости этого
реестра.
7. Проверено `docs/TOUCH-SUPPORT.md` (product contract: View — touch-first,
kiosk — primary supported environment) на предмет обязательного пункта DoR
§2.5 «влияние на touch… View и киоск — блокирующие».
8. Проверены обязательные разделы §7.1 построчно по тексту ТЗ.
9. `git show aa72704a --stat` и `-s --format=full` — трейлеры и состав коммита.
Гейты кода (`typecheck`/`test`/`build`/`check-docs`) не прогонялись: диапазон
не касается `src/**` и `custom_components/**`, только `docs/**`; на этой
стадии они не гейт ревью ТЗ. `check-docs.mjs`, о котором автор отчитался в
issue, тоже не относится к «правкам src» — но и не вредит, лишний прогон.
## Находки
### Medium (в скоупе задачи — правится в текущем ТЗ)
**M1. ТЗ не закрывает обязательный пункт DoR «влияние на touch» (`docs/TOUCH-SUPPORT.md`).**
- Файл: `docs/specs/448-alpha-switch.md`
- PROCESS.md §2.5 требует для перехода в «Готово к разработке»: «влияние на
touch по `docs/TOUCH-SUPPORT.md` (View и киоск — блокирующие)», названо явно
или явным «нет». `docs/TOUCH-SUPPORT.md` фиксирует View как **touch-first,
обязательный к полной поддержке**, а kiosk — как «primary supported
environment»: любой тач-дефект в этих поверхностях — не допустимая
деградация, а дефект продукта.
- В тексте ТЗ (проверено построчным поиском `touch|Touch|сенсор` —
ноль совпадений) нет ни одной строки о touch. Задача прямо называет
затронутой поверхностью «full-card View и kiosk gate» (аналитика) и пункт 13
контракта возвращает в View именно интерактивный контрол — существующую
кнопку `projection-toggle` (`src/houseplan-card.ts:11501-11507`), которая
сейчас недостижима из-за `expires: 1.65.0` и станет достижимой снова.
- Это не открытый продуктовый вопрос владельцу: сама кнопка и её
touch-поведение уже прошли ревью в #89/#122 и код не меняется — задача лишь
восстанавливает достижимость уже принятого контрола через новый резолвер.
Достаточно одной явной строки в ТЗ (например, в «UX и диагностика» или
отдельным подпунктом «Touch»), фиксирующей это рассуждение как решение
ревью, а не оставляющей пункт чек-листа непроверенным. Без такой строки
раздел DoR формально не закрыт, и это факт, а не стилистика: чек-лист §2.5
зовёт этот пункт поимённо и отмечает его блокирующим для View/kiosk.
- Воспроизведение: `grep -inE "touch|Touch|сенсор" docs/specs/448-alpha-switch.md` → нет совпадений.
- Не блокирует переход High-порогом, чинится добавлением строки в этом же ТЗ,
отдельный цикл не обязателен по существу (это не смена контракта), но по
процессу возврат один — правка ТЗ и повторный (лёгкий) заход.
## Что проверено и корректно
- **Обязательные разделы §7.1** все присутствуют и в правильном порядке:
сценарий, что человек увидит до/после, проблема, скоуп/не-скоуп, контракт
поведения, UX и диагностика, модель данных и миграция, i18n и accessibility,
критерии приёмки AC1–AC13 с доказательством, план автотестов, риски, откат,
release-артефакты, плюс необязательный, но полезный блок «Принятые
предположения».
- **AC1–AC13** пронумерованы, взаимно не пересекаются и у каждого указан явный
способ доказательства (unit / unit+smoke / source-contract / targeted smoke +
golden / performance profile / static contract). Ни один AC не сформулирован
как «работает корректно» без проверяемого критерия.
- **Ни одной непомеченной догадки о существующем поведении не найдено.**
Каждое фактическое утверждение о текущей системе сверено с кодом/каноном и
подтвердилось: version-expiry `1.65.0` действительно отфильтровывает `iso` на
линии 1.71 (`liveLabsFlags` + `LABS_FLAGS[0].expires`); переключатель Flat↔3-D
уже существует в full-card View и уже скрыт в kiosk (`!this._kiosk`) —
`src/houseplan-card.ts:11501`; per-space preference `houseplan_card_view_v1`
используется как заявлено (`LS_VIEW` в `houseplan-card.ts:489`); редакторы и
`houseplan-space-card` не проецируют iso — подтверждено `docs/ISOMETRIC.md`
(«Editors and houseplan-space-card are always flat»). Единственная
content-догадка о будущем поведении («явное неизвестное URL-значение не
портит сохранённое значение») корректно вынесена в блок «Принятые
предположения», как и требует PROCESS.md §7.1.
- **Продуктовые вопросы владельцу заданы по существу**, каждый с предложенным
default (способ включения/выключения `hp_alpha`; судьба legacy `iso`), ответ
получен и зафиксирован явным решением в третьем комментарии issue —
процессуально верно (§3.7.1: только «что видит/делает человек» и «объём
видимых изменений», без технических вопросов владельцу).
- **Скоуп/не-скоуп** точно очерчивают границу: явно исключены публичный запуск
3-D, Stage 3 (#160), серверное хранение/синхронизация, миграция старого
`iso`. Соответствует ответу владельца на Q2 (без миграции).
- **Откат** описан содержательно — включает явный запрет «плохого» отката
(продление `iso`-expiry, возврат нескольких внешних ключей), что и было
первоисточником проблемы.
- **Компат-модель**: раздел корректно утверждает, что схема плана/backend/HA-
запросы не меняются — проверено по `docs/CONFIG-COMPATIBILITY.md`, чья
область действия — persisted-поля конфигурации плана, а не browser-local
Labs-хранилище; обращение к этому реестру здесь действительно не требуется.
- **i18n**: заявлено «новых публичных строк нет» — проверено, `view.flat` /
`view.volumetric` уже существуют в `ru.json`/`en.json`; прозаические «Плоский
/ 3-D» в тексте ТЗ — не заявка на новую строку, а неформальный пересказ
существующих меток, реальный текст меток задачей не меняется.
- **Класс изменений и трейлеры коммита** верны: только `docs/**` (класс C),
`Issue: #448`, `User-Visible: no` — корректно для стадии, где поведение ещё
не менялось; продуктовый код не тронут ни одним файлом (правило №1 не
нарушено).
- **Персона/повод**: аналитика прямо связывает задачу с J1 SCOPE.md и с уже
одобренным исключением #89; формулировка «продвинутый
пользователь/тестировщик» в разделе «Сценарий» не совпадает дословно ни с
одной строкой таблицы персон SCOPE.md (`Home admin`/`Household
members`/`Guests`), но по контексту (URL-флаг, desktop) однозначно про Home
admin — рассмотрено, не поднято до отдельной находки: не создаёт
двусмысленности для реализации или проверки AC, чисто формальная
формулировка. Low, не фиксирую отдельно.
## Чего не проверял
- Не прогонял `npx tsc --noEmit` / `npm test` / `npm run build` — диапазон не
содержит кода класса A/B, эти гейты не гейтуют ревью ТЗ.
- Не прогонял `node scripts/check-docs.mjs` — диапазон не касается `src/**`
(отпечаток скриншотов документации), автор уже привёл `passed` в issue, но
это не обязательный гейт для docs-only диффа.
- Не проверял golden/smoke/performance-фикстуры буквально (их ещё нет — они
появятся в реализации, план автотестов на этой стадии оценивается как план,
а не как прогон).
- Не оценивал техническую реализуемость внутреннего резолвера построчно (не
моя роль на этой стадии и не предмет спор ТЗ↔код) — только соответствие
контракта существующему коду и канону.
## Вердикт
`hp_alpha` заменяет version-expiry контракт корректно очерченным,
непротиворечивым и полностью доказуемым ТЗ; единственная находка — реальный,
но локально устранимый пробел DoR по touch-влиянию, входящий в скоуп этой же
задачи.
Вердикт: жёлтый · заход r1 · блокирующих циклов 1/4 · High: 0 · Medium: 1 → в задаче
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/448-alpha-switch`, коммит `aa72704aacce` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `4bea42cb1c9dc9c0fc49c8de4005942035e965d1`
```
git log --all --format='%H %T' | grep 4bea42cb1c9d
```
- ТЗ `docs/specs/448-alpha-switch.md`, блоб `ba9b8e5f621f5ad8ecb881e1cbf40d3cc24573ef`
```
git log --all --find-object=ba9b8e5f621f5ad8ecb881e1cbf40d3cc24573ef -- docs/specs/448-alpha-switch.md
```