Колонки/реквизиты строк фиксированной длины (ИНН/КПП/коды) несут
<v8:AllowedLength>Fixed</v8:AllowedLength>, но DSL выражал только Variable:
компилятор хардкодил Variable, декомпилятор не читал AllowedLength → Fixed терялся
(форма ЭлектроннаяТранспортнаяНакладная/ТитулПеревозчика*: 3 LOST Fixed + 3 ADDED
Variable — мультимножественный учёт тех же колонок).
Корпус 8.3.24: AllowedLength ВСЕГДА присутствует в StringQualifiers (Variable
443127 + Fixed 2687, ABSENT=0) → always-эмиссия Variable верна. Fixed (2687)
всегда с длиной > 0 (12/10/3/1/36…); при Length=0 — всегда Variable.
Грамматика `string(N,fixed)` (по аналогии с `decimal(D,F,nonneg)`). Variable —
дефолт (опускаем суффикс); `variable` принимается forgiving. Emit-SingleType
(ps1+py) эмитит Fixed при суффиксе; декомпилятор Decompile-Type читает AllowedLength
(Fixed → суффикс, Variable/Length=0 → плоский string(N)). Общий путь типов
(реквизиты/колонки/valueType/составные).
Выборка 46 форм с Fixed (вкл. указанную): 0 потерь AllowedLength, целевая форма →
match. Round-trip декомпиляции снэпшота: string(12,fixed)/string(9,fixed) читаются
обратно. Кейс attributes-types (+ValueTable с Fixed-колонками ИНН/Код) сертифицирован
в 1С. Регресс 43/43 (ps1+py).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Две находки из корпусного хвоста (свериться помог category-forms.py против rt-24):
- **MultiLine факт. значение** (190 LOST в выборке rt-24): компилятор эмитил и
декомпилятор ловил только `true`, терялся явный `<MultiLine>false>` (425 в корпусе
8.3.24; absent 204694, true 5183). Теперь захват/эмиссия true/false при наличии,
отсутствие = дефолт (как PasswordMode). Эвристика autoMaxWidth (multiLineDefault)
не затронута — продолжает срабатывать только на true.
- **Shortcut → generic-скаляр** (94 LOST на 86 формах): эмитился/ловился только у
PictureField (инлайн), терялся на InputField (169), UsualGroup (41),
RadioButtonField (39), Page (22), Table (3), CheckBoxField (1). Перенёс в
GENERIC_SCALARS (любой элемент через Emit-Layout/Add-GenericScalars), убрал инлайн
PictureField. Команда — отдельный путь (§7), не трогаю.
Заодно подтверждено покрытие (category-forms против rt-24 = 0): ControlRepresentation
(1464), ShapeRepresentation (877), PasswordMode (689) — уже generic/факт. значение.
AllowedLength (625) — это cascade типов полей дин-списка (отдельный кластер, не трогаем).
Зеркало py (байт-в-байт). Выборка 73 формы (MultiLine=false + Shortcut на 6 типах
элементов): 0 потерь. Кейсы input-fields (+multiLine:false +shortcut на input),
groups (+shortcut на group), picture-field (shortcut через generic) сертифицированы
в 1С. Регресс 43/43 (ps1+py).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`<WarningOnEdit>` (мультиязычный текст предупреждения при редактировании)
встречается на InputField (576), CheckBoxField (119), RadioButtonField (54),
LabelField (1) по корпусу 8.3.24, но компилятор эмитил и декомпилятор ловил его
только у InputField → терялся на check/radio/labelField.
Расширил эмиссию (Emit-Check/Emit-Radio/Emit-LabelField, после Emit-Layout перед
Format) + захват в декомпиляторе (инлайн SelectSingleNode+Get-LangText в трёх
обработчиках, как у InputField). Парный enum `warningOnEditRepresentation`
(Show/DontShow) уже был generic-скаляром на любом поле — не трогаю. 1С толерантна
к позиции тега внутри поля (сертифицировано загрузкой).
Зеркало py (байт-в-байт). Выборка 46 форм с WarningOnEdit на check/radio:
0 потерь WarningOnEdit. Кейсы input-fields (+check multilang, +labelField) и
radio-tumbler-strings (+radio) сертифицированы в 1С. Регресс 43/43 (ps1+py).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Закрыты картиночные потери из ROOT-секции корпуса: Page>Picture (702),
PictureField>ValuesPicture (abs), Button>Picture (abs), а также RowsPicture
и командные/popup-картинки. ColumnGroup>HeaderPicture уже ловился (Add-CommonProps),
бэклог-числа были от старого прогона v0.62.
Две системные дыры + один полный пробел (по корпусу 36707 форм):
- xr:Abs (встроенная картинка) игнорировался везде, кроме PictureDecoration:
Get-PictureRef и Button/Popup/Command picture брали только <xr:Ref>. Теперь
src с префиксом "abs:" → <xr:Abs> (как у PictureDecoration). ~358 ValuesPicture
+ ~153 Button + хвост.
- xr:TransparentPixel ловился только у PictureDecoration. Теперь — в объектной
форме картинки-ссылки {src, loadTransparent?, transparentPixel:{x,y}} у
ValuesPicture/HeaderPicture/FooterPicture/RowsPicture/Page и у командных картинок.
- Page>Picture не поддерживался ни компилятором, ни декомпилятором. Новый ключ
picture на Page (конвенция ValuesPicture: дефолт LoadTransparent=false, по корпусу
416/286). Позиция XSD: после Title/ToolTip/флагов, перед Group/ShowTitle.
Компилятор: Emit-PictureRef + Emit-CommandPicture расширены abs/transparentPixel;
Emit-Page эмитит picture; RowsPicture переведён на Emit-PictureRef (был кастомный
блок без abs/TP). Декомпилятор: Get-PictureRef ловит xr:Abs/TransparentPixel;
новый хелпер Set-CommandPicture (Button/Popup/Command — abs + TP через объектную
форму при наличии TP, иначе скаляр); Page и RowsPicture через Get-PictureRef.
Зеркало py (байт-в-байт). abs валидируется раундтрипом на корпусе (нужен встроенный
бинарь — в синтет-кейсы не кладём); transparentPixel + Page picture сертифицированы
загрузкой в 1С (кейсы picture-field/pages/commands). Регресс 43/43 (ps1+py).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
По замечанию: код forgiving принимает широкий набор ориентаций (нужно для
раундтрипа — Horizontal/AlwaysVertical встречаются в корпусе), но для АВТОРИНГА
spec должен предлагать только доступные в конфигураторе значения, иначе модель
разметит форму недоступным значением. Помечены явно: страница/группа —
vertical/horizontalIfPossible/alwaysHorizontal; horizontal/alwaysVertical —
только раундтрип-совместимость, не для авторинга.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Страница (Page) и обычная группа (UsualGroup) теряли <Group>HorizontalIfPossible
</Group> — orientation-карта содержала Horizontal/Vertical/AlwaysHorizontal/
AlwaysVertical, но не HorizontalIfPossible (ROOT Page>Group 359 на 189 формах).
Доступные значения (по конфигуратору + корпусу): страница/обычная группа —
Vertical/HorizontalIfPossible/AlwaysHorizontal (+ Horizontal реально встречается:
1288 форм на странице — XML-enum шире UI-дропдауна, оставлен forgiving); группа
колонок таблицы — Vertical/Horizontal/InCell (уже обрабатывалось, не трогаем).
InCell на странице/группе не добавляем — в корпусе не встречается. Коэрция не
делается: фактическое значение сохраняется как есть (верность раундтрипа).
Добавлен horizontalIfPossible в Emit-Page + Emit-Group switch (ps1+py) и в gmap
декомпилятора (Page + UsualGroup). Таргет-верификация (выборка 50 из 189): 0
остатка, 29 стали match, 0 регрессов. Кейс pages пере-сертифицирован в 1С
(HorizontalIfPossible грузится). Регресс 43/43.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Дополнение к фиксу CommandSet: ключ excludedCommands теперь работает на любом
поле (input/label/check/spreadsheet/html/formatted/picField + таблица + форма),
а не только на таблице. Уточнил описание и значения по типам.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ранее excludedCommands обрабатывался только для Table-элемента и форм-уровня.
Обычные поля (InputField/LabelField/CheckBoxField/SpreadSheetDocumentField/HTML/
Formatted/Picture) идут через Emit-SimpleField и др. — CommandSet там терялся
(кластер SpreadSheetDocumentField>CommandSet, baseline impact ~1443).
Централизовал: захват в Add-CommonProps (декомпилятор, общий для всех полей),
эмит в Emit-Layout (компилятор ps1+py), убрал дубль из Table-эмиттера. CommandSet —
дочерний элемент базового FormField в схеме, позиция фиксирована независимо от
подтипа → ранняя (после TitleLocation, перед скалярами/Height), как у spreadsheet.
Таргет-верификация (новый цикл category-forms.py): 43 формы корпуса с CommandSet →
после фикса 0 остатка (CommandSet + ExcludedCommand cascade), 26 стали match.
Кейс table пере-сертифицирован в 1С (ранняя позиция грузится), ps1==py, регресс 43/43.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Из ROOT-секции корпусного прогона 8.3.24 (rt-24): дешёвые широкие generic-скаляры
(pass-through, обе стороны + py), не обрабатывались ранее:
- ControlRepresentation (свёртка группы, 1464) · ShapeRepresentation (форма кнопки/
попапа, 1023) · AutoAddIncomplete (516) · MarkNegatives (433) · InitialListView
(нач. позиция списка, 246) · ChoiceListHeight (143) · ThreeState (флажок, 119) ·
ScrollOnCompress (прокрутка страницы, 104).
PasswordMode на InputField: эмитился только при true → терялись 349/504 явных false
в корпусе (ROOT 689). Теперь факт. значение (как на LabelField/markIncomplete);
декомпилятор захватывает true/false при наличии тега.
Проверка: 15 корпусных форм с этими тегами — 0 расхождений по тегам. Регресс 43/43
(ps1+py). Совокупный ожидаемый impact ~4700 TOTAL.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Реквизит-диаграмма несёт <Settings xsi:type="d4p1:Chart"> — встроенный конфиг
(~110-130 версионно-вариативных полей: тип/серии/легенда/заголовок/шкалы/цвета/
оси, глубокая вложенность с повторяющимися именами). Корпус 8.3.24: 5 форм.
Подход (с пользователем): ГЕНЕРИК-движок. Ключ chart на реквизите; рекурсивный
захват/эмит поддерева d4p1, ключи = локальные имена тегов, порядок ключей =
порядок эмиссии → раундтрип ЛЮБОЙ версии/набора полей бит-в-бит (платформа
добавляет поля, не переставляет). Структуры распознаются по форме узла
(line {width,gap,style} / border {width,style} / font {kind} / ML / области
{left,right,top,bottom} / серии-массивы); малые name-set'ы: ML-поля, серии,
attrs-узлы (gaugeQualityBands). Расширяемость: любое из ~127 свойств — по
каноничному имени.
Авторинг с нуля: декомпиль рабочей диаграммы как шаблон + правка ядра
(chartType/серии/легенда/цвета). Default-fill через merge НЕ делаем — конфликт
с байт-точностью неполных форм (см. docs/form-dsl-spec.md).
Результат: 4 из 5 форм корпуса — байт-в-байт (включая версионно-вариативные).
5-я (точки/оси realPointData/realDataItems с типизир. значениями xsi:type,
xsi:nil, ML с префиксом d4p1:) → честный fail-ring3 (редкий вариант, не
поддержан генериком). Снят fail-ring3 для d4p1:Chart (GanttChart — Фаза 3).
Заодно фикс: d5p1:Dendrogram отсутствовал в specialTypeNs (ps1+py).
Декомпилятор ps1-only (генерик-рекурсия); компилятор зеркало py (ps1==py
байт-в-байт). Кейс chart-settings (полная диаграмма из эталона
ПроверкаКонтрагента) сертифицирован загрузкой в 1С. Регресс 42/42.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Расширение Phase 1 кластера Chart-Settings: реквизит pl:Planner теперь несёт
измерения планировщика (<pl:dimension> — «Измерения» в конфигураторе) с элементами.
DSL planner.dimensions[]: объект разреза (value — ссылка xr:DesignTimeRef или nil,
text-заголовок, цвета, font) + elements[] (элементы измерения, РЕКУРСИВНЫ — могут
нести вложенные elements, как показывает UI колонкой «Элементы»; поле
showOnlySubordinatesAreas). Тип value авто-выводится: ссылочный вид →
xsi:type="xr:DesignTimeRef", иначе xs:string. Пустой текст → самозакрывающийся
<pl:text/> (как в выгрузке). Общие хелперы Emit/Get-PlannerValue/Text применены
и к элементам расписания (items).
Раундтрип бит-в-бит: синтетика upload/epf/Диаграммы (items + 2 dimensions +
вложенные elements + period). Зеркало py (ps1==py байт-в-байт). Кейс chart-fields
расширен измерением (nil-разрез + xs:string-элемент + showOnlySubordinatesAreas),
сертифицирован загрузкой в 1С. Регресс 41/41 (ps1+py).
Ограничение: item.dimensionValues (привязка элемента расписания к элементам
измерений) пока всегда пустой.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Реквизит planner-типа несёт <Settings xsi:type="pl:Planner"> — встроенный конфиг
поля-планировщика (элементы расписания + оформление/поведение + шкала времени).
Раньше декомпилятор делал fail-ring3 (третий вид Settings после TypeDescription/
DynamicList). Корпус 8.3.24: Planner Settings = 1 реальная форма (КонтактныеЛица/
ФормаЛиды), всё chart-семейство = 38 форм. Решение (с пользователем): структурный
DSL ради возможности модели СОЗДАВАТЬ дашборды/планировщики, не только раундтрипить.
DSL: ключ planner:{…} на реквизите (docs/form-dsl-spec.md):
- items[] (элементы расписания) + appearance/поведение-скаляры + timeScale
(placement/levels[]/colors) + period;
- цвета verbatim, шрифт {kind:AutoFont}/ref, граница {width,style}, ML-форматы;
- компилятор подставляет дефолты для пропущенных ключей (краткий авторинг),
декомпилятор — полный захват (раундтрип бит-в-бит).
Снят fail-ring3 для pl:Planner (Chart/GanttChart остаются — Фазы 2/3).
Заодно фикс: d5p1:Dendrogram отсутствовал в specialTypeNs (эмитился без
xmlns-префикса) — добавлен в карту (ps1+py).
Раундтрип бит-в-бит: синтетика upload/epf/Диаграммы (с items+period) +
реальная ФормаЛиды (без items/period, иные значения скаляров). Зеркало py
(ps1==py байт-в-байт). Кейс chart-fields расширен (+planner +dendrogram),
сертифицирован загрузкой в 1С. Регресс 41/41 (ps1+py).
Ограничение Phase 1: dimensions/item.dimensionValues пока всегда пустые.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Снят fast-fail на 6 chart-полях. Все — простые скелеты (как document/gauge),
кроме GanttChart с вложенной <Table> (ключ ganttTable, переиспользует
Decompile/Emit-Element — устранена коллизия тип-ключа table). Типы реквизитов
уже в special-type ns-карте (d5p1:Chart/GanttChart/FlowchartContextType/
GeographicalSchema, pl:Planner) + v8:StandardPeriod. Edit/WarningOnEditRepresentation
у GraphicalSchema — через готовые GENERIC_SCALARS.
Guard: реквизит с design-time конфигом диаграммы/планировщика
(<Settings xsi:type="d4p1:GanttChart"/"pl:Planner"/…> — третий вид Settings
после TypeDescription/DynamicList) → честный fail-ring3 (не теряем молча).
Planner несёт Settings всегда; Chart/Gantt — при настройке. Поля без Settings
(диаграмма из кода/график-схема/период/дендрограмма/гео) роундтрипятся полностью.
Выборка 2.17: ring3 4→0 (весь ring3 разобран!). Кейс chart-fields
(chart+graphicalSchema+period+ganttChart с ganttTable) сертифицирован в 1С.
Зеркало py байт-в-байт. Регресс 41/41 (ps1+py).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Снят fast-fail на ConditionalAppearance (1304 формы, 4%). Структура — та же
DCS-грамматика, что settings.conditionalAppearance дин-списка, поэтому
переиспользованы Build-ConditionalAppearance (декомпилятор) и
Emit-ConditionalAppearance (компилятор) как есть.
Отличия от настроек списка: тег-обёртка <ConditionalAppearance> (без dcsset:,
параметр wrapTag) + нет блок-мета viewMode/userSettingID + размещение (последний
child <Attributes>, не отдельный Form-child). Форменный ключ conditionalAppearance
(selection/filter/appearance/presentation). Scope в формах не встречается
(0/6186) → fail-ring3 только при scope.
Заодно фикс: мультиязык-presentation элемента CA → xsi:type="v8:LocalStringType"
(был голый <dcsset:presentation>; чинит и settings CA path).
Выборка 2.17: ring3 7→4 (остаток — только chart-семейство), match 211→214,
CA-формы бит-в-бит. Зеркало py байт-в-байт, кейс input-fields
(+conditionalAppearance: selection+filter+appearance+presentation)
сертифицирован загрузкой в 1С. Регресс 40/40 (ps1+py).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PreserveWhitespace=false у XmlDocument стрипает значимый пробел в
<v8:content> </v8:content> → декомпилятор читал "" (неотличимо от суппресс-
маркера title:"") → компилятор не эмитил Title → LOST (надписи-разделители
"РазделительТумблеров" и т.п., 487 в корпусе).
Фикс в Get-MLFormattedValue (декорации label/picture): пустой текст ПРИ наличии
узла <v8:content> → исходно был пробел (платформа не эмитит пустой Title) →
восстанавливаем " ". Компилятор уже эмитит пробел корректно (" " truthy в
Emit-DecorationTitle). Decompiler-only.
Выборка 2.17: match 209→211, TOTAL 12→0 (остаток — только GroupList,
документированный не-покрываемый). Валидировано раунтрипом (форма
ЗадачаИсполнителя/ЗадачиПоПредметуБП → match).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Parse-DLParamShorthand брал тип regex'ом (\S+) — один токен без пробелов.
Составной тип (CatalogRef.X | CatalogRef.Y, с пробелами вокруг |) не матчился
→ вся строка уходила в name → компилятор эмитил <dcssch:name>Имя: TYPE | TYPE</…>
и ТЕРЯЛ <dcssch:valueType>.
Фикс: тип = ([^=]+?) (допускает пробелы/|, исключает '='-разделитель значения);
составной резолвится по частям (per-part Resolve-TypeStr, rejoin ' | ').
Emit-DLValueType уже split'ил по |, эмиссия корректна. Зеркало py.
Выборка 2.17: TOTAL 38→12 (составной тип у дин-списков Task/прочих восстановлен).
Кейс dynamic-list-parameters (+составной параметр DocumentRef | CatalogRef → два
TypeSet) сертифицирован загрузкой в 1С. Регресс 40/40 (ps1+py).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Снят fast-fail на CommandInterface (4388 форм, 13.5% корпуса — крупнейший
оставшийся триггер ring-3).
Форменный ключ commandInterface = панели commandBar + navigationPanel, списки
переопределений авто-расстановки (платформа эмитит только отклонения). Элемент:
command (verbatim; "0"=пустой), type (Auto опускаем/Added), defaultVisible,
visible (тот же xr-flag, что userVisible/use — bool или {common,roles}),
group (CommandGroup verbatim), index, attribute. Порядок тегов Item:
Command,Type,Attribute,CommandGroup,Index,DefaultVisible,Visible.
Две формы записи панели: плоский массив (декомпилятор эмитит её) + древовидная
{группа:[команды]} как входной сахар (алиасы important/goTo/seeAlso→
FormNavigationPanel*, important/createBasedOn→FormCommandBar*; иной ключ verbatim;
group из ключа, элементы не дублируют). Голый элемент → строка-shorthand.
Переиспользует Decompile-XrFlag/Emit-XrFlag.
Выборка 2.17: ring3 37→7, match 181→197; сам CommandInterface роундтрипится
бит-в-бит (0 CI-diff, остаток TOTAL — несвязанный хвост раскрытых форм). Зеркало
py байт-в-байт, кейс commands (+commandInterface tree-форма) сертифицирован
загрузкой в 1С. Регресс 40/40 (ps1+py).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Компилятор при отсутствии реквизитов не эмитил <Attributes> вовсе (предполагал
толерантность 1С — не проверено). Корпус: 100% форм (17033) имеют <Attributes>,
162 — пустой <Attributes/>, 0 без него. Платформа эмитит ВСЕГДА.
Emit-Attributes теперь эмитит <Attributes/> при пустом списке. Зеркало py. Кейс
minimal (форма только с заголовком) → снапшот +<Attributes/>, сертифицирован
загрузкой в 1С (форма с пустым Attributes грузится). Форма РазблокированиеРеквизитов
→ match. Раундтрип: match 156→157, with diff 3→2 (остаток — 2 GroupList,
осознанно непокрыты).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раундтрип TOTAL 21→0, match 153→156. Компилятор всегда эмитил ПОЛНЫЙ каноничный
скелет <ListSettings> (filter+order+conditionalAppearance+itemsViewMode+
itemsUserSettingID), а ~7% форм имеют частичный (напр. только <filter> с
userSettingID) → лишние контейнеры = ADDED.
- Декомпилятор: Get-ListSettingsShape фиксирует «форму» скелета в
settings.listSettings (ordered-карта present top-level: filter/order/
conditionalAppearance → блок-мета 'v'/'u'/'vu'/''; itemsViewMode/
itemsUserSettingID → true). Дескриптор пишется ТОЛЬКО для не-каноничных форм
($null для полного канона и неподдержанных top-level item/dataParameters/…).
- Компилятор: при наличии дескриптора эмитит ТОЛЬКО указанные части (контент из
settings.filter/order/CA, блок-мета из дескриптора); иначе — полный канон
(без изменений). Аддитивно, дескриптор-gated → 93% канон-форм не затронуты.
Зеркало py. Формы ОстаткиАлкогольнойПродукцииЕГАИС (filter-only) и
ОстаткиПартийЗЕРНО (filter+order) → ListSettings бит-в-бит. Регресс 39/39
(канон-путь). Партиал-путь — harness + provenance (подмножество канона).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раундтрип TOTAL 25→21, match 146→153. Батч из 6 хвостовых находок:
- DisplayImportance: атрибут открывающего тега ЛЮБОГО элемента (адаптивная
важность VeryHigh/High/Usual/Low/VeryLow). Хелпер DI-Attr/di_attr внедрён в
открывающие теги; декомпилятор захватывает в диспетчере (атрибут узла).
- MinValue/MaxValue (input): типизированные (xsi:type). Тип сохраняется через
тип JSON-значения: число → xs:decimal, строка → xs:string.
- verticalSpacing: generic-скаляр группы (<VerticalSpacing>).
- rowsPicture: объектная форма {src, loadTransparent} — компилятор хардкодил
LoadTransparent=false, теперь факт. значение (792 false / 327 true в корпусе).
- autoMaxWidth: суппресс multiLineDefault-эвристики (декомпилятор фиксирует факт.
значение; multiLine-input без тега → autoMaxWidth:true).
- RowPictureDataPath: снят гейт hasMainTable у реинъекции smart-default (дин-список
без mainTable тоже несёт <RowPictureDataPath>; ""-маркер ловит реальное отсутствие).
Зеркало py (компилятор). Кейсы input-fields/groups расширены и сертифицированы
загрузкой в 1С. Регресс 39/39 в обоих рантаймах.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Форменное свойство <GroupList>id:uuid</GroupList> ссылается на члена формы по
оригинальному id + непрозрачному uuid. Компилятор раздаёт id заново (глобальный
счётчик по порядку эмиссии) → оригинальный id не воспроизводится; uuid нигде
больше в форме нет. Корректный раундтрип требовал бы имя-резолва с предпроходом
присвоения id (свойство эмитится до реквизитов) — рефактор ради редкого (30 на
корпус) свойства неясной семантики. Verbatim прошёл бы harness, но молча испортил
бы ссылку при загрузке. Решение: честный LOST, документируем ограничение.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Свойство команды «Используемая таблица» — ссылка по ИМЕНИ элемента-таблицы
(<AssociatedTableElementId xsi:type="xs:string">Имя</…>, 240 в корпусе, всегда
xs:string). Команда работает в контексте этой таблицы (текущая строка).
- Ключ table; forgiving-синонимы associatedTableElementId (XML-тег) и
ИспользуемаяТаблица (рус., регистро-/пробело-незав.) — команды идут отдельным
путём Emit-Commands, не через PROP_SYNONYMS слой Emit-Element.
- CurrentRowUse («использование текущей строки») уже поддерживался.
Зеркало py. Кейс table расширен (table + currentRowUse), сертифицирован
загрузкой в 1С. Регресс 39/39 в обоих рантаймах.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
<Autofill>true> у таблицы появляется для вспомогательных таблиц динамического
списка (отборы/параметры/настройки, привязанные к КомпоновщикНастроек), где
состав колонок генерится платформой (ChildItems пуст). В палитре свойств не
показывается — внутренний флаг конструктора. Уточнено по домен-экспертизе.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DSL зря сводил оба тега в height, а компилятор для таблицы всегда эмитил
<HeightInTableRows> → таблица с <Height>5</Height> регенерилась как
<HeightInTableRows>5</HeightInTableRows> (форма БизнесСеть/ВыборОрганизации).
Это РАЗНЫЕ свойства (высота элемента vs высота в строках), сосуществуют в 237
таблицах корпуса (Height-only 1242, HeightInTableRows-only 755).
- Развёл: height → <Height> (generic Emit-Layout, как у всех элементов),
новый heightInTableRows → <HeightInTableRows>.
- Декомпилятор: Add-Layout ловит <Height> → height, Table-блок
<HeightInTableRows> → heightInTableRows.
Зеркало py. Кейс table расширен (оба тега), сертифицирован в 1С (платформа
принимает оба). Регресс 39/39 в обоих рантаймах. Раундтрип TOTAL 68→61.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раундтрип TOTAL 121→86 (−35), match 114→124.
- InputField choice-кнопки: захват/эмит «как есть» (ChoiceButton/ClearButton/
DropListButton/SpinButton эмитились только при true, теряя явный false;
ChoiceButton=true сидел под лишним StartChoice-гейтом). Убран дефолт
choiceButton=true у ref-полей в from-object — вывод не изменился.
- Новые InputField-скаляры: choiceListButton/quickChoice/autoChoiceIncomplete
(bool), choiceForm/choiceHistoryOnInput/choiceFoldersAndItems/footerDataPath (value).
- Button checked → <Check>true</Check> (пометка toggle-кнопки). Ключ checked,
не check (check — тип-ключ CheckBoxField, был бы конфликт диспетчера типов).
- fixingInTable — в generic-скаляры (input/labelField/колонки).
- Общий слой русских синонимов ключей-свойств ($propSynonyms/PROP_SYNONYMS):
Пометка/Заголовок/Ширина/КнопкаВыбора/ФормаВыбора/… → канон. Нормализация
в Emit-Element рядом с тип-синонимами; case/space-insensitive; англ. побеждает.
Зеркало py (контент байт-в-байт). Кейсы input-fields/table/synonyms расширены
и сертифицированы загрузкой в 1С. Регресс 39/39 зелёный в обоих рантаймах.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ключ collapsedTitle у группы → <CollapsedRepresentationTitle> (мультиязычный
текст, как title/inputHint). Заголовок свёрнутого представления у collapsible/
popup групп. 172 файла в корпусе, не обрабатывался.
Зеркало py (байт-в-байт). Кейс groups сертифицирован в 1С. Регресс 39/39 ps1+py.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Регресс из 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>