Конфигуратор пишет <Vendor/>, а не <Vendor></Vendor>: в 8 выгрузках cfsrc
(476 943 XML) пустых пар ноль. Шаблоны подставляли значение ВНУТРЬ пары, поэтому
при пустом значении получалась пара.
Собираем элемент целиком: <Vendor>/<Version> (cf-init, cfe-init),
<DefaultRoles> (cfe-init при -NoRole), <Key> и <Namespace> (meta-compile —
план обмена и веб-сервис). Образец рядом же: <Comment> и <Description> в
meta-compile так делали и раньше.
Дефект был в ОБОИХ портах одинаково — здесь дело не в сериализаторе, а в шаблоне.
Пустая пара <Namespace> в cfe-borrow была не его: он копирует свойства
заимствуемого объекта, а порождал их meta-compile.
Дрейф снэпшотов: 340 <Vendor/>, 339 <Version/>, по одному <Key/>, <Namespace/>,
<DefaultRoles/>. Содержательных изменений ноль. Тесты 641/641.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
.NET XmlWriter пишет `<a />`, а Конфигуратор — `<a/>`. Поскольку Save переписывает
файл целиком, meta-edit при добавлении одного реквизита переводил в пробельную форму
все пустые теги документа. Дефект только у PS-порта: lxml (45 из 49 py-портов) уже
пишет плотно, то есть порты расходились побайтово.
Канон измерен, а не предположен: чистая выгрузка пустой ИБ на Windows и macOS плюс
сплошной скан 8 выгрузок в cfsrc — 476 943 XML, 21 294 119 самозакрывающихся тегов,
пробельных 0. Форма не зависит от ОС, версии платформы (8.3.20-8.5) и наличия
атрибутов. Правило уже было реализовано в skd-edit — оттуда и взято.
Замена безопасна доказуемо: .NET экранирует `>` как `>` и в тексте, и в атрибутах,
поэтому ` />` после Save — только конец тега. Лазейки (CDATA, комментарии) в
1С-метаданных не встречаются — 0 из 476 943 файлов; гард на них всё равно стоит.
Одиннадцать скриптов писали прямо в FileStream без пост-обработки — переведены на
MemoryStream, что заодно чинит `encoding="utf-8"` строчными (335 файлов в снэпшотах).
В cfe-borrow правится и сборка Form.xml: куски берутся из OuterXml, а он спацовывает
так же, как XmlWriter.
Дрейф снэпшотов: 12 838 строк тегов + 335 деклараций, содержательных изменений ноль.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Навык нужен ровно для одного: не втаскивать в контекст мегабайтную схему ради
одного поля. Чистота диффа тут ни при чём — она уже обеспечена round-trip'ом
(замер: правка двух вещей через decompile→compile даёт 3 изменённые строки из 241).
Поэтому edit не заводит второй эмиттер, а строится поверх round-trip'а: пакет
выгружается в XSD, операция применяется к схеме, пакет собирается обратно
компилятором. Байт-точность для нетронутого достаётся даром, а смена namespace
перегенерирует все объявления префиксов сама — в EnterpriseData_1_20_2 их 5280.
На лишний шаг (загрузка XSD в DOM и пересохранение) заведён отдельный харнесс:
холостая правка не меняет ни байта на всех 760 пакетах.
Операции: add/replace/remove-property, add/remove-type, add-enum, add-import,
rename, set-synonym, set-comment, set-namespace. Содержимое — всегда фрагмент
XSD, тем же языком, что в компиляторе; отдельных -MinOccurs нет, свойство
меняется целиком через replace-property. Адресация точкой, путь заходит внутрь
встроенных типов.
rename трогает три места (объект метаданных, имена файла и каталога, регистрацию
в Configuration.xml). set-namespace правит свой пакет и перечисляет зависящие,
но не меняет их: при версионировании они и должны смотреть на прежнее
пространство имён. После правки автоматически запускается xdto-validate.
Проверено загрузкой в базу 8.3.24: add-property, add-enum и set-namespace
переживают db-load-xml + db-update.
Попутные ловушки портирования (детали — debug/xdto/FINDINGS.md): пустой элемент
в lxml ложен, из-за чего "or"-цепочка создавала бы вторую частицу в типе
с пустой sequence; диапазон [Ѐ-ӿԀ-ӿ] валиден в .NET и не компилируется в Python.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>