Регресс из ExtendedTooltip own-content коммита: при own-layout (Width/Height/…) +
форматированный мультиязычный Title объектная форма теряла текст и formatted.
Причины: (1) merge брал $textVal['text'] на плоском мультиязычном {ru,en} (без
ключа text) → null-текст → пустой <Title>; (2) formatted не захватывался явно, а
компилятор не re-детектит markup на мультиязычном dict → formatted="false".
Фикс: разводим обёртку {text,formatted} от мультиязычного {ru,en} по наличию
ключа 'text'; formatted берём ЯВНО из атрибута <Title formatted>.
Форма erp/МобильноеПриложениеЗаказыКлиентов/ФормаГлавногоУзла → round-trip match.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Баг: Emit-PictureDecoration брал $el.picture (тип-ключ = имя элемента) фолбэком
источника картинки → при отсутствии src писал <xr:Ref>ИмяДекорации>. Фикс:
источник картинки — ТОЛЬКО src.
<xr:Abs> (встроенная картинка, 131 в корпусе): декомпилятор ловил лишь xr:Ref →
теперь src:"abs:Имя" → <xr:Abs>Имя</xr:Abs> (префикс abs:, иначе <xr:Ref>).
Порядок: LabelDecoration эмитил Title перед own-content, а платформа — layout-first
(корпус 16970 vs 44). Переставил флаги/hyperlink/layout/оформление ПЕРЕД Title (как
ExtendedTooltip) — заодно убирает шум атрибуции харнесса на многострочном Title
(Height «уезжал» на родительскую группу; контент был корректен, ломалась line-
атрибуция). Форма МобильноеПриложениеПредприниматель → round-trip match.
Зеркало py (байт-в-байт). Снэпшоты events/element-appearance/additional-columns
обновлены (только порядок) и пере-сертифицированы в 1С. Регресс 39/39 ps1+py.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Пустой <Settings xsi:type="v8:TypeDescription"/> у ValueList (список без
ограничения типа) — частый случай (в корпусе пустых 1893 vs непустых 864).
Три состояния valueType: нет ключа → нет Settings; "" → пустой <Settings…/>;
тип → с типом. Компилятор эмитит по присутствию ключа (включая ""); декомпилятор
для пустого Settings пишет маркер "". (ValueList без Settings вовсе — 58%, без
ключа valueType.)
Зеркало py. Кейс attributes-types: + СписокЛюбой с valueType:"" (пустой Settings),
сертифицирован в 1С. Регресс 39/39 ps1+py.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ключ valueType у реквизита формы: <Settings xsi:type="v8:TypeDescription"> —
уточнение типа значений у реквизита типа ValueList (СписокЗначений). В корпусе
341/341 именно на ValueList. Грамматика значения = как у type (включая составной
"A | B" и квалификаторы string/decimal/date).
Forgiving-синонимы: typeDescription (1С «ОписаниеТипов» / зеркало XML xsi:type),
описаниеТипов, типЗначений — канон valueType (декомпилятор пишет его). ≠ дин-список
Settings (xsi:type="DynamicList", отдельный ключ settings).
Emit-Type параметризован тегом-обёрткой (Type / Settings), Decompile-Type работает
на любом type-узле. Зеркало py (байт-в-байт). Кейс attributes-types (составной
string(50)|decimal(10,2)) сертифицирован в 1С. Регресс 39/39 ps1+py.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Помогаем модели правильно вывести тип: принимаем англ. без префикса и рус.имя,
приводим к каноничному v8:X (эмитится verbatim):
- StandardPeriod / СтандартныйПериод → v8:StandardPeriod
- StandardBeginningDate / СтандартнаяДатаНачала → v8:StandardBeginningDate
- UUID / УникальныйИдентификатор → v8:UUID
- СписокЗначений → ValueList (v8:ValueListType)
Раньше bare StandardPeriod падал в "Unrecognized bare type" и эмитился без
префикса (невалидно). Input-сахар (декомпилятор пишет каноничный v8:). Зеркало
py. Кейс attributes-types использует рус. СтандартныйПериод (вывод тот же,
сертифицирован). Регресс 39/39 ps1+py.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ключ save на реквизите формы (<Save><Field>…):
- true → <Field>имя</Field> (голое имя, 93% случаев)
- строка/массив строк → под-поля с авто-префиксом "имя." (путь с точкой,
UUID 1/0:guid, или совпадающее с именем — берутся как есть)
- нет ключа или false → не эмитим
Гипотеза подтверждена на корпусе: Field=имя в 383/410 (93%); gating формовыми
SaveDataInSettings/AutoSaveDataInSettings НЕ требуется (51/160 форм с Save без них).
Период-кейс (голое имя Период + Период.EndDate/StartDate/Variant) round-trip
бит-в-бит. Переиспользует механику нормализации useAlways. ≠ savedData (отдельное,
уже было). Декомпилятор: один Field=имя → save:true, иначе массив со снятым
префиксом. Зеркало py (байт-в-байт), кейс attributes-types сертифицирован в 1С.
Регресс 39/39 ps1+py.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Свойство horizontalLocation у элемента cmdBar (<CommandBar>): auto (дефолт,
не эмитим) / left / right / center, forgiving + рус.синонимы. Переиспользует
Get-HLocation от дополнений (+ добавлен center). Только у <CommandBar> в корпусе
(104 шт, в осн. Right), не у ButtonGroup/Popup/AutoCommandBar.
Компилятор (ps1+py байт-в-байт) + декомпилятор (захват <HorizontalLocation>).
Форма с CommandBar HorizontalLocation → round-trip match. Кейс commands расширен,
сертифицирован в 1С. Регресс 39/39 ps1+py. Закрывает остаток CommandBar>HorizontalLocation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Негативные кейсы (ожидают [ERROR] + exit 1):
- form-compile: дубль имени элемента / дубль имени команды;
- form-edit: добавление элемента с уже существующим в форме именем;
- form-validate: форма с дублирующимся именем элемента.
Позитивный гард (компилируется без ошибок):
- form-compile: имя реквизита == имя элемента — легально, раздельные неймспейсы;
защищает emit_element от случайного слияния пулов имён.
Дополнительно прогнано на 38 781 реальной форме выгрузок ERP/ACC/УНФ —
ноль ложных срабатываний новой проверки.
Co-authored-by: brake71 <8448482+brake71@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Проверка уникальности имён элементов форм (основа — PR #21 от brake71),
портированная на актуальную ветку и расширенная на все именованные коллекции.
Корень проблемы: генератор формы счёта ПланаСчетов строил колонки таблицы
субконто с «голыми» именами (Валютный, ТолькоОбороты, ВидСубконто), из-за чего
флаг субконто сталкивался с одноимённым признаком учёта счёта → невалидный для
1С XML (форма не открывалась). Теперь имена колонок префиксуются именем таблицы
(ВидыСубконтоВалютный) — как делает generic-путь табчастей и типовая 1С.
- form-compile: fail-fast проверка уникальности в едином emit_element + по
реквизитам, колонкам (в пределах реквизита), параметрам и командам. Хелпер
вместо копипаста; проверка после нормализации синонимов.
- form-validate: проверка имён симметрично существующим id-пулам (элементы,
реквизиты, колонки, команды) + новый блок параметров.
- form-edit: дедуп внутри JSON-определения и против существующих в форме —
для элементов (рекурсивно), реквизитов (+колонки) и команд; WARN→ERROR.
Каждая коллекция — свой неймспейс (имя реквизита и имя элемента могут совпадать
легально). PS1 и PY — зеркальны. Версии: form-compile 1.74, form-validate 1.7,
form-edit 1.1. Все тест-сеты зелёные на обоих рантаймах.
Co-authored-by: brake71 <8448482+brake71@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Allowlist дрейфовал — element-level appearance-ключи (11 канонических +
12 рус.синонимов: textColor/цветтекста/font/шрифт/border/рамка/title*/footer*)
читаются через Get-AppearanceValue и НЕ переименовываются, поэтому сыпали
ложный warning «unknown key» для валидных свойств закрытого кластера Appearance.
Решение самоподдерживающееся: union allowlist с самими структурами
appearance — ps1 foreach по appearanceSpec/appearanceSynonyms.Keys после
литерала; py доп. проверка `not in APPEARANCE_SPEC/APPEARANCE_SYNONYMS`.
Не дрейфует при добавлении новых ключей/синонимов. + статический autoCmdBar.
Проверено: appearance-ключи (canonical + рус.синонимы) не предупреждают,
реальные опечатки (textColorr/bogusKey) по-прежнему ловятся — оба рантайма.
Регресс 36/36 ps1+py.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ключи format/editFormat на InputField/LabelField/CheckBoxField (1408/958
файлов в корпусе). LocalStringType как inputHint/title: строка или {ru,en} —
переиспользование Emit-MLText (компилятор) и Get-LangText (декомпилятор).
Декомпилятор: хелпер Add-FormatProps в 3 ветках. Зеркало py.
Round-trip чистый (0 остатка на 30 формах с Format/EditFormat). Кейс
input-fields: format/editFormat строкой на input/check + мультиязык-объект
на labelField; снэпшот сертифицирован загрузкой в 1С.
Заодно добавлены забытые ключи (format/editFormat/choiceParameters/
choiceParameterLinks/typeLink) в allowlist knownKeys (ps1+py), чтобы не
сыпать ложный warning «unknown key».
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Декомпилятор фиксирует пустой <Presentation/> элемента choiceList как
presentation:"" вместо опускания ключа. Раньше пустота терялась →
компилятор додумывал presentation из значения (Title-FromName для
DesignTimeRef) → LOST <Presentation/> + ADDED непустой <Presentation>.
Паттерн B (суппресс-маркер ""): компилятор УЖЕ обрабатывал presentation:""
корректно (hasPres=true → авто-вывод пропускается; Emit-ChoicePresentation
на "" → пустой <Presentation/>). Правка только в декомпиляторе.
Presentation ушёл из diff на Билеты/КлассификаторПАТСАТУРН/ОстаткиПартийСАТУРН
(подтверждено round-trip). Decompiler-only → регресс через harness.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Два общих бага value (всплыли на полном прогоне 2.17, чинят и choiceList,
и параметры выбора):
- Пустое строковое значение эмитилось <Value xsi:type="xs:string"></Value>
вместо самозакрывающегося <Value xsi:type="xs:string"/>. Введён хелпер
Get-ChoiceValueTag (3 места: choiceList scalar + choiceParam scalar +
FixedArray inner). Форма АктивныеПользователи теперь round-trip match.
- Enum.X.EmptyRef нормализатор ломал вставкой .EnumValue. → EnumValue.EmptyRef
(EmptyRef — пустая ссылка перечисления, не значение). Фикс в Normalize-
ChoiceValue (Enum-ветка): EmptyRef сохраняется как есть.
Зеркало py. Кейсы: input-fields (пустая строка в choiceList), radio-auto-enum
(Enum.X.EmptyRef) — оба сертифицированы загрузкой в 1С. Регресс 36/36 ps1+py.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Авто-детект ISO-datetime (^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$) в
Normalize-ChoiceValue → xs:dateTime вместо xs:string. Без изменения DSL:
декомпилятор уже отдаёт строку, компилятор распознаёт формат. Заодно
исправляет choiceList со значениями-датами (та же FormChoiceListDesTimeValue).
Round-trip бит-в-бит на 3 формах с датами в параметрах выбора. Кейс
input-fields: Отбор.Дата в объектной и короткой формах; снэпшот
сертифицирован загрузкой в 1С. Закрывает микро-хвост кластера ChoiceParameters.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Входной сахар (декомпилятор по-прежнему пишет объектную модель):
- choiceParameters: ["Отбор.Х=true", "Отбор.Вид=Enum.A, Enum.B"] — name=value,
запятые → массив, литералы коэрсятся (true/false → bool, число → number,
остальное → строка/ref через Normalize-ChoiceValue).
- choiceParameterLinks: ["Отбор.Орг=ОбычноеПоле", "Отбор.Тип=Поле:DontChange"] —
name=dataPath, опц. хвост :Clear/:DontChange (дефолт Clear).
- typeLink: "ПолеПодсказка" или "ПолеПодсказка#0".
Парсеры на входе каждого эмиттера (строка → объект), далее общий путь.
Байт-в-байт идентично объектной форме (проверено ps1+py). Кейс input-fields:
поле ПолеСвязиКратко на короткой форме рядом с объектным; снэпшот
сертифицирован загрузкой в 1С. Версия компилятора синхронизирована (py 1.67→1.69).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ранее отложил PictureDecoration, ошибочно решив, что падение загрузки = порядок тегов (XSD
расщепляет appearance вокруг <Title>). Разбор остатка показал: падало из-за НЕВАЛИДНОЙ ссылки
на картинку в тесте (picture:"Картинка" → <xr:Ref>Картинка</xr:Ref>, такой CommonPicture нет),
а не из-за оформления. Проверка с валидной StdPicture.Print + appearance → грузится чисто.
Ключевой факт: 1С ТОЛЕРАНТНА к порядку оформления внутри элемента. LabelDecoration в корпусе
тоже расщепляет appearance вокруг Title (TextColor/Font до Title — тысячи раз; BackColor/Border
после), но компилятор эмитит contiguous-после-Title — и LabelDecoration сертифицировался. Значит
профиль decoration валиден и для PictureDecoration.
Разведён 12-й эмиттер (pictureDecoration, профиль decoration), PS+Python. Кейс element-appearance
расширен PictureDecoration (StdPicture.Print, чистое имя через src). Сертификация загрузкой —
чисто. Регресс 36/36 ps+py. Harness: остаток appearance LOST = 0 (был PictureDecoration 2),
TOTAL 1146→1144; весь кластер Appearance 1326→1144 (−182). Версия form-compile v1.67.
Развёл Emit-Appearance ещё в 5 эмиттеров: UsualGroup/ColumnGroup/Table/PictureField/CalendarField
(профиль field; декомпилятор их уже захватывал в Add-CommonProps — теперь компилятор эмитит).
Порядок собственного оформления по корпусу: группа TitleTextColor/TitleFont/BackColor; таблица
BackColor/BorderColor — укладываются в field-профиль. Зеркало PS+Python.
PictureDecoration НЕ разведён намеренно: его XSD расщепляет оформление вокруг <Title>
(TextColor/Font до Title, Border после) + позиция <Picture> — отдельный мелкий кластер (2 строки).
Сертификация загрузкой в 1С 8.3.24: element-appearance (+ группа с BackColor),
dynamic-list-parameters (+ Table backColor/borderColor, колонка titleTextColor/border) — чисто.
Регресс 36/36 ps+py. Harness 1177→1146 (−31; весь кластер Appearance 1326→1146 = −180),
остаток appearance LOST = PictureDecoration 2, ADDED-регрессий 0.
Попутно: декодированы garbled \u-escape в КОММЕНТАРИЯХ form-compile.py (артефакт Edit-инструмента,
переэкранирующего кириллицу под ASCII-конвенцию файла; в комментариях \u не интерпретируется).
Строковые литералы (имена компаньонов) остаются \u-escaped — там escape функционален.
Версия form-compile v1.66.
verify-snapshots: при ManualQuery поля дин-списка = псевдонимы запроса (Код/Наименование),
а не авто-пути mainTable (Code/Description). Колонки кейса ссылались на Список.Code/Description
→ "Неверный путь к данным" при загрузке. Поправил пути под псевдонимы запроса, перегенерил снэпшот.
Форма (ручной запрос + полная грамматика параметров: availableValues/use/denyIncompleteValues)
загружается в платформу 8.3.24 чисто. Сами schema-параметры платформа приняла без замечаний.
Захват/эмиссия <Parameter> (DataCompositionSchemaParameter) внутри <Settings xsi:type="DynamicList"> —
та же сущность, что параметры СКД, но обёртка <Parameter> + дети dcssch:. Ранее теряли при
декомпиляции и не умели эмитить (компилятор обрывал на Field*→MainTable). Корпус acc+erp 8.3.24:
123 формы, 406 параметров.
DSL: ключ settings.parameters переиспользует грамматику параметров СКД ОДИН-В-ОДИН (shorthand
"Имя [Заголовок]: Тип = Значение @valueList @hidden" + объектная форма; ключи value/type/
availableValues/inputParameters/use/denyIncompleteValues/expression/availableAsField). Новых
сущностей не вводим — модель переносит знание skd-параметров напрямую.
Контекстные дефолты дин-списка (паттерн «умный дефолт у всегда-эмитируемого тега», для модели
невидимы — просто опускает ключ):
- useRestriction: эмитим ВСЕГДА, дефолт true (в СКД дефолт false); false → объект useRestriction:false;
- title: авто из имени через Title-FromName (camelCase-split с сохранением аббревиатур); явный
заголовок — только при отклонении от авто-вывода;
- value: пустое всегда xsi:nil, даже при известном типе (в отличие от типизированного пустого в СКД).
Канон. порядок детей по корпусу: name, title, valueType, value, useRestriction, expression,
availableValue*, valueListAllowed, availableAsField, inputParameters, denyIncompleteValues, use.
Декомпилятор PS-only (зеркало в py отложено, как и весь form-decompile); компилятор зеркалён в py.
Валидация: round-trip бит-в-бит на ФормаОстатков (субсет) + ПроверкаПользовательскихНастроек
(полная грамматика: availableValues/inputParameters/denyIncompleteValues/use). Регресс 35/35 ps+py.
Тест-кейс dynamic-list-parameters (+снэпшот). spec обновлён. Версии: form-compile v1.64, form-decompile v0.46.
Декомпилятор терял картинки колонок таблиц формы:
- HeaderPicture/FooterPicture (общие для любого поля-колонки: input/check/labelField/picField)
- ValuesPicture: захват флага LoadTransparent (раньше брался только Ref)
- EditMode у PictureField
Единый формат "картинка-ссылка" (headerPicture/footerPicture/valuesPicture):
скаляр (Ref, loadTransparent=false — частый случай по корпусу ~64%) ИЛИ
объект {src, loadTransparent:true} для отклонения. Платформа всегда эмитит
<xr:LoadTransparent>, дефолт DSL=false. Флаг на каждой картинке (на одном
поле их бывает несколько).
Компилятор: HeaderPicture эмитится сразу после <EditMode> (порядок XDTO
строгий — иначе LoadConfigFromFiles падает с XDTO-исключением).
Forgiving-объект для <Picture> кнопки/попапа/команды: общий хелпер
Emit-CommandPicture принимает скаляр ИЛИ {src, loadTransparent}, чтобы
модель могла описать картинку объектно по аналогии с headerPicture.
Полярность кнопки сохранена (дефолт true). Декомпилятор не трогали —
объект только на вход, раундтрип без изменений.
Раундтрип sample-2.17: TOTAL 1582→1457, dec-fail/compile-fail 0.
Снапшот picture-field пересертифицирован в 1С. Регресс 34/34 ps+python.
Декомпилятор v0.45, компилятор v1.63.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Декомпилятор при отсутствии <Group> подставлял дефолт (vertical у UsualGroup,
horizontal у ColumnGroup), и компилятор его эмитил → <Group> додумывался там,
где в оригинале тега нет (ADDED: ColumnGroup>Group=103, UsualGroup>Group=65).
«Опустить дефолт» не подходит: на корпусе Vertical у UsualGroup в двух ролях —
явный <Group>Vertical</Group> (51205, 36%, хранить) и опускаемый дефолт (10%,
тега нет). 1C сериализует «Группировку», только если задана в конфигураторе,
даже Vertical. По значению неразличимы → нужен отдельный маркер «тега не было».
Ключ group/columnGroup — тип-дискриминатор, опустить нельзя. Поэтому нет <Group>
→ значение '' (тип сохраняется, направление не эмитим). Компилятор уже опускает
<Group> при пустом/нераспознанном значении — правка только в декомпиляторе.
spec для group/columnGroup обновлён.
TOTAL diff lines выборки 2.17: 1750 → 1582 (−168); match 23 → 31.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Компилятор для не-main реквизита БЕЗ ключа title додумывал <Title> из имени,
хотя платформа реквизит без синонима хранит без <Title>. На корпусе (295609
реквизитов): 22% без <Title> — всем додумывался заголовок (ADDED Attribute>Title
= 170 в выборке).
Компилятор (ps1+py): эмиссия Title реквизита приведена к логике Emit-Title —
нет ключа → авто-вывод (кроме main); title "" → подавить (раньше "" был falsy
и уходил в авто-вывод — это и был баг); непустой → как есть.
Декомпилятор (ps1): нет <Title> → title:"" (суппресс-маркер); ru-only заголовок,
равный авто-выводу из имени → опускаем ключ (компилятор воспроизведёт, 35% =
103908 реквизитов корпуса); иначе → явный. Скопировано точное зеркало
Title-FromName для сверки.
Регресс: attributes-types.json — реквизит с title:"" (подавление) рядом с
авто-выводом + снэпшот. spec §реквизиты обновлён.
TOTAL diff lines выборки 2.17: 2255 → 1750 (−505); cascade ADDED 292 → 33.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
У Page/Pages ключ `group` означает направление раскладки детей
(<Group>Horizontal</Group>), а не тип UsualGroup. Диспетчер типа элемента
проверял `group` раньше `page`/`pages`, поэтому страница с горизонтальной
раскладкой компилировалась как <UsualGroup name="horizontal"> вместо <Page>.
Переставил `pages`/`page` перед `group` в TYPE_KEYS (ps1 + py зеркало) —
реальная UsualGroup ключа page/pages не несёт, конфликта нет. Emit-Page уже
корректно эмитит <Group> из ключа group.
Регресс: добавил group:horizontal на страницу в кейс pages.json + снэпшот.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Корень: тип-детекция элемента видела ключ 'picture' РАНЬШЕ 'popup'/'button' в списке
типов. Но 'picture' это и тип (PictureDecoration), и свойство-иконка у popup/button/cmdBar
(оба строковые → не развязать по значению). Попап «{ popup, picture, representation }»
ошибочно компилировался как <PictureDecoration name="StdPicture.X"> → терялся весь попап
+ каскад. Решение: понизить приоритет picture/picField (в конец TYPE_KEYS) — тип-ключ
владельца выигрывает.
+ Button DataPath: кнопки общих команд несут <DataPath> (Объект.Ref, Items.X.CurrentData.Поле,
2706 в корпусе) — привязка команды к контексту. Не захватывался. Добавлен ключ path у button.
TOTAL diff lines выборки 2.17: 2727 → 2489 (-238). Снапшот button-group (+popup с картинкой)
сертифицирован в 1С (8.3.24). Регресс form-compile 34/34 зелёный на ps + python.
decompile v0.41, compile v1.59.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Растягивание (<HorizontalStretch>/<VerticalStretch>) платформа эмитит явным значением
(false 38145 / true 25002 для HS; на Input/Label/Picture/Group/CommandBar). Декомпилятор/
компилятор работали только с true → явный false терялся.
Теперь захват и эмиссия фактического значения (true И false); отсутствие = дефолт
(не эмитим). Бэк-совместимо: true как раньше, +false. Раньше декомпилятор писал ключ
лишь при true — теперь и при false.
TOTAL diff lines выборки 2.17: 2912 → 2727 (-185), match 20 → 22. Stretch residual
92 → 1 (остаток — на companion ExtendedTooltip, отдельный кластер). Снапшот input-fields
(+stretch false) сертифицирован в 1С (8.3.24). Регресс form-compile 34/34 зелёный
на ps + python. decompile v0.40, compile v1.58.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
<Behavior> у UsualGroup: дефолт Авто (не эмитится), явные Обычное/Свертываемая/Всплывающая
эмитятся. Платформа пишет тег только при не-Авто (чистое правило эмиссии). Раньше
декомпилятор мапил только Collapsible (в group:'collapsible'), теряя явный Usual (28069)
и PopUp (141).
Развязаны group (направление) и behavior:
- group: horizontal/vertical/alwaysHorizontal/alwaysVertical (направление);
- behavior: usual/collapsible/popup → <Behavior>; отсутствие = Авто.
Legacy group:'collapsible' принимается (= vertical + behavior collapsible) — старые входы целы.
Collapsed обобщён: эмитится при collapsed:true независимо от behavior (в XML <Collapsed>
изредка есть и у PopUp/Usual — round-trip ловит фактическое наличие).
TOTAL diff lines выборки 2.17: 3347 → 3179 (-168). UsualGroup>Behavior residual → 0.
Снапшот groups (behavior usual + collapsible/collapsed) сертифицирован в 1С (8.3.24).
Регресс form-compile 34/34 зелёный на ps + python. decompile v0.38, compile v1.56.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
<Columns><AdditionalColumns table="Объект.ТабЧасть"><Column>…</AdditionalColumns></Columns>
у главного реквизита-объекта (3654 формы, 10187 блоков) — форма-определённые доп.
колонки табличных частей. Декомпилятор читал только прямые <Column> (SelectNodes lf:Column),
теряя AdditionalColumns целиком (часто весь <Columns> блок объекта).
Ключ реквизита additionalColumns: [{ table, columns: [<col>] }]; <col> — та же грамматика,
что у columns (name/type/title/functionalOptions). Общие хелперы Emit/Decompile-AttrColumn
(переиспользуются прямыми колонками и AdditionalColumns). Порядок схемы: прямые <Column>
сначала, затем AdditionalColumns-группы.
TOTAL diff lines выборки 2.17: 3695 → 3347 (-348). Attribute>Columns/AdditionalColumns
residual → 0. Новый кейс additional-columns (DataProcessor с табчастью + форма) сертифицирован
в 1С (8.3.24). Регресс form-compile 34/34 зелёный на ps + python.
decompile v0.37, compile v1.55.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
<UseAlways><Field>ИмяРеквизита.Поле</Field>…> у Attribute (5189: дин-список 3575 +
ValueTable ~788 + прочие) — не захватывался. Свойство «поля, всегда читаемые из БД».
DSL — две формы (сливаются компилятором):
- на реквизите: useAlways: ["Поле1","Поле2"] (короткие имена; forgiving с/без префикса);
- на колонке ValueTable: useAlways: true (columns[*]).
Компилятор собирает <Field>ИмяРеквизита.X</Field> из обоих источников (dedupe),
порядок схемы: после FillChecking, до FunctionalOptions/Columns/Settings.
Дин-список: колонки в XML не эмитятся, но если заданы в DSL с useAlways — формируют
UseAlways-массив (Columns подавляются при наличии settings).
Декомпилятор по контексту: ValueTable (есть columns) → useAlways:true на совпавшей
колонке; дин-список/прочие → массив useAlways на реквизите. Префикс «Имя.» снимается.
TOTAL diff lines выборки 2.17: 3869 → 3695 (-174), match 14 → 17 (+3 чистых формы).
Attribute>UseAlways residual → 0. Снапшот table (обе формы + merge) сертифицирован
в 1С (8.3.24). Регресс form-compile 33/33 зелёный на ps + python.
decompile v0.36, compile v1.54.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ChoiceList (<ChoiceList>) встречается на RadioButtonField (уже было) и InputField
(2142 в корпусе) — не захватывался у InputField. Логику вынесли в общие хелперы
Emit-ChoiceList / Decompile-ChoiceList (PS1) и emit_choice_list (PY), подключили к
обоим полям. Грамматика та же: [ { value, presentation?/title? } ] (+ рус. синонимы),
авто-вывод presentation. Порядок в InputField: после input-свойств/InputHint, до companions.
TOTAL diff lines выборки 2.17: 5149 → 4443 (-706). InputField>ChoiceList закрыт
(остаток ~5 — другое: app:value в app-неймспейсе = списки выбора параметров/настроек;
ChoiceListButton = отдельное input-свойство). Снапшот input-fields сертифицирован в 1С
(8.3.24). Регресс form-compile 33/33 зелёный на ps + python. decompile v0.33, compile v1.51.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ButtonGroup/CommandBar несут <CommandSource> (источник команд группы): Form (2478),
FormCommandPanelGlobalCommands (1267), Item.<ИмяЭлемента> (команды конкретного
элемента-таблицы). Декомпилятор не захватывал → LOST в форменных/элементных панелях.
Добавлен ключ commandSource (эмитится «как есть», после Title до Representation/Autofill).
Декомпилятор захватывает у ButtonGroup и CommandBar.
TOTAL diff lines выборки 2.17: 5189 → 5149 (-40). ButtonGroup/CommandBar CommandSource
LOST → 0. Снапшот button-group (группа глобальных команд с commandSource) сертифицирован
в 1С (8.3.24). Регресс form-compile 33/33 зелёный на ps + python.
decompile v0.32, compile v1.50.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Корень формы (id=-1) при голом <AutoCommandBar/> (autofill=true по умолчанию) терялся:
эвристика B3 (Compute-MainAcbAutofill) при наличии cmdBar-элемента в форме додумывает
Autofill=false → ADDED. Тот же приём, что у таблицы: декомпилятор зеркалит условие
эвристики (Test-AnyCmdBar) и при голом корне + наличии cmdBar пишет отклонение
autoCmdBar:{ autofill: true }. Компилятор не менялся (Compute-MainAcbAutofill уже
возвращает mainAcbDef.autofill; при true без детей корень эмитится голым).
TOTAL diff lines выборки 2.17: 5249 → 5189 (-60). AutoCommandBar ADDED 18 → 0
(голый корень закрыт). Регресс form-compile 33/33 зелёный на ps + python.
decompile v0.31.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Хвост кластера командных панелей: компилятор-эвристика додумывает Autofill=false
дин-список-таблицам (подавляет панель, чтобы не дублировать КП формы), но ~15%
таблиц имеют голый <AutoCommandBar/> (autofill=true по умолчанию — панель оставлена
при таблице). Раньше эвристика их перетирала → ADDED <Autofill>false>.
Решение (B): эвристика держит дефолт false (оптимальный — 85% дин-списков; контекст-
сигналы проверены по корпусу, ни один не даёт >50% «голых» → улучшать дефолт нечем),
а декомпилятор фиксирует ОТКЛОНЕНИЕ маркером commandBar:{ autofill: true }. commandBar
имеет приоритет над эвристикой.
Компилятор: Emit-CompanionPanel больше не пишет <Autofill>true</Autofill> (платформа
его не эмитит — true это дефолт); только <Autofill>false</Autofill>. autofill:true или
отсутствие → тег опускается, при пустой панели → self-closing <AutoCommandBar/>.
TOTAL diff lines выборки 2.17: 5293 → 5249 (-44). Table>AutoCommandBar ADDED 22 → 0
(полностью закрыт). Остаток AutoCommandBar 18 — форменная панель (heuristic B3, корень
формы) — отдельный пункт. Регресс form-compile 33/33 зелёный на ps + python.
decompile v0.30, compile v1.49.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Снапшоты отстали от компилятора (table additions с AdditionSource +
ExtendedTooltip companion таблицы; CheckBoxType у CheckBoxField — из прошлых
правок form-compile) — перегенерированы под текущий вывод. Не связано с
логикой form-validate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Крупнейший левередж-кластер. Companion-панели элемента (AutoCommandBar/ContextMenu)
теперь несут контент как СВОЙСТВА:
- commandBar → <AutoCommandBar> (командная панель)
- contextMenu → <ContextMenu> (контекстное меню)
Значение: массив = shorthand для { children }; объект { autofill?, horizontalAlign?,
children[] }. children — обычная грамматика button/buttonGroup/popup.
Forgiving-синонимы (commandBar ← autoCommandBar/AutoCommandBar/autoCmdBar/cmdBar/
КоманднаяПанель; contextMenu ← ContextMenu/КонтекстноеМеню). Разведение «тип-элемент
vs панель-свойство» — по ТИПУ значения: строка = элемент-тип в дереве (cmdBar:"Имя"),
объект/массив = companion-панель этого элемента. Тип-синонимы применяются только к
строковому значению. Механизм общий (любой элемент), декомпилятор захватывает в
Decompile-Element, компилятор — Emit-CompanionPanel.
Новый ключ кнопки commandName — глобальная команда «как есть» (CommonCommand.X,
Catalog.X.Command.Y) без обёртки Form. (раньше попадала в command и ошибочно
оборачивалась в Form.Command.). stdCommand/command без изменений.
Декомпилятор: для дин-список-таблицы пустой AutoCommandBar(autofill=false) не пишет
commandBar (восстановит heuristic) — без шума. tableAutofill остаётся shorthand,
commandBar имеет приоритет.
TOTAL diff lines выборки 2.17: 7560 → 5293 (-2267), match 11 → 13,
cascade LOST 3414 → 1805. Table>ContextMenu/Table>AutoCommandBar ушли из топа impact.
Снапшот table сертифицирован в 1С (8.3.24); регресс form-compile 33/33 зелёный
на ps + python. decompile v0.29, compile v1.48.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Кластер «доступ по ролям»: единый role-adjustable boolean платформы
(xr:Common + 0..N xr:Value name="Role.X") для четырёх владельцев одним
грамматиком значения:
- элемент → userVisible (<UserVisible>)
- реквизит → view, edit (<View>/<Edit>)
- команда → use (<Use>)
Значение DSL: скаляр false/true → голый <xr:Common>; объект
{ common, roles:{ Имя: bool } } → пер-ролевые исключения (три-state как в
конфигураторе: роль не указана → наследует common; указана → явный bool).
Имя роли forgiving: без префикса / Role. / Роль. → нормализуется в Role.
Отсутствие ключа = полный доступ (платформа тег не пишет) — дефолт не эмитим.
Декомпилятор инвертирует: голый Common → скаляр, есть Value → объект.
Компилятор: общий хелпер Emit-XrFlag / emit_xr_flag (ps1+py).
Порядок схемы: View → Edit после MainAttribute; Use после ToolTip до Action.
Раньше: userVisible умел только голый false (компилятор), декомпилятор не
захватывал ничего; view/edit/use не умел никто.
TOTAL diff lines выборки 2.17: 7911 → 7560 (-351), match 9 → 11.
Снапшоты attributes-types/commands сертифицированы в 1С (8.3.24);
регресс form-compile 33/33 зелёный на ps + python.
decompile v0.28, compile v1.47.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Платформа всегда ставит companion <ExtendedTooltip> на Table/CommandBar/Popup (подтверждено
корпусом: 13174/6086/15681 — 100%), но компилятор его не генерил (не было call-site в
Emit-Table/CommandBar/Popup) → пустой companion терялся при раундтрипе (вскрыто фиксом метрики).
Добавлена эмиссия ExtendedTooltip в Emit-Table (после AutoCommandBar), Emit-CommandBar и
Emit-Popup (перед ChildItems) — с контентом el.extendedTooltip (единый механизм). Зеркало
в form-compile.py идентично.
Валидация: ExtendedTooltip LOST 437→276 — Table(117→1)/CommandBar(46→0) закрыты, Popup
13→7; сертификация в 1С PASS; регресс 33/33 ps+py (снэпшоты перегенерированы — +ExtendedTooltip
и каскад перенумерации id); py==ps1; harness 8144→7911, match 8→9.
Остаток ExtendedTooltip LOST (Button 213 + ButtonGroup 34) — НЕ ExtendedTooltip: это cascade
от непокрытого контента AutoCommandBar (кастомные кнопки/ButtonGroup командной панели не
генерятся компилятором) — отдельный кластер. CheckBoxField 7 — ExtendedTooltip с own-layout
(<Width>). В BACKLOG.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Заголовок декорации — formatted-aware текст (как extendedTooltip). Раньше LabelDecoration
нёс formatted отдельным sibling-ключом, PictureDecoration терял атрибут formatted вовсе
(эмитил голый <Title> через generic Emit-Title). Теперь оба идут через общий
Emit-DecorationTitle → Resolve-MLFormatted (та же единая ML-text форма, что у extendedTooltip):
- title декорации: строка (formatted авто-детектится по разметке) / {ru,en} / {text, formatted}.
- атрибут <Title formatted="…"> эмитится ВСЕГДА (специфика декораций); для обычных элементов
Emit-Title остаётся без formatted (formatted — только у декораций, подтверждено корпусом:
LabelDecoration 6568 + PictureDecoration 2, прочие 0).
- back-compat: sibling-ключ formatted принимается как override авто-детекта; компилятор-вывод
LabelDecoration не изменился.
Декомпилятор (v0.27): декорации захватывают title через Get-MLFormattedValue (гибрид);
sibling formatted больше не выводится (форматированные обычно становятся просто строкой
с markup внутри). Компилятор (ps1+py v1.45): Emit-DecorationTitle для Label+Picture.
Валидация: LabelDecoration formatted round-trip CLEAN; PictureDecoration Title-formatted
закрыт (29→0); регресс 33/33 ps+py; py==ps1; harness 8202→8144. Spec обновлён.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Свойства таблицы, терявшиеся на раундтрипе. Часть была захвачена в декомпиляторе под
gate динсписка (<UpdateOnDataChange>) → терялась на обычных ValueTable-таблицах.
Новые скаляры (захват + эмиссия, все типы таблиц):
- choiceMode (компилятор уже эмитил — добавлен захват), selectionMode (SingleRow/…),
rowSelectionMode (Row/…), verticalLines/horizontalLines (явное false).
Дегейт (вынесены из блока динсписка в общую обработку Table — ловятся на ЛЮБОЙ таблице):
- useAlternationRowColor, initialTreeView, rowsPicture — захват/эмиссия без gate.
- rowPictureDataPath — инверсия умного дефолта DefaultPicture осталась дин-список-only;
обычные таблицы захватывают/эмитят литерал.
Зеркало form-compile.py идентично (py==ps1 проверено).
Валидация: все 7 целевых — 0 LOST / 0 ADDED; round-trip на ValueTable-формах
(АдреснаяКнига и др.); регресс 33/33 ps+py; harness 8448→8368 (на честной метрике
после фикса атрибуции), 0 fail. Остаток по таблицам — companion-контент
(ExtendedTooltip/AutoCommandBar/ContextMenu) и цвета/шрифты — отдельные кластеры.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Свойства редактируемых (ValueTable) таблиц формы, терявшиеся при раундтрипе:
- ChangeRowSet/ChangeRowOrder — теперь эмитятся явным значением, включая false
(платформа пишет <ChangeRowSet>false</ChangeRowSet> на ValueTable; раньше компилятор
эмитил только true → false терялся). Декомпилятор захватывает фактическое значение.
- AutoInsertNewRow — новый ключ (автодобавление строки), захват/эмиссия при true.
- EnableDrag — декомпилятор теперь захватывает (компилятор уже эмитил).
- RowFilter — nil-плейсхолдер <RowFilter xsi:nil="true"/> (в корпусе ВСЕГДА nil, 0 с
контентом). DSL-ключ rowFilter: null; компилятор эмитит nil при наличии ключа.
Зеркало в form-compile.py идентично (py==ps1 проверено на ValueTable-формах).
Валидация: все четыре — 0 LOST / 0 ADDED (полностью закрыты); round-trip CLEAN на
ValueTable-формах (БанкиУниверсальногоОбмена, БанковскиеСчета); регресс 33/33 ps+py;
harness 7971→7774 (−197), 0 fail. Вывод байт-идентичен реальным формам платформы.
Spec: changeRowSet/changeRowOrder/autoInsertNewRow/enableDrag/rowFilter в table-секции.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>