Files
houseplan-card/docs/reviews/SPEC-REVIEW-584-r1.md
T
2026-09-16 19:42:43 +00:00

19 KiB
Raw Blame History

SPEC-REVIEW-584-r1

Issue: #584 · Этап: ТЗ на ревью (S4-spec-review) · Заход: r1 · Трек: полный (аналитика от 2026-09-15 назвала критерий: сложность/риск >3, несколько модулей и поверхностей, меняется публичный контракт «см. в свойствах = видимый габарит»).

Вердикт: жёлтый


Скоуп проверки

ТЗ живёт в теле issue #584 под заголовком ## ТЗ (комментарий владельца от 2026-09-16T19:33:08Z объявляет переход в S4-spec-review). Материал ревью — текст issue на момент чтения (последний комментарий владельца, тот же, что поставил статус); отдельного файла в docs/specs/ нет и не создаётся (архив закрыт с #517).

Прочитано перед разбором: docs/SCOPE.md, AGENTS.md, PROCESS.md целиком (включая §2.4, §2.5, §2.7, §7.1, §12), тело issue #584 и все 6 комментариев (аналитика → вопросы Q1/Q2 → ответ владельца → полное ТЗ дизайнеру → присланный архив → приёмка пака дизайнером-исполнением). docs/TOUCH-SUPPORT.md и канонические документы подсистем (SUN/LIGHT/CANVAS/WALL-THICKNESS/UX-MODES/ CONFIG-COMPATIBILITY) просмотрены на предмет пересечения — задача их не затрагивает (чистая геометрия SVG-артворка мебели, не стены/не свет/не солнце).

Как проверялось

Поскольку задача целиком про фактическую геометрию, а не про рассказ, каждое фактическое утверждение ТЗ сверено с текущим состоянием репозитория (SHA 7c5fd32a, dev), а не принято на слово:

