18 KiB
SPEC-REVIEW-212-r1
- Issue: #212 — «Правки по новым иконкам»
- ТЗ:
docs/specs/212-device-icons-polish.md(обычный трек, неsmall) - Этап: ревью ТЗ (PROCESS.md §2.4)
- Вердикт: зелёный
- Цикл: r1/4
- High: 0 · Medium (в скоупе): 0 · Medium (вне скоупа): 0 · Low: 1 (снят с записью)
Скоуп ревью
Issue #212 — консолидация трёх открытых задач (#22 отклик на нажатие, #154
sticky touch-hover, #181 неверный адрес документации) плюс собственные пункты
владельца: уменьшение маркера устройства на 10% и исправление формы капсулы
display: value. ТЗ живёт файлом docs/specs/212-device-icons-polish.md
(трек «обычный», не small) — формат файла корректен для этого трека.
Проверялось: тело и комментарии #212, тела #22/#154/#181 (полностью, без
усечения), #179 и #211 (нормативный дизайн-пакет и его принятое исправление),
docs/SCOPE.md, docs/TOUCH-SUPPORT.md, docs/UX-MODES.md,
docs/CONFIG-COMPATIBILITY.md, сам текст ТЗ целиком (§1–§22) и — построчно —
код на dev, который ТЗ цитирует как «подтверждённую причину» в §3 и как
основание архитектурных решений в §16.
Как проверялось
Ревью на этапе spec не запускает гейты сборки/тестов — предмет проверки
это ambiguity, доказуемость AC и отсутствие выданных за факт догадок. Вместо
прогона тестов я построчно сверил каждое фактическое утверждение ТЗ о текущем
коде с самим кодом на dev (ec6f77b), поскольку §3 ТЗ прямо заявляет
«аудит текущего dev подтвердил четыре независимых дефекта» — такое заявление
обязано быть проверяемым, а не риторическим.
Сверено чтением (grep/sed по src/styles.ts, src/houseplan-card.ts,
src/space-card.ts, src/hp-dialog.ts, src/hp-help.ts,
src/hp-color-opacity.ts, src/vacuum.ts):
| Утверждение ТЗ | Где | Результат сверки |
|---|---|---|
§3.1: shell = 1.26875 × core, нет отдельного коэффициента 0.9 |
styles.ts:1877 |
подтверждено; grep на * 0.9 / --global-icon-factor — ноль совпадений |
§3.2: .device-core держит border-radius: 50% глобально, valonly растит только ширину |
styles.ts:1812–1816, 1991–2001 |
подтверждено — эллипс на широком value неизбежен |
§3.2: shell использует постоянный радиус device-shell-size/2 |
styles.ts:1939, 1955 |
подтверждено |
§3.3: _clickDevice() не создаёт transient feedback |
houseplan-card.ts (нет отдельного feedback-owner рядом с dispatch) |
подтверждено отсутствием |
§3.4: _touchSeen — статический (глобальный) флаг, _notePointer() закрывает только _tip |
houseplan-card.ts:5765,5776–5779 |
подтверждено |
§3.4: _hoverRoom пишется из mouseenter/mouseleave |
houseplan-card.ts:15837–15864 |
подтверждено |
§3.5/#181: hover-контракт View описан в UX-MODES.md, не в CANVAS.md |
UX-MODES.md «View — display and device interaction only» |
подтверждено дословно |
§7.3: Double-value pill уже имеет константу 0.39375 × core |
styles.ts:2248 |
подтверждено |
§7.2: vacuum puck зависит от --dev-size |
styles.ts:2556 (--puck-size: calc(var(--dev-size)…)) |
подтверждено |
§16: перечисленные файлы (device-face.ts, space-render.ts, hp-device-preview.ts, hp-dialog.ts, hp-help.ts, hp-color-opacity.ts, space-card.ts) существуют; pointer-modality.ts — новый |
ls src/ |
подтверждено |
§13: единственный :hover в space-card.ts — .hp-static-btn:hover |
space-card.ts:903 |
подтверждено |
§13: по одному :hover в hp-dialog.ts/hp-help.ts/hp-color-opacity.ts (.close, .trigger) |
построчный grep |
подтверждено |
§19.1: названные smoke-файлы существуют, «device action feedback smoke» — новый, не переиспользование smoke_feedback_v2.mjs |
ls demo/, чтение smoke_feedback_v2.mjs |
подтверждено; smoke_feedback_v2.mjs вообще не про device-маркеры (комнатная gear-кнопка) — ТЗ верно не сослалось на него |
| §4: версия пакета «1.1.1» | docs/specs/179-…md, docs/specs/211-…md, docs/TESTING.md:342 |
подтверждено предыдущими принятыми ТЗ, не изобретено |
| 44×44 CSS px как уже существующий пол, а не новое требование | styles.ts:1939 (max(44px, var(--device-shell-size))) |
подтверждено |
Все проверенные фактические утверждения ТЗ о текущем состоянии кода и документации оказались точными. Раздел §3 «Проблема и подтверждённая причина» не содержит ни одной догадки, выданной за факт, — каждый пункт воспроизводится в реальном коде по указанным строкам.
Дополнительно сверены структурные требования PROCESS.md §7.1: сценарий, «что человек увидит», проблема, скоуп/не-скоуп, поведенческий контракт, UX, данные/миграция/i18n, AC1…AC16 с указанием способа доказательства, план тестов, риски, откат, release-артефакты — все разделы присутствуют, ни один не сведён к формальной заглушке. Блок §22 «принятые технические предположения» оформлен явно и содержит только технические (не продуктовые) решения — ни один из семи пунктов не подменяет продуктовое решение техническим языком.
Находки
Low-1 — межевой случай «plan-wide setting» из #22 закрыт молча, без явной пометки
- Файл:
docs/specs/212-device-icons-polish.md, §6 «Не входит в задачу» - Что происходит: оригинальный текст #22 (полностью поглощаемого этим ТЗ) перечисляет ожидаемое поведение как «a subtle scale dip or flash, plan-wide setting, only on devices that actually act, reduced-motion fallback». Формулировка «plan-wide setting» синтаксически допускает два прочтения: (a) эффект применяется единообразно по всему плану, без per-marker переопределения — то, что фактически описывает ТЗ в §10; или (b) запрос на новый пользовательский переключатель уровня плана (вкл/выкл или интенсивность). ТЗ выбирает (a) молча и одновременно явно исключает (b) в §6 («новый пользовательский toggle интенсивности/ длительности feedback»), не фиксируя, что здесь вообще была развилка.
- Почему не Medium. Это ровно тот тип вопроса, который по PROCESS.md §7.1 адресуется владельцу («какой объём видимых изменений входит в этот issue»), но: (1) §4 ТЗ прямо и обоснованно ставит текст #212 выше текста #22 по приоритету, а сам #212 (написанный позже, тем же владельцем) перечисляет пять конкретных пунктов и ни словом не упоминает настройку; (2) §15 ТЗ уже держит открытым предохранитель — если реализация всё же потребует новую строку/переключатель, это автоматически трактуется как расширение скоупа с отдельным решением владельца, то есть риск «тихо потерять требование навсегда» отсутствует.
- Решение ревьюера: снимается с записью. Автору стоит одной строкой в §22 зафиксировать, что «plan-wide setting» прочитано как «единая политика на весь план, не per-marker», а не как новый UI-переключатель — это ничего не меняет по существу, но убирает тихое разночтение источника, которое иначе выглядит как то самое «оставили в тексте, а не решили».
Других находок — ни High, ни Medium, ни дополнительных Low — не выявлено.
Что проверено и корректно
- Формат трека. Issue не помечен
small/trivial(сложность и риск 8/10 по аналитике владельца) — файл вdocs/specs/обязателен и создан корректно,small-путь неприменим. - Продуктовые разделы. §1 «Сценарий» называет персону из
docs/SCOPE.md(домочадец на телефоне/панели/компьютере, админ в редакторе устройств) и момент («нажимает на устройство»); §2 «Что человек увидит» — одной парой фраз, без терминов реализации (не упоминает--dev-size, resolver, pointermodality и т.п.). - Обоснование скоупа по SCOPE.md. Задача закрывает J1/J2/J7 (спойлер
плашки для длинного значения читается хуже — J1; отклик на нажатие — J3;
честный touch-контракт — обязательное требование
TOUCH-SUPPORT.md, а не отдельная строка SCOPE, но сам документ называет touch-only дефект View продуктовым багом). Ничего из «Out of scope» SCOPE.md не задето: цвета, lock-инвариант, glyph viewport, LQI threshold — везде явно исключены в §6. - Lock-инвариант не тронут. §6 явно исключает изменение lock security;
§9 явно исключает feedback для «secure/no-target/unavailable/missing/
unsupported no-op»; confirmation-путь (§9) требует повторной валидации
target при подтверждении — согласуется с параграфом «The lock invariant»
docs/SCOPE.md(единственная санкционированная поверхность — кнопка Unlock/Lock внутри открытой карточки, а не тап по плану). - Правильный канонический адрес документации. §19.4 обновляет
docs/UX-MODES.md(неdocs/CANVAS.md) для hover/pressed-владения — именно то, что требует #181, с явной фразой «docs/CANVAS.mdне обновляется ради hover ownership». - AC1…AC16. Каждый критерий сформулирован как проверяемое числовое или
структурное утверждение (допуски
±0.005,±20 ms,≤0.5 CSS px,44×44 CSS px) и несёт способ доказательства (unit/smoke/golden/code review/performance profile), как того требует DoR (PROCESS.md §2.5). Ни один AC не сформулирован через реализацию так, что критерий нельзя было бы фальсифицировать независимо от кода. - Данные/миграция/i18n. §15 корректно фиксирует отсутствие новых
config/localStorage/backend-полей и отсутствие миграции; совместимость с
docs/CONFIG-COMPATIBILITY.mdне требует новой записи, так как round-trip не меняется — проверено чтением раздела «Status meanings» в этом документе. - Touch-контракт. Трейлер
Touch editor: best effort / intentionally degradedотносится к редакторам (Device/Plan/Background остаются desktop-first, §14), тогда как View/kiosk-touch — обязательная, release-blocking часть скоупа (AC8–AC12) в полном соответствии сdocs/TOUCH-SUPPORT.md(«A touch-only failure in View is a product defect»). Формат трейлера соответствует одному из трёх канонических значений документа. - Откат. §20 указывает на одиночный revert реализации без миграции данных и без storage rollback — согласуется с «Migration не нужна» (§15).
- Никаких искусственно вычисленных «Fresh»-цифр. Числа 0.90/0.95/200 ms трассируются либо к телу #212 (5%, 0.2s), либо к уже принятому ТЗ #22 (перенос контракта eligibility/confirmation/reduced-motion, §4), а не придуманы автором ТЗ.
- Единственный открытый вопрос не требуется. Явных продуктовых развилок, которые нельзя было бы разрешить чтением #212/#22/#154/#181 и уже принятых #179/#211, не найдено — комментарий аналитики владельца прямо закрывает этот путь («Продуктовых вопросов не осталось»), а единственная найденная двусмысленность (Low-1) не поднимается до уровня, требующего его участия.
Чего не проверял
- Не запускал
npx tsc --noEmit,npm test,npm run build— на этапеspecкода ещё нет, эти гейты относятся к код-ревью (PROCESS.md §2.7) и реализации (§2.6). - Не запускал browser-смоки/golden — они тоже принадлежат циклу реализации и код-ревью, а не ревью ТЗ.
- Не проверял
custom_components/**/*.py— ТЗ прямо заявляет отсутствие изменений бэкенда и новых config-полей (§15), backend-путей в «Ожидаемые файлы» (§16) нет. - Не оценивал реализуемость 200 ms/0.95 анимации в конкретном браузерном движке (WAAPI vs CSS transition) — это явно помечено в §22 как «принято предположительно, ревьюер вправе изменить свободно» и будет предметом код-ревью, а не ревью ТЗ.
Итог
docs/specs/212-device-icons-polish.md — самодостаточное, добросовестно
проверяемое ТЗ: каждое фактическое утверждение о текущем коде подтверждено
построчной сверкой, каждый AC проверяем и несёт способ доказательства, скоуп и
не-скоуп аккуратно очерчены и не задевают lock-инвариант или другие
ограничители docs/SCOPE.md, канонический адрес документации (#181)
исправлен верно. Единственная находка — Low, снимается с запиской автору, не
блокирует переход в «Готово к разработке».
Вердикт: зелёный · цикл r1/4 · High: 0 · Medium: 0 в задаче