Files
houseplan-card/docs/reviews/SPEC-REVIEW-478-r1.md
T
2026-09-06 17:37:09 +03:00

210 lines
16 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 — issue #478, заход r1
- **Issue:** https://github.com/Matysh/houseplan-card/issues/478
- **Этап:** spec (PROCESS.md §2.4)
- **ТЗ:** `docs/specs/478-remove-room-drafts.md`
- **Ветка/SHA:** `issue/478-remove-room-drafts` @ `30a16ed36461246e06d395f2bab7f4b6d9e12eaa`
- **Заход:** r1 · блокирующих циклов израсходовано 0 из 4 (первый заход, бюджет §4 не тратится)
- **Вердикт: зелёный**
## Скоуп ревью
Задача не помечена `small` (метки: `P2`, `S4-spec-review`, `tech-debt`; автор сам
классифицировал её как полный трек — миграция схемы v9→v10, несколько
поверхностей, изменение контракта сохранения незамкнутой цепочки). Поэтому ТЗ
обязано жить в `docs/specs/`, что и сделано; файла лишнего в теле issue нет.
Диапазон изменений этого раунда — только `docs/specs/478-remove-room-drafts.md`
и одна строка в `docs/specs/README.md` (класс C, документация, ожидаемо для
этапа spec):
```
docs/specs/478-remove-room-drafts.md | 531 +++++++++++++++++++++++
docs/specs/README.md | 1 +
```
Продуктового кода в ветке нет — это правильно для стадии `S4-spec-review`.
## Как проверялось
1. Прочитан `docs/SCOPE.md`, `AGENTS.md`, `PROCESS.md` §2.4/§7.1/§4/§7.2/§12.
2. Прочитано тело issue #478 целиком и все 3 комментария (аналитика, занятие,
передача на ревью, решения владельца от 06.09.2026).
3. Прочитан ТЗ целиком (531 строка, разделы 1–20).
4. Прочитаны канонические документы, которые ТЗ обязуется обновить при
реализации: `docs/CANVAS.md`, `docs/WALL-THICKNESS.md`,
`docs/CONFIG-COMPATIBILITY.md`, `docs/ARCHITECTURE.md`,
`docs/USER-GUIDE.ru.md` — сверена терминология («черновик», «независимая
стена», resume-жест) с тем, что уже описано там сегодня.
5. Технические утверждения ТЗ и исходного текста issue сверены с текущим
кодом на `origin/dev` (`fc5973c2`), а не приняты на слово:
- `MAX_ROOM_DRAFTS=200`, `MAX_DRAFT_SEGMENTS=2000`, `MAX_PARTITIONS=2000` —
существуют в `src/houseplan-card.ts`, `src/houseplan-editor-runtime.ts`,
`custom_components/houseplan/validation.py` ровно как описано;
- `_offerWallFaces`, `_offerExistingWallFace`, `_wallGraphSources`,
`_planStructuralGeometrySnapshot` — существуют в
`src/houseplan-editor-runtime.ts` с сигнатурами, соответствующими
описанию в issue;
- `fixedTopologyWallLineageHints` — существует в `src/wall-segment-model.ts`
и используется в `houseplan-editor-runtime.ts`;
- `partitionsReconciled` / `redundantDraftsRemoved` — существуют в
`src/plan-optimizer.ts` и `src/coincident-partitions.ts` ровно с той
семантикой, которую ТЗ предлагает свести к нулю;
- `draft-live-preflight.ts` / `draft-live-commit.ts` (Fast path #461) —
существуют, есть тест `test/draft-live-preflight.test.mjs`;
- `WALL_SEGMENT_MODEL_VERSION` и `PLAN_MODEL_VERSION` действительно равны
`9` сегодня и исторически бампались синхронно (`git log -p` по обеим
константам) — заявленный переход v9→v10 не расходится с прецедентом;
- `wall_model_client_outdated` — существующий код ошибки
(`src/houseplan-card.ts`, `src/space-copy-runtime.ts`, все локали), а не
изобретённый в ТЗ;
- `mutation-gate` как механизм (AC13 требует «мутант... краснит gate») —
реально существующая инфраструктура (`scripts/mutation-gate.mjs`,
`test/mutation-gate.test.mjs`, `docs/TESTING.md`), не выдуманный
инструмент.
6. Сверена таблица `docs/specs/README.md`: новая строка вставлена без колонки
«Статус ТЗ» — соответствует зачистке из PROCESS.md §7.3 п.1, уже принятой в
остальной таблице.
7. Проверено соответствие §7.1 (обязательные разделы) и формату AC (каждый
пункт называет способ доказательства).
Гейты (typecheck/test/build) не гонялись: на этом этапе (spec) продуктового
кода в ветке нет, гонять их не над чем. Это не пропуск гейта, а его
неприменимость к диапазону изменений раунда.
## Разбор по требованиям процесса
### §7.1 — обязательные разделы
Все присутствуют, хотя «контракт поведения» не оформлен единым заголовком, а
распределён по §8–12 (активная цепочка / face detection / Undo-Redo / limits /
import-export) — это не нарушение, содержание есть и логично сгруппировано:
сценарий (§1) · что человек увидит (§2) · проблема (§3) · скоуп/не-скоуп (§5) ·
контракт поведения (§8–12) · UX/i18n (§13) · модель данных и миграция (§6–7) ·
критерии приёмки AC1–AC15, каждый со способом доказательства (§14) · план
автотестов (§15) · риски (§17) · откат (§18) · release-артефакты (§19).
Два продуктовых раздела («сценарий», «что человек увидит») идут первыми, как
требует PROCESS.md, и оба не используют термины реализации.
### Продуктовые вопросы vs технические
Открытых продуктовых вопросов нет: владелец 06.09.2026 ответил ровно на два
продуктовых вопроса (жест возобновления контура; подсветка незамкнутых стен),
и оба ответа перенесены в §4 ТЗ дословно. Раздел 20 «Принятые технические
предположения» содержит только техническое: имя/расположение
session-состояния, переименование файлов fast-path, источник fallback ID,
место экстракции reconciliation-логики, судьба deprecated-счётчика, механизм
CSS-подсветки. Ни один из этих семи пунктов не задевает то, что видит
пользователь — деление между продуктовым и техническим сделано верно, ничего
техническое не выдано владельцу, и ничего продуктовое не спрятано в
«технические предположения».
### Догадка, выданная за факт
Не найдена. Каждое нетривиальное техническое утверждение («уже сегодня
предложение комнаты работает и на чужих партициях», «дубли схлопывает только
оптимизатор», названные функции и константы) проверено против кода и
подтвердилось — см. предыдущий раздел. Формулировки вида «предполагаю»
отсутствуют там, где нужно было бы решение, потому что владелец их уже принял.
### Однозначность AC
15 AC, каждый называет способ доказательства (`unit`, `unit + Python parity`,
`smoke`, `performance + mutation`, `golden verify`, `typecheck+unit+build+docs
review`). Формулировки конкретны и допускают проверку «упало/не упало»:
например AC7 требует «итог содержит одну masonry, нет coincident partitions»
— проверяемо инвариантом, а не оценочно. AC13 явно требует существования
красного мутанта на «coincident partition либо draft» — это ровно дисциплина
«тест должен уметь падать», перенесённая в план ещё до кода.
### Миграция и откат
Миграция v9→v10 нормативно описана (§7.1–7.3): один partition на одно legacy
edge, без слияния/дедупликации, детерминированные ID с указанным источником
энтропии, требование TS/Python parity. Откат (§18) корректно разделяет
кодовый revert (безопасен) и уже сохранённый v10-конфиг (несовместим со старой
карточкой по замыслу, downgrade запрещён явно) — это соответствует
`docs/CONFIG-COMPATIBILITY.md`, где подобные необратимые migrate-on-write
переходы уже прецедент.
### Соответствие docs/SCOPE.md
Задача — tech debt/миграция модели, устраняющая дублирующую сущность и
невидимо накапливающийся артефакт (`room_drafts`, не отличимый от обычной
стены после reload, блокирующий resize соседней стены). Это поддерживает J6
(«Keep the plan true as the home evolves») — упрощает и делает надёжнее
механизм разметки контура/комнаты, не расширяя видимый функционал за пределы
уже существующего поведения. Новых кнопок, настроек или диалогов ТЗ явно не
вводит (§5.2, §13) — соответствует принципу «View mode остаётся продуктом»,
редакторская сложность не растёт для пользователя.
### Release-артефакты и User-Visible
`User-Visible: yes` обоснован верно (§19): исчезает resume персистентного
черновика, меняется видимое поведение незамкнутых стен после reload. Список
документов для обновления полный и включает оба changelog, что при реализации
обязано попасть в тот же коммит по AGENTS.md.
## Что проверено и корректно
- Обязательные разделы §7.1 — все на месте.
- Каждый AC — с методом доказательства, формулировки допускают падение теста.
- Технические утверждения ТЗ и предпосылки issue — верны по факту чтения кода
`origin/dev`, догадок, выданных за решённый факт, не найдено.
- Продуктовые решения владельца зафиксированы дословно и исчерпывающе;
раздел «технические предположения» не содержит скрытых продуктовых развилок.
- Скоуп/не-скоуп конкретны и проверяемы, границы задачи не размыты.
- Миграция и откат внутренне согласованы и соответствуют прецеденту
`docs/CONFIG-COMPATIBILITY.md`.
- `docs/specs/README.md` обновлён в формате, уже принятом для остальной
таблицы (без колонки статуса).
## Чего не проверял
- Не гонял `npx tsc --noEmit`/`npm test`/`npm run build` — в ветке нет
продуктового кода, гонять их не над чем на этапе spec.
- Не проверял `npm run invariants` — геометрия ещё не реализована, инварианты
модели проверять не на чем.
- Не читал полностью весь текст `docs/CANVAS.md`/`docs/WALL-THICKNESS.md`/
`docs/ARCHITECTURE.md` построчно — выборочно сверил только фрагменты,
относящиеся к `room_drafts`/lineage/reconciliation, поскольку остальное не
затрагивается этим ТЗ.
- Не оценивал реализуемость помодульно (файлы/хелперы) — ТЗ прямо и верно
относит это к техническим решениям вне продуктового ревью (§20, PROCESS.md
§7.1 «всё, чего пользователь не наблюдает, агенты решают сами»).
- Не связывался с #477/#461/#173/#282/#314 по существу — они упомянуты как
контекст связи, не как обязательства этого ТЗ; не-скоуп (§5.2) явно
исключает пересечение с #461.
## Находки
Нет ни одной находки уровня High или Medium. Low-находок, требующих правки или
пометки waived, тоже нет.
## Итог
ТЗ полное, однозначное, все обязательные разделы на месте, каждый AC проверяем
и называет способ доказательства, продуктовых вопросов не осталось, а
технические утверждения подтверждены чтением актуального кода, а не приняты на
веру. Задача полностью укладывается в `docs/SCOPE.md` (J6) и не расширяет
скоуп за счёт незаявленной пользователю функциональности.
**Вердикт: зелёный · заход r1 · блокирующих циклов 0/4 · High: 0 · Medium: 0**
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/478-remove-room-drafts`, коммит `30a16ed36461` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `66116fde28ee91b0ee64d7dc0d3125b82c972505`
```
git log --all --format='%H %T' | grep 66116fde28ee
```
- ТЗ `docs/specs/478-remove-room-drafts.md`, блоб `8817d2c4307eed78b4eba9f731b3b6fd7c5270c3`
```
git log --all --find-object=8817d2c4307eed78b4eba9f731b3b6fd7c5270c3 -- docs/specs/478-remove-room-drafts.md
```