diff --git a/docs/reviews/SPEC-REVIEW-223-r3.md b/docs/reviews/SPEC-REVIEW-223-r3.md new file mode 100644 index 00000000..ef8bc1a8 --- /dev/null +++ b/docs/reviews/SPEC-REVIEW-223-r3.md @@ -0,0 +1,168 @@ +# SPEC-REVIEW-223-r3 + +- Issue: [#223](https://github.com/Matysh/houseplan-card/issues/223) «Оптимизировать планы» должна + канонизировать координаты, а не консервировать floating-point шум +- ТЗ: [`docs/specs/223-optimize-coordinate-canonicalization.md`](../specs/223-optimize-coordinate-canonicalization.md) + на коммите `8c9e5feae3503c086cc9f987d57f676e5435e537` (HEAD) +- Раунд: r3/4 +- Вердикт: **зелёный** + +## Скоуп ревью (по дельте, PROCESS.md §2.10) + +Round r2 получен на `965711ee2005b8ec2587b9c70fb9b14735c7756e` (SHA назван в +самом документе `docs/reviews/SPEC-REVIEW-223-r2.md`, вердикт жёлтый, High: 0, +Medium: 1). Предмет этого раунда — `git diff 965711e..HEAD`. Диапазон состоит +из двух коммитов: + +- `981d3d6` — публикация документа `docs/reviews/SPEC-REVIEW-223-r2.md` + (артефакт самого ревью, не правка ТЗ); +- `8c9e5fe` («docs: clarify optimize report terminology») — единственная + содержательная правка: 4 вставки / 4 удаления в + `docs/specs/223-optimize-coordinate-canonicalization.md`, три места — + §7 (текст диалога), строка AC6 и строка риска в §11. Меняется только слово + «нормализовано»/«normalized» → «обновлено»/«updated» для существующего + счётчика `c`; структура, семантика, доказательная матрица AC не затронуты. + +Дельта локальна текстом (§2.10): нет ребейза, нет смены контракта поведения, +не задета новая подсистема, объём (8 строк) на порядок меньше и исходного ТЗ +(~230 строк), и даже правки r2 (42 строки). Полный разбор не открывается. + +Отдельно проверено, не расширяет ли эта правка скоуп и не ломает ли AC, +которые r1/r2 уже приняли (§2.10 п.5, регрессия по образцу #102) — нет: правка +меняет исключительно пользовательскую метку одного и того же существующего +показателя `c`, не его состав, не структуру `OptimizeReport`, не AC4/AC5/§6/§8. + +## Как проверялось + +1. Восстановлен вердикт r2 и его SHA командой `gh issue view 223 --json + comments` — `965711e`, назван в документе r2 (в этом раунде замечание + «SHA не назван» не применимо — второй раунд подряд его исправно называет). +2. `git show 8c9e5fe` — построчный разбор правки, единственная содержательная + правка в диапазоне. +3. Проверено буквальное закрытие находки r2: `grep -in "нормализ|normali" + docs/specs/223-optimize-coordinate-canonicalization.md` — осталось ровно + два вхождения: (а) `§6`, «нормализованного числа» — легитимное употребление + термина в его устоявшемся во всём проекте значении (координата 0..1 + холста, никак не связано со счётчиком `c`); (б) `§11`, строка риска, где + слово упомянуто явно как «занятый термин, не используемый для `c`» — то + есть подтверждение отказа от него, а не остаточное использование. Нового + употребления «нормализовано»/«normalized» как метки счётчика `c` не + осталось нигде. +4. Проверено, не создаёт ли выбранная замена («обновлено»/«updated») новую + коллизию того же класса, которую уже дважды находил этот цикл ревью + (находка r1 №2 — «канонизировано» дважды; находка r2 — «нормализовано» + занято координатной системой): + - `grep -rn "\bupdated\b" docs/CANVAS.md docs/ARCHITECTURE.md` — ноль + совпадений: слово не занято описанием координатной системы ни в одном + каноническом документе; + - `grep -rn "обновлен" docs/*.md` — единственное релевантное совпадение + вне `CHANGELOG.ru.md` (журнал, не термин) — `toast.room_updated` / + «Комната обновлена» (`src/i18n/ru.json:562`, `en.json:562`): это + обобщённое подтверждение сохранения формы редактора комнаты, не термин + геометрии и не соседствует с координатным текстом Optimize — коллизии + смысла нет; + - `docs/CANVAS.md` §9.5 (строка 421) — канонический документ фичи называет + операцию, которую считает `c`, термином «exact open-span + canonicalisation»; «обновлено»/«updated» нейтрально по отношению к этому + термину и не конкурирует с ним за то же слово, в отличие от отвергнутых + «канонизировано» и «нормализовано»; + - выбранное слово — буквально один из двух вариантов по умолчанию, + предложенных самим ревью r2 в качестве примера («например + "обновлено"/"updated"»); автор использовал предложенный дефолт, а не + самостоятельно ввёл новый термин, что снижает риск третьей итерации той + же коллизии. +5. Сверено, что правка синхронна во всех трёх местах (§7, AC6, риск §11) и в + обоих языках (RU/EN) — да, во всех трёх местах пара + «обновлено»/«обновлённые»/«spaces updated» согласована, расхождений между + местами нет. +6. Перечитаны комментарии issue #223 целиком на предмет незаявленного + расширения скоупа — не найдено; хендофф r2→r3 (комментарий 2026-08-20 + 19:13:25Z) точно описывает сделанную правку. +7. Проверено происхождение семантики `c` в коде: `src/plan-optimizer.ts:404-500` + — `canonicalized++` инкрементируется по каждому элементу цикла + `for (let i = 0; i < config.spaces.length; i++)`, то есть ровно по + пространствам (`space`), чьё сериализованное представление + `open_spans`/`open_to`/`walls` изменилось. Формулировка «обновлено + пространств: {c}» / «spaces updated: {c}» точно соответствует коду, + который считает счётчик. + +Код не проверялся: реализация не написана, этап `spec`, ни один файл класса +A/B в диапазоне `965711e..HEAD` не менялся (`git diff --stat` — только +`docs/reviews/**` и `docs/specs/**`). + +## Закрытие раунда r2 + +| Находка r2 | Чем закрыта | Где видно | +|---|---|---| +| Medium — замена «нормализовано»/«normalized» для `c` заново создаёт коллизию того же класса: слово устойчиво занято координатной системой 0..1 во всём проекте, включая канонический документ фичи (`CANVAS.md`), который к тому же называет саму операцию `c` термином «canonicalisation», а не «normalisation» | Термин «нормализовано»/«normalized» заменён на «обновлено»/«updated» во всех трёх местах — §7 (диалоговая строка), AC6 (доказательная формулировка), §11 (строка риска); слово выбрано ровно из набора дефолтов, предложенных самим ревью r2, и не пересекается ни с «канонизировано» (занято `p`), ни с «нормализовано» (занято координатной системой) | `docs/specs/223-optimize-coordinate-canonicalization.md` §7, AC6 (таблица §9), §11, коммит `8c9e5fe` | + +Закрытие точное и полное: `grep` не находит остаточного использования слова +в роли пользовательской метки счётчика, а выбранная замена проверена на тот +же класс коллизии, который дважды всплывал в предыдущих раундах (r1 №2, r2), +и не воспроизводит его в третий раз. + +## Находки + +Новых находок нет. High: 0, Medium: 0. + +## Что проверено и корректно + +- Находка r2 закрыта буквально и без побочной коллизии (см. выше). +- Три места правки (§7/AC6/§11) синхронны между собой и с новой пользовательской + формулировкой; ни AC4/AC5/§6/§8/§9(остальные AC)/§10/§12/§13, ни структура + `OptimizeReport`/`AlignReport` дельтой не задеты. +- `c` семантически описан точно тому, что делает код (`plan-optimizer.ts:500`). +- Скоуп задачи не расширился и не сузился; продуктовых вопросов по-прежнему + нет, дельта чисто терминологическая. +- Обязательные разделы ТЗ по PROCESS.md §7.1 присутствуют полностью (не + повторная проверка формы — унаследовано, см. ниже, — но сам факт, что + правка не удалила и не сломала ни один раздел, проверен диффом). + +## Чего не проверял + +- Код реализации — не написан, этап `spec`. +- Гейты (`typecheck`/`test`/`build`) — не запускались; дельта не затрагивает + класс A/B (только `docs/specs/**` и `docs/reviews/**`), гейты для этапа + `spec` не требуются. +- Текст `docs/USER-GUIDE.ru.md`/`docs/CANVAS.md`/`docs/CHANGELOG*` после + будущей реализации — они по плану переписываются в реализации (AC9, + §12), не в ТЗ; r3 проверял только формулировку самого ТЗ. +- Все AC и разделы, которых дельта `965711e..HEAD` не касается (AC1, AC2, + AC3, AC4, AC5, AC7, AC8, AC9, AC10, §1–§6, §8, §10, §12, §13) — + унаследованы из r2 без повторной проверки, ниже. + +## Унаследовано из r2 + +Принято без повторной проверки в этом раунде, по документу +`docs/reviews/SPEC-REVIEW-223-r2.md` на SHA `965711ee2005b8ec2587b9c70fb9b14735c7756e`: + +- скоуп по `docs/SCOPE.md` (J6) и выбор обычного трека — не изменился, дельта + трек-критерии не затрагивает; +- обязательные разделы ТЗ по PROCESS.md §7.1 присутствуют и по форме верны + (подтверждено ещё в r1, дельта r2 и r3 разделов не удаляла); +- подтверждённая причина и порядок величин шума (issue, §3 ТЗ) — арифметика + `EPS`/`GRID_STEP_N` из `src/align-grid.ts:62-72`, не менялась ни в r2, ни + здесь; +- контракт снапа §6, идемпотентность (AC5), исключение проёмов из счётчика, + отсутствие вызовов `snapN()` вне `align-grid.ts`, отсутствие роста + `moved`/`maxShift*` от near-node замен — код и раздел §6 не входят в дельту + ни r2, ни r3; +- AC4/`partitions`/`wall_columns` (находка r1 №1) — закрыта в r2, дельта r3 + этих разделов (§9 AC4, §10, §11 соответствующей строки риска) не касается; +- AC1, AC2, AC3, AC4, AC5, AC7, AC8, AC9, AC10 — доказательство ни одного из + них дельта r3 не задевает (правка только в §7-фрагменте, строке AC6 и + строке риска §11, причём даже внутри AC6 меняется только слово, а не сама + проверяемая формулировка контракта); +- ссылка issue ↔ ТЗ в `docs/specs/README.md`, release-артефакты §12 — не + входят в дельту; +- отсутствие продуктовых вопросов владельцу — подтверждено r1 и r2, дельта r3 + чисто терминологическая правка одной пользовательской строки, новых + продуктовых вопросов не порождает. + +## Вердикт + +Вердикт: зелёный · цикл r3/4 · High: 0 · Medium: 0 + +Обе находки предыдущих раундов (r1 №1, r1 №2/r2) закрыты по существу, третья +попытка того же класса коллизии не воспроизвелась. ТЗ готово к переходу в +«Готово к разработке».