Files
houseplan-card/docs/reviews/SPEC-REVIEW-249-r2.md
T
2026-08-23 03:47:19 +00:00

117 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-249-r2
- Issue: [#249](https://github.com/Matysh/houseplan-card/issues/249) — «Стык трёх стен разной толщины рисуется шипом наружу вместо соединённого узла»
- ТЗ: `docs/specs/249-multiwall-junction-bevel.md`, ветка `issue/249-multiwall-junction-bevel`, коммит `675294b9a0c62fb412220bdc04194f6eabedc0c4`
- Этап: spec (PROCESS.md §2.4), заход **r2**, блокирующих циклов израсходовано **1 из 4**
- Трек: обычный (не `small`) — файл в `docs/specs/` существует
- Вердикт: **зелёный**
## Скоуп ревью — по дельте (PROCESS.md §2.10)
Предыдущий вердикт найден в комментарии issue от `claude` (2026-08-23T02:18:27Z):
жёлтый, заход r1, High 0 / Medium 2 (M1 — отсутствует раздел «Риски», M2 —
внутреннее противоречие mitre/bevel в §7.2). **SHA, на котором получен вердикт
r1, в самом вердикте не назван** — это находка процесса r1, а не r2; я
восстановил его по цепочке коммитов: документ ревью `748d484` («review
document for #249») зафиксировал `docs/reviews/SPEC-REVIEW-249-r1.md` с явной
строкой «ТЗ: … коммит `8d2e00bbbfbb9151ca2079eaf6e51f916cb59eff`», и по времени
(`8d2e00b` — 05:07:48, вердикт — 02:18:27 UTC = 05:18:27 MSK, `748d484` —
05:18:37 MSK) это единственный кандидат. Далее — SHA r1.
Дельта раунда: `git diff 8d2e00b..675294b -- docs/specs/249-multiwall-junction-bevel.md`.
Дельта **локальна**: изменена статусная строка шапки, переписан §7.2 (пункты
1–2, добавлены пункты 3–4), добавлен новый раздел 11 «Риски и меры снижения»
(R1–R5), старые §11 «Откат» и §12 «Предположения» сдвинуты на §12/§13. Ни
сценарий, ни AC, ни scope/не-scope, ни термины §6, ни §7.1/7.3/7.4/7.5, ни
раздел 10 не тронуты. Смены контракта поведения, ребейза или новой подсистемы
нет — правило mitre/bevel то же самое (`d <= R` → митра, `d > R` → фаска),
неоднозначная полоса убрана, а не расширена. Поэтому разбор — по дельте, не
заново.
## Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
| **M1** — обязательный раздел «Риски» отсутствовал полностью | Добавлен раздел 11 «Риски и меры снижения» с пятью пунктами (R1 blast radius T-стыков, R2 щель/ложная кладка, R3 порядок/winding/scale, R4 boolean-ошибка, R5 перформанс), каждый с явной митигацией | `docs/specs/249-multiwall-junction-bevel.md:297-350` (см. `git diff 8d2e00b..675294b`, добавленные `+### R1.` … `+### R5.`); R1 прямо называет тот самый риск, что был предметом M1: «Сегодня визуально приемлемая митра в диапазоне `(1.25×H, 4×H]` станет фаской… изменение может затронуть golden-сценарии, не связанные с #249», митигация — обязательный полный `golden:verify` перед бетой с просмотром **всех** изменённых кадров, а не только нового crop |
| **M2** — правила §7.2.1/7.2.2 противоречили друг другу в полосе `(R, R+epsilon]` | Оба правила переписаны на единственную границу `R`: п.1 «остаётся митрой, если его **конечное** расстояние от node `d <= R`», п.2 «если пересечения нет, оно не конечное либо `d > R` — фаска». Добавлен явный п.3: «epsilon не расширяет область выбора митры: branch decision всегда разделён единственной границей `R`. Допуск epsilon используется только при проверке и сравнении уже вычисленных floating-point координат» | `docs/specs/249-multiwall-junction-bevel.md:138-151`; выбран ровно вариант закрытия, предложенный r1 («либо оба правила используют R, а epsilon остаётся только допуском сравнения») |
Оба закрытия проверены по тексту диффа, не по заявлению автора комментария.
### Побочная проверка: делает ли фикс M2 что-то ещё непоследовательным
§7.5 «Ошибки и fallback» (не тронут дельтой) уже содержал формулировку «если
точная митра не укладывается в `R`, результатом служит фаска» — то есть до
фикса M2 этот раздел молчаливо предполагал границу `R`, а §7.2 колебался между
`R` и `R+epsilon`. Новая редакция §7.2 приводит оба места к одному порогу без
дополнительной правки §7.5 — расхождение снято, а не создано новое. AC1 (§9,
не тронут) по-прежнему использует `1.25×H + epsilon` как допуск **проверки**
результата (п.4 нового §7.2), а не как границу branch decision — противоречия
между AC1 и переписанным §7.2 нет.
Внутренние перекрёстные ссылки (`§7.5`, `§8` — единственные, что встречаются
в тексте документа) не задеты сдвигом нумерации §11→12, §12→13; проверено
`grep -n "§[0-9]"` по всему файлу.
## Унаследовано из r1
Без повторной проверки в этом раунде приняты выводы `docs/reviews/SPEC-REVIEW-249-r1.md`
(коммит ТЗ `8d2e00b`, документ опубликован коммитом `748d484`):
- сценарий и соответствие J1 (`docs/SCOPE.md`);
- подтверждение корневой причины по коду на `HEAD` (`MITRE_LIMIT = 4` в
`src/wall-thickness.ts:46`, независимые митры двух комнат в
`insetContour()`/`outsetContour()`, строки 1030/2238/701/1853;
`wall-merge.ts` `junctionAt()`/`spaceMergeGeometry()` действительно не
формируют этот узел);
- согласованность чисел `H = 4.8611`, спайк `8.7312 ≈ 1.80×H`;
- перенос решений владельца Q1/Q2 в §4 без искажений;
- Scope/не-scope §5;
- термины §6 (`ray`, `node`, `join vertex`), обоснованные кодом (`Math.max` при
слиянии дублей, строка 626);
- полнота и проверяемость AC1–AC7 (таблица AC из r1) — дельта их текст не
меняла;
- соответствие терминологии `docs/USER-GUIDE.ru.md` («стык», «митра/фаска»);
- Low-находка о нестандартной структуре заголовков — принята как снятая
ревьюером r1 без требования правки, автор её и не трогал.
Эти пункты не переверялись повторно, так как дельта r2 их не касается.
## Что проверено в этом раунде (сверх таблицы закрытия)
- DoR-чеклист §2.5 PROCESS.md: «риски перечислены» и «открытых продуктовых
вопросов нет» — оба условия теперь выполнены (риски — новый §11; открытых
вопросов в тексте r2 не появилось, оба Q1/Q2 остались решёнными в §4).
- Новый раздел рисков внутренне согласован с остальным ТЗ: R1↔AC3 (двухлучевые
expected values не меняются), R2↔AC1/AC2 (ненулевая связность, отсутствие
hole), R3↔AC2 (матрица permutation/winding/`coordScale=1000`), R4↔§7.5 и
regression #197, R5↔§8 (`O(E)`/`O(E log E)`) и обязательный
предрелизный performance smoke. Ни один риск не изобретён — все пять уже
фигурировали как отдельные абзацы аналитики/issue до этого ТЗ (см. первый
комментарий владельца в issue: «Риск: 6/10… ошибка способна дать щель, лишнюю
кладку либо изменить обычные двухлучевые углы»), r2 их структурировал под
требуемый раздел, а не придумал заново.
- Тонкая граница `d <= R` вместо `d <= R + epsilon` не расширяет,
а сужает зону неоднозначности до нуля — это не новый риск детерминизма,
а устранение единственного такого риска, названного в M2.
## Чего не проверял
- Не запускал `typecheck`/`test`/`build` — класс A (`src/**`) в дельте r1→r2 не
менялся, дифф ограничен `docs/specs/249-multiwall-junction-bevel.md`.
- Не переисполнял AC1–AC7 (соответствующих файлов тестов/smoke/fixture ещё не
существует — ожидаемо для этапа ТЗ, будет предметом код-ревью).
- Не проводил повторный полный разбор сценария, root cause, scope и терминов —
см. раздел «Унаследовано из r1»: делта их не касается, значит не задевает и их
доказательства.
## Итог
Обе Medium-находки r1 закрыты точечно и именно так, как предлагало ревью:
раздел «Риски» добавлен по существу (не формальная заглушка — пять пунктов с
митигациями, согласованных с остальным ТЗ), а противоречие mitre/bevel снято
единой границей `R` с epsilon только как допуском проверки. Дельта раунда
локальна, не затрагивает AC/scope/термины и не создаёт нового расхождения.
Открытых High/Medium находок нет.
**Вердикт: зелёный · заход r2 · блокирующих циклов 1/4 · High: 0 · Medium: 0**