Утверждение ТЗ Проверка Результат
44 плановых SVG в svg/plan, 33 иконки в svg/menu ls assets/furniture/houseplan-0.3.0/svg/plan | wc -l, svg/menu 44 и 33 — совпадает
furnitureRenderTransform существует grep -r furnitureRenderTransform src/ найден в houseplan-card.ts, houseplan-editor-runtime.ts, furniture.ts
parseSvgPath — производственный парсер экспорта grep -r parseSvgPath src/ единственное определение в src/pdf/svg-path.ts
kitchen_floor — дизайнерский символ 60×60, svg/plan/kitchen_floor.svg pack.json строки 580-600 width_cm: 60, depth_cm: 60, file: svg/plan/kitchen_floor.svg — совпадает
dishwasher — legacy-примитив 60×60, заполняющий unit box pack.json (единственная запись — svg/menu/dishwasher.svg, без width_cm) + src/furniture.ts:155 (w: 60, h: 60, g: [box(), …]) подтверждено: dishwasher не входит в дизайнерский пак, это legacy-примитив из RETAINED_IDS, box() рисует полный 0..1×0..1
plant — единственный legacy-символ с полями 2% src/furniture.ts:226-231 (e 0.5,0.5,0.22,0.22 + лучи-линии до 0.02/0.98) внешний bbox линий действительно 0.02…0.98 — 2% с каждой стороны, совпадает
Генератор склеивает path простой конкатенацией paths.join(' ') scripts/generate-furniture-assets.mjs:97 return { d: paths.join(' '), … } — подтверждён ровно описанный дефект
furniture-plan-art.generated.ts, furniture-plan-catalog.generated.ts существуют ls src/*.generated.ts оба файла на месте
furniture:check — существующий гейт package.json:47 "furniture:check": "node scripts/generate-furniture-assets.mjs --check"
test/furniture-*.test.mjs — свидетели AC1–AC5 прочитаны furniture-stroke-contract.test.mjs, furniture-transform-contract.test.mjs оба существуют, но проверяют другие контракты (#361/#376/#383 — экранный stroke-resolver, resize/rotate editor-контракт), а не bounds SVG-геометрии; конфликта с новыми AC нет, но новые unit-тесты AC1–AC4, скорее всего, лягут в отдельный новый файл — это техническая деталь, не продуктовая, решать разработчику

Все фактические утверждения ТЗ подтвердились чтением кода — ни одной догадки, выданной за факт, не найдено. Отдельно ценно, что владелец не просто принял присланный дизайнером пак на слово, а перепроверил его тем же production-парсером, которым будет проверяться AC1/AC2 (комментарий от 2026-09-16T19:33:08Z: 44 из 44, худшее отклонение 0.000000) — то есть контракт уже был воспроизведён на реальных файлах ещё до передачи в разработку.

§7.1 — обязательные разделы

Раздел §7.1 Есть в ТЗ Комментарий
Сценарий ✅ «Пользовательский сценарий» персона не названа явно (home admin), но контекст (свойства мебели, план) её однозначно определяет
Что человек увидит до/после ✅ числа названы (14% по стороне, 30% по площади), формулировка «это исправление, а не регрессия» — по делу
Проблема ✅ в теле issue выше ## ТЗ («Что происходит»)
Скоуп и не-скоуп ⚠️ распределено явного заголовка нет; не-скоуп фактически задан AC7 («редактор, hit-area, привязка к стенам, схема конфига и i18n не меняются») — содержание есть, форма нет. Low, не блокирует
Контракт поведения ✅ «Контракт», пп. 1–8 однозначен, проверен по коду (см. таблицу выше)
UX ⚠️ отсутствует явно по существу — «нет нового UX-контракта» (задача не трогает интеракции), это следует из AC7, но отдельного раздела нет. Low, не блокирует
Модель данных и миграция ✅ «Совместимость и миграция» миграции нет, обосновано
i18n ✅ явное «новых ключей нет»
AC1…ACn с доказательством ✅ AC1–AC8 у каждого назван способ (unit/golden/review/гейты)
План автотестов ⚠️ распределено не оформлен отдельным разделом, но каждый AC называет тип теста и файлы перечислены в «Затронутые файлы» — по существу план есть
Риски ✅ «Риски» 3 пункта, по делу (маскировка регрессии golden-пересъёмкой, склейка путей, рост ленивого чанка)
Откат ✅ «возврат коммита» — корректно для непереносимой миграции
Release-артефакты ⚠️ частично changelog RU+EN и golden названы (в «Затронутые файлы»), перф — отдельным разделом; security явно не упомянут (ни разу, даже «нет»)

Находки

Medium (в скоупе) — влияние на touch не названо

Файл: тело issue #584, раздел ## ТЗ.

DoR §2.5 явно требует пункт «влияние на touch по docs/TOUCH-SUPPORT.md (View и киоск — блокирующие)» как обязательный, отдельно от i18n и производительности, которые в ТЗ присутствуют. В тексте ТЗ слова «touch», «тач», «киоск» не встречаются вообще — раздел не просто краток, он отсутствует.

Почему это не тривиальная придирка: задача меняет физический видимый размер мебели в View/kiosk тоже, не только в редакторе (мебель рендерится и там, и там одним и тем же furnitureRenderTransform). AC7 отдельно фиксирует «hit-area… не меняются», что фактически закрывает главный touch-риск (позиция resize/rotate-хэндлов на touch не сдвигается), но это написано как граница скоупа редактора, а не как ответ на явно предусмотренный процессом пункт. Реальный риск, скорее всего, нулевой — но DoR требует явного «нет», а не выводимого из соседнего пункта.

Как закрыть: одно предложение в ТЗ, например: «Touch: изменение непосредственно не затрагивает — View/kiosk остаются readonly-поверхностью, позиции hit-area и resize/rotate-хэндлов не пересчитываются (AC7); мебель в редакторе визуально крупнее/меньше на ту же величину, что и в View, новых touch-жестов не добавляется.» Правки кода не требует.

Серьёзность: Medium, в скоупе — блокирует переход в DoR (§2.5 явно требует пункт), но правится добавлением одного абзаца в тот же issue, без нового цикла имплементации. Без High это жёлтый вердикт.

Low (снимается с записью, не блокирует)

  1. Раздел «UX» и «скоуп/не-скоуп» не оформлены отдельными заголовками. Содержание по факту присутствует: AC7 однозначно перечисляет, что НЕ меняется (редактор, hit-area, привязка к стенам, схема конфига, i18n), а отсутствие нового UX-контракта следует из того же AC7 и из того, что задача правит только артворк и генератор. Формального заголовка нет, но переспрашивать автора ради двух заголовков дороже, чем цена неясности — снимаю с записью.
  2. Security как release-артефакт не назван даже «нет». Задача не затрагивает ни одну поверхность из OWASP-класса рисков (правятся SVG-пути мебели и генератор ассетов, без сетевых вызовов, парсинга пользовательского ввода на новом пути или новых прав) — риска не вижу, но пункт DoR формально пуст. Снимаю с записью, а не как Medium: в отличие от touch, здесь нет спорной поверхности (View/kiosk), которую процесс называет блокирующей явно.
  3. AC3 «допуск, пропорциональный масштабу» не даёт формулу. Это разумно оставить на усмотрение разработчика (технический, не продуктовый вопрос — §7.1: «то, чего пользователь не наблюдает, агенты решают сами») при условии, что реализация зафиксирует конкретную формулу и она останется проверяемой (не «плавает» между прогонами). Ревьюер кода должен убедиться, что тест «умеет падать» на конкретной, а не абстрактной величине допуска — отмечаю на будущее, не как находку ТЗ.

Что проверено и корректно

  • AC1–AC8 однозначны и снабжены способом доказательства (unit / unit-generator / golden / review / гейты) — ни один не пришлось домысливать.
  • AC2 конкретен: именно пара kitchen_floor/dishwasher, оба подтверждены в pack.json/furniture.ts как реальные 60×60 записи — тест будет проверять то, что реально описано в баг-репорте, а не абстракцию.
  • AC4 и контракт п.6 точно описывают дефект склейки путей — сверено с реальным кодом генератора (paths.join(' ')), включая упомянутые coffee_table_round/table_round.
  • Ни одной догадки, выданной за факт: все количественные утверждения (44 символа, доля полей 2,7–3,9 у дизайнерских, 2% у plant, конкретные id и размеры) подтверждаются либо кодом, либо независимым измерением владельца тем же production-парсером, которым будет доказываться AC1.
  • Продуктовые вопросы закрыты владельцем предметно (Q1 — видимый габарит = осевая линия контура, обводка не считается; Q2 — без миграции, центрируется в прежнем физическом боксе), открытых продуктовых вопросов в тексте не осталось; технические решения (склейка путей, plant) вынесены в явный блок «Принятые предположения», как требует §7.1.
  • Границы скоупа (AC7) явно исключают редактор/hit-area/привязку к стенам/схему конфига/i18n — правка не расползается на соседние подсистемы.
  • Откат и совместимость описаны корректно для правки без миграции: x/y, w/h, угол, зеркалирование сохраняются, откат — реверт коммита.
  • Риски названы предметно, включая специфичный для этой задачи риск — маскировку чужой регрессии golden-пересъёмкой.

Чего не проверял

  • Не проверял сам присланный дизайнером ZIP-архив (fix-584-1) — на этапе ревью ТЗ кода/ассетов ещё нет, они появятся в ветке реализации; их проверка (в том числе повторное измерение AC1/AC2 после факта) — предмет код-ревью.
  • Не запускал furniture:check, npm test, golden:verify и т.п. — на этом этапе нет ни одной строки кода/ассета, гейты нечего гонять; это предмет §8 на код-ревью, не ревью ТЗ.
  • Не проверял docs/CONFIG-COMPATIBILITY.md построчно на предмет дополнительных полей совместимости сверх того, что решает п.8 контракта — задача явно не трогает схему конфига (AC7), риск счёл пренебрежимым для ревью ТЗ.

Итог

ТЗ содержательно сильное: контракт точен, AC проверяемы и уже частично эмпирически подтверждены владельцем на реальном присланном паке тем же инструментом, которым будет доказываться AC1. Единственная находка, требующая правки текста, — отсутствующий явный пункт про touch/View/kiosk, обязательный по DoR §2.5. High-находок нет, поэтому вердикт жёлтый: одно предложение в ТЗ, без нового раунда имплементации.


Материал раунда

  • Issue: https://github.com/Matysh/houseplan-card/issues/584
  • Материал ТЗ: тело issue #584, раздел ## ТЗ, редакция комментария от 2026-09-16T19:33:08Z (тот же комментарий ставит S4-spec-review).
  • Репозиторий на момент ревью: dev @ 7c5fd32a08f07177d55905d65990180a354dd0ec (кода по задаче ещё нет — ревью ТЗ смотрит только текст issue и сверяет его утверждения с текущим dev).

Материал раунда

  • Ветка: dev, коммит 7c5fd32a08f0 — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: 2b57427cbed60f2f3b46aaf1b2c9a84147a8ed88
    git log --all --format='%H %T' | grep 2b57427cbed6
    
  • Тело issue: a4ec41f212d36f3ec2d313b534161c25a38e58c118ed2f7b97ab437de1593eb3
  • Вердикт конвейера: yellow · High 0