Files
houseplan-card/docs/reviews/SPEC-REVIEW-329-r2.md
T
2026-08-27 23:29:49 +03:00

199 lines
19 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-329-r2
Issue: #329 · Этап: spec (S4-spec-review) · Заход: r2 · Трек: обычный ·
Блокирующих циклов израсходовано до этого раунда: 1/4
ТЗ: `docs/specs/329-junction-limits.md`.
Ревизия под ревью — коммит `783c04d1813b0b201efb21b8bae1b0c497978cf1`
(«docs: spec #329 revision 2 — per-surface refusal channels, AC5 split,
absolute thresholds»), базовый SHA раунда r1 — `8dce8453975121a89263d44243e49059f7000da7`.
Класс C (`docs/specs/**`), продуктовый код не тронут — `git show --stat 783c04d1`
подтверждает единственный файл в диффе.
## Скоуп ревью (по дельте, PROCESS.md §2.9)
Раунд не первый. Предыдущий вердикт — жёлтый, r1, найден в комментарии issue
`claude[bot]` от 2026-08-27T16:37:06Z, зафиксирован на SHA `8dce8453` (назван
в шапке `docs/reviews/SPEC-REVIEW-329-r1.md`, committed at `9f7d1fd4`). Автор
объявил делту в комментарии от 2026-08-27T16:39:52Z: «Ревизия 2 (783c04d1):
M1 — ..., M2 — ..., L1 — ...».
Дельта — `git diff 8dce8453..783c04d1 -- docs/specs/329-junction-limits.md`:
38 строк (29 добавлено, 9 удалено) внутри одного файла, только в §2
(нормативные ограничения/канал отказа) и §8 (AC5 → AC5a/AC5b). Остальной
документ (§1, §3 body, §4, §5, §6, §7, AC1–AC4, AC6, AC8–AC10, §9, §10, §11)
байт-не тронут diff'ом.
Делта локальна: это не ребейз на ушедший вперёд dev, не смена контракта
поведения продукта (та же формулировка решений владельца, что и в r1), не
задета новая подсистема. Полный разбор документа не требуется — разбираю
делту плюс всё, до чего она дотягивается логически (это как раз и вскрыло
находку ниже: обновлённое §2 разошлось с AC7, который delta не тронула).
## Как проверялось
- Прочитан диф `git diff 8dce8453..783c04d1` построчно — оба заявленных
изменения (M1, M2) сверены с текстом находок r1 дословно; L1 тоже
проверен, хотя автор не был обязан его чинить.
- Перечитан `docs/USER-GUIDE.ru.md`, раздел «Resize» (строки 473–493,
таблица 477–484) и «Толщина стены» (515–528) — сверка новой формулировки
канала §2 с уже задокументированным поведением инструментов.
- `git log --all --oneline | grep 313` + `git show 5e5dad27 --stat` —
проверен прецедент #313, на который ссылается §2 для канала «Толщины»
(commit message: «Ноль/пусто для независимой кладки отклоняется
существующим тостом диапазона») — ссылка не выдумана, поведение реальное.
- Перепроверена математика AC5b: равносторонний треугольник, сторона `a`,
inradius `r = a/(2√3)`. При `a=60`: `r≈17.32` см, полутолщина стены
33/2=16.5 см → остаток `r-half≈0.82` см, внутренний треугольник (offset)
имеет сторону `a·(r-half)/r ≈ 60·0.82/17.32 ≈ 2.84` см, площадь
`(√3/4)·2.84²≈3.5` см² — меньше 25 см², П5 отказывает при выполненном П1
(60°≥15°). При `a=120`: `r≈34.64` см, остаток `34.64-16.5=18.14` см,
сторона внутреннего треугольника `≈120·18.14/34.64≈62.8` см, площадь
`≈1706` см² — намного больше 25 см², проходит. Числа в AC5b (`17.3`,
`34.6`, «<25 см²», «проходит») подтверждаются независимым пересчётом.
Побочно проверено, что синтетика AC5b не задевает другие правила
(П2: 2 стены/узел ≤6; П3: длина стороны 60/120 см ≥ толщины 33 см) — тест
действительно изолирует П5 от остальных ограничений, как заявлено.
- Grep по `git show --stat` для `783c04d1` — подтверждено, что кроме
`docs/specs/329-junction-limits.md` ничего не менялось: гейты кода
(`tsc`/`test`/`build`/`check-docs`/инварианты/смоки) не относятся к
чисто документационной ревизии на этапе spec, не прогонял — так же, как
в r1.
- Перечитаны §3, §6, §7, §9 целиком (не только делта) — чтобы убедиться,
что обновлённое §2 не противоречит соседним разделам, которые delta не
трогала (см. находку ниже про AC7).
## Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
| **M1** — единый «тост» заявлен как канал отказа для всех пяти поверхностей, включая Resize, что расходится с уже задокументированным контрактом ручек (USER-GUIDE, строки 482–483) | §2 переписан: явный список из трёх каналов по поверхностям — тост (рисование/черновики/независимые/merge-split), существующий контракт приглушённой ручки с объяснением по hover/focus/нажатию для Resize (тост явно исключён: «тост не используется»), тост-в-трее по образцу #313 для «Толщины». Формулировка Resize синтезирует уже документированные строки 482–484 USER-GUIDE (упор в последнюю допустимую позицию + приглушение с объяснением), не изобретает новый визуальный канал | `docs/specs/329-junction-limits.md` §2, строки 26–38 |
| **M2** — AC5 сливал повтор фикстуры issue (нарушает П1 напрямую, дублирует AC1) и непроверяемую гипотезу «П5 независим от П1» без конкретных чисел | AC5 разделён: AC5a — сквозной смок фикстуры issue поверх AC1 (честно назван дублирующим по цели, не по механике: unit vs smoke); AC5b — синтетика с названными числами (сторона 60 см / стены 33 см → отказ по П5 при выполненном П1; сторона 120 см → проходит). Числа проверены пересчётом выше — корректны | `docs/specs/329-junction-limits.md` §8, строки 129–136 |
| **L1** (Low, не обязана) — параллель «(1 клетка)» у абсолютных порогов П4/П5 могла увести к масштабированию на `cell_cm` | Скобки убраны, П4 и П5 явно помечены «порог абсолютный ... не зависит от `cell_cm`» | `docs/specs/329-junction-limits.md` §2, строки 49–50, 52–53 |
Все три находки закрыты по существу, не переформулированы уклончиво: M1 и M2
дают именно то, что просил r1 (раздельные каналы по поверхности; отдельная
синтетика с числами), а не косметическую перефразировку исходного текста.
## Находки (r2)
### r2-M1 (Medium, в скоупе) — AC7 не обновлён вместе с §2 и не проверяет заявленный канал отказа для Resize/«Толщины»
`docs/specs/329-junction-limits.md`, §8, AC7 (текст не менялся диффом
r1→r2):
> «AC7. Resize/«Толщина», приводящие к нарушению любого из П1–П5, — отказ
> fail-closed, план байт-неизменен.»
M1 в r1 требовал: «Явно расписать, какой канал обратной связи используется
на КАЖДОЙ из пяти поверхностей» — и отдельно указывал, что «AC7
(Resize/«Толщина») тоже не называет способ обратной связи ... что
расходится с общей формулировкой §2». Автор исправил §2 (теперь там
детальный, специфичный по каждой поверхности контракт — вплоть до
формулировки «текст объяснения называет нарушенное правило П1–П5» для
Resize и «причина показывается тостом с названием правила (П3/П5)» для
«Толщины»), но **AC7 остался прежним** и по-прежнему не тестирует канал —
только байт-неизменность плана. §6 (план тестов) тоже не называет
конкретный тест на текст ручки/тоста для этих двух поверхностей — там есть
только «юниты на каждую формулу П1–П5» и «смок репро-фикстуры #329»,
которые формулу проверяют, а не канал отказа.
Это ровно тот класс дефекта, который правился в M1: нормативный текст §2
теперь делает более специфичные утверждения о видимом поведении (что
именно называет объяснение ручки, что именно показывает трей), чем было в
r1 — но ни одна acceptance criteria не привязана к доказательству именно
этой специфики, и §9 («принято предположительно») её тоже не перечисляет
как допущение.
**Чем это грозит.** Риск, который в r1 сформулирован как последствие
M1 («реализация по букве §2 добавит тост поверх существующей ручки, либо
автор тихо перепишет UX Resize»), не устранён полностью: теперь у §2 есть
правильный нормативный текст, но у AC7 нет проверки, что реализация ему
соответствует. Разработчик, ориентирующийся на AC (а не на прозу §2) при
написании тестов на этапе кода, может закрыть AC7 голым fail-closed-тестом,
не проверив, что ручка называет П1–П5, а трей — П3/П5, и разойтись с §2
незамеченным до код-ревью или позже.
**Что нужно сделать.** Дополнить AC7 (или завести AC7a/AC7b по аналогии с
AC5) явной проверкой канала: для Resize — текст hover/focus/click называет
нарушенное правило (П1–П5) и тост при этом не появляется; для «Толщины» —
трей показывает отказ значения с тостом, называющим правило (П3/П5). Либо,
если такая гранулярность признаётся избыточной для AC и достаточно прозы
§2, явно снять эту находку в комментарии автора с той же аргументацией —
но не оставлять молча, раз в этом раунде именно расхождение AC и §2 было
предметом M1.
## Унаследовано из r1
Не проверялось заново — делта r1→r2 (`git diff 8dce8453..783c04d1`) эти
разделы байт-не тронула, и ни одно новое r2-наблюдение до них логически не
дотягивается:
- Продуктовая рамка (`docs/SCOPE.md`, соответствие J6/J1/J5/J7) — принято
без повторной проверки.
- §1 (сценарий), §4 (рендер легаси-острия, ссылки на #309/#310 в
`docs/WALL-THICKNESS.md`), §5 (бэкенд, прецедент
`invalid_partition_opening_jamb_margin`) — принято без повторной
проверки.
- §6 (артефакты/поверхности, i18n-ключи, golden-сцена), §7
(производительность/touch) — принято без повторной проверки, за
вычетом отмеченного выше пробела AC7↔§2 в §8, который относится к §8, а
не к §6.
- AC1–AC4, AC6, AC8–AC10 — формулировки не менялись диффом, границы и
способ доказательства уже проверены в r1 — принято без повторной
проверки.
- §9 («принято предположительно»), §10 (риски), §11 (откат) — не менялись,
принято без повторной проверки.
- Обязательные разделы §7.1 присутствуют по содержанию, артефакт
корректного класса (полноценный файл ТЗ, задача не `small`) — принято
без повторной проверки.
- Пять численных ограничений П1–П5 совпадают с решением владельца в чате
issue дословно (проверено в r1) — сами числа delta не меняла (менялась
только форма записи П4/П5 без «(1 клетка)», см. закрытие L1 выше),
повторная сверка с чатом владельца не требовалась.
Источник: `docs/reviews/SPEC-REVIEW-329-r1.md` (committed at `9f7d1fd4`),
вывод получен на SHA `8dce8453975121a89263d44243e49059f7000da7`.
## Что проверено и корректно (делта r2)
- M1 закрыт по существу: канал отказа расписан по всем пяти поверхностям
отдельно, Resize явно НЕ использует тост (снимает риск дублирующего
сообщения из r1), формулировка синтезирует уже задокументированное
поведение USER-GUIDE (строки 482–484), а не изобретает новый визуальный
контракт.
- Канал «Толщины» (тост-в-трее по образцу #313) подтверждён существующим
прецедентом — не выдумка, коммит `5e5dad27` содержит именно такое
поведение для независимой кладки.
- M2 закрыт по существу: AC5a/AC5b разделены корректно, числа AC5b
математически верны (пересчитано независимо, см. «Как проверялось»),
синтетика действительно изолирует П5 от П1/П2/П3.
- L1 закрыт (не был обязателен) — абсолютность порогов П4/П5 теперь
explicit, скобка с «клеткой» убрана, не вводит в заблуждение.
- Никаких новых догадок, выданных за факт, в самой делте (кроме находки
r2-M1, которая не про новую догадку в тексте, а про рассинхрон текста и
AC) не обнаружено.
## Чего не проверял
- Весь материал, перечисленный в разделе «Унаследовано из r1» — сознательно
не перепроверял, делта его не касается (см. обоснование там же).
- Код не менялся в этом коммите (только `docs/specs/**`, класс C) — гейты
`typecheck`/`test`/`build`/`check-docs`/инварианты модели/смоки не
прогонял: они не относятся к чисто документационной правке на этапе
spec-review.
- Не проверял, как именно разработчик в итоге сформулирует текст
ручки/тоста при реализации — это предмет код-ревью, а не спек-ревью;
здесь оценивается только наличие проверяемого критерия в ТЗ (которого,
по находке r2-M1, для этой специфики пока нет).
- Не запрашивал у владельца дополнительных продуктовых уточнений —
находка r2-M1 технического характера (согласованность AC с прозой),
решается автором ТЗ, а не владельцем.
## Вердикт
Жёлтый. Один Medium в скоупе задачи (r2-M1), High-находок нет. Оба Medium
раунда r1 (M1, M2) закрыты корректно и не переоткрываются. Находка r2-M1
чинится в этом же ТЗ (правка AC7/§8) без смены архитектуры документа;
отдельный issue не заводится (#202, находка в скоупе).