Платформа хранит текст ячейки по элементу на язык. Декомпилятор брал ПЕРВЫЙ и терял
остальное, компилятор писал всегда ru захардкоженно. В корпусе ERP текст лежит и под
ru, и под en у 10 730 макетов из 10 924 — то есть терялось у 98%.
Форма взята готовая — конвенция ML-значений из docs/meta-dsl-spec.md §4.4, по которой
уже живут synonym, tooltip и title в метаданных и формах: строка означает русский
текст, объект даёт по надписи на язык в порядке ключей. Новых понятий не вводили,
ключи те же (text и template).
Документный ключ для языков НЕ заводили, и это измерение, а не экономия: блок
languageSettings мы и так эмитим байт в байт как платформа (currentLanguage ru,
defaultLanguage ru, один languageInfo). Отклонения редки — 8 макетов ERP с
currentLanguage en, 3 без него, 157 с объявленной парой ru+en, всего около 1,6%.
Заодно это снимает развилку из разбора PR #62: список языков компилятор дописывать
не должен, платформа его не дописывает.
Эффект на пилоте: категория row[].cell[].tl упала с 47 252 до 12 488 — минус 74%,
самое крупное улучшение кампании. Остаток частично классифицирован: 348 строк — ячейки
с ПУСТЫМ <tl> у оригинала, которых мы не эмитим вовсе; полностью разобрать мешает
обрезка диффа по 400 строк на объект.
Снэпшоты не дрейфанули: кейсы пишут текст строкой, и вывод для неё прежний.
Проверено: тесты 54/54 на обоих рантаймах, verify-snapshots 24/24, вывод портов
совпадает байт в байт и в компиляции, и в декомпиляции.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Инкремент B изменил DSL, а документация осталась от предыдущей версии.
Добавлены columnSets в карту структуры и в таблицу верхнего уровня, раздел про
колоночные раскладки со ссылкой columnSet у области, оговорка что columns: 0 —
допустимая величина (все строки живут в именованных раскладках) и что позиции
колонок проверяются по ширине раскладки своей области.
Из ограничений убран пункт про несколько наборов колонок: теперь поддержаны.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Продолжение чистки протёкшей реализации.
- «тип заполнения: param → Parameter, text → Text, template → Template» — автор DSL
ключ fillType не пишет и в выводе mxl-compile его не видит, это имена XML-перечисления.
Заменено на то, что действительно нужно: содержимое задаётся одним из ключей param /
text / template, где template — текст со вставками [Параметр]. Раньше синтаксис вставок
в инструкции не упоминался вовсе, хотя он куда полезнее перечисления. (У mxl-info
fillType остаётся: там навык объясняет свой собственный вывод.)
- «компилятор создаёт ячейки для ВСЕХ колонок строки» — механика. Оставлен наблюдаемый
контракт: стиль применяется ко всей ширине строки, оттуда сплошные рамки.
- «заданное имя компилятор разворачивает в именованную область типа строки» — то же самое.
Теперь сказано, что даёт имя автору: область доступна как ПолучитьОбласть("Имя").
- убран пункт «"|" продолжает ячейку, только если её позиция известна явно». Он ссылался
на поведение, которого в документации нет (позиция ячеек без col выводится прощающим
вводом), то есть документированное ограничение опиралось на недокументированную
механику. Случай закрыт сообщением об ошибке.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Продолжение чистки после перечитывания глазами модели, которая применяет навык.
- из раздела ограничений убраны доли по корпусу ERP. Это результат исследования, а не
то, что помогает применять навык: модель работает с конкретным макетом, а не с
популяцией, и числа стареют. Перечень того, что теряется при round-trip, остался
списком; замеры живут в материалах кампании;
- фраза про ошибки короткой формы была вырвана из контекста: шла после списка
ограничений, начиналась с символа в кавычках, и до самого конца было непонятно, что
речь про отказ. Плюс в один ряд попало разнородное — три случая про сам шорткат и
переполнение columns, которое к короткой форме не привязано. Переписано правилами:
маркеру нужно, что продолжать; объектный элемент не несёт col; элементов не больше
columns. Поведение при нарушении — одной фразой в конце;
- в SKILL.md ключевые правила шли вперемешку по уровням (страница, ячейка, строка,
ячейка, область). Пересобраны сверху вниз: документ → область → строка → ячейка;
- буллет про namedAreas сокращён: обнаружимость ключа даёт карта структуры, а из
правил там неочевидно только отсутствие ключа type.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Раздел ограничений врал в обе стороны. Он обещал потерю областей Columns и
Rectangle — они поддержаны предыдущим коммитом; и молчал про то, что теряется на
самом деле. Проверено по коду обоих навыков, доли — по корпусу ERP 8.3.24:
ячейки-поля ввода (53% макетов), несколько наборов колонок (63%), объединения вне
ячеек (16%), рисунки (2%), цвета, скрытые строки, отступ, посторонние стили линий,
группировки, колонтитулы и параметры печати. Отдельно записано, что многоязычные
надписи не поддерживаются: при разборе берётся первый вариант текста, при генерации
язык всегда ru — для двуязычных макетов остальные языки теряются.
Заодно убрано то, что описывает реализацию, а не использование:
- таблицы с точными текстами сообщений об ошибках и кодом возврата. Модель, вызвавшая
навык, видит и текст, и код прямо в выводе; документировать их незачем, а протухают
они молча — ровно как протух раздел ограничений. Правила, из-за которых ошибка
возникает, остались; сами строки зафиксированы в кейсах через expectError, где
расхождение ловится механически. В остальных пяти спеках таких таблиц и не было —
там принята одна фраза «ненулевой код выхода и сообщение в stderr»;
- фраза про порядок эмиссии именованных элементов: автор DSL на него не влияет.
Сам факт (платформа хранит их отсортированными по имени) перенесён в
docs/1c-spreadsheet-spec.md, где описывается XML-уровень, вместе с оговоркой,
что случай с «ё» не проверен.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Перечитал инструкцию глазами модели, которая приходит делать макет:
- в карте структуры отсутствовал ключ namedAreas — модель, которой нужна область
из колонок (в печатных формах это обычное дело), из инструкции не узнала бы, что
такое вообще выразимо. Карта верхнего уровня должна быть полной;
- в одном предложении соседствовали «область» и «блок». Платформа знает только
«область», второй термин появился по дороге — убран из инструкции и спеки;
- пример строк-массивов висел без подводки.
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>
Фраза «та же форма, что у макетов в /skd-compile» ничего не даёт модели, которая
про DSL СКД не знает, и подталкивает к лишнему ту, которая знает: рядом с rows
там живут widths, minHeight, пресеты стилей и параметры с drilldown, которых в
макете табличного документа нет. Совпадают только четыре соглашения внутри строки,
а «та же форма» читается как «работает так же целиком».
Правило и пример описывают форму полностью и без ссылок вовне. Происхождение
решения осталось в комментариях кода, где оно адресовано сопровождающему.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Строка, записанная массивом ("rows": [["А","Б","В"]]), молча превращалась в
пустую строку в обоих портах. Форма не выдумана: ровно так документированы
макеты в skd-compile, и привычка естественно переносится на табличный документ.
Масштаб потери был виден в самом репозитории — ПЯТЬ кейсов семейства mxl-*
написаны в этой форме и потому проверяли пустые макеты: снэпшот
lenient-key-case содержал единственную строку <empty>true</empty>. После правки
все пять снэпшотов наполнились ячейками, которые терялись.
Семантика повторяет skd-compile: позиция ячейки — индекс в массиве, ">"
продолжает ячейку слева (span), "|" — сверху (rowspan), null пропускает
колонку, "{Имя}" даёт параметр. Элемент можно записать и объектом, когда нужен
style или detail; col в нём запрещён — это смешение двух способов адресации.
Разворот идёт отдельным пред-проходом в обычные строки с явными col/span/rowspan,
поэтому остальной компилятор о короткой форме не знает.
Форма документирована — в отличие от прощающего пропуска col: модель пишет канон
соседнего навыка, и выравнивание двух табличных DSL убирает развилку. По каскаду
в SKILL.md только правило и пример, подробности и таблица ошибок — в спеке
(обе копии: docs/ и reference/ навыка).
Правка на ps1, зазеркалена в py: вывод портов совпадает байт в байт, decompile →
compile возвращает исходный XML байт в байт.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Приводим авторский контент (.ps1/.psm1/.py/.mjs/.md/.json, пин .bsl)
к единому LF и закрепляем политикой в .gitattributes. Инструмент правки
всегда пишет LF, поэтому единый LF убирает EOL-шум в диффах, ложные
срабатывания blame и налог на ручную синхронизацию CRLF-файлов.
BOM на .ps1 сохранён (git с eol=lf меняет только CR<->LF, BOM не трогает).
Данные 1С (*.xml) и бинарники под нормализацию не берём.
Гейт: PS-порт 459/459, Python-порт 459/459, web-test E2E 22/22 (с пересборкой стенда).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- New skill /img-grid: overlays numbered grid on images to help
determine column proportions for MXL template generation
- Add "page" field to MXL DSL ("A4-landscape", "A4-portrait", or
number) that auto-calculates defaultWidth from column proportions
- Update DSL spec, mxl-compile SKILL.md, MXL guide, README
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allows specifying column widths as multiplier of defaultWidth (e.g. "2x",
"0.5x") alongside absolute values. Makes template generation from images
easier — model specifies proportions instead of exact pixel values.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Decompiler: remove styles not referenced by any cell or rowStyle
- Decompiler: compress consecutive empty rows into {"empty": N}
- Compiler: support {"empty": N} row placeholder
- DSL spec: document empty field on rows
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shared spec for mxl-compile and future mxl-decompile.
Compiler SKILL.md now references the spec instead of inlining it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>