Контролируемый стенд (upload/epf/МакетТабличныйДокумент) вскрыл четыре
системных расхождения подряд. После правок 7 макетов стенда из 10 проходят
раундтрип БАЙТ В БАЙТ обоими портами — до этого ни один.
1. Объявление языков макета жёстко писалось как «только русский». Это не то же
самое, что textLanguages: почти во всех макетах ERP объявлен один ru, а текст
лежит и под ru, и под en, поэтому выводить одно из другого нельзя. Заведены
недокументированные ключи languages / currentLanguage / defaultLanguage —
автору они не нужны, нужны раундтрипу. defaultLanguage несём, а не выводим:
«всегда ru» — наблюдение на четырёх русских типовых, а не правило формата.
2. <font> писался в каждом формате. Платформа пишет его только когда шрифт
задан: треть форматов корпуса (23 003 из 69 581) обходится без него.
3. Декомпилятор считал шрифт с индексом 0 «обычным» и не писал его в стиль.
Нулевой шрифт вовсе не обязан быть обычным — в макетах стенда он курсивный
и жирный, и начертание терялось.
4. Формат, несущий ТОЛЬКО шрифт, выглядел пустым: у ячейки он получал
зарезервированное имя default и не записывался, у строки терялся целиком.
Остаток на стенде — три макета, и все три про одно: ссылка ячейки на запись
ширины, оставшуюся от прежнего состояния документа. Это не воспроизводится
принципиально, разобрано в docs/1c-spreadsheet-spec.md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Мы регистрировали формат по умолчанию первым, из-за чего вся палитра шла
со сдвигом относительно платформенной. На корпусе он последний в 8285 макетах
из 10 863, первым — в 25.
Подтверждено контролируемым стендом: в макетах, где ширины заданы на уровне
документа, палитра идёт «ширины колонок в порядке колонок, умолчание последним».
Порядок палитры не виден в семантическом диффе (правило palette-index разрешает
ссылки и тем самым его прячет), поэтому мерялся отдельно: на пилоте совпавших
с оригиналом записей с начала палитры стало 467 из 2274 против 23, палитр,
совпавших целиком, — 4 против 2.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
У строки есть собственный формат: платформа хранит в нём скрытие (17 423 вхождения
в корпусе), шрифт (9 216), фон, выравнивания, защиту. Мы писали туда только высоту,
всё остальное теряли.
Разбор на контролируемом стенде показал, что это два разных случая, а не один.
Оформление, применённое к строке целиком, платформа пишет И строке, И каждой
ячейке (backColor: 13 899 ячеек повторяют против 96). Скрытие — только строке
(24 026 против 62 856). Поэтому одного правила «rowStyle красит ячейки» мало.
Теперь rowStyle — стиль строки: по умолчанию ложится и на строку, и на ячейки,
как это делает платформа. Объектная форма { style, apply } задаёт исключения:
"row" — только строке, "cells" — только ячейкам. Модификатор нужен раундтрипу,
в описании DSL его нет.
Скрытие и высота — собственные свойства строки, ключами рядом: у ячейки таких
свойств не бывает, и в её оформление они не попадают.
На пилоте категория row[].formatIndex упала с 1964 до 201 потерянного факта.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Снэпшоты mxl-decompile/mxl-info/mxl-validate строятся preRun-прогоном
mxl-compile. Дрейф одного вида: четыре одинаковые стороны рамки стали
одним <border>.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Снэпшоты mxl-decompile/mxl-info/mxl-validate строятся preRun-прогоном
mxl-compile, поэтому дрейфуют вместе с ним. Дрейф ровно двух видов:
убран избыточный <i> и схлопнуты пустые строки в indexTo.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Две правки по корпусу и по 1С-сертификации.
fillType=Text платформа практически не пишет: на выборке корпуса 344 981 текстовая
ячейка из 348 023 (99,1%) ссылается на формат БЕЗ fillType — наличие <tl> и так
означает текст. Parameter и Template платформа пишет, их оставляем. Правило то же,
что и везде: эмитим то, что эмитит платформа, а не то, что верно в рантайме.
Идентификатор колоночной раскладки платформа хранит как UUID и другой не принимает —
макет с <id>узкая</id> она отвергала целиком. Имя, похожее на UUID (то есть пришедшее
декомпиляцией), проходит насквозь, иначе поехал бы раундтрип; читаемое имя автора
превращается в UUID ДЕТЕРМИНИРОВАННО, из хэша имени, чтобы повторная компиляция
давала тот же файл. Оба порта дают одинаковый хэш.
Дефект с идентификатором нашла 1С-сертификация: ни юнит-кейсы, ни раундтрип по
корпусу его не видели — там идентификаторы приходят из исходных макетов и уже
являются UUID.
Дрейф 33 снэпшотов разобран построчно, посторонних строк нет: 116 сменившихся
индексов формата, 49 удалённых fillType, 43 перестановки свойств внутри палитры,
16 границ <format> (палитра стала короче).
Проверено: тесты 53/53 на обоих рантаймах, verify-snapshots 23/23.
Замечание на будущее: на корпусе эта правка снимает лишь 170 расхождений из 64 865
в категории формата ячейки. Основная причина другая — платформа даёт неоформленной
ячейке ссылку на формат по умолчанию, а компилятор заводит ей собственный формат
с <font>. Это отдельный заход, он сдвинет снэпшоты повторно.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Инкремент A кампании mxl-roundtrip. Блочная форма DSL не выражала больше половины
корпуса: у 34% макетов ERP есть строки вне именованных областей, у 21% нет ни одной
области типа Rows. Декомпилятор такие строки терял, а на макетах целиком из
Rectangle отдавал areas: [] — компилятор отвечал "Required field 'areas' is missing".
На пилоте из 40 макетов это 10 отказов из 26.
Что сделано:
- имя у блока стало необязательным. Блок без имени — просто кусок сетки; именованную
область он не создаёт. Отдельный «плоский режим» не нужен: макет без выразимых
блоков это один безымянный блок;
- namedAreas — именованные области координатами, для всего, что блоком не ложится
(не-Rows и пересекающиеся). Тип области НЕ указывается: он выводится из заданных
осей, ровно как в ТабличныйДокумент.Область() — только строки дают полосу строк,
только колонки полосу колонок, обе оси прямоугольник. Так нельзя написать
противоречие вроде type: Rows с колоночными координатами;
- диапазон записывается уже существующей грамматикой DSL (как ключи columnWidths):
число или "N-M". Список через запятую запрещён — область непрерывна, платформа
разрывную не хранит;
- прощающим вводом принимается платформенный адрес "R1C1:R2C2" и правило «0 значит 1»;
в документацию не вынесено;
- декомпилятор перестал пропускать области не-Rows (там стоял безусловный continue) и
режет сетку на блоки детерминированно: непересекающиеся Rows задают границы, дыры
становятся безымянными блоками, остальное уходит в namedAreas.
Отдельно: именованные элементы теперь эмитятся отсортированными по имени. Платформа
хранит их именно так — на выборке 541 макета с несколькими элементами иного порядка
нет ни разу. Сортировка ординальная и регистронезависимая; Sort-Object по умолчанию
сортирует по текущей культуре и на кириллице дал бы другой порядок. Отсюда дрейф 13
снэпшотов — чистая перестановка, диффы симметричны, число элементов не изменилось.
На пилоте отказы areas: [] закрыты полностью (10 → 0), цикл переживают 24 макета
вместо 14. Оставшиеся 16 отказов — колоночные раскладки, это инкремент B.
Правка на ps1, зазеркалена в py; вывод портов и в компиляции, и в декомпиляции
совпадает байт в байт.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Конфигуратор не пишет перевод строки в конце файла — последний байт `>`. Это видно
на чистой выгрузке пустой ИБ (Windows и macOS) и на всех 8 выгрузках в cfsrc.
Наши эмиттеры добавляли лишний, причём оба порта и по разным причинам:
- PS: StringBuilder.AppendLine дописывает Environment.NewLine после последней строки;
- PY: '\n'.join(lines) + '\n' — хвост добавлен явно.
В meta-compile заведена единая точка записи Write-XmlFile: там документ собирают
и AppendLine, и явные `n в билдерах Predefined/Content/Flowchart, а выходов семь.
В остальных обрезка стоит в самом вызове записи.
Модули .bsl, JSON-выход form-compile, HTML-справка help-add и XSD из xdto-decompile
сюда НЕ входят: канон Конфигуратора описывает XML метаданных, а у этих артефактов
свои правила. Результаты XmlDocument.Save тоже не трогаются — у них хвоста нет.
Навыки редактирования продолжают сохранять стиль ВХОДНОГО файла: кейс
subsystem-edit/roundtrip-crlf-preserve, где фикстура намеренно с хвостом, остаётся
зелёным. Это контракт #44/#46/#47, и он не отменяется.
Дрейф снэпшотов: 547 файлов, у каждого только последняя строка, содержательных
изменений ноль. Тесты 641/641.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add 195 new test cases covering examples from SKILL.md, edge cases,
and parameter combinations. Create _skill.json for form-edit, skd-edit,
subsystem-edit. Add fixtures for negative validate cases. Fix
normalizeUuids in meta-validate/meta-info configs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>