mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-01 20:29:00 +00:00
@@ -0,0 +1,213 @@
|
||||
# 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`
|
||||
(commit `a06c94b9`, ветка `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`. Открытых продуктовых
|
||||
вопросов владельцу нет — все находки технические, снимаются автором ТЗ.
|
||||
Reference in New Issue
Block a user