Ревью вскрыло два дефекта во вчерашней ветке добавления языка — оба
воспроизведены руками.
1. Миграция старой раскладки шла ДО проверки дубля языка. При дефолтном -Lang ru
(самый вероятный способ повторно позвать навык на старом макете) Template.html
уже был перенесён, затем срабатывал отказ «страница ru уже существует» — и
дескриптор не записывался вовсе. Макет оставался разобранным: страница есть,
дескриптора нет, платформа такую раскладку снова молча игнорирует. Печатавшийся
при этом [WARN] «создан дескриптор» был неправдой.
2. Файл страницы писался безусловно, а проверялся только список <Page> в
дескрипторе. При рассинхроне (страница на диске есть, в дескрипторе нет —
в том числе после дефекта 1) содержимое затиралось пустым скелетом с кодом 0.
Теперь ветка сначала разбирает состояние целиком и только потом пишет, файл
страницы не перезаписывается никогда: существующая страница подхватывается, в
дескриптор дописывается <Page>. Старая раскладка с -Lang ru — это не коллизия,
а ровно тот случай, ради которого миграция и нужна. Состояние, где есть и
Template.html, и Template/ru.html, навык не разруливает сам: отказ до изменений.
Плюс валидация -Lang: код языка идёт и в текст XML, и в имя файла, поэтому пустое
значение давало файл «.html» с пустым <Page></Page>, а разделитель пути — запись
мимо Ext/Template. Оба отказа платформы были бы тихими.
Четыре новых кейса закрывают каждый сценарий; паритет портов сверен побайтово.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>