Files
houseplan-card/docs/reviews/SPEC-REVIEW-354-r1.md
T
2026-08-28 14:45:28 +00:00

174 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-354-r2
- **Issue:** https://github.com/Matysh/houseplan-card/issues/354
- **Этап:** ревью ТЗ (PROCESS.md §2.4), лёгкий трек (`small`)
- **Заход:** r2 · блокирующих циклов израсходовано 1 из 2 (лимит ТЗ на лёгком треке — 2; r1 был жёлтым и потратил 1 цикл — §4/#227)
- **ТЗ:** тело issue #354, «Ревизия 2» (файл в `docs/specs/` отсутствует — корректно для `small`)
- **SHA на момент ревью:** `149b2af7` (`dev`, рабочее дерево чистое; с момента r1 (`77302eaf`) в код не внесено ни одного продуктового коммита — единственный новый коммит `149b2af7` кладёт документ ревью r1, продуктового/тестового кода не касается)
- **Вердикт: зелёный**
## Примечание о нумерации захода
Стартовые данные этой сессии указывали «Заход: r1 · блокирующих циклов
израсходовано 0 из 2». Это не соответствует фактическому состоянию: в
`docs/reviews/SPEC-REVIEW-354-r1.md` (закоммичен `149b2af7`) и в комментариях
issue уже есть завершённый раунд r1 — жёлтый вердикт от `claude` (комментарий
`IC_kwDOTOcLQM8AAAABRRPAyw`, 2026-08-28T14:40:01Z, SHA `77302eaf`), за которым
последовала правка автора («Ревизия 2 ТЗ по r1», комментарий
`IC_kwDOTOcLQM8AAAABRRPa0g`) и возврат метки `S4-spec-review`. Раунд, который
разбирает эта сессия, — второй по факту (`r2`), а не первый; бюджет цикла к
этому моменту уже потратил 1 из 2 (жёлтый вердикт r1 расходует бюджет по §4).
Документ поэтому назван и пронумерован как `r2`, вопреки стартовым данным —
иначе он затёр бы уже существующий `SPEC-REVIEW-354-r1.md` или конфликтовал
бы с ним по номеру, ровно тот сценарий, от которого предостерегает сам номер
захода. Расхождение стартовых данных со стоянием репозитория — само по себе
не блокирует эту задачу, но стоит показать тому, кто обслуживает конвейер.
## Скоуп
Без изменений относительно r1: собрать продакшн-`LANGUAGE_RUNTIME` в
`src/i18n/registry.ts` как `new LanguageRuntime(...)` вместо рукописного
литерала (`germanDictionary`/`germanPending`/`germanFailed`/`settleGerman`),
чтобы существующий `test/i18n-runtime.test.mjs` действительно проверял код
продакшна, плюс попутный (N7) тост при отказе загрузки словаря локали.
Ревизия 2 не меняет предмет задачи и не расширяет её — правит формулировку
одного контракта (К2) и переименовывает один i18n-ключ. Конфликта со
`docs/SCOPE.md` по-прежнему нет (см. SPEC-REVIEW-354-r1.md, раздел «Скоуп» —
наследуется, ниже).
## Дельта r1 → r2
`git diff <SHA r1>..HEAD` не показателен: SHA r1 (`77302eaf`) и текущий
(`149b2af7`) отличаются только doc-коммитом ревью r1, продуктового кода нет
вообще (стадия ТЗ). Предмет дельты — правка тела issue #354, зафиксированная
автором как «Ревизия 2 ТЗ по r1» (комментарий `IC_kwDOTOcLQM8AAAABRRPa0g`).
Сверено построчно с текстом, процитированным в `SPEC-REVIEW-354-r1.md`:
1. **К2** — было (цит. по r1, находка M1): «Тост показывается ... Карточка
подписывается при подключении... показывает тост» (без указания, какая из
четырёх поверхностей рендер-гейта). Стало: «Тост показывается ТОЛЬКО в
`houseplan-card` (View — единственная поверхность с тост-инфраструктурой
`_showToast`)... Остальные три поверхности рантайма (`space-card`,
GUI-редакторы обеих карточек) остаются при `console.warn`, как сейчас, —
тост-инфраструктура там не заводится.»
2. **Ключ тоста** — было `i18n.load_failed` (находка L1). Стало
`toast.locale_load_failed`, в К2 и в AC4.
3. Остальной текст (К1, К3, AC1–AC3, «Откат», трейлер `User-Visible: yes`)
не изменился — сверено посимвольно с цитатами в `SPEC-REVIEW-354-r1.md`
(разделы «Что проверено и корректно», «Скоуп»).
Дельта локальна (правка формулировки одного контракта плюс переименование
одного ключа), не задевает новую подсистему, не меняет контракт поведения
сверх уже согласованного в r1, по объёму несопоставима с исходной задачей —
условие «разбор остаётся полным» (PROCESS.md §2.10) не наступает. Разбор
этого раунда ограничен дельтой: заново проверялись только К2 (N7) и ключ
тоста — единственное, что дельта задевает.
## Как проверялось (r2)
1. Прочитано текущее тело issue #354 целиком, сверено с цитатами r1 —
найдены ровно две правки (см. «Дельта» выше), больше отличий нет.
2. Прочитан комментарий владельца «Ревизия 2 ТЗ по r1» — подтверждает, что
обе правки целенаправленно закрывают M1 и L1, а не что-то другое.
3. Перечитан текст К2 revision 2 на однозначность: названа ровно одна
поверхность (`houseplan-card`/View), явно перечислены три поверхности,
остающиеся при `console.warn`, явно сказано «тост-инфраструктура там не
заводится» — двух прочтений эта формулировка больше не допускает.
4. `grep -n '"toast\.' src/i18n/en.json` — подтверждён неймспейс `toast.*`
(40+ существующих ключей); `grep -rn "locale_load_failed\|i18n.load_failed"
src/ test/ demo/` — пусто: новый ключ не конфликтует с существующим кодом
и ещё не реализован (ожидаемо для стадии ТЗ).
5. `grep -n "6.3\|houseplan-space-card" docs/specs/348-german-localization.md`
— подтверждён раздел «6.3. Render gate» и список из четырёх поверхностей,
на который опирается формулировка К2 (та же ссылка, что использовал r1).
6. `git log 77302eaf..HEAD --oneline` — один коммит (`149b2af7`, doc r1),
без изменений в `src/**`/`test/**`: код и его состояние идентичны
зафиксированным в r1, повторная проверка К1/К3/AC1–AC3 по коду не нужна.
Гейты (`tsc`/`test`/`build`) не гонялись — стадия ревью ТЗ, кода по задаче ещё
нет; как и в r1, это не пропуск, а неприменимость этапа.
## Находки
Нет. High: 0, Medium: 0, Low: 0.
Обе находки r1 закрыты правкой текста, новых находок дельта не вносит.
## Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
| **M1** (Medium, в скоупе) — К2 не называл, на какой из четырёх поверхностей рендер-гейта показывается тост N7; формулировка «Карточка» в единственном числе была совместима с двумя разными объёмами работы. | К2 переписан: «Тост показывается ТОЛЬКО в `houseplan-card` (View...)... Остальные три поверхности рантайма (`space-card`, GUI-редакторы обеих карточек) остаются при `console.warn`, как сейчас, — тост-инфраструктура там не заводится.» Формулировка совпадает с предложенным в r1 вариантом по умолчанию почти дословно. | Тело issue #354, раздел «Контракт», К2, первый и последний абзацы. |
| **L1** (Low, зафиксирована) — ключ `i18n.load_failed` был единственным вне пространства `toast.*`. | Ключ переименован в `toast.locale_load_failed` — и в К2, и в AC4. | Тело issue #354, К2 («новым ключом `toast.locale_load_failed`») и AC4 («текстом `toast.locale_load_failed`»). |
## Унаследовано из r1
Без повторной проверки в этом раунде — код и тесты с r1 не менялись
(единственный новый коммит — doc-коммит ревью, класс C), проверка велась
только над текстом ТЗ:
- **Скоуп задачи и соответствие `docs/SCOPE.md`** — принято по
`SPEC-REVIEW-354-r1.md`, раздел «Скоуп» (SHA `77302eaf`).
- **К1 (замена литерала на `new LanguageRuntime(...)`) реализуема без
побочных поломок** — все четыре вызывающих места используют только
контракт `state/dictionary/ensure` — принято по `SPEC-REVIEW-354-r1.md`,
раздел «Что проверено и корректно», пп. 1–2 (SHA `77302eaf`, строки кода
`houseplan-card.ts:10713`, `editor.ts:118`, `space-card.ts:766`,
`space-editor.ts:60`).
- **АС1–АС3 однозначны и механически проверяемы** (grep, instanceof-юнит,
мутационный тест на К3) — принято по `SPEC-REVIEW-354-r1.md`, раздел «Что
проверено и корректно» (SHA `77302eaf`); текст АС1–АС3 в ревизии 2 не
менялся (сверено построчно, см. «Дельта» выше).
- **Паритет-тесты (`test/i18n.test.mjs`) действительно стерегут новый ключ
независимо от его имени** — принято по `SPEC-REVIEW-354-r1.md`, пп. 7 и
L1 (SHA `77302eaf`); вывод не зависит от конкретного имени ключа, поэтому
переименование в `toast.locale_load_failed` его не меняет.
- **Существующий смок `demo/smoke_german_locale.mjs` уже содержит сценарий
«оба ретрая упали → English»**, в который AC4 добавляет проверку тоста без
новой инфраструктуры смоков — принято по `SPEC-REVIEW-354-r1.md`, п. 8
(SHA `77302eaf`).
- **Подписка/отписка (К2) соответствует принятой конвенции
`subscribeXxx(...)`** — принято по `SPEC-REVIEW-354-r1.md`, п. 9 (SHA
`77302eaf`).
- **Открытый нефинирующий пункт для код-ревью**: не проверялось, как
`subscribeLanguageLoadFailures`-колбэк получит код локали `de` из
`warn(message, error)` (сигнатура класса передаёт только текст). Не
находка (решаемо замыканием при единственном сегодня ленивом языке), но
стоит явно проговорить на код-ревью, если добавится второй ленивый язык —
перенесено из `SPEC-REVIEW-354-r1.md`, раздел «Чего не проверял».
## Что проверено и корректно (r2, по дельте)
- К2 revision 2 однозначен: ровно одна поверхность для тоста
(`houseplan-card`), явно перечислены три поверхности без тоста, явно
сказано, что новая тост-инфраструктура на них не заводится — двух
прочтений формулировка не допускает, находка M1 закрыта по существу, а не
косметически.
- Новый ключ `toast.locale_load_failed` следует существующей конвенции
именования тостов (проверено grep по `src/i18n/en.json`, 40+ ключей в том
же пространстве) и не конфликтует с уже существующим кодом (grep пуст).
- Правка не расширяет скоуп и не вводит новый UX-контракт: критерии лёгкого
трека (§5 PROCESS.md) по-прежнему выполнены — ревизия 2 их не колеблет
(одна поверхность тоста явно зафиксирована как единственная, а не
расширена на четыре).
- АС4 (после ревизии) по-прежнему проверяем механически: юнит на
`subscribeLanguageLoadFailures`, смок `smoke_german_locale` с проверкой
`card._toast`, мутационный тест на «тост выброшен».
## Чего не проверял
- Код по задаче ещё не написан (стадия ТЗ) — гейты `tsc`/`test`/`build` не
запускались, как и в r1; на этой стадии они неприменимы.
- Не проверял заново K1/K3/AC1–AC3 по коду — код с момента r1 не менялся
(см. «Дельта» и «Унаследовано из r1» выше), текст этих пунктов ТЗ тоже не
менялся.
- Не проверял реальные тексты переводов для `toast.locale_load_failed`
(en/ru/de) — их ещё нет; сверка с паритет-тестами и glossary
`docs/specs/348-german-localization.md` — задача код-ревью.
## Итог
Вердикт **зелёный**: обе находки r1 (M1 Medium, L1 Low) закрыты точечной
правкой текста, дельта не вносит новых находок и не задевает то, что r1 уже
принял. Issue переходит в `S5-ready`.