Files
houseplan-card/docs/reviews/SPEC-REVIEW-209-r1.md
T
2026-08-28 20:01:24 +00:00

146 lines
12 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 — issue #209 · заход r1
- Этап: spec (PROCESS.md §2.4)
- Артефакт ТЗ: `docs/specs/209-vacuum-trail-smoothing.md` (SHA `43516cc1`, ветка `issue/209-vacuum-trail-smoothing`)
- Вердикт: **зелёный**
- Блокирующих циклов израсходовано: 0 из 4
## Скоуп ревью
Первый раунд, дельта не применяется (§2.9 — правило дельты действует только
для r2+). Разобрано полностью:
1. Тело issue #209 и все 3 комментария (анализ Codex, два решения владельца,
финальная передача на ревью).
2. Полный текст `docs/specs/209-vacuum-trail-smoothing.md`.
3. `docs/SCOPE.md` — соответствие Core user jobs.
4. `PROCESS.md` §2.4, §7.1 — обязательные разделы ТЗ и порог продуктовых
вопросов.
5. `docs/VACUUM.md`, `docs/USER-GUIDE.ru.md` (раздел «Позиция и путь»),
`docs/USER-GUIDE.md` (раздел «Robot vacuums»), `docs/ARCHITECTURE.md` — как
канонические источники терминологии и текущего контракта.
6. Исходный код `src/houseplan-card.ts` (`_renderVacuums`, ~11819–11905) и
`src/vacuum.ts` (`normalizeVacPath`, `resolveCurrentVacPath`,
`trimVacPathTarget`, `VAC_PATH_MAX_SEGMENTS/POINTS`, `TRAIL_MAX`) и
`custom_components/houseplan/trails.py` (`TRAIL_CAP`) — сверка каждого
факта, на который ссылается ТЗ.
7. `docs/TESTING.md` — существование `scripts/mutation-gate.mjs` и практики
мутационных гвардов, на которые ссылается план автотестов ТЗ.
## Как проверялось
Продуктовая часть (docs/SCOPE.md, персона, сценарий) читалась первой и
отдельно от технической, как требует §7.1. Технические утверждения ТЗ
(номера строк, имена функций, константы лимитов, порядок affine → build →
`_scenePoint()`) верифицированы построчным чтением текущего кода, а не
доверием тексту ТЗ. Отдельно перепроверено математическое обоснование предела
17,5 см в §6.2 (см. ниже) — это не тривиальное утверждение, и ложное
доказательство было бы поводом для High.
## Находки
Находок нет — ни High, ни Medium, ни Low.
Разобранные кандидаты, которые не подтвердились как дефект:
- **Отсутствие docs/USER-GUIDE.md (EN) в списке release-артефактов §13.**
Проверено: `docs/USER-GUIDE.md` раздел «16. Robot vacuums» не описывает
форму линии следа (M/L vs кривая) — он делегирует детали в `VACUUM.md`
одной фразой. `VACUUM.md` (канонический для этого контракта, EN) в списке
§13 присутствует. Правки нечего вносить в `USER-GUIDE.md`, значит его
отсутствие в перечне не является пропуском.
- **Утверждение issue-body про поверхность «статический рендер».** Тело issue
перечисляет «View, киоск, статический рендер» как поверхности показа следа.
Проверено: `src/space-card.ts` и `src/space-render.ts` (инертная
`houseplan-space-card`) не содержат ни одного упоминания vacuum/trail —
сейчас след там не рисуется. Само ТЗ, однако, этой ошибки не наследует: §1
описывает только View/киоск/редакторы, а §4 Scope формулирует охват как
«поверхности, где след уже рисуется» — не перечисляя конкретный список.
§5 Non-scope прямо запрещает «добавление следа ... на поверхности, которые
его сейчас не имеют». Формулировка ТЗ самодостаточно корректна независимо
от неточности в исходном issue-анализе.
- **Математика предела в §6.2.** Проверено: для точки на `conv{P, B, Q}`
расстояние до `B` ограничено `r = min(17.5см, |AB|/2, |BC|/2)` в силу
выпуклости нормы (максимум выпуклой функции на симплексе достигается в
вершине); P и Q лежат на исходных отрезках, поэтому граница до исходной
ломаной действительно ≤ r ≤ 17,5 см. Отдельно проверено недопущение
наложения соседних скруглений: раз `r_B2 ≤ |s2|/2` и `r_B3 ≤ |s2|/2` для
общего отрезка `s2`, точка `Q` вершины `B2` не может оказаться дальше по
отрезку, чем точка `P` вершины `B3` — соседние скругления не меняются
местами. Довод в тексте ТЗ корректен, не голословен.
- **Эпсилон разворота ~180°.** Помечен явно как техническое решение автора
реализации, фиксируемое unit-тестом (§14 п.3), а не выдан за факт — это
ровно то отличие «предположения» от «незамеченной догадки», которое требует
проверять инструкция ревью.
## Что проверено и корректно
- **Персона/сценарий/до-после** — первые два раздела (§7.1) заполнены
корректно и без терминов реализации; соответствуют J1 (`docs/SCOPE.md`:
«Show the whole home and what's happening right now»).
- **Продуктовые вопросы владельцу** заданы по существу (граница сглаживания,
вкл/выкл, previous run) — все три ровно того типа, что разрешён §7.1
(«что видно», «объём видимых изменений»), без технических вопросов,
вынесенных наружу. Ответы получены и зафиксированы в issue до отправки ТЗ
на ревью — блокировка снята в срок.
- **Все обязательные разделы §7.1 присутствуют**: сценарий, до/после,
проблема, scope/non-scope, контракт поведения, UX/a11y/touch/i18n, модель
данных и совместимость, AC1–AC11 с методом доказательства для каждого,
план автотестов, риски, release-артефакты, откат.
- **AC однозначны и проверяемы**: каждый сформулирован как измеримое
утверждение (endpoints совпадают, отклонение ≤17,5 см, число команд ≤2N,
таблица режимов не меняется и т.д.), не «сделать нормально»/«работает как
ожидается».
- **Факты о коде подтверждены построчно**: `VAC_PATH_MAX_SEGMENTS = 64`,
`VAC_PATH_MAX_POINTS = 4000` (`src/vacuum.ts:14-15`), `TRAIL_MAX = 600`
(`src/vacuum.ts:477`), `TRAIL_CAP = 2000`
(`custom_components/houseplan/trails.py:27`), `resolveCurrentVacPath`,
`trimVacPathTarget`, `normalizeVacPath` (`src/vacuum.ts:169,201,222`) —
все совпадают с ТЗ. Текущий рендер (`_renderVacuums`,
`src/houseplan-card.ts:11819-11905`) действительно строит current как
единый `path` с `M`/`L` по подпутям и previous — отдельным `polyline`
(`:11855`), обе ветки применяют affine и затем `_scenePoint()` на каждую
точку — план ТЗ перенести этот порядок на «affine всего подпути → builder →
проекция» архитектурно согласован с существующим кодом, не выдумка.
`src/vacuum.ts` уже существует и уже владеет `normalizeVacPath`/
`resolveCurrentVacPath`/`trimVacPathTarget` — ровно тот модуль, куда ТЗ
просит добавить pure builder (§9), это не новый файл и не смена владения.
- **Non-scope согласован со scope**: явно исключены изменения хранения,
лимитов, arbitration, trail modes, добавление следа туда, где его нет —
ни один пункт scope не противоречит этому списку.
- **Терминология согласована** с `docs/USER-GUIDE.ru.md` («Никогда/Во время
уборки/Всегда», «текущий путь»/«последний завершённый путь») — таблица
§6.4 ТЗ не меняет и не путает этот контракт.
- **i18n/touch/миграция/откат** — по каждому пункту явное «нет изменений» с
обоснованием, а не молчание.
- **Track = полный** обоснован верно: видимый контракт подачи меняется,
задействовано несколько поверхностей и golden-эталоны — критерий `small`
не проходит.
- **Продуктовая оценка (польза/сложность/риск)** реалистична и не
противоречит `docs/SCOPE.md`: ценность признана косметической (4/10), что
корректно для P3-полировки, не блокирующей и не требующей ускоренного
трека.
## Чего не проверял
- Реализацию — её не существует, стадия spec.
- `npx tsc --noEmit` / `npm test` / `npm run build` — не прогонял: гейт не
применим к этапу ревью ТЗ (нет кода для компиляции), а не пропущен по
экономии.
- Golden/смоки/инварианты модели — не прогонял: задача геометрию модели
(рёбра, `layout`, `marker.space`, `open_spans`) не трогает (явный
non-scope), это этап spec, инструментальные гейты этого раунда не
применимы.
- Не проверял, действительно ли выбранный владельцем способ (quadratic
Bézier по хордам) — лучший вариант из трёх предложенных в issue
(Catmull-Rom/Chaikin/Безье): ТЗ прямо отдаёт выбор техники автору
реализации, зафиксировав только измеримую границу (17,5 см) и семантику
(endpoints, gaps, no bridge) — это корректная граница ответственности
spec-ревью, а не пробел.
## Итог
ТЗ полное, однозначное, без выданных за факт догадок, предметно
верифицировано по коду и документам. Продуктовые вопросы владельцу заданы и
закрыты до отправки на ревью. Готово к статусу «Готово к разработке».