docs: review document for #474

Issue: #474
User-Visible: no
This commit is contained in:
claude[bot]
2026-09-06 16:10:01 +03:00
committed by Codex
parent 9f572b85b2
commit e37285c756
+159
View File
@@ -0,0 +1,159 @@
# SPEC-REVIEW-474-r2
- **Issue:** #474 — «Стартовый граф: арт мебели уходит в ленивый чанк»
- **ТЗ:** `docs/specs/474-lazy-furniture-art.md`
- **Предыдущий раунд:** r1, вердикт красный, документ `docs/reviews/SPEC-REVIEW-474-r1.md`
(коммит `54efafbd`), материал на SHA `bb180899ff7932dd81f5a3afc8fe4975ede8df76`.
- **Правка автора:** коммит `ce08dc2c7102d3923e438dbdb10a788ab899e37a` («докс: ТЗ #474
r1 — редактор передаёт арт рантайму синхронно, golden-ожидание по образцу iso»).
- **SHA материала этого раунда:** `ce08dc2c7102d3923e438dbdb10a788ab899e37a`
(единственный файл в дельте — `docs/specs/474-lazy-furniture-art.md`,
27 добавлено / 9 удалено; `git diff bb180899..ce08dc2c -- docs/specs/474-lazy-furniture-art.md`).
- **Трек:** полный. Заход r2, блокирующих циклов израсходовано 1 из 4 до этого вердикта.
- **Вердикт: жёлтый** (Medium ниже, в скоупе задачи, без High).
## Скоуп разбора
Раунд не первый и дельта строго локальна: один файл, один коммит поверх материала
r1, оба абзаца дельты — прямой ответ на High- и Low-находки r1 (третья точка
готовности арта в редакторе; неточная аналогия в риске golden). Полного разбора
ТЗ заново не делаю — см. «Унаследовано из r1» ниже. Разбираю: (а) закрывает ли
правка обе находки r1 по существу, а не по заявлению; (б) не завела ли сама
правка новую неоднозначность в контракте или AC, которую дельта затрагивает
(изменённые разделы: §2 п.3, §4.2 таблица методов, §4.3 «Запуск и бут», §4.6
таблица свидетелей, §6 AC7, §6.2 риск golden, §8 затронутые файлы).
## Как проверялось
- `git diff bb180899..ce08dc2c -- docs/specs/474-lazy-furniture-art.md` — построчно.
- Каждое новое фактическое утверждение сверено с деревом на `ce08dc2c` (код не
менялся с r1, дерево то же, что и в r1, плюс сам ТЗ):
- `src/editor-runtime-loader.ts` — подтверждён `EditorRuntimeLoaderOptions.install:
(runtime) => void`, вызывается из `_loadWithRetry()` один раз после
конструктора и до `_setState('ready')` — ровно то, на что ссылается новый
текст §4.3 («install в EditorRuntimeLoader редактора»), это не домысел;
- `src/decor-image-editor.ts:271/282` (`renderFurniturePalette`, `preview`) и
`src/houseplan-editor-runtime.ts:4931` (`_renderFurniturePlacementPreview`) —
имена и точки вызова, названные в правке, существуют, номера строк сходятся
с точностью до контекста;
- `demo/golden/harness.mjs:818` (`ensureIsoRuntime`) — реальный прецедент,
на который теперь ссылается исправленный риск в §6.2, вместо снятой ложной
аналогии с языком;
- полный текст ТЗ на `ce08dc2c` прочитан целиком, чтобы дельта (два абзаца)
не проверялась в отрыве от остального контракта — так нашлась находка ниже.
- Гейты (`typecheck`/`test`/`build`/`bundle:budget`) не гонялись: этап spec,
продуктового кода по задаче нет — прогон был бы гейтом на пустом месте, как и
в r1.
## Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
| **High** — единственная точка запуска `ensure()` (приём конфига) не покрывает открытие палитры/призрака в редакторе на конфиге без мебели; AC7 ломается для сценария «первый предмет» | Добавлена третья, синхронная точка готовности: `FurnitureArtRuntime.adopt(art, fingerprint)`, вызываемая из `install` редакторного `EditorRuntimeLoader` при статическом импорте арта редактором. `pending` в редакторе теперь структурно невозможен: `adopt` отрабатывает до первого рендера палитры, не дожидаясь `ensure()`/содержимого конфига | §4.2 (новая строка `adopt` в таблице методов), §4.3 абзац «Редактор — третья точка, синхронная (ревью r1)», AC7 переформулирован под «pending в редакторе не бывает», новый свидетель `furniture-art-editor-adopt-skipped` (§4.6), гард которого — `smoke_furniture` на конфиге без мебели (тот же смок и то же условие `decor=[]`, что и в воспроизведении r1) |
| **Low** — риск §6.2 ссылался на несуществующее ожидание `LANGUAGE_RUNTIME` в harness «как ждёт язык» | Формулировка заменена на реальный прецедент `ensureIsoRuntime`; дополнительно риск усилен требованием, чтобы harness бросал, если в сцене с мебелью `.dfurn` меньше числа предметов конфига (fallback должен быть красным, а не пустым кадром) | §6.2, строка «Golden-сцены с мебелью станут недетерминированными» |
Обе находки закрыты по существу, не только по заявлению: механизм `adopt`
проверяется реальным контрактом `EditorRuntimeLoader.install`, а не новым
самостоятельным изобретением, и ссылка на `ensureIsoRuntime` — существующий код,
а не повторная неточная аналогия.
## Унаследовано из r1
Без повторной проверки в этом раунде принято всё, чего дельта не касалась
(документ `docs/reviews/SPEC-REVIEW-474-r1.md`, SHA `bb180899`):
- сценарий и «что человек увидит» (§1.1–1.2), продуктовая рамка и связь с
персоной `docs/SCOPE.md`;
- разрез каталог/арт (§4.1) и единственная точка чтения арта во View
(`houseplan-card.ts` `furnitureGraphic`), перевод магнита `furniture-placement`
на `furnitureSymbol`;
- корректность образца `LanguageRuntime` и нонс-механизма (`hp_retry`) как базы
контракта `FurnitureArtRuntime`;
- `core-file-budget` и заявление «ядро не растёт» (числа не менялись дельтой);
- не-скоуп по `houseplan-space-card` (§3);
- i18n-ключ `toast.furniture_art_load_failed` (не занят, по образцу
`toast.locale_load_failed`);
- нумерация и полнота обязательных разделов §7.1, явный блок предположений (§9),
связь issue↔ТЗ.
Эти пункты дельта r1→r2 не трогает ни текстуально, ни по содержанию (см. diff
выше — правки только в §2 п.3, §4.2, §4.3, §4.6, AC7, §6.2, §8), поэтому
переносятся без повторной проверки.
## Находки этого раунда
### [Medium, в скоупе] Счётчик свидетелей в AC9 и §8 не обновлён после добавления седьмого
**Файл:** `docs/specs/474-lazy-furniture-art.md`, AC9 (раздел 6) и раздел 8
(«Затронутые файлы»).
Правка r1→r2 добавила в таблицу §4.6 новую строку — седьмой свидетель
`furniture-art-editor-adopt-skipped` (гард `install` редактора не вызывает
`adopt`) — не убрав ни одной из прежних шести. Итого в §4.6 сейчас семь строк:
`furniture-art-eager-import`, `furniture-art-fallback-never-settles`,
`furniture-art-no-retry-nonce`, `furniture-art-boot-gate-ignored`,
`furniture-placement-needs-art`, `furniture-art-fingerprint-unchecked`,
`furniture-art-editor-adopt-skipped`.
При этом:
- AC9: «**Шесть** свидетелей §4.6 в реестре, каждый «поймано 1 из 1»» — число не
правлено этим коммитом (в r1-версии ТЗ, где строк было шесть, формулировка была
верна: r1-документ ревью прямо фиксирует «шесть свидетелей §4.6», см.
`docs/reviews/SPEC-REVIEW-474-r1.md`, «Чего не проверял»);
- §8 «Затронутые файлы»: «`scripts/mutation-gate.mjs` — **шесть** мутантов» — та
же стале число, тот же коммит её не тронул.
Это не спор о поведении — контракт по существу понятен и AC7 закрыт корректно
(находка выше). Но code review будет сверять реестр мутантов с AC9 буквально
(«шесть, каждый поймано 1 из 1») и рискует не заметить необходимость завести
седьмой мутант `furniture-art-editor-adopt-skipped` в `mutation-gate.mjs`, если
проверять только по счётчику, а не по факту чтения §4.6. AC должен быть
самодостаточным числом, а не требовать сверки с другой таблицей, которая была
изменена позже.
**Что нужно ТЗ:** заменить «шесть» на «семь» в AC9 и в §8 (`scripts/mutation-gate.mjs`
— семь мутантов), либо явно сослаться на §4.6 без числа. Это правка на месте
(в скоупе задачи, не отдельный issue) — Medium без High даёт жёлтый вердикт.
## Что проверено и корректно (сверх наследуемого)
- Новый метод `adopt` в §4.2 не противоречит остальной таблице: идемпотентность
(«повторный adopt — no-op»), проверка отпечатка ровно как у `ensure()` — общее
защитное свойство теперь явно распространено на оба входа, и `furniture-art-fingerprint-unchecked`
в §4.6 обновлён («ensure и adopt»), а не оставлен только для одного пути.
- AC7 переформулирован согласованно с текстом §4.3 (то же «pending в редакторе не
бывает», тот же список смоков) — не осталось двух разных описаний одного и
того же сценария в разных разделах.
- §6.2 golden-риск теперь описывает поведение, согласованное с §4.3 (единый
бут-гейт `hpboot`, ожидание встроено, а не отдельная golden-специфичная
реализация) — не вводит второй, конкурирующий механизм ожидания.
- Идентификаторы, на которые ссылается правка (`EditorRuntimeLoaderOptions.install`,
`renderFurniturePalette`, `preview`, `_renderFurniturePlacementPreview`,
`ensureIsoRuntime`), существуют в дереве под теми же именами — утверждение о
поведении не выдано за факт без основания.
## Чего не проверял
- Всё, что перечислено в «Унаследовано из r1» — не проверялось повторно, дельта
этих разделов не касается.
- Численные пороги AC1 и реализуемость семи (после исправления счётчика) свидетелей
как мутантов в `scripts/mutation-gate.mjs` — как и в r1, это код, которого пока
нет; переносится на code review.
- Гейты (`typecheck`/`test`/`build`/`bundle:budget`/`golden`/смоки) не гонялись —
этап spec, кода по задаче ещё нет.
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/474-lazy-furniture-art`, коммит `ce08dc2c7102` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `b087deec17ea42c9cd87f4738a90b69f7deba132`
```
git log --all --format='%H %T' | grep b087deec17ea
```
- ТЗ `docs/specs/474-lazy-furniture-art.md`, блоб `9ac07c2aad7a940779d0fb060e74524fc492afbb`
```
git log --all --find-object=9ac07c2aad7a940779d0fb060e74524fc492afbb -- docs/specs/474-lazy-furniture-art.md
```