14 KiB
SPEC-REVIEW-289-r2
- Issue: https://github.com/Matysh/houseplan-card/issues/289
- Артефакт ТЗ:
docs/specs/289-no-mixed-role-resize.md - Ветка/коммит:
issue/289-no-mixed-role-resize@e02c282d(origin/dev+ 2 коммита сверх r1:1dae3b0c— документ ревью r1,e02c282d— правки автора; подтвержденоgit diff origin/dev..HEAD --stat— только два docs-файла, продуктовый код не тронут) - Заход: r2 · блокирующих циклов израсходовано 1 из 4
- Вердикт: зелёный · High: 0 · Medium: 0 · Low: 1 (снят с запиской, не блокирует)
Скоуп ревью
Раунд r1 (см. docs/reviews/SPEC-REVIEW-289-r1.md, коммит 5e169f48) дал
жёлтый вердикт: High 0, Medium 3 (M1 «Риски» отсутствует, M2 «Откат»
отсутствует, M3 — 6 из 9 AC без способа доказательства), Low 2 (L1
терминология «рукоятка»/«ручка», L2 — i18n-ключ не назван буквально).
Технический контракт §2–§4, AC1–AC9 по существу и границы скоупа §5 в r1 уже
признаны корректными точным чтением кода и канона. Автор ответил правками в
e02c282d («докcs: add evidence and rollback to resize spec») и сообщил в
issue, что внёс все три Medium.
Эта дельта — предмет r2: git diff 5e169f48..e02c282d -- docs/specs/289-no-mixed-role-resize.md.
Дельта локальна (добавление разделов и строк «Доказательство», без изменения
самого контракта, AC-формулировок или скоупа) — полный повторный разбор
продукта не требуется, объём разбора сокращён до делты и её последствий.
Как проверялось
- Нашёл вердикт r1 в комментариях issue #289 (комментарий от 2026-08-24
10:48:29) и SHA, на котором он получен. В самом комментарии-вердикте SHA не
назван — по инструкции это сигнал для проверки; но опубликованный документ
docs/reviews/SPEC-REVIEW-289-r1.md:5называет его явно:5e169f48. Ложной тревоги нет, SHA подтверждён. git diff 5e169f48..e02c282d -- docs/specs/289-no-mixed-role-resize.md— построчно, каждый добавленный/изменённый хунк сверен с тем, какую находку r1 он должен закрывать (таблица ниже).git diff 5e169f48..e02c282d --stat(весь коммит, не только spec-файл) — подтвердил, что в дельте нет ничего кроме ожидаемого: сам spec-файл плюс документ ревью r1 (публикация предыдущего раунда, не предмет этого ревью).- Пересчитал нумерацию разделов файла целиком (
grep -n "^## [0-9]") — после вставки §8/§9 разделы 8–12 сдвинулись; последовательность 1…12 без пропусков и дублей, внутренних ссылок§Nна старые номера в файле нет — реформат не оставил битых ссылок. - Проверил заявление о каноническом термине:
docs/USER-GUIDE.ru.md(раздел Resize, таблица сценариев) называет элемент управления «Ручка», слова «рукоятка» в проекте вне этого ТЗ нет — сверил актуальное количество вхождений в текущей редакции файла (grep -ni), а не унаследовал цифру из текста r1. - Не прогонял
typecheck/test/build/инварианты —git diff origin/dev..HEAD --statпоказывает только два docs-файла (docs/specs/289-*.md,docs/reviews/SPEC-REVIEW-289-r1.md), продуктового кода на ветке всё ещё нет. Гейты класса A/B неприменимы к чисто документационному изменению на этапе ТЗ — тот же вывод, что и в r1, дельта его не меняет.
Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
| M1 — раздел «Риски» отсутствует полностью | Добавлен раздел «8. Риски и меры»: три риска (чрезмерно строгий ownership → ложный disable легитимных жестов; чрезмерно мягкий → возврат mixed-role; расхождение owners между preview и commit), каждый со ссылкой на конкретный AC-барьер (AC3/AC4, AC1/AC5/AC8, AC6) | docs/specs/289-no-mixed-role-resize.md:210-218 |
| M2 — раздел «Откат» отсутствует полностью | Добавлен раздел «9. Откат»: явно зафиксировано «чистый revert коммита», без флага/миграции, обосновано неизменностью persisted geometry/schema — то самое тривиальное решение, которое r1 предсказал, но потребовал записать явно | docs/specs/289-no-mixed-role-resize.md:220-223 |
| M3 — 6 из 9 AC (AC1–AC6) без способа доказательства | Каждому AC1–AC6 добавлена строка «Доказательство: …» с конкретным инструментом (unit в test/resize.test.mjs, production-bundle smoke, scripts/model-invariants.mjs) — по одной на каждый |
docs/specs/289-no-mixed-role-resize.md:120-121,129-130,139-140,151-152,161-162,171-172 |
| L2 — i18n-ключ не назван буквально | В разделе «Ожидаемые файлы» ключ resize.disabled.partial-shared назван по имени, а не только как значение reason |
docs/specs/289-no-mixed-role-resize.md:231-232 |
| L1 — «рукоятка» вместо канонической «ручка» | Не исправлено. В §2 (строка 35) и §3 (строка 44) слово «рукоятка» осталось; правки касались только новых разделов и не задели прозу §2/§3 | docs/specs/289-no-mixed-role-resize.md:35,44 |
Уточнение по L1: текст r1 указывал «использовано 5 раз (§2, §3, §4.2×3)» — это
не подтвердилось. В §4.2 (строки 64–78) на самом деле используется английское
слово handle (та же RU/EN смесь технических терминов, что и у «moving
edge»/«side edges» по всему документу, которую сам r1 признал соответствующей
канону), а не «рукоятка». Фактическое количество вхождений слова «рукоятка» в
редакции 5e169f48 и в текущей e02c282d одинаково — 2, не 5, и дельта r2 в
этом месте нулевая. Обе строки чисто описательные (не согласованный с
владельцем disabled-текст AC2, который дословно совпадает с решением
владельца и не содержит «рукоятка»/«ручка»). Расхождение с каноническим
термином реально, но не влияет на реализуемость или проверяемость ни одного
AC — снимаю как Low с запиской, не требую четвёртого цикла ради двух слов в
прозе.
Унаследовано из r1
Без повторной проверки в r2 принято на основании
docs/reviews/SPEC-REVIEW-289-r1.md (документ на SHA 5e169f48), так как
дельта 5e169f48..e02c282d не касается этих утверждений:
- Технический контракт §1/§4 (ownership-модель, запрещённая смена роли,
thickness preservation) — соответствие
resolveSafeResize()/validateSafeResize()вsrc/resize.tsподтверждено чтением кода в r1; дельта не меняет ни одной строки §1/§4. - Симметричность контракта §4.2 (оба направления жеста небезопасны в exact-репро, mixed-role у соседней комнаты при укорачивании) — геометрически проверено в r1; текст §4.2 не менялся.
- AC1–AC9 по существу (что каждый критерий требует) — проверено в r1 построчно против кода и канона; дельта добавила только строки «Доказательство:», не изменив ни одной формулировки требования.
- Существование и семантика инструментов:
checkMixedRoleRecords,checkWallRecordsPreserved,checkWallKeys,checkReferences,checkPhysicalGeometry(scripts/model-invariants.mjs),resize.disabled.partial-sharedиresize.commit_failed(оба i18n-файла) — подтверждено чтением исходников в r1, дельта их не касается. - Границы скоупа §5 (не входит: разрез записи, смена толщины, каскад топологии, рефактор #264, ретро-починка через Optimize, #288, #290) — сверено с историей issue в r1, текст §5 не менялся.
- Продуктовое решение §2 соответствует ответу владельца на Q1 — сверено в r1 слово в слово, текст §2 (кроме уже учтённого L1) не менялся.
- Совместимость §7 (schema/model version не меняются, touch — best effort,
безопасный pointermove-путь) — сверено в r1 с
docs/CONFIG-COMPATIBILITY.mdиdocs/TOUCH-SUPPORT.md, текст §7 не менялся.
Что проверено и корректно в этом раунде (не находка, а подтверждение)
- Все три Medium из r1 закрыты предметно, а не декларативно: каждая правка — конкретный текст в конкретной строке, а не общая фраза «риски учтены» (проверено построчным диффом, см. таблицу выше).
- Реформат нумерации разделов (8→10, 9→11, 10→12) не оставил битых внутренних ссылок и не изменил порядок обязательных по §7.1 PROCESS.md разделов.
- Раздел «Риски» не декоративен: каждый из трёх рисков привязан к конкретному AC-барьеру, который его закрывает, а не общей фразой «риски будут обнаружены на код-ревью».
- Раздел «Откат» согласован с остальным документом: «schema/model version не меняются» из §7 и «persisted-данные не переписываются» из §4.3 — одно и то же утверждение, не новое допущение, придуманное только для раздела 9.
Чего не проверял
- Продуктовый код и тесты — на ветке их всё ещё нет (
git diff origin/dev..HEAD --statпоказывает только два docs-файла); гейтыtypecheck/test/build/invariants/смоки неприменимы на этапе ТЗ, как и в r1. - Всё, что унаследовано из r1 и перечислено выше отдельным разделом, — не перепроверялось повторно, так как дельта его не задевает.
- Формулировка Low L1 не эскалирована владельцу — это стилистическая правка внутри уже принятого текста, не продуктовый вопрос.
Итог
High: 0. Medium: 0 — все три Medium-находки r1 закрыты предметно в e02c282d.
Low: 1 из двух устранён (L2), один (L1, «рукоятка»/«ручка») остаётся, но снят
решением ревьюера с запиской: расхождение только в описательной прозе §2/§3,
не в согласованном с владельцем disabled-тексте AC2, и не влияет на
реализуемость ни одного AC. Технический контракт, AC1–AC9 и границы скоупа
наследуются из r1 без повторной проверки (дельта их не касается). ТЗ готово к
разработке.