Files
houseplan-card/docs/reviews/SPEC-REVIEW-271-r1.md
T
2026-08-23 21:06:00 +03:00

127 lines
11 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-271-r1
Issue: #271 — «Degree-3 узел достраивает короткий луч до 8×H и рисует несуществующую стену и тень»
Этап: spec (PROCESS.md §2.4)
Заход: r1 · блокирующих циклов израсходовано 0 из 4
ТЗ: `docs/specs/271-finite-multiwall-rays.md`, SHA `482b2be512b38cadb40855b79b710f6602d5eb54`
## Скоуп разбора
Первый заход — разбор полный. Проверено: `docs/SCOPE.md`, `AGENTS.md`, `PROCESS.md`
(включая §2.4, §7.1, §4), тело issue #271 и оба комментария (аналитика +
«ТЗ готово к ревью»), канонический `docs/WALL-THICKNESS.md`, сам ТЗ, исходный код
`src/wall-thickness.ts` (интерфейс `MultiWallNodeRay`, `buildMultiWallNodeMap`,
`bevelMultiWallBody`, константы `MITRE_LIMIT`, `MULTI_WALL_JOIN_LIMIT`), связанные
issue #249/#261/#270/#272/#273 (заголовки и статусы — все закрыты либо остаются
открытыми отдельными задачами, ни одна не дублирует #271).
## Как проверялось
1. Сверил числа из таблицы issue/ТЗ (реальная длина луча vs. текущий rebuild) с
формулой в коде: `radius = MITRE_LIMIT * node.halfDepth + eps*2`,
`extent = radius * 2` (`src/wall-thickness.ts:2032-2033`) — при `MITRE_LIMIT=4`
это ровно `8×halfDepth`. Пример узла 2 `(2404.167, 1245.833)`: `H=62.5` →
`8×62.5=500.000`, совпадает с «Текущий rebuild» в таблице ТЗ. Формула и цифры
не выдуманы, а прослеживаются до реального кода.
2. Проверил, что `MultiWallNodeRay` (`src/wall-thickness.ts:51-54`) действительно
хранит только `{u, halfDepth}` без длины — корневая причина, заявленная в §3
ТЗ, подтверждена чтением, не только цитированием issue.
3. Сверил каждый обязательный раздел ТЗ с перечнем PROCESS.md §7.1: сценарий,
что человек увидит, проблема, скоуп/не-скоуп, контракт, UX, модель
данных/миграция, i18n, AC1…ACn с доказательством, план автотестов, риски,
откат, release-артефакты — присутствуют все.
4. Прочитал все девять AC на однозначность и способ доказательства; для каждого
проверил, что критерий формулирует наблюдаемое условие (геометрия/присутствие
material), а не расплывчатое «стало лучше».
5. Проверил список «не входит» (§5) против реально открытых соседних issue
(#272 — белые треугольные дыры вне probe #261; #273 — sub-grid островок при
Optimize) — границы скоупа корректны, чужого не захватывают.
6. Проверил путь ТЗ (`docs/specs/271-finite-multiwall-rays.md`) — issue не
помечен `small`, файл обязателен и создан по имени `<NN>-<slug>.md`, что
соответствует правилу.
7. Проверил, что упомянутые файлы существуют: `test/wall-thickness.test.mjs`,
`docs/ARCHITECTURE.md`, `docs/TESTING.md`, `docs/CONFIG-COMPATIBILITY.md` —
все на месте, ссылки не битые.
Гейты кода в этом раунде не гоняются — стадия spec, продуктовый код не менялся
(единственный коммит раунда — `docs(spec): ...`, класс C). `npm test`/`typecheck`
/`build` не относятся к предмету ревью ТЗ и не запускались.
## Находки
Нет. Ни одной High или Medium находки — ни в скоупе, ни вне его.
Разобрано отдельно и отклонено как находка:
- **Полнота списка документации (§9).** ТЗ включает `docs/USER-GUIDE.md` /
`docs/USER-GUIDE.ru.md` в список документов на обновление, хотя пользователю
не добавляется ни один новый видимый термин или контрол. Это не дефект: раз
видимая геометрия меняется (`User-Visible: yes` в §10), а требование
AGENTS.md — обновлять UI-терминологию из USER-GUIDE при изменении видимого
поведения — включение файла в список консервативно и не создаёт риска;
решение оставить формулировку в тексте или сократить список — на усмотрение
автора при реализации, Low, не фиксирую отдельно.
- **Отсутствие имени конкретного нового smoke-файла в AC4/AC5.** Смок ещё не
существует (создаётся в реализации), поэтому называть файл в ТЗ не требуется —
PROCESS.md §7.1/2.5 просит указать *категорию* доказательства (`smoke`), а не
имя ещё не написанного файла. Не находка.
## Что проверено и корректно
- **Корневая причина** (§3 ТЗ) совпадает с кодом посимвольно: `MultiWallNodeRay`
теряет длину, `bevelMultiWallBody` перестраивает луч на `8×H`. Не догадка —
прослежено до строк кода.
- **Сценарий и персона** (§1): администратор нажимает Optimize → Plan/View,
видит несуществующую стену/тень — прямая связь с J1 («правдиво показывать
дом») и J6 (одна геометрия для всех потребителей), обе строки есть в
`docs/SCOPE.md`.
- **Скоуп/не-скоуп** (§5) явно исключает соседние открытые дефекты (#272 белые
дыры, #273 sub-grid островок, форма #249 bevel, `MITRE_LIMIT`/
`MULTI_WALL_JOIN_LIMIT`) — задача не разрастается на смежные баги.
- **Контракт §6** формулирует финитность луча через проверяемые условия:
локальная полоса существует только на `t ∈ [0, length]`; правило дедупликации
co-directional дубликатов явно запрещает «перекрыть зазор» присутствием
соседнего короткого/толстого дубликата (типичная ловушка, которую легко
упустить) — прямо закрыто текстом контракта.
- **AC1-AC9** — каждый формулирует наблюдаемое состояние геометрии
(присутствие/отсутствие material в конкретной точке, конкретные числа
`20.833 → не 500`, `12.5 → не 110`) и называет способ доказательства (unit /
geometry unit / targeted smoke / golden semantic probe / mutation). AC7
отдельно требует, чтобы мутант **уронил** AC2 или AC4 — то есть тест на
фальсифицируемость заложен в само ТЗ, а не оставлен на усмотрение код-ревью.
- **Технические предположения (§13)** помечены явно как «assumed, change
freely» и действительно являются техническими (внутреннее представление
finite support), а не спрятанным продуктовым решением. Предположение про
`wall_columns` унаследовано от собственного анализа владельца в комментарии
аналитики, а не изобретено автором ТЗ.
- **Совместимость/UX/perf/touch** (§7): персистентная модель не меняется,
миграции нет, новых контролов/i18n/HA-вызовов нет, touch явно назван («новых
keyboard/touch/focus/ARIA... нет»), perf ограничен явным запретом нового
глобального `O(E²)` прохода.
- **Откат (§12)** запрещает частичный откат только тестов — учтён урок, из-за
которого регрессия становится снова невидимой.
- Продуктовых вопросов владельцу нет и не должно быть: единственное решение
задачи («физическое тело не может продолжаться дальше конца отрезка») уже
прямо следует из J1 и не требует выбора между персонами или трактовки
пограничного случая.
## Чего не проверял
- Не проверял реализацию (её нет — это стадия spec, код не менялся).
- Не прогонял `typecheck`/`test`/`build`/`check-docs` — не относится к этому
этапу, диапазон изменений раунда состоит из одного документного коммита.
- Не воспроизводил приватные `1.json`/`2.json` владельца — они не в репозитории
по правилу «не коммитить пользовательские данные»; проверка ограничилась
числами, которые ТЗ и issue цитируют, и сверкой формулы в коде.
- Не оценивал, оптимальна ли выбранная будущая технической реализация
(union конечных spans vs. clipped polygon) — это по §13 оставлено автору
реализации и будет предметом код-ревью.
## Вердикт
Все обязательные разделы (PROCESS.md §7.1) присутствуют, каждый AC однозначен и
называет способ доказательства, корневая причина подтверждена чтением кода, а
не выдана за факт без опоры. Открытых продуктовых вопросов нет и не должно
быть.
**Зелёный.**