15 KiB
SPEC-REVIEW-313-r1
Issue: #313 · этап: ТЗ (spec) · трек: small (лёгкий) · заход: r1 · лимит циклов ТЗ: 2 · израсходовано: 0
Скоуп
Инструмент «Толщина» (_wallThickHit/_wallThickHover/_wallThickClick/_wallThickApply,
src/houseplan-card.ts) сейчас видит только атомарные интервалы контуров комнат
(wallIntervals(space.rooms, …)) и не видит независимую кладку — перегородки
(space.partitions) и сегменты сохранённых черновиков (space.room_drafts[].points).
ТЗ расширяет резолвер, hover, диалог и запись на все три источника, с приоритетом
независимой кладки при наложении и без кнопки «на всю комнату» для неё. Модуль один,
файл один — критерии small (сложность/риск ≤3, одна поверхность, без миграции,
без нового UX-контракта, без влияния на перф/touch) соответствуют содержанию задачи.
Первый вопрос по docs/SCOPE.md: чью работу закрывает правка. Инструмент правки
геометрии Plan-редактора — часть J6 («Keep the plan true as the home evolves»,
два редактора, drag/resize/merge/split). Конфликта со SCOPE нет: это устранение
дыры в уже существующем, одобренном инструменте, а не новая функциональность.
Как проверялось
Ревью ТЗ этапа S4-spec-review, r1 — полный разбор (первый заход, дельты нет).
Читал: docs/SCOPE.md, AGENTS.md, PROCESS.md (§1–§12), тело issue #313 и
единственный комментарий (аналитика + решения владельца от 2026-08-26), канонический
документ подсистемы docs/WALL-THICKNESS.md, срез docs/USER-GUIDE.ru.md по
инструменту «Толщина», связанные issues #308 (закрыт), #306 (open, S3-spec),
#229 (закрыт), #303 (закрыт).
Код читался в дереве dev @ a78deb7c (текущий HEAD), не исполнялся — это ревью ТЗ,
не код-ревью, автотестов ещё нет. Каждое фактическое утверждение ТЗ (сигнатуры,
существование функций/полей, номера строк, тексты тостов, содержимое смоков)
проверено чтением исходников и docs/WALL-THICKNESS.md, а не принято на слово:
_wallThickHit(:11915) действительно перебирает толькоwallIntervals(space.rooms, …)— подтверждено чтением, совпадает с описанием «Причина (код)»._wallThickApply(:11978) действительно пишет только черезsp.walls/setWallThicknessForRoom— writer дляpartition.cm/draft.segments[i].cmотсутствует, подтверждено.wallThickHoverHalfUnits(hit.cm, …)уже принимаетcm(:11946, импорт :312) — подтверждено, hover-контракт из #303 переиспользуется без изменений.PartitionCfg(src/types.ts:64) иRoomDraftCfg.segments[i](src/types.ts:56-61) уже содержат обязательное числовое полеcm— модель не меняется, миграция не нужна.docs/WALL-THICKNESS.md§9 УЖЕ фиксирует инвариант «1–100 см для перегородок и сегментов драфта, ноль не существует» и «Invalid input blocks the commit and reports the valid range» — решение владельца №2 (запретить 0/пусто для независимой кладки) не догадка, а совпадение с задокументированным контрактом модели. Это же объясняет, почему у комнатных стен 0 легитимен (§6 канона: «empty/0 clears»), а у независимой кладки — нет: два разных, уже описанных контракта, ТЗ их не путает.toast.wallthick_pick/toast.wallthick_open/toast.physical_range(src/i18n/ru.json:533-537) существуют и достаточно общие для переиспользования на перегородках/драфтах — новых ключей i18n действительно не требуется, как заявлено в аналитике._commitPhysicalGeometry+history.wall_thickness(:12017) — существующая физическая транзакция с одним Undo, переиспользуется корректно.- Правило приоритета независимой кладки над контуром комнаты уже реализовано и
используется в смежном коде —
_boundaryBlocked(:11285-11309, комментарий «Independent masonry owns its hit zone…») перебираетwall_columns,partitionsиroom_draftsименно в этом порядке приоритета для операций границы/select. Формулировка ТЗ «согласуется с select-инструментом» подтверждена, а не голословна. _activeDraftId(:1548) переживает переключение инструмента/пространства (:1291, :2188) — «активный драфт инструменту не виден» описывает реальную достижимую ситуацию (недорисованная цепочка, отложенная переключением тула), а не искусственный кейс; исключение активного драфта уже так работает у snap-геометрии (excludeDraftId, :6746; комментарий :20349) — переиспользование обосновано.- Три смока, названные в AC4, существуют:
demo/smoke_wall_thickness.mjs,demo/smoke_wallthick_hover_width.mjs,demo/smoke_resize_wall_thickness.mjs. - Кнопка «на всю комнату» (
wallthick.apply_room, :12558-12560) сейчас рендерится безусловно — условный рендер по «есть лиroomId/kindroom» технически тривиален, контракт (п.3) реализуем как описано. - #308 (пример наложения перегородки на ребро комнаты, фикстура-экспорт в
приложении к отчёту) — issue закрыт без комментария к закрытию и без метки
rejected, при этом сохраняет статусную меткуS1-new(в нарушение §2.9/§9 PROCESS.md — закрытый issue не должен нестиS*). Это не блокирует #313: своя AC3 (приоритет при наложении) самодостаточна и не зависит от того, будет ли когда-нибудь сделана «согласованная правка обоих источников» из решения владельца №3. Но пункт «остаётся скоупом #308» из решения владельца сейчас ссылается в никуда — фиксирую это как наблюдение, не как находку против #313.
Гейты кода не гонялись — на этапе ТЗ кода ещё нет, тестировать нечего
(typecheck/test/build/check-docs относятся к код-ревью, §2.7/§8).
Находки
Ни одной High/Medium. Одна Low, снимаю с записью (не блокирует, автору можно поправить попутно при написании ТЗ AC/PR, отдельного цикла не требует):
- Low — неверный номер строки в цитате. В разделе «Что нужно» (п.1) и в
разделе «Причина» issue правило «Independent masonry owns its hit zone»
указано по адресу
:11104. Наdev @ a78deb7cпо этому адресу лежит фрагмент диалога decor-текста (цветовой пикер), правило по факту находится в_boundaryBlocked,src/houseplan-card.ts:11285. Раздел «Контракт» (та часть ТЗ, что реально нормативна) этот номер не повторяет — там же цитата дана без строки, поэтому имплементация не пострадает. Правлю с записью: верный адрес —src/houseplan-card.ts:11285.
Что проверено и корректно
- Трек
smallвыбран обоснованно, все пять критериев §5 выполнены (одна поверхность/один файл, риск/сложность ≤3, без миграции, без нового UX-контракта — кнопкаapply_roomпросто скрывается там, где нет комнаты, остальной диалог тот же, — без влияния на touch/perf). - Обязательные для light-трека разделы (проблема · контракт · AC · откат) присутствуют, ни один не пуст.
- Три продуктовых решения владельца (комментарий 2026-08-26) корректно перенесены в «Контракт» и не переизобретены заново.
- Все 4 AC пронумерованы, каждый называет способ доказательства (
smoke/unit), AC1/AC2 явно фиксируют текущее красное состояние («падает на текущем dev — hit = null»), AC3 задаёт конкретную регрессионную фикстуру (#308), AC4 защищает от регрессии по существующим гейтам — тест на «AC умеет упасть» проходит на уровне формулировки (для AC1/AC2 это прямо написано). - Ни одного продуктового вопроса не осталось открытым: три развилки, требовавшие решения владельца (кнопка диалога, ноль/пусто, приоритет при наложении), закрыты явными решениями в комментарии аналитики, а не угаданы автором.
- Утверждений о поведении, не подтверждённых документом/кодом и не помеченных как предположение, не найдено — единственная фактическая неточность (строка :11104) разобрана выше как Low.
- Откат («один revert, без миграций и новых полей конфига») соответствует факту: модель данных не меняется, меняется только резолвер/writer инструмента.
- Конфликта со
docs/SCOPE.mdиdocs/TOUCH-SUPPORT.mdне нашёл: правка редактора Plan (десктоп-первый инструмент), в View не протекает.
Чего не проверял
- Не проверял по коду, что hit-резолвер после правки не даст обратной регрессии для контуров комнат при наличии рядом коллинеарной перегородки НЕ на кейсе #308 (общий случай «рядом, но не точно на ребре») — в ТЗ такой AC не заявлен явно за пределами AC3/AC4, это забота код-ревью и, при необходимости, находка для отдельного цикла на этапе кода, а не пробел ТЗ (AC4 достаточно узко и корректно защищает именно регрессию контуров).
- Не проверял столбы (
space.wall_columns) на предмет того, должен ли инструмент «Толщина» также брать их — симптом, аналитика и AC ни разу их не упоминают, а вdocs/USER-GUIDE.ru.mdу колонны уже отдельный диалог размера через select (не через «Толщина»); границу считаю намеренной и не отношу к находкам. - Не прогонял никаких автотестов/смоков — на этапе ТЗ кода нет, гонять нечего; сами тексты AC1/AC2 содержат обязательство, что новый смок «падает на текущем dev», это будет предметом код-ревью, а не этого документа.
- Не проверял
#306(замена виртуальных стен стенами cm=0) по существу — он открыт, вS3-spec,blocked, и в контракт #313 входит только требованием «точка записи не должна требовать переписывания под будущую ветку 0», что является технической, а не продуктовой договорённостью и не подлежит проверке на этом этапе.
Вердикт
Готово к разработке. Both AC-доказательства и продуктовые развилки закрыты решениями владельца; единственная находка — Low, снята с запиской в этом документе, отдельного цикла не требует.