docs: review document for #271

Issue: #271
User-Visible: no
This commit is contained in:
claude[bot]
2026-08-23 21:06:00 +03:00
committed by Sergey Matyunin
parent 154af2692f
commit ffbbb217b5
+126
View File
@@ -0,0 +1,126 @@
# 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 однозначен и
называет способ доказательства, корневая причина подтверждена чтением кода, а
не выдана за факт без опоры. Открытых продуктовых вопросов нет и не должно
быть.
**Зелёный.**