mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-04 21:58:56 +00:00
174 lines
16 KiB
Markdown
174 lines
16 KiB
Markdown
# 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`.
|