# SPEC-REVIEW-62-r2 - **Issue:** https://github.com/Matysh/houseplan-card/issues/62 - **ТЗ:** `docs/specs/062-i18n-registry.md` - **Материал ревью:** ветка `issue/62-i18n-registry`, SHA `0a203649` - **Заход:** r2 (повторный, разбор по дельте — PROCESS.md §2.10, issue #214) - **Предыдущий раунд:** SPEC-REVIEW-62-r1, SHA `21d47c52`, вердикт жёлтый (High: 0, Medium: 1 → в задаче), документ `docs/reviews/SPEC-REVIEW-62-r1.md` - **Трек:** полный (без изменений с r1) — критерий `small` не выполняется, задета class A i18n сразу в нескольких поверхностях. ## Дельта `git diff 21d47c52..0a203649` затрагивает ровно один файл — `docs/specs/062-i18n-registry.md`, +8/-2 строк, два места: 1. §9 (i18n и документация) — добавлен абзац о судьбе существующей строки `Ground rules` в `CONTRIBUTING.md`. 2. §10 (AC и доказательства) — уточнены формулировки доказательств AC2, AC5, AC8. Комментарий автора от 2026-08-27 подтверждает тот же объём: «убран ложный scope lazy loading, исправлена политика документации, добавлен compatibility-контракт … доказательства AC» — но фактический diff между r1 и r2 меньше объявленного: lazy loading и compatibility-контракт неизвестного языка (§6.3/§8) были частью диапазона **до** r1 (SHA `21d47c52` уже их содержал и был материалом r1), в диапазоне r1→r2 их нет. Не расхождение с текущей проверкой — просто автор описал изменения с более раннего SHA, чем зафиксированный r1; дельта r1→r2 сама по себе локальна и не требует полного разбора (§2.10: правка не меняет контракт поведения, не задевает новую подсистему, размер несопоставим с задачей). Дешёвые гейты (`typecheck`/`test`/`build`) не прогонялись по той же причине, что и в r1: диапазон `origin/dev...HEAD` не содержит ни одного файла class A/B, только документы. Продуктового кода по-прежнему нет — это ожидаемо для этапа ТЗ. ## Закрытие раунда r1 | Находка r1 | Чем закрыта | Где это видно | | --- | --- | --- | | **M1** (Medium, в скоупе): §9/AC9 добавляют новый раздел «Translations», но не отменяют существующую в `CONTRIBUTING.md` строку Ground rules «one JSON file + registering it in `src/i18n.ts`» — реализация оставит два противоречащих flow | В §9 добавлен явный абзац: «Существующая строка в `Ground rules` … не остаётся рядом вторым контрактом: она заменяется ссылкой на новый раздел и формулировкой про frontend/backend JSON и `src/i18n/registry.ts`» | `docs/specs/062-i18n-registry.md:196-199` (diff `21d47c52..0a203649`) | | **L1** (Low, снят с записью в r1, не требовал правки): AC2 без явного маркера «Доказательство:» | Добавлен явный маркер | `docs/specs/062-i18n-registry.md:209` — «**Доказательство:** unit-тест pure resolver.» | | **L2** (Low, снят с записью в r1, не требовал правки): AC5/AC8 используют слово «inspection» вместо канонического словаря доказательств | Слово «inspection» убрано из обеих AC, заменено на дифф-ориентированные формулировки | `docs/specs/062-i18n-registry.md:217` — «unit на pure options helper и source diff `src/editor.ts` без ручного списка локалей»; `:225` — «static registry source diff + успешный production build» | M1 был единственной блокирующей (Medium) находкой r1. Формулировка в §9 конкретна и исполнима: указывает, что именно происходит со старой строкой (заменяется, а не остаётся вторым источником истины) и чем — ссылкой на новый раздел плюс актуальным описанием flow. Проверено чтением: `CONTRIBUTING.md:49` на текущий момент действительно содержит цитируемую в r1 строку `Adding a language = adding one JSON file + registering it in src/i18n.ts.` — референт находки не устарел, и правка §9 бьёт точно по нему. L1/L2 не требовали правки по вердикту r1 («снимается без правки текста ТЗ»), но автор закрыл их тоже — это не создаёт риска и не меняет решение раунда. Отдельно проверено: новая формулировка AC8 («static registry source diff + успешный production build») не ослабляет доказательство относительно версии r1. Утверждение AC8 — «в production bundle нет dynamic import/Promise-based translation path» — при отсутствии `import(` в исходниках (что показывает `source diff`) гарантированно не воспроизводится и в бандле статическим TypeScript/Rollup пайплайном; сам r1 уже принял эквивалентный по строгости метод («inspection») как допустимую категорию «проверено чтением, не исполнением» (см. L2 в r1). Понижения строгости нет. ## Унаследовано из r1 Без повторной проверки в r2 приняты следующие выводы SPEC-REVIEW-62-r1.md (SHA `21d47c52`), поскольку дельта r1→r2 их не задевает: - Обязательные разделы §7.1 ТЗ присутствуют полностью (сценарий, что человек увидит, проблема, скоуп/не-скоуп, контракт поведения, UX, модель данных и миграция, i18n, AC1–AC9, план автотестов, риски, откат, release-артефакты). - Продуктовых вопросов владельцу по существу нет; пограничный случай (неизвестный сохранённый `language` в редакторе, §6.3/AC6) решён автором обоснованно, без домысливания и без необходимости эскалации. - Резолюция языка (§6.2) построчно проверена на эквивалентность текущему рантайму для всех обычных значений HA locale; AC7 не нарушается. - Заявление «English/Russian пользователь изменений не увидит» подтверждено чтением: единственная новая видимая ветвь (временная option) активируется только для кода, отсутствующего в registry. - Тестовая стратегия (§11) опирается на уже используемый в проекте паттерн (`test-build/*.js`), а не изобретает новый. - Non-scope (§5), откат (§13) и release-артефакты (§14) заполнены осмысленно. - Трек (полный) и его обоснование соответствуют умолчанию AGENTS.md/#338. - Фактические утверждения ТЗ о текущем коде (`src/i18n.ts`, `src/editor.ts`, `test/i18n.test.mjs`, `custom_components/houseplan/translations/`, `tsconfig.test.json`, `src/types.ts:276`) сверены с деревом в r1 и дельта r1→r2 их не меняет — код не изменился, диапазон `origin/dev...HEAD` по-прежнему содержит только документы. ## Что проверено в r2 и признано корректным - AC2/AC5/AC8 (§10) после правки используют канонический словарь доказательств (`unit`, diff, «успешный production build») без потери проверяемости метода. - §9 больше не оставляет `CONTRIBUTING.md` с двумя конфликтующими описаниями contribution flow — инструкция для реализации однозначна. - Изменение локально: не задевает контракт поведения (§6), не открывает новую подсистему, не требует ребейза (origin/dev не продвинулся вперёд — `git merge-base origin/dev HEAD` совпадает с текущим tip `dev`, `fffe9fb1`). ## Чего не проверял и почему - **Гейты `typecheck`/`npm test`/`npm run build`/`check-docs.mjs`/smoke/golden/ backend pytest** — не запускались, как и в r1: диапазон `origin/dev...HEAD` по-прежнему не содержит ни одного файла class A/B, только `docs/**`. Продуктового кода нет — гонять их не на чем на этапе ТЗ. - **Инварианты модели / `smoke-select.mjs`** — не применимо, дельта не затрагивает геометрию, `layout`, `marker.space`, `open_spans`, код вообще. - Полный повторный разбор ТЗ (сценарий, non-scope, риски, откат и т.д.) не проводился по правилам §2.10 — дельта локальна и не задевает эти разделы; соответствующие выводы наследуются из r1 (см. раздел выше) без риска регрессии, так как сами разделы текстуально не менялись между `21d47c52` и `0a203649`. ## Вердикт Единственная Medium-находка r1 закрыта конкретной, исполнимой формулировкой в §9, оба Low-замечания закрыты сверх требуемого. Новых находок дельта r1→r2 не вносит. High нет, Medium нет. **Вердикт: зелёный · заход r2 · блокирующих циклов 1/4 · High: 0 · Medium: 0**