docs: #402 spec revision 2 per SPEC-REVIEW-402-r1

User-Visible: no
Issue: #402
This commit is contained in:
Codex
2026-08-31 16:22:50 +03:00
parent 9b29df28db
commit 11959e4c85
+48 -3
View File
@@ -2,7 +2,8 @@
- Issue: https://github.com/Matysh/houseplan-card/issues/402
- Приоритет: P1, bug (регресс против поведения до #32); полный трек — класс A
- Ревизия: 1 (2026-08-31)
- Ревизия: 2 (2026-08-31) — по SPEC-REVIEW-402-r1 (H1: touch/kiosk; M1: причина
исключения соседних подтверждений)
## Сценарий
@@ -83,14 +84,48 @@ promiseSettledOrDialogShown: false (ожидание 200 мс)
смоки и мутанты.
**Не в скоупе**: содержимое и оформление диалога (#32), ревалидация после
`await` у вызывающих (#32), роль `alertdialog` и `aria-describedby` (#406),
`_tapConfirm` и `_vacCalConfirm` — у них своя механика и свои ветки.
`await` у вызывающих (#32), роль `alertdialog` и `aria-describedby` (#406).
**`_tapConfirm` и `_vacCalConfirm` — не в скоупе, и причина не та, что я
написал в ревизии 1.** Они рендерятся в той же финальной ветке `render()`
(`:11802-11878`), что и `_dangerConfirm`, — «свои ветки» было неверным
утверждением. Настоящих причин две, и обе по существу:
1. У них **нет промиса**: `_tapConfirm` хранит синхронный `exec()`, который
вызывается прямо из обработчика кнопки, а `_vacCalConfirm` — это
информационный диалог с закрытием по `hp-close`. Ни один вызывающий не
ждёт разрешения, поэтому «висящего промиса» — самого дефекта этой задачи —
у них не бывает.
2. Их точки входа недостижимы из ранних веток: тап по маркеру и калибровка
пылесоса требуют отрисованного плана, то есть той самой основной ветки.
Из этого следует практическое требование к реализации: при выносе
`hp-confirm` из цепочки **соседние два блока остаются на месте**. Утащить их
за компанию — значит без нужды поменять поведение диалогов, для которых эта
задача ничего не обещает.
## UX
Видимых изменений в оформлении нет. Меняется только то, что подтверждение
появляется там, где раньше действие молча не работало.
## Touch и kiosk
`docs/TOUCH-SUPPORT.md` § Safety floor запрещает «best effort» в трёх вещах,
и одна из них — обход подтверждения разрушающего действия. Сейчас на touch
этот пол пробит ровно так же, как на мыши: в ветке онбординга подтверждения
нет вовсе, то есть действие либо не работает, либо (если бы работало) шло бы
без спроса. Задача поднимает пол обратно на всех вводах сразу.
Поведение по вводам после правки одинаково и специальной работы не требует:
переносится **место рендера** одного и того же компонента `hp-confirm`,
разметка, размеры целей нажатия, поведение scrim и футера (#32 §6.2) не
меняются ни на строку. Kiosk отдельного пути не имеет — он рисуется той же
основной веткой, где подтверждение и так работало.
Доказательство — AC8: смок из плана прогоняется в touch-эмуляции, то есть
проверяет ветку онбординга не только мышью.
## Модель данных и миграция
Не применимо.
@@ -122,6 +157,13 @@ promiseSettledOrDialogShown: false (ожидание 200 мс)
остаётся зелёным без правок его утверждений.
- **AC7**. Бюджет initial не растёт (правка структурная). Доказательство:
`npm run bundle:budget` до и после.
- **AC8**. На touch подтверждение в ветке онбординга работает так же, как
мышью: диалог появляется, тап по «Отмена» резолвит промис `false`, тап по
scrim не проваливается в план. Доказательство: тот же смок в
touch-эмуляции (`hasTouch`), как это делают существующие touch-смоки.
- **AC9**. `_tapConfirm` и `_vacCalConfirm` остались в основной ветке и их
поведение не изменилось. Доказательство: существующие смоки тапа и
калибровки зелёные без правок их утверждений.
## План автотестов
@@ -135,6 +177,9 @@ promiseSettledOrDialogShown: false (ожидание 200 мс)
решение резолвит промис (AC4).
5. Языковой гейт `warm` → запрос резолвится `false` сразу, `render()`
по-прежнему возвращает `noChange` (AC5).
6. Тот же сценарий (1) в touch-эмуляции: диалог появляется, тап по «Отмена»
резолвит `false`, тап по scrim не доходит до плана (AC8).
7. Один `hp-confirm` в DOM — не два (риск двойного рендера ниже).
**Мутант** (`scripts/mutation-gate.mjs`):