mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-03 05:08:53 +00:00
211 lines
18 KiB
Markdown
211 lines
18 KiB
Markdown
# SPEC-REVIEW-402-r2
|
||
|
||
- Issue: https://github.com/Matysh/houseplan-card/issues/402
|
||
- Артефакт ТЗ: `docs/specs/402-confirm-outside-main-branch.md` (полный трек, класс A)
|
||
- Заход: r2 · лимит циклов ревью ТЗ для полного трека — 4 (§4), блокирующих
|
||
циклов израсходовано 1/4 (зелёные вердикты бюджет не тратят, #227)
|
||
- Ревьюер: Claude (роль «ревьюер ТЗ»), независимая сессия
|
||
- Раунд r1: вердикт красный, `docs/reviews/SPEC-REVIEW-402-r1.md`, база
|
||
`d94db87e` (коммит, добавивший спецификацию)
|
||
- Раунд r2: правка ТЗ — коммит `11959e4c` («docs: #402 spec revision 2 per
|
||
SPEC-REVIEW-402-r1»), HEAD ревью — `11959e4c`
|
||
|
||
## Скоуп ревью (§2.10, по дельте)
|
||
|
||
r1 закончился красным (High: 1, Medium: 1). Дельта этого раунда —
|
||
`git diff d94db87e..11959e4c -- docs/specs/402-confirm-outside-main-branch.md`:
|
||
правка ровно двух мест ТЗ (текст «Touch и kiosk» + переформулировка
|
||
обоснования не-скоупа для `_tapConfirm`/`_vacCalConfirm`), плюс AC8, AC9 и
|
||
два пункта плана автотестов. Никакого продуктового кода в дереве нет (этап —
|
||
ТЗ), контракт поведения не изменился, новая подсистема не задета, объём
|
||
дельты явно меньше исходной задачи → разбор ограничен дельтой плюс
|
||
проверкой, что она не сломала уже принятое (§2.10 п.4-5).
|
||
|
||
## Как проверялось
|
||
|
||
1. Прочитан весь диапазон изменений r1→r2 (`git diff d94db87e..HEAD`),
|
||
построчно, для файла ТЗ.
|
||
2. Найден вердикт r1 и SHA, на котором он получен (`d94db87e`, назван в
|
||
шапке `SPEC-REVIEW-402-r1.md` — не пришлось восстанавливать).
|
||
3. По каждой находке r1 (H1, M1) сверено текстом дельты, чем именно она
|
||
закрыта — раздел «Закрытие раунда r1» ниже.
|
||
4. Технические утверждения новой дельты сверены с текущим деревом на
|
||
`11959e4c` (код не менялся с `d94db87e`, но проверка не наследуется
|
||
автоматически — новый текст мог сослаться на код неточно):
|
||
- структура `render()` (`src/houseplan-card.ts:11165-11878`) — семь
|
||
ранних `return`, отсутствие `return` между `:11248` и `:11872`
|
||
(`awk`-проверка по диапазону) — подтверждает утверждение M1, что
|
||
`_tapConfirm` (`:11852`), `_vacCalConfirm` (`:11802`) и `_dangerConfirm`
|
||
(`:11872-11878`) лежат в одной и той же финальной ветке без разрыва;
|
||
- `docs/TOUCH-SUPPORT.md` § «Safety floor that still applies to touch
|
||
editors» (`:69-79`) — сверено число пунктов и их содержание против
|
||
фразы ТЗ «запрещает best effort в трёх вещах» — см. находку L1;
|
||
- `docs/TOUCH-SUPPORT.md` § «Testing and release gates» (`:139-151`) —
|
||
сверено, что touch-editor safety floor входит в release-blocking
|
||
гарантии (п.4), а не только View/kiosk (п.2) — это меняет оценку
|
||
находки H1 (см. ниже);
|
||
- `hasTouch` — паттерн существующих touch-смоков (`grep -rn hasTouch
|
||
demo/smoke_*.mjs`) реально существует и используется ровно так, как
|
||
описывает AC8 (`demo/smoke_color_picker.mjs`,
|
||
`demo/smoke_isometric_live_touch.mjs`, `demo/smoke_touch_tips.mjs`);
|
||
- смоки, на которые ссылается AC9 (тап и калибровка пылесоса),
|
||
существуют: `demo/smoke_tap_run.mjs`, `demo/smoke_tap_ctx.mjs`,
|
||
`demo/smoke_vacuum.mjs`, `demo/smoke_vacuum_firstuse.mjs`,
|
||
`demo/smoke_cold_view_vacuum.mjs`.
|
||
5. Проверено, остаются ли §7.1-обязательные разделы на месте после правки —
|
||
да, ни один не удалён, добавился один новый («Touch и kiosk»).
|
||
6. Гейты кода не гонялись — на этапе ТЗ продуктового диффа нет (см. «Чего не
|
||
проверял»).
|
||
|
||
## Закрытие раунда r1
|
||
|
||
| Находка r1 | Чем закрыта | Где это видно |
|
||
|---|---|---|
|
||
| **H1** (High) — ТЗ не называет влияние на touch/kiosk | Добавлен раздел «Touch и kiosk»: цитирует `TOUCH-SUPPORT.md` § Safety floor, называет её блокирующей для touch, объясняет, почему перенос точки рендера не меняет touch-поведение (тот же компонент, разметка, scrim, футер не меняются), добавлен AC8 (смок в touch-эмуляции на буквальном сценарии issue) | `docs/specs/402-confirm-outside-main-branch.md`, раздел «Touch и kiosk» (строки ~112-127 текущей редакции), AC8 |
|
||
| **M1** (Medium, в скоупе) — ложное обоснование «свои ветки» для `_tapConfirm`/`_vacCalConfirm` | Формулировка заменена на две настоящие причины: (1) нет промиса — синхронный `exec()` / закрытие по `hp-close`; (2) точка входа недостижима из ранних веток. Добавлено явное требование к реализации не трогать расположение этих двух блоков при выносе `_dangerConfirm`, плюс AC9 фиксирует это как критерий приёмки | `docs/specs/402-confirm-outside-main-branch.md`, раздел «Скоуп / не-скоуп» (абзац «`_tapConfirm` и `_vacCalConfirm` — не в скоупе...»), AC9 |
|
||
|
||
M1 закрыта полностью и точно — построчная сверка (`:11802`, `:11852`,
|
||
`:11872-11878`, отсутствие `return` между ними) подтверждает переформулировку
|
||
слово в слово.
|
||
|
||
H1 закрыта по существу, с одной оговоркой (см. находку L1 ниже): текст
|
||
верно поднимает safety floor и даёт достаточное объяснение для
|
||
блокирующей части DoR (View/kiosk), но не называет явно 5 call site'ов
|
||
`_confirmDanger` в `houseplan-editor-runtime.ts`, про которые r1 просил
|
||
отдельную строку `Touch editor: …`. Разобрано отдельно ниже, почему это не
|
||
держит вердикт красным/жёлтым.
|
||
|
||
## Унаследовано из r1
|
||
|
||
Без повторной проверки принято всё, чего дельта не касалась — документ
|
||
`docs/reviews/SPEC-REVIEW-402-r1.md`, SHA `d94db87e`:
|
||
|
||
- диагноз дефекта (структура `render()`, семь ранних веток, `hp-confirm`
|
||
только в финальной) — построчно сверен в r1, дельта эти строки не меняла;
|
||
- корректность `HpConfirmController` (`cancel`/`resolve`/токен) —
|
||
`src/danger-confirm.ts` не тронут дельтой;
|
||
- буквальный сценарий issue (`_deleteServerPlan` →
|
||
`houseplan-onboarding-runtime.ts:218-224,273`) — не тронут;
|
||
- факт «`noChange` нигде не оборачивается в шаблон» — граница ТЗ для
|
||
языкового гейта `warm`, код не менялся;
|
||
- AC1-AC4, AC6 — проверяемость и реалистичность доказательства
|
||
(`demo/smoke_danger_confirmation.mjs`) — текст этих AC дельта не
|
||
меняла;
|
||
- AC5 — рассуждение про недостижимость `!hass/!_config` после первого
|
||
монтирования и про то, что `noChange` не трогает уже открытый диалог;
|
||
- AC7 — `hp-confirm` импортируется не лениво (`houseplan-card.ts:14`),
|
||
бюджет не растёт;
|
||
- граница скоупа с #32 (содержимое диалога, ревалидация после `await`) и с
|
||
#406 (`alertdialog`/`aria-describedby`) — абзац не менялся;
|
||
- соответствие `docs/SCOPE.md` (J4, J6) — не затронуто дельтой;
|
||
- присутствие всех обязательных разделов §7.1, кроме нового «Touch и
|
||
kiosk» — остальные разделы не удалялись и не переписывались.
|
||
|
||
## Находки
|
||
|
||
### L1 (Low, наблюдение — не блокирует). Число в цитате TOUCH-SUPPORT.md неверно
|
||
|
||
**Где**: `docs/specs/402-confirm-outside-main-branch.md`, раздел «Touch и
|
||
kiosk»: «`docs/TOUCH-SUPPORT.md` § Safety floor запрещает «best effort» в
|
||
**трёх** вещах».
|
||
|
||
**Проверено чтением**: `docs/TOUCH-SUPPORT.md:71-79` перечисляет **шесть**
|
||
пунктов под «"Best effort" never permits:» — потерю данных, небезопасный
|
||
вызов HA, обход подтверждения, залипание карточки вне View, поломку View/
|
||
kiosk соседним редактором, случайное сохранение геометрии от неверно
|
||
понятого жеста. Ни разу не три.
|
||
|
||
**Последствие**: не меняет вывод ТЗ — пункт «обход подтверждения
|
||
разрушающего действия» реален и процитирован верно, вывод («задача поднимает
|
||
пол обратно») не зависит от точного числа. Это неточная цифра в
|
||
пересказе документа, а не выданная за факт догадка о продуктовом поведении.
|
||
|
||
**Решение ревьюера**: снимаю как Low с записью, не блокирует. Автору стоит
|
||
поправить «трёх» на «шесть» (или убрать число вовсе) в следующей правке,
|
||
которую он уже будет делать по другому поводу — заводить цикл ради одного
|
||
слова нецелесообразно (тот же принцип, что «r2 по #150» в §2.10).
|
||
|
||
### L2 (Low, наблюдение — не блокирует). Явного упоминания touch-статуса пяти вызовов из `houseplan-editor-runtime.ts` по-прежнему нет
|
||
|
||
**Где**: раздел «Touch и kiosk» рассуждает в общем виде («тот же компонент,
|
||
разметка не меняется») и доказывает это AC8, но AC8 сформулирован только
|
||
для ветки онбординга; ни разу не назван `houseplan-editor-runtime.ts` и
|
||
пять его вызовов `_confirmDanger`.
|
||
|
||
**Почему это не блокирует, хотя r1 просил именно это**. Я перепроверил
|
||
довод по существу, а не только по форме:
|
||
|
||
- `docs/TOUCH-SUPPORT.md:139-151` («Testing and release gates») перечисляет
|
||
четыре release-blocking гарантии, и «touch-editor safety floor» — в их
|
||
числе (п.4), не только View/kiosk (п.2). Так что для полноты формально
|
||
стоило бы явно назвать и редакторские call site'ы, как просил r1.
|
||
- Но по коду («Контракт» ТЗ + AC1, AC2, AC4, AC5) `hp-confirm` выносится из
|
||
цепочки `render()` **как единый механизм**, не привязанный к тому, кто
|
||
вызвал `_confirmDanger`. AC4 («Открытое подтверждение переживает смену
|
||
ветки») сформулирован без привязки к вызывающему — он покрывает и случай,
|
||
когда подтверждение открыл редакторский call site, а карточка тем временем
|
||
потеряла последнее пространство (`model.length` дошёл до нуля во время
|
||
открытого диалога — ровно тот сценарий, который сам текст ТЗ называет
|
||
«второй половиной дефекта»). Отдельного AC для редакторских call site'ов
|
||
не нужно ровно потому, что контракт написан на уровне компонента, а не
|
||
вызывающего.
|
||
- Поэтому вывод раздела «Touch и kiosk» («разметка, размер целей нажатия,
|
||
scrim, футер не меняются ни на строку») уже покрывает и эти пять
|
||
call site'ов — только не называет их явно. Это пробел в полноте текста,
|
||
не в контракте: настоящей неопределённости, которая изменила бы AC или
|
||
поведение, за этим не стоит.
|
||
|
||
**Решение ревьюера**: снимаю как Low, не как Medium — субстанция уже
|
||
доказана на уровне механизма (AC1-AC5), формальная строка `Touch editor:
|
||
supported` для пяти call site'ов была бы уместна для полноты, но её
|
||
отсутствие не оставляет открытого продуктового вопроса и не меняет объём
|
||
реализации. Не завожу повторный цикл ради одной строки текста (тот же
|
||
принцип §2.10, что и для L1). Рекомендация автору — добавить эту строку
|
||
попутно при следующей правке, не обязательно сейчас.
|
||
|
||
## Что проверено и признано корректным (дельта r2)
|
||
|
||
- Раздел «Touch и kiosk» по существу верно определяет, что затронутая
|
||
ветка (View-диалог онбординга) относится к «Fully supported» категории
|
||
`TOUCH-SUPPORT.md` и что перенос точки рендера сам по себе не меняет
|
||
touch-поведение компонента.
|
||
- AC8 технически обоснован: паттерн `hasTouch` реален и используется в
|
||
существующих touch-смоках так же, как описано в АС.
|
||
- AC9 корректно фиксирует инвариант «блоки на месте» — построчная сверка
|
||
подтверждает, что все три диалога (`_tapConfirm`, `_vacCalConfirm`,
|
||
`_dangerConfirm`) в текущем дереве действительно в одной ветке без
|
||
`return` между ними, то есть требование реализации не тащить их за
|
||
компанию — обоснованное и проверяемое.
|
||
- M1 закрыта полностью и точно, без остаточных вопросов.
|
||
- Новый раздел не удаляет и не противоречит ни одному из ранее принятых
|
||
разделов ТЗ (§7.1 набор полон).
|
||
- Пункты 6-7 плана автотестов (touch-повтор сценария 1, проверка «один
|
||
`hp-confirm` в DOM») соответствуют AC8 и риску «двойной рендер», названному
|
||
в разделе «Риски» ещё в r1.
|
||
|
||
## Чего не проверял
|
||
|
||
- **Гейты кода** (`npx tsc --noEmit`, `npm test`, `npm run build`,
|
||
`check-docs`, смоки, `bundle:budget`, инварианты модели) — не гонялись:
|
||
на этапе ТЗ продуктового кода по-прежнему нет, дифф пуст. Это предмет
|
||
код-ревью после реализации.
|
||
- **`scripts/mutation-gate.mjs` / `demo/smoke_danger_confirmation.mjs`** —
|
||
не запускал; в r2 они не менялись, наследую проверку существования файлов
|
||
из r1.
|
||
- **Реальный браузерный рендер** — не переисполнял; воспроизведение из
|
||
аналитики issue взято на веру, как и в r1 (это будет предметом
|
||
смок-доказательства AC1-AC9 в код-ревью).
|
||
- **`docs/specs/README.md`** — строка для #402 по-прежнему не добавлена;
|
||
унаследованное из r1 решение не поднимать это отдельной находкой
|
||
(известный долг §7.3 п.1) остаётся в силе.
|
||
|
||
## Вывод
|
||
|
||
Обе находки r1 закрыты по существу (таблица выше). Дельта r2 не вносит
|
||
новых Medium/High — только два наблюдения Low (неверное число в цитате
|
||
документа, отсутствие явной строки про touch-статус пяти редакторских
|
||
call site'ов), оба сняты ревьюером с записью и не блокируют выход в
|
||
«Готово к разработке».
|
||
|
||
**Вердикт: зелёный · заход r2 · блокирующих циклов 1/4 · High: 0 · Medium: 0**
|