Files
2026-09-27 11:52:45 +00:00

17 KiB
Raw Permalink Blame History

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



Материал раунда

  • Ветка: dev, коммит 19edda83e35e — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: 4963bc95c5187a923844c4e6ab5ae387a0af5094
    git log --all --format='%H %T' | grep 4963bc95c518
    
  • Тело issue: 72bccdffa1d7cdfdd71c8c8ee5d1cd66f64b6aba7db2003b718c0af2f2292183
  • Вердикт конвейера: green · High 0