docs: review document for #676

Issue: #676
User-Visible: no
This commit is contained in:
claude[bot]
2026-09-27 11:52:45 +00:00
parent 19edda83e3
commit 9a7020ce42
2 changed files with 202 additions and 1 deletions
+2 -1
View File
@@ -1,11 +1,12 @@
# Индекс ревью
Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 1107, issue: 396. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`.
Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 1108, issue: 396. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`.
| Issue | Документ | Этап · раунд | Вердикт | H | M | Находки | Файлы |
|---|---|---|---|---:|---:|---|---|
| #676 | [SPEC-REVIEW-676-r1.md](SPEC-REVIEW-676-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | AC8 не называет проверку двух из трёх ветвей подавления подсказки; риск «рамка перехватывает события под другим инструментом» не привязан ни к одному AC; не задан tie-break для равного протяжки по обеим осям (снимаю сам) | `src/stairs-editor-model.ts` `stairs-view.ts` `demo/smoke_stairs.mjs` `src/furniture.ts` |
| #676 | [SPEC-REVIEW-676-r2.md](SPEC-REVIEW-676-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | AC8/К8 перечисляют четыре ветви stairTargetState, а не пять; состояние self выпадает из… | `src/stairs-editor-model.ts` `docs/STAIRS.md` `src/stairs.ts` `stairs-view.ts` |
| #676 | [SPEC-REVIEW-676-r3.md](SPEC-REVIEW-676-r3.md) | spec · r3 | 🟢 зелёный | 0 | 0 | — | — |
| #675 | [CODE-REVIEW-675-r1.md](CODE-REVIEW-675-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — |
| #673 | [CODE-REVIEW-673-r1.md](CODE-REVIEW-673-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | docs/images/screenshots.json: закоммиченный sourceFingerprint не совпадает с тем, что р…; Комментарий автора в issue #673 называет SHA реализации 557d4e38e26b647437f2c931454737f… | `docs/images/screenshots.json` `demo/golden/matrix.mjs` `scripts/source-fingerprint.mjs` `accept.mjs` `policy.mjs` `AGENTS.md` `baselines-index.json` |
| #673 | [CODE-REVIEW-673-r2.md](CODE-REVIEW-673-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — |
+200
View File
@@ -0,0 +1,200 @@
# 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 через корректную навигацию/подсказку лестницы в
Просмотре.
## Как проверялось
1. Подтверждено, что кода задачи всё ещё нет: `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/**` в диффе нет.
2. Прочитано тело issue #676 целиком (`gh issue view 676 --json body`,
sha256 `72bccdff…2183`) и все 7 комментариев (`gh issue view 676 --json
comments`), включая новый (редакция 3, `IC_…XQSkCA`) и вердикт r2
(`IC_…XQQAzQ`).
3. Сверена ровно одна правка редакции 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.
4. Перепроверена не только текстуально, а по исходной функции: заново
прочитан `src/stairs-editor-model.ts:97-104` (`stairTargetState`,
актуальный код на `HEAD` `19edda83`) — сигнатура и порядок веток не
изменились с r2: возвращает `active | missing | self | deleted | fixed`;
ветка `self` — `stair.target_space_id === currentSpaceId` (строка 101),
проверяется до `spaceIds.has(...)`. Формулировка К8/AC8 редакции 3
(«`self` — цель, совпадающая с текущим пространством», пример
`target_space_id: 'f1'` на этаже `f1`) буквально соответствует этому
коду — не является догадкой.
5. Перепроверено, что не-скоуповый код Просмотра (`src/stairs-view.ts:64`,
актуальная строка на `HEAD`: `const active = interactive && targetState
=== 'active';`) уже применяет ровно ту же инверсию к навигации, что К8
редакции 3 теперь явно требует для тултипа — новая формулировка
контракта согласована с уже работающим соседним поведением, а не
противоречит ему (одно условие `=== 'active'`, один источник истины для
«когда лестница активна»).
6. Сверено, что `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` как непроходной для активации исход, задача лишь
явно называет его вместо того, чтобы полагаться на «остальное».
7. Разделы, не тронутые дельтой 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`, порядок отрисовки
`wallbodies` vs `_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
---
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `dev`, коммит `19edda83e35e` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `4963bc95c5187a923844c4e6ab5ae387a0af5094`
```
git log --all --format='%H %T' | grep 4963bc95c518
```
- Тело issue: `72bccdffa1d7cdfdd71c8c8ee5d1cd66f64b6aba7db2003b718c0af2f2292183`
- Вердикт конвейера: `green` · High 0