mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
Ревью #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
75 lines
16 KiB
Markdown
75 lines
16 KiB
Markdown
# 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`
|