16 KiB
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» не завожу — по счётчику
конвейера это первый действительный заход, и я перепроверил всё заново, а
не по дельте.
Как проверялось
Ничего не принято на слово из текста ТЗ или прежнего черновика — каждое
утверждение перепроверено чтением дерева на HEAD=9d6d6eb9:
- 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), то есть текущее ТЗ точнее черновика, а не расходится с деревом задним числом. _openMarkerDialog()жив, контракт не меняется.src/houseplan-editor-runtime.ts:7628public _openMarkerDialog(d?: DevItem); вызов без аргумента — путь диалога нового устройства. Кнопка «Устройства» вызывает другой метод,_openDeviceInbox()(houseplan-editor-runtime.ts:11545), а «Добавить виртуальное устройство» внутри каталога вызывает тот же_openMarkerDialog()без аргумента (houseplan-editor-runtime.ts:11578,openVirtual). Значит новая кнопка получает ровно тот же путь, что уже используется каталогом для того же исхода — вторая, независимая проверка того, что AC2 просит воспроизводимую, а не новую логику.- 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— пусто), значит работа по их возврату реальна, а не фиктивна. - Немецкий текст — согласованное предположение, не догадка.
de.jsonуже использует"device_inbox.add": "Hinzufügen"для того же действия и паттерн «существительное + hinzufügen» для похожих подписей ("title.add_space": "Bereich hinzufügen"). Предложенные"Hinzufügen"/"Gerät zum Plan hinzufügen"этому соответствуют. Помечено в ТЗ как принятое предположение, которое ревьюер вправе оспорить — не оспариваю. - Паритет словарей ловит забытую локаль.
test/i18n.test.mjs:109-112:assert.deepEqual(Object.keys(dictionary).sort(), enKeys)для каждого языка реестра. Пропуск любого из 6 значений (2 ключа × 3 локали) краситnpm test. AC4 доказуемо этим тестом, и тест умеет падать (сейчас ключей нет ни в одном словаре — не найти это на голом дереве, если ключ забыт, тест обязан споткнуться). - Место вставки и порядок. Текущий
_renderDevicesBar()(houseplan-editor-runtime.ts:11541-11553) начинается с кнопкиdevice_inbox.button(«Устройства»), затемdevbar.rules(«Правила иконок»). До #29 первой кнопкой была «Добавить» (git show cab8d128^:src/houseplan-card.ts— фрагмент, приведённый в теле issue, подтверждён отдельно). Вставка новой кнопки перед «Устройства» восстанавливает этот порядок; номера строк в S2-аналитике (:11491) немного разошлись с текущими из-за более поздних коммитов — не находка, метод и разметка на месте. - Каталог и его «Добавить виртуальное устройство» не задеты.
_renderDeviceInbox()/openVirtual()вне диапазона правок ТЗ.demo/smoke_device_inbox.mjsсуществует, его заголовок прямо ссылается на #29 («one lifecycle catalog replaces the separate Add / hidden-device paths») — подходящий существующий регресс-щуп для AC3. - RU/EN руководство действительно потеряло строку.
docs/USER-GUIDE.ru.md:775-786— таблица «Редактор устройств» содержит «Устройства» и «Добавить виртуальное устройство», строки про «Добавить» нет.docs/USER-GUIDE.md:519-529— список без пункта «Add». Оба файла названы в «Затронутых файлах». - 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 — точная и единственная нужная пометка. - UX-MODES.md / TOUCH-SUPPORT.md — персистентный инструмент в основном
тулбаре,
barcloseостаётся в правом торце (editbar-end, не тронут); новых touch-целей и жестов не вводится. Конфликта с «редакторы desktop-first, touch — best effort» нет. - Обязательные разделы §7.1 — сценарий+результат, скоуп/не-скоуп, контракт поведения и UX, данные/совместимость (модель не меняется), i18n, AC1-AC8 с доказательством каждого, план тестов и мутанты, риски и откат, release-артефакты — все присутствуют в теле issue.
- Продуктовые вопросы, которые могли уйти владельцу как технические — не найдены: три «принятых предположения» (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-darkvsdevice-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
подтверждён повторно.