17 KiB
SPEC-REVIEW-676-r3
- Issue: https://github.com/Matysh/houseplan-card/issues/676
- Этап:
S4-spec-review(ревью ТЗ, PROCESS.md §2.4) - Трек: полный (метки
bug,P1,S4-spec-review; лёгкий трек — нет, подтверждено аналитиком в r1: несколько поверхностей, новый UX-контракт размещения протяжкой и подсказки, сложность > 3). - Материал: тело issue #676, раздел
## ТЗ(редакция 3, 27.09,sha256 72bccdff…2183) + 7 комментариев (добавился ровно один — «редакция 3» — и вердикт r2). - Заход: r3 · блокирующих циклов израсходовано 2 из 4 (лимит для полного трека — 4; зелёный вердикт этого раунда цикл не тратит)
- Роль: ревьюер ТЗ (не автор)
Скоуп ревью (по дельте, PROCESS.md §2.10)
Предмет r3 — ровно одна точечная правка редакции 3, объявленная автором в
комментарии IC_kwDOTOcLQM8AAAABXQSkCA: «К8 сформулирован инверсией —
подсказка только при stairTargetState === 'active', то же условие, что
делает лестницу ссылкой; остальные четыре состояния перечислены поимённо,
включая self. AC8 получил пятый шаг смока: target_space_id: 'f1' на
этаже f1 → подсказки нет.»
Это единственная находка Medium раунда r2 («AC8/К8 перечисляют четыре ветви
stairTargetState, а не пять; состояние self выпадает из контракта
тултипа»). Код задачи по-прежнему не существует: ветки issue/676-* нет
(git branch -a | grep -i 676 — пусто), git diff 9fe7f88c..HEAD --stat
между материалом r2 и текущим HEAD (19edda83) показывает только
публикацию документа SPEC-REVIEW-676-r2.md и обновление
docs/reviews/INDEX.md — ни одной строки продуктового кода. Дифф кода для
этой задачи не существует, гейты typecheck/npm test/npm run build/
check-docs.mjs/смоки/golden:verify/инварианты — неприменимы на этом
этапе, как и в r1/r2 (см. «Чего не проверял»).
Остальные разделы ТЗ (Сценарий, Скоуп/Не-скоуп, К1–К7, UX, модель данных, i18n, план автотестов кроме строки AC8, риски, откат, release-артефакты, «принято предположительно») дельтой r2→r3 не задеты — построчно сверены с содержанием, процитированным/подтверждённым в r1 и r2, расхождений нет; они наследуются без повторной проверки (см. «Унаследовано из r2»).
SCOPE-проверка (docs/SCOPE.md): не меняется относительно r1/r2 —
сценарий закрывает J6 (редактирование объектов плана без регресса в
сохранённых данных) и J1/J2 через корректную навигацию/подсказку лестницы в
Просмотре.
Как проверялось
- Подтверждено, что кода задачи всё ещё нет:
git branch -a | grep -i 676не находит рабочую ветку;git diff 9fe7f88c..HEAD --stat(материал r2 → текущийHEAD) — толькоdocs/reviews/INDEX.md(+3/-1) и добавлениеdocs/reviews/SPEC-REVIEW-676-r2.md(211 строк, публикация отчёта r2). Никаких файловsrc/**/test/**/demo/**в диффе нет. - Прочитано тело issue #676 целиком (
gh issue view 676 --json body, sha25672bccdff…2183) и все 7 комментариев (gh issue view 676 --json comments), включая новый (редакция 3,IC_…XQSkCA) и вердикт r2 (IC_…XQQAzQ). - Сверена ровно одна правка редакции 3 с текстом находки r2 построчно:
- Medium (self, r2): требовал либо переформулировать К8/AC8 как
инверсию с пятым смоук-шагом на
self, либо явно обосновать пропуск. Новый К8: «Подсказка показывается только когдаstairTargetState(...) === 'active'— то же условие, что делает лестницу ссылкой… все остальные четыре состояния функции —missing…self…deleted…fixed… — подсказки не дают» — это ровно формулировка-инверсия из варианта (а), рекомендованного r2, с явным перечислением всех пяти исходов по имени. Новый AC8: «все пять состоянийstairTargetState:active…missing…self(target_space_id: 'f1'на этажеf1) —null…deleted…fixed…» — пятый шаг добавлен буквально так, как просил r2.
- Medium (self, r2): требовал либо переформулировать К8/AC8 как
инверсию с пятым смоук-шагом на
- Перепроверена не только текстуально, а по исходной функции: заново
прочитан
src/stairs-editor-model.ts:97-104(stairTargetState, актуальный код наHEAD19edda83) — сигнатура и порядок веток не изменились с r2: возвращаетactive | missing | self | deleted | fixed; веткаself—stair.target_space_id === currentSpaceId(строка 101), проверяется доspaceIds.has(...). Формулировка К8/AC8 редакции 3 («self— цель, совпадающая с текущим пространством», примерtarget_space_id: 'f1'на этажеf1) буквально соответствует этому коду — не является догадкой. - Перепроверено, что не-скоуповый код Просмотра (
src/stairs-view.ts:64, актуальная строка наHEAD:const active = interactive && targetState === 'active';) уже применяет ровно ту же инверсию к навигации, что К8 редакции 3 теперь явно требует для тултипа — новая формулировка контракта согласована с уже работающим соседним поведением, а не противоречит ему (одно условие=== 'active', один источник истины для «когда лестница активна»). - Сверено, что
docs/STAIRS.md:21-23(«A missing, self or deleted target leaves the stair visible and editable but shows a repair warning…») не противоречит новой формулировке К8 — канон уже группируетselfсmissing/deletedкак непроходной для активации исход, задача лишь явно называет его вместо того, чтобы полагаться на «остальное». - Разделы, не тронутые дельтой r2→r3 (Сценарий, Скоуп/Не-скоуп, К1–К7 кроме упомянутого в п. 3, UX, модель данных, i18n, план автотестов кроме строки AC8, риски, откат, release-артефакты, «принято предположительно»), не перечитывались заново построчно против кода — они уже проверены в r1/r2 и текстуально идентичны в текущем теле issue (сверено чтением полного текущего тела против содержания, процитированного в SPEC-REVIEW-676-r1.md и SPEC-REVIEW-676-r2.md); см. «Унаследовано из r2».
Находки
Нет. Единственная находка r2 (Medium, ветка self в К8/AC8) закрыта именно
так, как r2 рекомендовал технически (вариант «а» — инверсия условия плюс
пятый смоук-шаг), формулировка проверена по актуальному коду
(stairs-editor-model.ts, stairs-view.ts) и не расходится с ним. Новых
несоответствий, внесённых самой правкой r3, не найдено.
Закрытие раунда r2
| Находка r2 | Чем закрыта | Где это видно |
|---|---|---|
Medium: АС8/К8 перечисляют четыре ветви stairTargetState, а не пять; self выпадает из контракта тултипа |
К8 переформулирован как инверсия («подсказка только при active», остальные четыре ветви — включая self — перечислены поимённо); AC8 получил пятый смоук-шаг для self |
Тело issue #676, редакция 3, разделы «Контракт поведения → К8» и таблица «Критерии приёмки → AC8» (комментарий IC_kwDOTOcLQM8AAAABXQSkCA); подтверждено чтением src/stairs-editor-model.ts:97-104 на HEAD 19edda83 — сигнатура и ветка self совпадают с текстом К8/AC8 |
Унаследовано из r2 (и транзитивно из r1)
Принято без повторной построчной проверки против кода в этом раунде — проверено ранее и не задето дельтой r2→r3:
- Обязательные разделы §7.1 (Сценарий, Что человек увидит, Проблема, Скоуп/Не-скоуп, Контракт К1–К7, UX, Модель данных и миграция, i18n, План автотестов кроме строки AC8, Риски, Откат, Release-артефакты, Принято предположительно) — присутствуют и однозначны (SPEC-REVIEW-676-r1.md, раздел «Как проверялось» пп. 4–8; SPEC-REVIEW-676-r2.md, раздел «Что проверено и корректно»).
- Диагностика «Проблема» и фактический фундамент контракта (константы
STAIR_MIN_CM/STAIR_MAX_CM/FURN_WALL_CELLS, существующие функцииresizeFurnitureTransform,fieldToCm/clampWallCm, порядок отрисовкиwallbodiesvs_renderTextFrame, единый CSS-класс курсора, i18n-паритет, 4 golden-сцены лестниц) — сверены с кодом на материале r1 (f1a87fba/4c3048e8) и не менялись с тех пор ни в issue, ни в соответствующем коде (точечно перепроверено дляstairs-editor-model.tsиstairs-view.tsв этом раунде, см. «Как проверялось» пп. 4–5; остальные файлы не тронуты дельтой и не перечитывались). - AC12 (инертность рамки узлов под другими инструментами) и его связь с К2 — закрыты в r2, текст не менялся в r3 (SPEC-REVIEW-676-r2.md, «Что проверено и корректно»).
- Tie-break диагонали 45° в К1 — закрыт в r2 (низкая находка r1), текст не менялся в r3.
- Все 9 исходных дефектов из «Что происходит» сведены к контрактам К1–К8 и покрыты AC1–AC11 (плюс AC12 из r2) без пропусков — установлено в r1, не затронуто дельтой r2→r3 (SPEC-REVIEW-676-r1.md, «Что проверено и корректно»).
- Откат и модель данных не меняются,
docs/CONFIG-COMPATIBILITY.mdне задевается — установлено в r1, текст раздела не менялся.
Что проверено и корректно (этот раунд)
- Правка редакции 3 текстуально и по коду закрывает ровно ту находку, ради которой был начат раунд r3 — не больше и не меньше (не расширяет и не сужает скоуп, не меняет ничего в других разделах ТЗ).
- Новая формулировка К8 согласована с уже существующим, не-скоуповым кодом
Просмотра (
stairs-view.ts:64, инверсия=== 'active') — один источник истины для «когда лестница активна», а не два разных условия для тултипа и навигации. - AC8 остаётся однозначным и называет способ доказательства (
smoke, пять отдельных шагов с отдельными флагами) для каждого из пяти состояний функции — буквальная реализация по тексту не может закрыть AC8, пропустивself, как это было возможно с редакцией 2. - Материал раунда корректно идентифицирован: код задачи по-прежнему
отсутствует (только публикация документа r2 в диффе
9fe7f88c..HEAD), так что вся оценка — снова чисто по тексту ТЗ и по уже существующему коду соседних (не-скоуповых) модулей, которые контракт называет.
Чего не проверял
- Не запускал
npm run typecheck/npm test/npm run build,node scripts/check-docs.mjs, смоки,golden:verify, инварианты модели — кода задачи не существует ни на материале r1/r2, ни на текущемHEAD(19edda83):git branch -aне находит веткуissue/676-*,git diff 9fe7f88c..HEADсодержит только документ ревью r2 и индекс. Дифф для этих гейтов не существует, они относятся к этапу код-ревью, который наступит после реализации. - Не перечитывал заново построчно против кода разделы, не тронутые дельтой
r2→r3 (К1–К7 кроме ветки
self, УХ, модель данных, i18n, план автотестов кроме AC8, риски, откат, release-артефакты) — они уже дважды проверены (r1 по коду, r2 текстуально против r1) и текстуально идентичны в текущем теле issue; см. «Унаследовано из r2». - Не проверял заново достижимость
selfчерез реальный UI (перенос/слияние помещений) — для снятия находки r2 было достаточно того, что модель (stairs.ts:84) не отвергает такие данные и канон (STAIRS.md:21-23) документирует состояние как поддерживаемое; глубже не уходил, как и в r2. - Не проверял #663/#669 по существу (смежные задачи, не в скоупе).
Вердикт
Вердикт: зелёный · заход r3 · блокирующих циклов 2/4 · High: 0 · Medium: 0
Материал раунда
- Ветка:
dev, коммит19edda83e35e— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
4963bc95c5187a923844c4e6ab5ae387a0af5094git log --all --format='%H %T' | grep 4963bc95c518 - Тело issue:
72bccdffa1d7cdfdd71c8c8ee5d1cd66f64b6aba7db2003b718c0af2f2292183 - Вердикт конвейера:
green· High 0