19 KiB
SPEC-REVIEW-276-r1
- Issue: https://github.com/Matysh/houseplan-card/issues/276
- Этап: ТЗ на ревью (PROCESS.md §2.4)
- Заход: r1 · блокирующих циклов израсходовано 0 из 4
- ТЗ:
docs/specs/276-coincident-partition-reconciliation.md(commita06c94b9, веткаissue/276-reconcile-coincident-partition) - Вердикт: красный · High: 1 · Medium: 3 (все в скоупе задачи)
Скоуп
Обычный трек (не small), ТЗ — отдельный файл docs/specs/276-*.md. Диффом
этого раунда является вся первая редакция ТЗ (это r1, дельта не
применяется — §2.10 не в силе). Продуктовый код не менялся, диапазон правок —
только docs/specs/276-coincident-partition-reconciliation.md и
docs/specs/README.md (commit a06c94b9, 249 добавленных строк).
Как проверялось
- Прочитаны
docs/SCOPE.md,AGENTS.md,PROCESS.md§2, §4, §7.1, §7.2, §2.5 (DoR). - Прочитано тело issue #276 и все 4 комментария (аналитика, связанные #277/ #278, claim, хендофф).
- Прочитан целиком сам документ ТЗ (
docs/specs/276-coincident-partition- reconciliation.md, 249 строк). - Сверка терминологии и заявленной причины с канонической документацией:
docs/WALL-THICKNESS.md(модель independent partitions, §9), фрагментыdocs/USER-GUIDE.ru.mdпро инструмент «Граница», «Оптимизировать планы» и проёмы на совпадающей независимой стене,docs/ARCHITECTURE.md(Undo/Redo стек, Optimize/model-v7). - Сверка упомянутых в ТЗ функций и артефактов с фактическим деревом
(
grep/findпоsrc/**,docs/**):physicalBodyParts(),_boundaryBlocked(),_wallUnionGeometry(),mergeCollinearPartitions(),optimizePlans(),PLAN_MODEL_VERSION,resolveOpeningWallAssociation,test/plan-geometry-preflight.test.mjs— все существуют, заявленное поведение соответствует коду. - Прочитан код Optimize Undo/Apply (
src/houseplan-card.ts:15120–15208) для проверки заявленного контракта Undo/Redo (см. находку H1). - Docs-гейты для этого дифф-скоупа (spec-only, класс C) — не запускались:
правки не трогают
src/**,node scripts/check-docs.mjsне относится к этому раунду (автор уже отчитался о зелёном прогоне в хендоффе, что достаточно для docs-диффа).tsc/test/buildнеприменимы — код не менялся.
Находки
H1 (High, блокирует). Заявленный Redo для серверной отмены Optimize не существует и не заявлен как новая работа
Где: §6 «UI и отчёт Optimize», абзац «После Apply»: «Undo одним действием
восстанавливает partition и исходный hosted host, Redo снова
канонизирует.» Тот же контракт закреплён в §12 AC7: «Apply — один WS call,
Undo/Redo восстанавливают обе формы.»
Как воспроизвести противоречие: Optimize использует не общий 50-командный
_geometryHistory (Ctrl+Z/Ctrl+Shift+Z), а отдельный one-shot серверный
snapshot:
_alignOptimizedConfirm()(src/houseplan-card.ts:15120–15150) после Apply очищает_geometryHistory.clear()и включает единственный флаг_canOptimizeUndoпо ответу сервера (can_undo);_undoPlanOptimization()(src/houseplan-card.ts:15169–15208) наhouseplan/plan/optimize_undoснова зовёт_geometryHistory.clear()и ставит_canOptimizeUndo = false— после отмены никакого «Redo» не существует: кнопка в блоке Undo Optimize (src/houseplan-card.ts:16434– 16437) только одна,mdi:undo-variant, без парного redo-действия;docs/USER-GUIDE.ru.md:1444независимо описывает тот же контракт словами для пользователя: «После оптимизации доступна одна серверная отмена, но только до следующего изменения плана… Новый edit делает резервную копию оптимизации устаревшей.» Ни там, ни вdocs/ARCHITECTURE.mdнет упоминания Redo применительно к Optimize.
Итого: заявление «Redo снова канонизирует» не соответствует ни одному существующему механизму и не помечено в ТЗ как предположение или как новая работа (в §7 «В скоупе» / §9 «Архитектурный контракт» о добавлении Redo-пути для Optimize нет ни слова, в §8 «Не входит» — тоже). Это ровно тот случай, который процесс называет замечанием: «утверждение о поведении, которого нет ни в одном документе и которое не помечено как предположение». AC7 в текущей форме либо недоказуем (Redo нечем закрыть без изобретения новой функциональности за пределами заявленного скоупа), либо реализация втихую досоздаст Redo-путь для Optimize, чего никто не решал.
Требуется: либо убрать пункт про Redo из §6/AC7 и явно описать, что после Undo Optimize канонизация не восстанавливается автоматически (пользователь может только повторно нажать «Оптимизировать»), либо — если Redo для Optimize действительно нужен продукту — вынести это отдельным продуктовым вопросом владельцу (это расширение существующего контракта one-shot undo, а не деталь реализации).
M1 (Medium, в скоупе). Раздел «Риски» отсутствует — обязательный пункт DoR
PROCESS.md §2.5 требует явно: «открытых продуктовых вопросов нет; риски
перечислены» — как отдельный обязательный пункт перед переводом в
S5-ready. В документе нет ни заголовка, ни абзаца, который перечислял бы
риски и меры (аналог §11 «Риски и меры» в предыдущем спеке той же подсистемы,
docs/specs/275-multiwall-strip-containment.md:402). §10 «Производительность»
задаёт бюджет как контракт, а не как риск с митигацией; §14 обсуждает только
rollback. Ничего не сказано, например, про риск того, что реальные экспорты
(на которые ссылается сама issue) содержат ещё не описанные комбинации
(частичное перекрытие, разная толщина), которые попадут в «неоднозначный
случай» и останутся неисправленными молча — это стоит явно назвать риском с
принятой мерой (отчёт Optimize должен это показывать/не показывать?).
Требуется: добавить раздел «Риски» с перечислением и принятыми мерами.
M2 (Medium, в скоупе). Не перечислены затронутые файлы и модули — обязательный пункт DoR
PROCESS.md §2.5: «перечислены затронутые файлы и модули» — обязательный
пункт. В документе нет ни одного упоминания src/*.ts (проверено: grep -n "src/\|\.ts\b" по файлу спецификации — 0 совпадений), хотя аналитика в
комментарии issue #276 уже называет конкретные функции (physicalBodyParts(),
_boundaryBlocked(), _wallUnionGeometry(), optimizePlans(),
mergeCollinearPartitions()) и, значит, авторы уже знают, где лежит код.
Раздел 9 «Архитектурный контракт» говорит только расплывчато: «Pure helper
живёт рядом с Optimize/wall merge либо в отдельном модуле» — этого
недостаточно для DoR-чеклиста, который требует список файлов/модулей, а не
намерение.
Требуется: явный список (src/plan-optimizer.ts, src/wall-merge.ts,
src/physical-geometry.ts, src/houseplan-card.ts — или что решит автор) —
хотя бы приблизительный, он и так «принято предположительно, поменять
свободно» по §7.1.
M3 (Medium, в скоупе). Ссылка на несуществующий канонический документ docs/PLAN-OPTIMIZE.md
Файл упомянут дважды: в шапке («Связано: …, docs/WALL-THICKNESS.md,
docs/PLAN-OPTIMIZE.md», строка 12) и в §14 «Release-артефакты и rollback»
как документ, который коммит реализации обязан обновить (строка 228).
Проверено: find docs -iname "*optimiz*" не находит такого файла — в
репозитории существуют только спеки docs/specs/{198,199,223,248,252,273}- optimize-*.md, а канонический материал по Optimize фактически распределён
между docs/USER-GUIDE.ru.md (раздел про «Общие настройки → Оптимизировать
планы», строки ~1392–1449) и docs/ARCHITECTURE.md (строка 1036: «Optimize
Plans performs the equivalent idempotent model-v7 migration»). Утверждение о
существовании отдельного канонического файла — факт, поданный без пометки
«предположение», и он неверен уже сейчас: если раздел §14 будет исполнен
буквально, автор реализации не найдёт файл для правки.
Требуется: заменить ссылку на реально существующие документы
(docs/USER-GUIDE.ru.md, docs/ARCHITECTURE.md) либо явно решить создать
новый docs/PLAN-OPTIMIZE.md и пометить это как отдельное техническое
решение автора (§7.1 разрешает такие решения принимать самостоятельно, но не
молча выдавать несуществующее за существующее).
Что проверено и корректно
- Первые два продуктовых раздела по сути отвечают на нужные вопросы, хотя
и не оформлены отдельным «Что человек увидит до и после» (как это сделано в
docs/specs/275-*.md, §4): §1 даёт сценарий и персону, §6 «После Apply» перечисляет наблюдаемый результат (толщина сразу видна, Boundary разрешает virtual, проём не двигается). Контент присутствует, просто размазан по двум разделам и не сведён в одну фразу без терминов реализации — граница между этим и полноценным замечанием тонкая, решил не заводить отдельным пунктом поверх H1/M1–M3, но авторам стоит это поправить попутно. - Причина дефекта подтверждена документами, а не выдумана. Root-cause в
§2 совпадает и с issue-аналитикой, и с
docs/WALL-THICKNESS.md§9 («A precisely collinear room wall covering the same interval is cut as a composite; a crossing/nearby body is not») иdocs/USER-GUIDE.ru.md:555(«Если независимая стена точно совпадает со стеной комнаты, House Plan использует её как явную привязку и прорезает единое составное тело») — то есть рендер/cut уже корректно строит составное тело, а баг именно там, где указано: thickness edit,_boundaryBlocked(), Optimize dedup. Ни одна упомянутая функция/константа не выдумана — все существуют вsrc/. проверено чтением, не исполнением. - Условие безопасной канонизации (§4) консервативно и покрыто негативной матрицей (AC2): partial/longer/shorter/composite/non-shared/virtual/ different-cm/ambiguous-extra остаются без изменений. Это разумный default, не требующий отдельного вопроса владельцу — граница технической, а не продуктовой ответственности (§7.1).
- Скоуп согласован с
docs/SCOPE.md. Комментарий аналитики верно относит задачу к J4/J6; View mode не получает новых интеракций, touch-контракт не расширяется (Plan editor остаётся desktop-first) — соответствуетTOUCH-SUPPORT.mdи §7.1 разделу 11 самого ТЗ. - Связанные issue корректно разведены. #277 (Resize ambiguity) и #278 (общий wall-union fallback при исчезновении кладки) верно исключены из скоупа (§8) и совпадают с формулировками в комментарии владельца к #276.
- Все AC1–AC14 указывают способ доказательства (unit/negative-matrix/ golden/smoke/benchmark/review), ни один не оставлен без «Доказательство».
- Производительность и touch закрывают DoR-пункты явными числами (§10: ≤15% p95 / ≤25 ms) и явным «новых жестов нет» (§11) — нет необходимости возвращать как замечание.
- Preflight-механизм (#199), на который опирается §4.8 и AC9, реально
существует и тестируем (
src/plan-geometry-preflight.ts,test/plan-geometry-preflight.test.mjs) — проверено чтением, план «Injectable unit» правдоподобен. - i18n: формат отчёта (два RU/EN счётчика, нулевые строки скрыты)
совпадает с уже принятым паттерном Optimize preview в
USER-GUIDE.ru.md. Конкретные ключи (gs.*) не названы буквально — это Low, не блокирует; автор решает при реализации.
Чего не проверял
- Не запускал
npx tsc --noEmit/npm test/npm run build/node scripts/check-docs.mjs— диапазон коммита r1 не трогаетsrc/**и не является кодом; гейты реализации к спек-ревью неприменимы, продуктовый код не менялся. - Не запускал browser smoke / golden / инварианты модели — geometry/wall/ layout ещё не менялись, это фикстуры и код будущей реализации.
- Не проверял реальный пользовательский экспорт, упомянутый в issue (владелец не приложил его из-за пользовательских данных) — верю описанию из комментария аналитики, синтетическая fixture в ТЗ (§7, §13) — это корректная замена по правилам issue.
- Не оценивал сложность/трудозатраты реализации (7/10 в аналитике) — вне компетенции спек-ревью.
Вывод
High-находка (H1) блокирует переход в S5-ready: контракт Redo для Optimize
Undo не существует и не заявлен как новая работа, из-за чего AC7 недоказуем
как написано. Три Medium-находки (M1–M3) — все в скоупе задачи и чинятся тем
же автором в этом же ТЗ без нового issue: отсутствующий раздел «Риски»,
отсутствующий список затронутых файлов/модулей (оба — обязательные пункты DoR
§2.5) и ссылка на несуществующий docs/PLAN-OPTIMIZE.md. Открытых продуктовых
вопросов владельцу нет — все находки технические, снимаются автором ТЗ.