Files
houseplan-card/legacy/reviews/v1.68.0/SPEC-REVIEW-282-r2.md
T
Claudeandclaude[bot] 0991c45374 fix(tools): архив переписывает относительные ссылки перенесённых документов (#682)
Ревью #682 r1, Medium: перенос добавляет документу уровень вложенности
(`docs/reviews/X.md` → `legacy/reviews/<тег>/X.md`, `docs/specs/` →
`legacy/specs/`), а относительные ссылки внутри перенесённых документов и в
соседях, ссылавшихся на них, никто не пересчитывал — на `97d19268` 53 битые
ссылки в 46 файлах (заявление «все 26 резолвятся» в `7feb6177` было верно
только до переноса документов ревью). Гейты архив не смотрят.

`reviews-archive.mjs`: `repairLinks` пересчитывает ссылку, если она не
резолвится от нового места, а цель находится от нового или старого места
через карту переносов; битая и до переноса ссылка не трогается. `--apply`
делает это само, `--repair-links=<rev>` — для всех переименований
`<rev>..HEAD`, `--check-links` печатает битые. Этим коммитом
`--repair-links=origin/dev` переписал ровно 53 ссылки в 46 файлах; остались
две прежние «...»-заглушки в CODE-REVIEW-448-r2 (битые и на dev). Тесты:
перенесённый документ, сосед со ссылкой в архив, ТЗ со ссылкой на позже
перенесённое ревью, битая-до-переноса не трогается, в `legacy/` битых нет;
мутант `reviews-archive-links-from-new-place-only`. PROCESS §2.10 и
DEVELOPMENT › Release называют переписывание и `--check-links`.

Issue: #682
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
2026-09-27 22:10:47 +00:00

75 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SPEC-REVIEW-282-r2
- **Issue:** [#282 — Геометрия стен: сменить представление, а не чинить последствия](https://github.com/Matysh/houseplan-card/issues/282)
- **Этап:** spec (PROCESS.md §2.4)
- **Заход:** r2 · блокирующих циклов израсходовано 1 из 4 (§2.10, §4: зелёный вердикт r1 не был — r1 был жёлтым и потратил цикл 1; если этот заход зелёный, он сам цикла не образует)
- **Артефакт ТЗ:** [`docs/specs/282-stable-wall-segment-identity.md`](../../specs/282-stable-wall-segment-identity.md)
- **SHA ТЗ на момент этого ревью:** `2f30c481` (`docs: address wall identity spec review`)
- **SHA предыдущего ревью (r1):** `8856fbda` (`docs: specify stable wall segment identity`)
- **Документ r1:** [`docs/reviews/SPEC-REVIEW-282-r1.md`](./SPEC-REVIEW-282-r1.md), вердикт жёлтый, High: 0, Medium: 2 (обе в скоупе)
## Скоуп ревью r2 — по дельте (PROCESS.md §2.10)
Между `8856fbda` и `2f30c481` изменён **только** `docs/specs/282-stable-wall-segment-identity.md`
(`git diff 8856fbda..HEAD --stat`: 37 строк в одном файле; второй файл в diffstat —
сам `docs/reviews/SPEC-REVIEW-282-r1.md`, зафиксированный шагом публикации, не автором ТЗ).
Продуктовый код (`src/**`, `custom_components/**`) не тронут — его для #282 всё ещё нет.
Изменение целиком является прямым ответом на M1/M2 из r1: не рёбейз, не смена контракта,
не новая подсистема, объём дельты (37 строк из 663) несопоставим с объёмом задачи. Полный
разбор ТЗ заново не требуется — разбирается дельта плюс AC, которых она касается (AC1),
остальное наследуется из r1 без повторной проверки.
## Как проверялось
1. Найден вердикт r1 и SHA, на котором он получен (`8856fbda`, указан в шапке `SPEC-REVIEW-282-r1.md` — в отличие от типового риска этого пункта, здесь SHA был назван явно, задача «найти SHA» тривиальна).
2. Объявлена дельта: `git diff 8856fbda..HEAD` — построчно прочитан весь diff `docs/specs/282-stable-wall-segment-identity.md` (7 хансов).
3. По каждой находке r1 (M1, M2) проверено, чем именно она закрыта — конкретной строкой изменённого текста, а не комментарием автора «исправлено» (комментарий issue #282 от Matysh, `2f30c48`, только заявляет закрытие; настоящая проверка — ниже).
4. Прочитан целиком раздел «§7 Атомизация и deterministic migration v7 → v8» (включая нетронутый §7.2) и «§9 Writers и единый identity barrier» в текущей редакции — чтобы убедиться, что новое определение `exact` в §7.1 корректно распространяется на §7.2, который сам не редактировался.
5. Перечитан AC1 целиком (единственный AC, чей текст изменён) на предмет однозначности и проверяемости после правки.
6. Проверена терминология нового i18n/UX-текста против источника интерфейса (PROCESS.md требует брать термины из `docs/USER-GUIDE.ru.md`, не изобретать): `grep` по `src/i18n/ru.json` подтвердил `gs.align_all`/`gs.align_title` = «Оптимизировать планы» — тот же лейбл, что и в новом тексте тоста и в §2; `docs/USER-GUIDE.ru.md:998` (`backup.preserved_unresolved_hint`) уже использует ровно ту же конструкцию «запустите «Оптимизировать планы»» — формулировка не придумана, а повторяет существующий паттерн продукта.
7. Проверено, что дельта не расширяет скоуп и не меняет контракт вне того, что закрывают M1/M2 (§4/§5/§6/§8/§10/§13/§14 кроме AC1/§15–§19 кроме п.5 не тронуты).
## Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
| **M1** (Medium) — не специфицирован порядок атомизации Stage 1 относительно lattice-барьера #291, и какой из двух существующих допусков (`1e-4` vs `max(pitch·10⁻⁶,10⁻⁹)`) применяется | §7.1 получил абзац: канонизация #291 запускается **до** breakpoint-вычисления и до любых v8 ID/ref; порог принадлежит только #291 (`LATTICE_NOISE_STEPS = 1e-4`); слово `exact` везде в §7 означает побитовое равенство **уже канонизированных** координат; третий допуск не вводится. §9 добавил тот же порядок в описание barrier-пайплайна («сначала… `canonicalizeConfigGeometry` #291, затем… `commitWallSegmentModel`», «одна атомарная commit-транзакция»). §19 п.5 повторяет то же для момента миграции. AC1 расширен явным требованием: fixtures с шумом по обе стороны порога дают byte-equivalent v8 candidate, шум внутри порога канонизируется и не создаёт micro-segments, координата вне порога не схлопывается молча. | `docs/specs/282-stable-wall-segment-identity.md:199-205` (§7.1), `:333-338` (§9), `:655-657` (§19 п.5), `:439-445` (AC1) |
| **M2** (Medium) — §2/§11 обещают тексту тоста конкретный совет («Optimize либо исправление»), но `toast.wall_model_migration_blocked` в §12 не содержал никакого действия | §2 переформулирован под фактический текст: «предлагает сначала запустить «Оптимизировать планы», а при повторном отказе — исправить конфликтующую геометрию стен». §12 переписан в обе стороны (RU/EN): `toast.wall_model_migration_blocked` теперь буквально содержит «Запустите «Оптимизировать планы»; если ошибка повторится, исправьте конфликтующую геометрию стен.» / «Run "Optimize plans"; if the error repeats, fix the conflicting wall geometry.» — текст §2 и текст ключа теперь описывают одно и то же действие в одном порядке. | `docs/specs/282-stable-wall-segment-identity.md:32-34` (§2), `:412` (§12, таблица i18n) |
Обе находки закрыты текстом, а не заявлением: конкретные строки процитированы выше и прочитаны целиком в контексте (см. «Как проверялось», пп. 3–4).
### Дополнительная проверка терминологии (не отдельная находка, часть проверки закрытия M2)
Новая формулировка «Оптимизировать планы» — не изобретённый ревьюером или автором термин: это точное название существующей кнопки (`gs.align_all`/`gs.align_title`, `src/i18n/ru.json:807-808`) и уже употреблённый в `docs/USER-GUIDE.ru.md:998` паттерн «запустите «Оптимизировать планы»» для родственного случая (нерешённые ссылки после импорта). Правка M2 не только закрывает находку, но и делает это в терминах, которые уже существуют в продукте — соответствует требованию PROCESS.md брать терминологию интерфейса из `USER-GUIDE.ru.md`, а не изобретать.
## Что переразобрано в этом раунде (AC, которых касается дельта)
- **AC1** — единственный AC с изменённым текстом. Новая формулировка добавляет случай `lattice-noise по обе стороны порога #291` к уже существующему списку fixture-классов (outer/shared/partial-overlap/T/X/diagonal/open span/key-only/exact walls). Критерий остаётся однозначным и проверяемым тем же способом доказательства (`TS migration unit matrix + golden/static path comparison + backend fixture parity`): для шума ниже `1e-4` ожидается, что после канонизации #291 атомизация не порождает лишних микросегментов; для расхождения выше порога — coordinate не схлопывается. Оба утверждения формулируются как конкретные fixture-проверки (сравнение catalog до/после на данных внутри/вне порога), а не как качественное пожелание — критерий выполнимости не потерян правкой.
- Остальные AC2–AC17 текстуально не изменились дельтой; их доказательство не зависит от порядка canonicalization/atomization (эта деталь относится только к самому механизму миграции, не к результату, который проверяют AC2 и далее) — повторный разбор не требуется, см. «Унаследовано» ниже.
## Унаследовано из r1 (без повторной проверки)
Всё нижеперечисленное принято из `docs/reviews/SPEC-REVIEW-282-r1.md` на SHA `8856fbda`, так как дельта r1→r2 их текста и логики не касается:
- Соответствие `docs/SCOPE.md`/J6, отсутствие расширения UX/новой функциональности — §4/§5 не изменены дельтой.
- Продуктовые разделы §1 «Сценарий» и §2 «Что человек увидит» присутствуют и различимы (PROCESS.md §7.1); §2 в этом раунде получил только точечную правку текста тоста-совета (см. M2 выше), структура и персона не менялись.
- Построчная сверка фактических утверждений ТЗ о текущей модели (v7, `MAX_ROOMS/MAX_POLY_POINTS=200000`, `host?: {kind:'partition',...}`, `wallKey`/`rekeyWallsAfterMove`/`exactCoveringWall`/`edgeKinds`/`sharedSegsOf`/`atomicPolyForRoom`, существование `src/coordinate-canonicalization.ts`/`canonicalizeConfigGeometry`/`LATTICE_NOISE_STEPS`, существование скриптов `config-field-registry.mjs`/`model-invariants.mjs`/`mutation-gate.mjs`/`smoke-select.mjs`, i18n-префиксы `toast.*`/`gs.*`) — код в этих частях не менялся между r1 и r2, повторная сверка не требуется.
- AC2–AC17 однозначны и проверяемы, каждый называет способ доказательства — текст этих AC не изменён дельтой.
- Не-скоуп (§5) корректно ограничивает риск, держит границу Stage 1 против Stage 2–4 — не изменён.
- Откат и release-артефакты (§17–18) реалистичны — не изменены.
- Ссылки на существующий тулинг и гейты (§10.4, §17) верны — не изменены.
- «Чего не проверял» из r1 (ARCHITECTURE.md/CANVAS.md/UX-MODES.md/TOUCH-SUPPORT.md целиком; история регрессионных issues из AC12 построчно; typecheck/test/build — кода нет; вероятность hash-коллизии §7.3 математически) — основания этих пропусков не изменились дельтой, пропуски наследуются на тех же условиях.
## Чего не проверял в r2
- Не перечитывал целиком ADR `docs/adr/282-wall-geometry-representation.md` заново — дельта его не касается, а r1 уже подтвердил соответствие ТЗ этому ADR.
- Не гонял `npx tsc --noEmit`/`npm test`/`npm run build` — дельта не касается ни одного файла класса A/B (только `docs/specs/*.md`, класс C), продуктового кода для #282 по-прежнему нет; гонять эти гейты в этом раунде нечего.
- Не проверял математически вероятность hash-коллизии §7.3 — не тронуто дельтой, унаследовано из r1.
- Не проверял согласованность нового текста тоста (M2) с фактическими лимитами длины UI-тоста/типографикой — это находится за пределами ТЗ-ревью (вопрос реализации/визуального QA на этапе код-ревью), а не критерий выполнимости ТЗ.
## Вердикт
Обе Medium-находки r1 закрыты точечными, проверяемыми правками текста: M1 — явным порядком «канонизация #291 → атомизация» и запретом третьего допуска, с расширением AC1 под fixture с шумом по обе стороны порога; M2 — синхронизацией текста §2/§11 с фактическим i18n-ключом, использующей существующую терминологию интерфейса, а не изобретённую. Новых High- или Medium-находок дельта не создала. Дельта локальна (только текст ТЗ, 37 строк), полного повторного разбора не требует.
`Вердикт: зелёный · заход r2 · блокирующих циклов 1/4 · High: 0 · Medium: 0 · Документ: docs/reviews/SPEC-REVIEW-282-r2.md`