Files
houseplan-card/docs/reviews/SPEC-REVIEW-363-r1.md
T
2026-08-29 09:23:00 +00:00

183 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-363-r1
Issue: #363 · Этап: spec (PROCESS.md §2.4) · Трек: `small` (лёгкий) · Заход r1 ·
блокирующих циклов израсходовано 0 из 2 (лимит лёгкого трека — 2, §5)
## Скоуп
ТЗ в теле issue #363: возврат кнопки «Добавить» в основной тулбар Device
editor рядом с «Устройства» — короткий путь к уже существующему диалогу
нового устройства (`_openMarkerDialog()` без аргумента), убранной в `cab8d128`
(#29) вместе с каталогом «Устройства». Каталог не трогается. Класс изменения —
A (`src/houseplan-editor-runtime.ts`, три словаря `src/i18n/*.json`) плюс C
(`docs/USER-GUIDE*.md`, оба changelog). Метка `small` подтверждена в
аналитике владельца (S2): сложность 2/10, одна поверхность, миграций нет,
нового UX-контракта нет (контракт — тот же, что до #29).
## Важное обстоятельство состояния (проверить перед чтением остального)
В issue уже есть более ранняя попытка этого же захода: комментарий от
`claude` (2026-08-29T09:16:10Z, жёлтый вердикт, `Заход r1 · блокирующих
циклов 1/2 · High: 0 · Medium: 1`) и закоммиченный на `dev`
`docs/reviews/SPEC-REVIEW-363-r1.md` (коммит `9d6d6eb9`, тот же SHA, что и
текущий HEAD). Тот документ нашёл **M1**: раздел «Release-артефакты» не
называл обязательный прогон workflow «Скриншоты документации» и
`docs:accept --reviewed`, из-за чего `docs`-job в CI Validate стал бы
красным по расхождению `sourceFingerprint`, даже если ни один PNG не
изменился (сценарий #230/#234).
Задача даёт этому заходу метаданные `Заход r1 · 0 из 2` — то есть с точки
зрения конвейера предыдущая попытка цикл не потратила: судя по всему, тот
прогон не дошёл до финального структурированного ответа (без него, по
инструкции конвейера, метка не переставляется), поэтому официально не
засчитан, а issue не уходил в `S3-spec`. Тем не менее тело issue уже
переписано в «ТЗ · revision 2» и текстуально закрывает M1 (см. ниже) — то
есть автор (владелец, пишущий ТЗ прямо в issue на лёгком треке) увидел
незасчитанный комментарий и поправил текст до этого захода. Я не доверяю
этому на слово и ниже перепроверяю сам, что revision 2 действительно
закрывает M1 и что остальные утверждения черновика остаются верными на
текущем дереве. Раздела «Унаследовано из r<N-1>» не завожу — по счётчику
конвейера это первый действительный заход, и я перепроверил всё заново, а
не по дельте.
## Как проверялось
Ничего не принято на слово из текста ТЗ или прежнего черновика — каждое
утверждение перепроверено чтением дерева на `HEAD=9d6d6eb9`:
1. **M1 закрыт.** AC7 сейчас: «...полный артефакт принимается через `npm run
docs:accept -- --reviewed --from=<artifact>`, а обновлённый
`docs/images/screenshots.json` коммитится... Все PNG канонического набора
(сейчас 10) ожидаются пиксельно неизменными». Раздел «Release-артефакты»
дублирует то же требование и явно называет workflow «Скриншоты
документации» обязательной «даже если видимая композиция кадров не
меняется». Проверил, что названные команда и workflow существуют:
`.github/workflows/docs-screenshots.yml` (шаг публикует
`docs/images/screenshots.json` артефактом), `package.json:16` —
`"docs:accept": "node scripts/docs-accept.mjs"`. Прежний черновик просил
именно это, только называл «9 PNG» — сейчас в дереве
`demo/docs/screenshots.mjs` действительно **10** сценариев (проверил
`grep -n "id:" demo/docs/screenshots.mjs` и `docs/images/screenshots.json
→ scenarios.length`), то есть текущее ТЗ точнее черновика, а не расходится
с деревом задним числом.
2. **`_openMarkerDialog()` жив, контракт не меняется.**
`src/houseplan-editor-runtime.ts:7628` `public _openMarkerDialog(d?:
DevItem)`; вызов без аргумента — путь диалога нового устройства. Кнопка
«Устройства» вызывает другой метод, `_openDeviceInbox()`
(`houseplan-editor-runtime.ts:11545`), а «Добавить виртуальное устройство»
внутри каталога вызывает тот же `_openMarkerDialog()` без аргумента
(`houseplan-editor-runtime.ts:11578`, `openVirtual`). Значит новая кнопка
получает ровно тот же путь, что уже используется каталогом для того же
исхода — вторая, независимая проверка того, что AC2 просит воспроизводимую,
а не новую логику.
3. **i18n-таблица побайтово совпадает с состоянием до `cab8d128`.**
`git show cab8d128^:src/i18n/en.json` и `...ru.json` дают ровно
`"devbar.add": "Add"` / `"Добавить"` и `"title.add_device": "Add a device
to the plan"` / `"Добавить устройство на план"` — совпадает посимвольно с
таблицей ТЗ. Оба ключа сейчас отсутствуют во всех трёх словарях
(`grep -n "devbar.add\|title.add_device" src/i18n/{en,ru,de}.json` — пусто),
значит работа по их возврату реальна, а не фиктивна.
4. **Немецкий текст — согласованное предположение, не догадка.** `de.json`
уже использует `"device_inbox.add": "Hinzufügen"` для того же действия и
паттерн «существительное + hinzufügen» для похожих подписей
(`"title.add_space": "Bereich hinzufügen"`). Предложенные `"Hinzufügen"` /
`"Gerät zum Plan hinzufügen"` этому соответствуют. Помечено в ТЗ как
принятое предположение, которое ревьюер вправе оспорить — не оспариваю.
5. **Паритет словарей ловит забытую локаль.** `test/i18n.test.mjs:109-112`:
`assert.deepEqual(Object.keys(dictionary).sort(), enKeys)` для каждого
языка реестра. Пропуск любого из 6 значений (2 ключа × 3 локали) красит
`npm test`. AC4 доказуемо этим тестом, и тест умеет падать (сейчас ключей
нет ни в одном словаре — не найти это на голом дереве, если ключ забыт,
тест обязан споткнуться).
6. **Место вставки и порядок.** Текущий `_renderDevicesBar()`
(`houseplan-editor-runtime.ts:11541-11553`) начинается с кнопки
`device_inbox.button` («Устройства»), затем `devbar.rules` («Правила
иконок»). До #29 первой кнопкой была «Добавить»
(`git show cab8d128^:src/houseplan-card.ts` — фрагмент, приведённый в теле
issue, подтверждён отдельно). Вставка новой кнопки перед «Устройства»
восстанавливает этот порядок; номера строк в S2-аналитике (`:11491`)
немного разошлись с текущими из-за более поздних коммитов — не находка,
метод и разметка на месте.
7. **Каталог и его «Добавить виртуальное устройство» не задеты.**
`_renderDeviceInbox()` / `openVirtual()` вне диапазона правок ТЗ.
`demo/smoke_device_inbox.mjs` существует, его заголовок прямо ссылается на
#29 («one lifecycle catalog replaces the separate Add / hidden-device
paths») — подходящий существующий регресс-щуп для AC3.
8. **RU/EN руководство действительно потеряло строку.**
`docs/USER-GUIDE.ru.md:775-786` — таблица «Редактор устройств» содержит
«Устройства» и «Добавить виртуальное устройство», строки про «Добавить»
нет. `docs/USER-GUIDE.md:519-529` — список без пункта «Add». Оба файла
названы в «Затронутых файлах».
9. **Golden-сцены разведены верно.** `demo/golden/matrix.mjs:381` —
`geometry-devices-editor-dark`: `mode: 'devices'`, **без** ключа `dialog` —
тулбар виден целиком, третья кнопка попадёт в кадр. `device-inbox-*`
(строки 383-390) все три несут `dialog: 'device-inbox'` — модальный
каталог перекрывает тулбар, эти кадры не должны измениться.
`--expect-change=geometry-devices-editor-dark` в AC8 — точная и
единственная нужная пометка.
10. **UX-MODES.md / TOUCH-SUPPORT.md** — персистентный инструмент в основном
тулбаре, `barclose` остаётся в правом торце (`editbar-end`, не тронут);
новых touch-целей и жестов не вводится. Конфликта с «редакторы
desktop-first, touch — best effort» нет.
11. **Обязательные разделы §7.1** — сценарий+результат, скоуп/не-скоуп,
контракт поведения и UX, данные/совместимость (модель не меняется),
i18n, AC1-AC8 с доказательством каждого, план тестов и мутанты, риски и
откат, release-артефакты — все присутствуют в теле issue.
12. **Продуктовые вопросы, которые могли уйти владельцу как технические** —
не найдены: три «принятых предположения» (CSS-классы/wrap, отсутствие
отдельного disabled-state, немецкий перевод) — все технические/оформ-
ительские, ни одно не требует продуктового решения.
## Гейты этого захода
Материал — только текст issue, продуктового кода по #363 в дереве ещё нет
(`git log --all --oneline | grep 363` и `git branch -a | grep 363` не находят
ветки/коммитов задачи, кроме случайных числовых совпадений `3633a3db`
(#159), `9d6d6eb9`/это же ревью). Прогонять `typecheck`/`test`/`build`/
`check-docs` не над чем — это ревью текста (§2.4), а не кода (§2.7); их место
в коде-ревью после реализации. Отдельно перечитал и вручную проверил
исполняемость `test/i18n.test.mjs` (пункт 5) и существование
`demo/smoke_device_inbox.mjs`, `.github/workflows/docs-screenshots.yml`,
`scripts/docs-accept.mjs` чтением, не запуском — их сегодняшнее содержимое,
а не будущее поведение, было предметом проверки.
## Находки
Нет. M1 предыдущего (незасчитанного) захода закрыт текстом ТЗ (см. пункт 1
выше) и проверен по дереву, а не на слово. Догадок, выданных за решение, не
найдено. Технических вопросов, которые следовало решить самому вместо
эскалации владельцу, не найдено — их и не было.
## Что проверено и корректно
- Обработчик `_openMarkerDialog()` и его контракт (пункт 2).
- Побайтовое совпадение i18n-таблицы с состоянием до `cab8d128` и паритет-тест
(пункты 3, 5).
- Согласованность предложенного немецкого текста с действующим словарём
(пункт 4).
- Место вставки и восстановленный порядок кнопок (пункт 6).
- Независимость каталога и его «Добавить виртуальное устройство» (пункт 7).
- Пропуск строки тулбара в RU/EN руководстве (пункт 8).
- Разведение golden-сцен `geometry-devices-editor-dark` vs `device-inbox-*`
(пункт 9).
- Отсутствие конфликта с UX-MODES.md / TOUCH-SUPPORT.md (пункт 10).
- Полнота обязательных разделов ТЗ §7.1 и отсутствие невынесенных
продуктовых вопросов (пункты 11-12).
- Закрытие M1 предыдущего захода текстом revision 2 (пункт 1).
## Чего не проверял
- Реализацию — её ещё нет; код-ревью (§2.7) проверит diff, а не текст ТЗ.
- Фактический прогон `typecheck`/`test`/`build`/`check-docs`/golden — не
применимо к этому заходу, материала для прогона (diff) не существует.
- Browser-смоки и golden-захват — то же самое, нечего запускать.
- Реальный CI-прогон workflow «Скриншоты документации» — оценивалась только
корректность его упоминания в ТЗ, а не его будущее исполнение.
## Вердикт
Зелёный. High: 0, Medium: 0. ТЗ полно, однозначно, каждый AC привязан к
способу доказательства, единственная находка предыдущей (незасчитанной)
попытки закрыта текстом и подтверждена чтением дерева. Трек `small`
подтверждён повторно.