17 KiB
SPEC-REVIEW-348-r1
- Issue: https://github.com/Matysh/houseplan-card/issues/348
- Этап: spec (PROCESS.md §2.4)
- Заход: r1 (первый и единственный документ ревью на этот issue)
- Ветка / SHA материала:
issue/348-german-localization@2e650a02(один коммитdocs: specify German localizationповерхdev@918fc9e2) - Трек: полный (обоснование в S2-analysis корректно: несколько поверхностей, новый языковой/loading UX-контракт, влияние на perf budget и touch — критерии §5 не проходят одновременно)
- Вердикт: зелёный
Скоуп ревью
Диф origin/dev..origin/issue/348-german-localization — только класс C:
docs/specs/348-german-localization.md | 385 +++++++++++++++++++++++++
docs/specs/README.md | 1 +
Продуктового кода нет, гейты code-уровня (typecheck/test/build) к
предмету ревью неприменимы — это ревью текста ТЗ, а не кода. Ниже —
раздел «Гейты и проверки» с тем, что фактически было прогнано для проверки
технических утверждений документа.
Как проверялось
Ревью состязательное: документ прочитан целиком, каждое проверяемое
техническое утверждение сверено с реальным состоянием origin/dev, а не
принято на слово автора.
- Зависимость #62. Проверено
gh issue view 62—S8-merged, то есть инфраструктура (typed registry, locale resolution, parity gates) уже вdev, а не гипотетическая. Прочитанsrc/i18n/registry.ts:LANGUAGE_REGISTRY,resolveLanguageCode(exact → primary → fallback),languageOptions— контракт locale resolution, который ТЗ обещает не менять, действительно существует в описанном виде. - Бюджет initial View. Число «255 910 B gzip из 256 000 B» — не
принято на веру: собран бандл с
origin/dev(npm run build+node scripts/bundle-budget.mjs), результат:initial View: 255910 B gzip,lazy editor: 131779 B gzip— точное совпадение с ТЗ, включая экстремально узкий запас (90 B).INITIAL_VIEW_GZIP_BUDGET = 256_000подтверждён вscripts/bundle-budget.mjs. - Классификация lazy-групп в манифесте. Прочитан
scripts/bundle-manifest.mjs: сейчас ровно два динамических класса (lazyOnboardingFilesпо имени чанка, всё остальное —lazyEditorFiles). Требование ТЗ добавить третий классlazyLocaleFiles— реальное изменение этого файла, и он прямо назван в §12 «Затронутые файлы» — не забыт. - Прецедент lazy-loading + bounded retry. Найдены
EDITOR_RETRY_ASSET_TOKEN/ONBOARDING_RETRY_ASSET_TOKENвscripts/bundle-manifest.mjsи рабочиеawait import('./houseplan-editor-runtime')/import('./houseplan-onboarding-runtime')вsrc/houseplan-card.ts, а также браузерный тестdemo/smoke_lazy_editor_chunk.mjsс перехватом маршрута (page.route). План §6 (dedupe, page-lifetime cache, bounded retry, fail-open English, fingerprint) и план тестов AC4/AC5 (задержанный импорт, provoked failure) — не фантазия, а расширение уже работающего в продукте паттерна на новый субъект (locale вместо editor/onboarding). - Терминология и реальность строк. Проверены по
src/i18n/en.jsonключи, стоящие за глоссарием ТЗ:markup.partition→ «Partition»,markup.column→ «Column»,space.zero_wall_style→ «Zero-thickness walls»,decor.fill→ «Fill»,space.glow_enabled/marker.glow_radius_label→ «Glow» и т.д. — термины глоссария не изобретены, они соответствуют реальным строкам продукта. Сверено сdocs/USER-GUIDE.ru.md: «Space» → «Пространство» в действующей русской терминологии, немецкое «Bereich» не противоречит смыслу. - Мёртвые legacy-ключи.
editor.lang_en/editor.lang_ruвsrc/i18n/en.jsonсуществуют и не встречаются больше нигде вsrc/*.tsиtest/*.mjs— заявление §7 «доказанно неиспользуемые» подтверждено поиском, а не принято на слово. - Backend translations.
custom_components/houseplan/translations/en.jsonреально содержит толькоconfig/options/issues— соответствует §3.1 («config flow, options flow и repair issue»). - CONFIG-COMPATIBILITY.md не упоминает
languageвовсе — подтверждает заявление ТЗ «languageостаётся строковым полем без изменения schema и миграции», а не пропуск темы. - 390 px как канонический touch-viewport. Подтверждено по
demo/smoke_*.mjs(card_controls,color_picker,gear_tabs,plan_pickerи др. используютwidth: 390) — ссылка ТЗ на этот размер в §8 не выдумана. - Существование release-артефактов.
docs/USER-GUIDE.md,docs/USER-GUIDE.ru.md,docs/TESTING.md, обаCHANGELOG*.mdсуществуют — §12/§15 указывают на реальные файлы. - Обязательные разделы §7.1 PROCESS.md. Сценарий (§1), что человек увидит до/после (§2), скоуп/не-скоуп перевода (§3), контракт поведения (§4–9), модель данных и миграция (§5, §14 — «миграция не нужна»), AC1…AC10 с доказательством (§10), план автотестов (§11), риски (§13), откат (§14), release-артефакты (§15) — присутствуют по существу, не только по заголовку.
Находки
Ни одной находки уровня High или Medium. Два Low-замечания, оба решением ревьюера сняты без правки (документ остаётся годным для DoR), с записью причины ниже — как того требует §12 PROCESS.md («Оставили в тексте ревью» не считается закрытием, поэтому обе оставлены явной записью, а не формулировкой «доработать»).
L1 — de-CH унаследует «ß», хотя стандартная швейцарская орфография его не использует
docs/specs/348-german-localization.md, §4 правило 3 («Используются
настоящие ä, ö, ü, ß…») применяется к единственному словарю de, на который
по §5 резолвится и de-CH. Реальный швейцарский стандартный немецкий не
использует «ß» вовсе (пишет «ss»), поэтому носитель de-CH увидит
орфографически нетипичный для своего региона текст.
Почему не блокирует. Это решение — прямое следствие уже принятого на этапе S2-analysis и не оспоренного владельцем "safe default" — «de-DE/de-AT/de-CH используют общий de» (единый словарь для регионов был явно объявлен и принят молчанием владельца по §2.2 до написания ТЗ). Требовать от одного словаря одновременно двух орфографий — уже отдельная, более крупная задача (региональные варианты внутри одного языка), а не пробел этого ТЗ. Дефект не функциональный: интерфейс остаётся читаемым, AC2 (locale resolution) не страдает.
Решение ревьюера: снято с записью. Если в будущем швейцарские пользователи укажут на несоответствие, это отдельный issue на региональный вариант орфографии, не возврат текущего ТЗ.
L2 — явного блока «принято предположительно, поменять свободно» в конце документа нет
PROCESS.md §7.1 предписывает собирать не-продуктовые технические решения в отдельный блок в конце ТЗ, чтобы ревьюер мог их оспорить одним взглядом. В этом документе такие решения (устройство page-lifetime cache, форма dedupe, retry policy, разбиение ролей в manifest) разбросаны по §6–§7 как формулировки контракта, а не собраны отдельным блоком.
Почему не блокирует. По содержанию все технические решения либо прямо привязаны к проверяемому AC (AC4, AC5, AC6, AC7 — это не «свободно меняемые предположения», а часть контракта, который тестами и будет доказываться), либо повторяют уже работающий в проекте паттерн (editor/onboarding lazy-loading, retry-asset token). Оспаривать в них нечего — ревью выше по каждому пункту нашло реальное покрытие, а не догадку. Форматное требование не задевает проверяемость ТЗ.
Решение ревьюера: снято с записью, правка не нужна.
Что проверено и признано корректным
- Классификация трека (полный) и перечисление нарушенных критериев §5 в S2-analysis — соответствует содержанию задачи.
- Зависимость #62 реально
S8-merged, её API (LANGUAGE_REGISTRY,resolveLanguageCode,languageOptions) совпадает с тем, что ТЗ обещает расширить, а не заменить. - Locale resolution matrix (§5) не меняет существующую политику exact →
primary → English — подтверждено чтением
resolveLanguageCode. - Заявленный текущий bundle budget (255 910 / 256 000 B gzip) — точное, а не приблизительное число; проверено сборкой.
- План тестов (AC1–AC10) — для каждого назван реалистичный, уже
прецедентный на проекте способ доказательства (unit registry-parity,
Playwright semantic smoke, delayed-import smoke по образцу
smoke_lazy_editor_chunk.mjs, bundle-manifest unit). - Не-скоуп (§3.2) корректно исключает контент, который карточка принципиально не переводит нигде (имена HA-сущностей, значения, README) — согласовано со SCOPE.md («мы не редактируем реестр HA», «UI, не документация»).
- Откат (§14) не требует миграции данных — подтверждено отсутствием
languageв CONFIG-COMPATIBILITY.md. - Оба changelog, оба User Guide, TESTING.md существуют как файлы — release artifacts (§15) указывают на реальные, а не гипотетические цели правки.
- Открытых продуктовых вопросов действительно не осталось: все пять дефолтов, которые ТЗ фиксирует как решённые (native label, единый словарь для de-*, отсутствие перевода HA-контента, English fallback, отсутствие регрессии EN/RU), были явно объявлены и приняты по правилу «молчание — согласие» ещё в S2-analysis, до написания ТЗ — это соответствует предписанному в PROCESS.md порядку (продуктовые вопросы решаются пачкой, с дефолтом, не в спеке задним числом).
Чего не проверял и почему
- Гейты
typecheck/test/build/bundle:budgetна самой ветке задачи — diff ветки не содержит кода (толькоdocs/specs/**), гейты этого рода проверяют код, а не текст ТЗ; прогон дал бы тот же результат, что и наdev, и ничего не доказал бы про качество спецификации. Вместо этого сборкаdevиспользована лишь как источник факта (текущий bundle budget), см. пункт 2 «Как проверялось». node scripts/check-docs.mjs— diff не касаетсяsrc/**, условие запуска (PROCESS.md §8) не выполнено.- Смоки, golden, backend pytest — нет кода для прогона; они появятся только на этапе реализации и будут предметом код-ревью.
- Точный итоговый размер lazy-loader кода (риск «Loader превышает initial budget даже без словаря», §13 ТЗ) — не проверяем и не можем проверить на этапе спецификации: кода ещё нет. Риск в документе назван явно, с мерой («только доказанная очистка мёртвых i18n keys, budget не повышается») и с проверкой через AC6 (bundle-manifest/budget unit) — этого достаточно для DoR; если реализация не уложится, это остановит код-ревью, а не проходит на этом этапе незамеченным.
- Ручной аудит немецкого перевода на естественность/грамматику — вне полномочий этого ревью (ревьюер ТЗ не носитель и не переводчик); проверена структура контракта (glossary, правила капитализации, placeholders, no-English-fallback gate), а не текстовое качество конкретных строк, которых на этапе ТЗ ещё и не существует (кроме примеров таблицы §4).
Унаследовано из предыдущего раунда
Неприменимо — это первый и единственный заход (r1), лимит циклов ТЗ на полном треке (4) не тронут.
Итог
ТЗ полное, проверяемое, все десять AC имеют названный способ доказательства,
технические утверждения документа сверены с реальным состоянием репозитория
и не являются догадками, выданными за факт. Продуктовые вопросы закрыты
корректно на этапе аналитики. Два Low-замечания сняты с записью причины.
Задача готова к переходу в S5-ready.