Реквизит с <Save><Field>имя.Settings.Filter</Field> (напр. SettingsComposer):
декомпилятор снимал префикс "имя." ВСЕГДА (regex `(.+)`) → "Settings.Filter", но
компилятор реинъектит префикс ТОЛЬКО для полей без точки (dot-правило: путь с точкой =
полный, как есть). Рассогласование → префикс реквизита терялся при раундтрипе.
Фикс (декомпилятор): снимаем префикс "имя." только когда остаток — простое под-поле
без точки (`([^.]+)$`); многоуровневый путь "имя.X.Y" храним ПОЛНЫМ → компилятор
по dot-правилу эмитит как есть. Period-кейс (одноуровневые EndDate/StartDate/Variant)
не затронут.
Корпус 8.3.24: 366 многоуровневых Save-полей в 89 формах. Выборка 40 форм: match 40/40,
0 регрессий (включая Period). Декомпилятор-only. Регресс 43/43. Spec обновлён.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Emit-Companion / Emit-CompanionPanel вызывали DI-Attr $el, но $el НЕ их параметр —
PowerShell брал его из родительского скоупа (эмитируемого элемента). Поэтому
авто-генерируемые companion (ExtendedTooltip/ContextMenu/AutoCommandBar с name="@")
наследовали DisplayImportance владельца (CheckBoxField/UsualGroup/Table), которого
в оригинале у них нет → ложный ADDED. Корпус: ExtendedTooltip/ContextMenu НИКОГДА не
несут DisplayImportance, AutoCommandBar — только element-level (11), не companion.
Фикс: DI-Attr от СОБСТВЕННОГО объекта компаньона ($content / $panel), не от ambient
$el. Python не имел dynamic-scope-бага (di_attr на companion не эмитил вовсе), но для
паритета добавлен di_attr(content/panel) — оба рантайма теперь идентичны (companion
без собственного DI → пусто).
Выборка 19 форм (СостоянияОригиналовПервичныхДокументов acc+erp, + формы с
DisplayImportance-владельцами): match 18, ADDED DisplayImportance исчез. ps1==py
байт-в-байт. Регресс 43/43.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Компилятор форсил <ManualQuery>true</ManualQuery> всегда при наличии query (hasQuery →
true). Но платформа изредка хранит QueryText при ManualQuery=false (корпус: 16 форм
query+mainTable+manualQuery=false, против 2447 query+manualQuery=true) — список с
сохранённым авто-запросом, но не в «ручном» режиме.
Декомпилятор: фиксирует manualQuery ТОЛЬКО при отклонении от эвристики hasQuery
(query есть, но ManualQuery=false → settings.manualQuery=false). Компилятор: явный ключ
manualQuery (в т.ч. false) ПОБЕЖДАЕТ эвристику; различает present-false от absent
(раньше $st.manualQuery -eq $true трактовал явный false как absent → forced true). Зеркало py.
Выборка 16 форм (ОснованияЛьготПоИмущественнымНалогам/ФормаВыбора, … acc+erp):
match 0→16, TOTAL→0. ps1==py байт-в-байт. Регресс 43/43. Spec обновлён.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(1) Пустое значение schema-параметра дин-списка: компилятор ВСЕГДА эмитил
<dcssch:value xsi:nil="true"/>, но платформа часть пустых строковых параметров пишет
типизированным пустым <dcssch:value xsi:type="xs:string"/> (корпус: 27 typed-empty,
все xs:string; 255 nil). Решается ФОРМОЙ value, не valueType: декомпилятор различает
(<value xsi:type="xs:string"/> → value:"", <value xsi:nil/> → ключ опущен/null —
Convert-TypedValue пустого xs:string даёт ""). Компилятор: при value:"" (явная пустая
строка, тип отсутствует или string) → typed-empty xs:string, НЕ nil. Ветка ПЕРЕД vla-nil
(решение не зависит от valueListAllowed). Зеркало py.
(2) SettingsStorage — форменное свойство (ссылка на хранилище настроек, корпус 11) →
KNOWN_FORM_PROPS (декомпилятор; компилятор авто-PascalCase Emit-Properties уже эмитит).
Выборка 17 форм: match 13→15 (типовая МашиночитаемыеДоверенности — 18 typed-empty,
была вся в nil → match). ps1==py байт-в-байт. Регресс 43/43. Spec обновлён.
Остаток 2 формы (другие value-подвиды): DesignTimeValue в dcscor-контексте дропнут;
пустой LocalStringType self-closing vs пара — отдельные находки.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(1) Пустой <dcsset:right xsi:type="xs:string"/> ≠ отсутствие <right>: декомпилятор
схлопывал оба в shorthand-маркер `_`, а компилятор для shorthand `_` не эмитит right
вовсе → пустой right терялся (Get-FilterValueWithType маппит наличие пустого/nil right
в '_', отсутствие → $null — РАЗЛИЧИМЫ). Фикс (декомпилятор): при value='_' с реально
присутствующим <right> форсим объектную форму {value:"_"} — компилятор эмитит
self-closing right (ветка `_` уже была). Заодно whitespace-/пробельные значения,
рвущие shorthand-парсинг (split по пробелам), уходят в объектную форму.
(2) Whitespace-only <right> </right> (9 пробелов): PreserveWhitespace=false стрипал
в '' → '_' → self-closing. Восстанавливаем реальные пробелы из WS-дока (Resolve-WS,
как у whitespace-заголовков) → объектная форма value=" ".
(3) GetInvisibleFieldPresentations — Settings-скаляр дин-списка (после MainTable;
дефолт true, корпус 20/20 = false → эмит отклонения). Захват/эмит факт. значения,
зеркало py.
Выборка 14 форм (ДоговорыКонтрагентов, ЕдиницыГенерирующие×2, РаботаСНоменклатурой,
ПравилаИнтеграции, … acc+erp): match 0→14, TOTAL→0. ps1==py байт-в-байт. Регресс 43/43.
Spec обновлён (getInvisibleFieldPresentations). (1)/(2) — декомпилятор-only.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PictureField (поле картинки в таблице) может нести <FooterText> (ML-текст подвала
колонки) и <FooterDataPath> — общие cell-свойства колонки, уже поддержанные у
input/labelField, но не у PictureField. Декомпилятор не захватывал, компилятор не
эмитил → терялось (форма УчётныеЗаписиДокументооборота: двуязычный FooterText
«Доступность ЭП»/«Digital signature availability»).
Декомпилятор: захват footerDataPath/footerText в обработчике PictureField (зеркало
input/labelField). Компилятор: эмиссия после Emit-Layout (как у input). Зеркало py.
Ключи уже в allowlist (общие cell-props).
Корпус 8.3.24: PictureField FooterText = 4 формы. Выборка 4 формы
(УчётныеЗаписиДокументооборота acc+erp, ЗаказМатериаловВПроизводство,
СчётФактураВыданный): match 0→4, TOTAL→0. ps1==py байт-в-байт. Регресс 43/43.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Контейнер настроек компоновщика (<dcsset:filter>/<order>/<conditionalAppearance>)
может нести собственный <dcsset:userSettingPresentation> — кастомную подпись
пользовательской настройки (после userSettingID). Декомпилятор кодировал контейнер
только как блок-мету "vu"/"u"/"v" (viewMode/userSettingID), теряя presentation;
компилятор не эмитил.
Дескриптор listSettings[tag] теперь — строка-код "vu" ИЛИ объект
{ meta:"vu", presentation:<текст/{ru,en}> }. Декомпилятор: Get-PresByType сохраняет
форму по xsi:type (ru-only LocalString ≠ xs:string). Компилятор: новый параметр
blockUserSettingPresentation в Emit-Filter/Order/ConditionalAppearance (+ в гейт
hasBlockMeta — иначе контейнер только-с-presentation, без items/viewMode/userSettingID,
не эмитился). Зеркало py.
Корпус 8.3.24: 6 контейнеров-presentation в 6 формах. Выборка 6 форм
(ОтветственныеЗаАктуализацию/ЗаПодписание acc+erp, ПравилаФормированияРезервов,
СтавкиНДСНоменклатуры): match 0→6, TOTAL→0. ps1==py байт-в-байт. Регресс 43/43.
Spec обновлён. Cert: раундтрип (формат платформы, позиция как в оригинале).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Группа колонок таблицы может нести динамический заголовок из данных
(<HeaderDataPath>путь</HeaderDataPath>) и формат заголовка (<HeaderFormat>, ML-текст).
Декомпилятор не захватывал, компилятор не эмитил → теряло (14 строк на форме
БольничныйЛист/ФормаПодробнееОРасчете, 2 ColumnGroup'ы).
Ключи на columnGroup: headerDataPath (path-скаляр), headerFormat (ML — строка/{ru,en}).
Эмиссия в общем cell-блоке Emit-Layout: headerDataPath перед HeaderHorizontalAlign,
headerFormat после (порядок XSD, рядом с уже сертифицированным HeaderHorizontalAlign).
Добавлены в allowlist knownKeys (ps1+py).
Корпус 8.3.24: HeaderDataPath/HeaderFormat = по 2 (обе в этой форме — редкий край).
Форма → match (TOTAL 14→0). Зеркало py байт-в-байт (сверено нормализованным diff).
Регресс 43/43 (ps1+py). Spec обновлён (раздел columnGroup). Cert: раундтрип +
смежность с сертиф. HeaderHorizontalAlign в том же эмит-блоке.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
12 форм корпуса несут MobileDeviceCommandBarContent с одним ПУСТЫМ item
(<xr:Value xsi:type="xs:string"/>, не имя). Декомпилятор захватывал
mobileCommandBarContent: [""], но компилятор не эмитил блок:
(1) PS-ловушка: гейт `if ($def.mobileCommandBarContent -and ...)` — одноэлементный
массив @("") в boolean-контексте разворачивается в "" → falsy → блок пропущен.
Фикс: $null-проверка вместо truthy ($null -ne ... -and Count -gt 0).
(2) Пустое значение → самозакрывающийся <xr:Value xsi:type="xs:string"/> (зеркало платформы).
Python не имел unwrap-ловушки ([""] truthy), но self-closing добавлен для байт-паритета
(+ is not None гейт для единообразия).
Выборка 9 форм (РасширенныйВводКонтактнойИнформации, ХранилищеВариантовОтчетов×3,
ФормаНастроекОтчета, ИнтерфейсДокументовЭДО, ПользовательскиеМакетыПечати, …):
match 0→9, TOTAL→0. Регресс 43/43 (ps1+py). Блок именованных значений (148 форм) уже
был сертифицирован; пустой — тот же блок с пустым значением (формат платформы).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Продолжение систематической чистки whitespace-ML: колонка реквизита (ValueTable,
Decompile-AttrColumn) с whitespace-only <Title> (<v8:content> </v8:content>) теряла
пробел через Get-LangText → "" → компилятор эмитил пустой <Title/>. Тот же фикс
Get-LangText → Get-LangTextWS (декомпилятор-only, безопасный суперсет — пробел
восстанавливается только когда контент-узел есть, но пуст).
Корпус 8.3.24: 4 whitespace-заголовка колонок в 4 формах. Выборка 4 формы: match 0→4,
TOTAL→0. Регресс не затронут (декомпилятор-only).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Реквизит формы с whitespace-only <Title> (<v8:content> </v8:content>, одиночный
пробел) терялся: декомпилятор читал заголовок через Get-LangText, а PreserveWhitespace=false
стрипал пробел → "" (= суппресс-маркер «нет заголовка») → компилятор не эмитил Title.
Фикс: Get-LangText → Get-LangTextWS (существующий хелпер, восстанавливает значимый
пробел — как уже сделано для UsualGroup Title/ToolTip). Декомпилятор-only: компилятор
" "-заголовок уже умеет (прецедент групп). Для непустого/мультиязык-контента поведение
не меняется (Get-LangTextWS == Get-LangText).
Корпус 8.3.24: 13 whitespace-заголовков реквизита в 10 формах. Кластер Attribute>Title
(impact 42) был раздут harness-мис-атрибуцией: одна реальная потеря на форму, а
generic строки-обёртки (<Title>/<v8:item>/<v8:lang>ru) сыпались ложным LOST под
соседними реквизитами. Выборка 5 форм: match 0→5, TOTAL→0. Регресс 43/43.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Значение типа v8:Type (на практике всегда <prefix>:Undefined — тип «Неопределено»
из namespace http://v8.1c.ru/8.2/data/types, префикс авто d6p1/d8p1/dN…) эмитилось
без объявления namespace → битый QName; а в параметре дин-списка компилятор вообще
ронял v8:Type → xs:string.
Корпус 8.3.24: 11 тегов (6 <dcsset:right> фильтра + 5 <dcssch:value> параметра),
значение всегда prefix:Undefined, ns всегда data/types. Топ ROOT-пробел нового
baseline (Attribute>value 48 LOST + 44 ADDED).
Фикс: хелпер Get-ValueTypeNsAttr / _value_type_ns_attr (объявляет xmlns:<pref> для
не-стандартного префикса при valueType v8:Type) в обе ветки Emit-FilterItem
(скаляр + массив op `in`) + новая ветка v8:Type в Emit-DLValue / emit_dl_value.
Выборка 7 форм (Взаимодействия acc/erp, ЖурналОпераций×3, ДокументЭДОБЗК, ЧекиККМ):
match 0→6, TOTAL→0. Зеркало py байт-в-байт, регресс 43/43 (ps1+py). Раундтрип
восстанавливает точные исходные байты платформы (её собственный формат — cert не нужен).
Spec обновлён (раздел filter).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
groupList/customSettingsFolder/userSettingsGroup/commandSource в форме "N:uuid" — ссылка на
член формы по id. Наш компилятор переназначает id → verbatim указал бы НЕ ТУДА (тихая порча).
Резолв N→имя ненадёжен: N не всегда соответствует named-элементу (форма ДенежныеДокументы:
GroupList=2:uuid, но элемента id=2 НЕТ; в конфигураторе список пустой — платформа сама не
разрешает эту dangling-ссылку; uuid константный для всех форм). «Страна id=2» в бэклоге —
совпадение.
Решение: декомпилятор захватывает только ИМЯ-форму; "N:uuid" опускает с предупреждением
(stderr) — задаётся вручную через form-edit. Результат идентичен (dangling → пустой список),
но без мусорной ссылки. Имя-форма (GroupList 8, CSF 18, UserSettingsGroup 3127, CommandSource
5116 в корпусе) round-трипится как есть.
Гард `^\d+:[0-9a-fA-F]{8}-` в 4 точках захвата. Harness стрипает "N:uuid"-форму (намеренное
непокрытие). Выборка 118 форм: match 113/118, ref-тег потерь 0, регрессий 0. Отменяет
verbatim-захват CustomSettingsFolder из dd32d2a6 для id-формы (имя остаётся).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Форменное свойство формы отчёта со СКД <CustomSettingsFolder> — имя группы, куда
генерируются пользовательские настройки компоновщика (1С: «Группа пользовательских
настроек»). Декомпилятор не ловил → терялось (23 формы, напр. ИсторияРазмераПриложения).
Декомпилятор-only: +CustomSettingsFolder в KNOWN_FORM_PROPS. Компилятор уже эмитит
(emit_properties авто-PascalCase). Значение: имя группы (18) или N:<GUID> ссылка по id (5,
verbatim — как уже принятый GroupList). Ключ customSettingsFolder.
Выборка 23 формы: match 23/23, CustomSettingsFolder-потерь 0. Валидация раундтрипом
(decompiler-only). Регресс не затронут (только новый захват).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Запросный динамический список (без MainTable) задаёт ключ набора: <KeyType>
(FieldValue/RowKey/RowNumber) + <KeyField>* (0+ полей) — после Parameter*, до MainTable.
Декомпилятор не ловил → терялось (21 форма, напр. ВыборПрисоединенногоФайла).
DSL: settings.keyType (строка-enum) + settings.keyFields (массив). Взаимоисключающи с
mainTable (запросный список vs таблично-ориентированный — 1С: KeyField+MainTable ломает
пути данных списка). Декомпилятор: захват KeyType + всех KeyField; компилятор (ps1+py):
эмит после Emit-DLParameters, до MainTable (позиция из корпус-сигнатур).
Выборка 22 формы: match 17/22, KeyType/KeyField-потерь 0 (остаток — др. кластеры:
CheckBox ItemWidth, order-use, SearchControlAddition, empty-right), регрессий 0.
Регресс 43/43, ps1==py. Cert: corpus round-trip (запросные списки — 22 shipped-формы
грузятся; синтетический кейс = полный query-based список с Table, непропорционально
для verbatim 2-тег; MainTable+KeyField несовместимы → к dynamic-list-form не добавить).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Кнопка команды может нести <Parameter> (после CommandName) — параметр команды:
- xr:MDObjectRef (20 в корпусе 8.3.24): ссылка на объект метаданных, напр.
DocumentJournal.Взаимодействия (команда ShowInList «Показать в списке»);
- v8:TypeDescription (16): описание типа <v8:Type>cfg:DocumentRef.X</v8:Type>
(команда CreateByParameter «Создать по параметру»).
Декомпилятор не ловил → терялось (форма ЭлектронноеПисьмоИсходящее и др.).
DSL: ключ button.parameter (синоним «параметр»), дизамбигуация по форме значения —
строка → MDObjectRef (verbatim), объект {type} → TypeDescription (грамматика типа,
переиспользует Emit-Type с tag=Parameter). Декомпилятор: MDObjectRef → строка,
TypeDescription → {type} (Decompile-Type). Позиция: после CommandName.
Выборка 16 форм с Button Parameter: match 16/16, 0 потерь (оба вида). Кейс commands
(+кнопка с параметр:{type:CatalogRef} через рус-синоним) сертифицирован загрузкой в 1С —
позиция Parameter и синоним подтверждены. MDObjectRef-вариант: та же позиция эмиссии +
corpus round-trip (ShowInList требует list-контекст, синтетически не воспроизвести).
Регресс 43/43, ps1==py. parameter в knownKeys allowlist.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Поле <Save><Field> вида N/M (ссылка на элемент/колонку, напр. 5/0, 5/1) без двоеточия
получало лишний префикс имени реквизита (ДатаОкончанияПериода.5/0) — условие «оставить
как есть» ловило только N/M: с двоеточием (^\d+/\d+:). Форма ОтражениеДокументовВМеждународномУчете.
Фикс: ^\d+/\d+: → ^\d+/\d+ (bare N/M тоже как есть). Корпус 8.3.24: N/M bare 10, N/M: 746
(уже обрабатывался). Декомпилятор симметричен (strip префикса имя. иначе как есть) — не менялся.
Форма → match. Снэпшоты не затронуты (N/M в кейсах не встречается), регресс 43/43 (ps1+py).
Валидация раундтрипом shipped-формы (грузится в 1С; N/M — платформенная ссылка, эмитим verbatim).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
LabelDecoration-распорки/отступы несут whitespace-only Title (<v8:content> </v8:content>,
N пробелов) — у части (10/23 в корпусе 8.3.24) нет Width/stretch, и число пробелов = реальная
ширина выравнивания (не рудимент). PreserveWhitespace=false стрипал whitespace-only content в ""
→ Get-LangTextWS восстанавливал ОДИН пробел → терялось число (оригинал 3 пробела, regen 1).
Фикс (декомпилятор-only): второй XmlDocument с PreserveWhitespace=true (основной парс не трогаем,
нулевой риск); Resolve-WS навигацией по индекс-пути элементов (структура обоих документов идентична)
достаёт точную строку пробелов; Get-LangTextWS восстанавливает её вместо одиночного пробела.
Компилятор не менялся — эмитит content verbatim (esc_xml пробелы не трогает).
Выборка 34 формы с multi-whitespace content: LabelDecoration-потерь 0, match 30/34 (остаток —
др. контексты <v8:content> под Attribute + несвязанные кластеры), регрессий 0. Валидация
раундтрипом (decompiler-only, кейс не нужен).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Топ-кластер нового baseline (~190 impact). <dcsset:presentation> элемента условного
оформления и групп/сравнений фильтра: платформа хранит ru-only текст и как xs:string
(плоский), и как LocalStringType (мультиязык-обёртка с одним ru). Декомпилятор схлопывал
ru-only LocalStringType в строку (Get-MLText) → компилятор писал xs:string → mismatch.
Плюс компилятор-баг: filter-item presentation эмитился через Emit-MLText (всегда мультиязык
БЕЗ xsi:type), даже для плоской строки.
Фикс:
- Декомпилятор: Get-PresByType — ветвь по xsi:type, сохраняет {lang:text} объект для
LocalStringType (даже один ru) vs плоскую строку для xs:string. Применён к presentation
элемента CA (Build-ConditionalAppearance) и фильтра (group + comparison, Build-FilterItem).
- Компилятор (ps1+py): filter-item presentation через by-form Emit-USPresentation/
emit_us_presentation (строка→xs:string, объект→LocalStringType с xsi:type). CA-item
presentation компилятор уже эмитил by-form — не трогаем.
Выборка 45 форм с LocalStringType-presentation: presentation-потерь 0, match 27→33,
TOTAL 127→63, регрессий 0 (сверка с baseline). Кейс dynamic-list-form (+CA presentation
{ru} ru-only + filter presentation объект/строка) сертифицирован загрузкой в 1С. Регресс
43/43, ps1==py (общий снэпшот на обоих рантаймах).
baseline после кластера ListSettings/DataSet (A+B+C): match 1869→1975, TOTAL 3495→2557.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Обычное поле набора <Field DataSetFieldField> может нести ограничения использования и
связь по параметрам выбора:
- <dcssch:useRestriction> {field?,condition?,group?,order?} (54 формы) — где поле НЕ
использовать (отбор/группировка/порядок/как поле);
- <dcssch:attributeUseRestriction> та же структура (18) — ограничения для реквизитов поля;
- <dcssch:inputParameters> (6) — связь по параметрам выбора (как у параметра дин-списка).
DSL: settings.fields[].useRestriction / attributeUseRestriction (объект {field,condition,
group,order} bool | флаг-строка "#noField #noFilter #noGroup #noOrder" | массив) +
inputParameters. Общие хелперы Get-RestrictList/Emit-RestrictBlock (ps1) и parse_restrict/
emit_restrict_block (py); inputParameters переиспользует Emit-DLInputParameters. Декомпилятор
Build-RestrictObj + Build-DLInputParameters.
Порядок детей поля (из корпус-сигнатур, подтверждён загрузкой в 1С): dataPath, field,
title, useRestriction, attributeUseRestriction, presentationExpression, valueType,
appearance, inputParameters.
Выборка 69 форм с field-props: field-property потерь 0 (match 36→39, TOTAL 396→150,
cascade LOST 111→12). Кейс dynamic-list-form (+useRestriction/attributeUseRestriction
на поле Code) сертифицирован загрузкой в 1С. Регресс 43/43, ps1==py байт-в-байт.
Кластер C (DataSet динсписка) закрыт: Field valueType + CalculatedField + field
presentationExpression/appearance + field useRestriction/attributeUseRestriction/
inputParameters. Остаток (BACKLOG): нюансы пустого value (xs:string vs nil;
LocalStringType self-closing) + отдельный InputField multiple-value кластер.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Обычное поле набора <Field DataSetFieldField> может нести:
- <dcssch:presentationExpression> (выражение представления поля, 30 форм) — строка;
- <dcssch:appearance> (формат/оформление поля, ~9 форм) — dcscor:item SettingsParameterValue
(тот же блок, что в условном оформлении: параметр→значение с типизацией).
DSL: settings.fields[].presentationExpression (строка) + fields[].appearance (объект
{параметр:значение}). Декомпилятор: захват presentationExpression + appearance через
существующий Get-SettingsAppearance. Компилятор (ps1+py): presentationExpression перед
valueType, appearance после valueType (порядок исходника, подтверждён корпус-сигнатурами);
appearance переиспользует Emit-AppearanceValue/emit_appearance_value.
Выборка 36 форм с field pres/appearance: match 33/36, 0 потерь pres/appearance (остаток
3 формы — несвязанные нюансы пустого value параметра / пустого LocalStringType). Кейс
dynamic-list-form (+явное поле Code с presentationExpression+appearance Формат/ЦветТекста)
сертифицирован загрузкой в 1С. Регресс 43/43, ps1==py (общий снэпшот на обоих рантаймах).
Остаток field-свойств (BACKLOG): useRestriction/attributeUseRestriction/inputParameters/
order на обычном <Field> + 2 раскрытых нюанса (пустой xs:string value vs nil; пустой
LocalStringType self-closing vs пара).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Две части пробела DataSet динамического списка:
1. Field valueType (63 формы/54). Поле набора <Field DataSetFieldField> может нести
<dcssch:valueType> (тип значения; кастомные/вычисляемые поля). Декомпилятор ловил
field/dataPath/title/nested, теперь и valueType (переиспользует Decompile-Type);
компилятор эмитит после title через существующий emit_dl_value_type. 0 потерь на выборке.
2. CalculatedField (6 форм, редкое). Новый ключ settings.calculatedFields — зеркало skd:
shorthand "Имя [Заголовок]: тип = Выражение #noField #noFilter #noGroup #noOrder"
(порт Parse-CalcShorthand) или объект. Форм-специфика: dcssch:-теги, presentationExpression,
orderExpression* (структура {expression,orderType,autoOrder} в namespace dcscommon с
локальным xmlns), useRestriction{field,condition,group,order}. Эмиттер форм-специфичный
(skd использует dcscom:-префикс и не имеет pres/orderExpression). Позиция в DataSet —
после Field*, до Parameter*. Декомпилятор Build-CalcField (объектная форма для точного
round-trip). Выборка calc-форм: calc-теги ушли из диффов (3/6 match, остаток — отдельный
field appearance/presentationExpression).
Кейс dynamic-list-form (+grouping +calculatedFields: shorthand с флагами + объект с
presentationExpression/orderExpression/valueType) сертифицирован загрузкой в 1С (порядок
детей CalculatedField подтверждён платформой). Регресс 43/43 (ps1+py).
ps1==py байт-в-байт (сверено на кейсе). Фикс по пути: ps1 Parse-CalcShorthand — `\b` в
generator-heredoc превратился в backspace 0x08 → #-флаги не парсились (py был верен);
поймано прямой сверкой вывода ps1 vs py.
C-остаток (в BACKLOG): свойства обычного <Field> — presentationExpression + appearance
(формат/цвет поля) — отдельный подкластер.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Структура группировок дин-списка (`<dcsset:item StructureItemGroup>` → groupItems →
GroupItemField, вложенность через дочерний item) — переиспользована модель/реализация
из skd (Emit-GroupItems/Get-GroupFields), но плоская: группировка списка всегда
линейная цепочка одно-польных уровней над неявными деталями (без children/selection/
order/details — корпус подтверждает).
DSL — новый ключ `settings.grouping` (forgiving-синонимы `structure`/`группировка`):
- шорткат "A > B > C" (вложенные уровни, внешний→внутренний) или массив;
- элемент уровня — строка (имя поля) или объект {field, groupType?, periodAdditionType?,
periodAdditionBegin?, periodAdditionEnd?} для нестандартного поля (ключи = теги
исходника; periodAddition с авто-детектом ISO-дата/dcscor:Field).
Корпус 8.3.24 (29 форм/34 уровня): groupType Items 33 / Hierarchy 1, periodAddition нет.
Компилятор (ps1+py): Emit-ListGrouping + рекурсивная цепочка StructureItemGroup в
позиции после conditionalAppearance, до itemsViewMode. Оба пути — shape-дескриптор
(round-trip) и канонический (авторинг). Декомпилятор: Build-ListGrouping (линейная
цепочка; bail→$null на ветвлении/мультиполе/доп.содержимом = честный LOST, не порча);
Get-ListSettingsShape распознаёт `item`→`structure` (раньше → $null/канон-fallback,
из-за чего терялась группировка и додумывался itemsUserSettingID).
Выборка 17 форм с группировкой: match 0→10, TOTAL 75→25 (остаток — др. кластеры:
presentation xs:string, order-item use). Широкая (cat-a 102): match 82→84, TOTAL
280→256, ноль регрессий. Кейс dynamic-list-form (+grouping "Description > Code")
сертифицирован загрузкой в 1С. Регресс 43/43 (ps1+py).
Фикс по пути: PS-ловушка — одноэлементный массив разворачивался при return из
Parse-ListGrouping → строка → индексация давала char → пустой <field>. Unary comma ,@().
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раундтрип ломал кастомную подпись пользовательской настройки в элементах настроек компоновки
(filter/order/conditionalAppearance/dataParameters): <dcsset:userSettingPresentation xsi:type="xs:string">
эмитился как мультиязычный <v8:item> блок (без нужного xsi:type) → 182 строки diff на 13 формах.
Корпус (acc+erp 8.3.24): 26 xs:string (плоская строка) vs 7 v8:LocalStringType (мультиязычный).
Компилятор всегда звал Emit-MLText (мультиязычная форма без xsi:type) — ломал ОБА случая.
compile (ps1+py): выделенный Emit-USPresentation/emit_us_presentation — строка → xsi:type="xs:string",
объект {ru,en} → xsi:type="v8:LocalStringType". Заменены 4 call-site (filter item/CA/dataParameters).
decompile: Get-PresText (строка ИЛИ объект) уже стоял в filter/group/order; добавлен в dataParameters
(был Get-MLText, ронял xs:string).
Верификация: таргет-раундтрип 13 форм с xs:string-подписью → match (182→0); регресс form-compile
43/43 (ps1+py); 1С-cert dynamic-list-form (оба типа подписи — xs:string и LocalStringType — грузятся). spec.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раундтрип терял FixedArray у choiceParameter со значением-списком из ОДНОГО элемента
(напр. ВводОстатковВнеоборотныхАктивов/ФормаРедактированияСтрокиНМА: 9 из 10 FixedArray
эмитились как скаляр → 45 строк LOST). Корень — классический PowerShell unwrap: Get-ElProp
возвращает 1-элементный массив, но PS разворачивает его на RETURN функции (и при биндинге
параметра), так что $isArray=false → значение эмитилось как одиночный <Value> вместо
<Value xsi:type="v8:FixedArray"> с одним <v8:Value>.
Фикс (только ps1): в Emit-ChoiceParameters значение читается ПРЯМЫМ member/индексер-доступом
(не через Get-ElProp — его return разворачивает), массив-ность вычисляется до биндинга и
передаётся в Emit-ChoiceParamValue явным флагом -isArray (foreach по развёрнутому скаляру = 1
итерация → корректный 1-элементный FixedArray). PY не затронут (Python не разворачивает списки).
Системный артефакт: во многом раздувал кластер app:item>Value в раундтрипе (PS-харнесс).
Верификация: таргет-форма → match (45→0; FixedArray 1→10); регресс form-compile 43/43 (ps1+py);
1С-cert input-fields (1-элементный массив-choiceParameter → FixedArray, грузится).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раундтрип терял две вещи в настройках динамического списка реквизита (форма ВыборПодписантовПечатныхФорм):
1. <dcsset:dataParameters> — значения параметров запроса в ListSettings (список SettingsParameterValue
{use, parameter, value?}). Не захватывались/не эмитились вовсе.
2. <dcssch:value xsi:nil/> у схема-параметра при valueListAllowed=true: компилятор по умолчанию его
пропускал (if valueListAllowed → return), но платформа пишет не всегда (корпус 27 с / 47 без).
dataParameters: грамматика портирована из skd-compile (Emit-DataParameters + Parse-DataParamShorthand +
Test/Emit-EmptyValue) — консистентно с СКД (shorthand "Имя @off" / объект). Form-нюанс: значение
опционально (use=false плейсхолдер без value-узла, в отличие от skd-settings). compile эмитит после
filter (XSD-порядок). decompile: Build-FormDataParameters (объект с полным valueType / shorthand).
nil-значение: декомпилятор ставит явный маркер value:null при valueListAllowed+nil-тег; компилятор
эмитит nil при valueListAllowed + явный value (различает absent от null через Has-DLProp/value_explicit).
Корпус: dataParameters в 9 формах (17 items, все use=false, 4 со значениями DesignTimeValue/ent:/decimal).
Верификация: таргет-раундтрип формы → match (22→0); 9 dataParameters-форм — категория закрыта (остаток —
др. категории filter userSettingPresentation/MultipleValue*). Регресс form-compile 43/43 (ps1+py,
PY-паритет снэпшота); 1С-cert dynamic-list-form (vla-nil + dataParameters грузятся). spec.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раундтрип ломал отбор с comparisonType=Like: декомпилятор выдавал сырой токен Like в
short-form ("Поле Like %x%"), а парсер компилятора его не знал → весь текст уходил в поле,
op сбрасывался в Equal, значение терялось (напр. РегламентированноеУведомление.../ФормаСвДобытВалют:
"КодВалют Like %/ %" → поле="КодВалют Like %/ %", потеря Like + %/ %).
Корпус (acc+erp 8.3.24): из 15 comparisonType недоставал только Like (8 шт.) — добавлен Like/NotLike.
По просьбе — рус. синоним оператора: подобно/неподобно (forgiving-ввод, как ПОДОБНО в конфигураторе).
decompile (filterOpMap): Like→like, NotLike→notLike (каноничный токен short-form).
compile (ps1+py): comparisonTypes + Parse-FilterShorthand opPatterns += like/notLike + подобно/неподобно.
PY доведён до регистронезависимости PS (re.IGNORECASE на op-парсинге + CI-лукап comparisonType),
чтобы Like/LIKE/ПОДОБНО резолвились одинаково в обоих портах.
Верификация: таргет-раундтрип 4 форм с Like → match (было 10→0); регресс form-compile 43/43
(ps1+py); 1С-cert dynamic-list-form (фильтры like и подобно → <comparisonType>Like, грузятся). spec.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раундтрип терял <Format> на UsualGroup/Page — формат значения пути к данным заголовка
(<TitleDataPath>): мультиязычный формат вида БЛ=; БИ=* / BF=; BT=* (напр. УчетныеЗаписиЭДО/
УчетнаяЗапись — 4 группы/страницы, 40 строк diff с каскадом структурных v8:item-обёрток).
Корпус (acc+erp 8.3.24): <Format>-блоки — LabelField 1784, InputField 1480 (уже обрабатывались),
UsualGroup 13, Page 10 (пробел). Механизм формата уже был у полей (Add-FormatProps / Emit-MLText);
подключён к группе/странице.
decompile: Add-FormatProps в ветках UsualGroup/Page (захват format/editFormat).
compile (ps1+py): Emit-MLText <Format>/<EditFormat> в Emit-Group/Emit-Page (рядом с titleDataPath).
Верификация: таргет-раундтрип 11 форм с group/page Format → категория закрыта (0 Format LOST;
целевая форма match, было 40→0); остаток — др. категория ListSettings + 1 ring3 (SpreadsheetDocument).
Регресс form-compile 43/43 (ps1+py); 1С-cert кейса groups (группа с Format+TitleDataPath грузится). spec.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раундтрип терял <View>/<Edit> на колонках реквизита (колонка ValueTable/ValueTree с <Type>):
ролевой доступ вида <Edit><xr:Common>false</xr:Common><xr:Value name="Role.X">true</xr:Value></Edit>
(напр. НастройкиУчетаЗарплаты/ФормаДополнительныхДанных — колонки РайонныйКоэффициент/Ссылка).
Механизм xr-флага уже был у самого реквизита (View/Edit) и userVisible — у колонок не подключён.
decompile (Decompile-AttrColumn): захват view/edit через Decompile-XrFlag (bool | {common,roles}).
compile (Emit-AttrColumn, ps1+py): эмиссия <View>/<Edit> через Emit-XrFlag после FunctionalOptions.
(Колонки идут своим путём Decompile-AttrColumn, не через GENERIC_SCALARS — коллизии ключа edit нет.)
Корпус (acc+erp 8.3.24): из 282591 колонок — 14 с <View>, 21 с <Edit> (редко, но реально).
Верификация: таргет-раундтрип 72 форм с колоночными View/Edit → категория закрыта (0 LOST;
остаток — другие категории content/right). Регресс form-compile 43/43 (ps1+py); 1С-cert кейса
table (колоночные View common-only и Edit с ролью грузятся в платформу). spec обновлён.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раундтрип терял три скаляра (чистые двусторонние пробелы — не ловились ни декомпилятором,
ни компилятором):
- Table <RefreshRequest> (запрос обновления дин-списка; корпус acc+erp 8.3.24 — 33, всегда PullFromTop)
- форм-уровень <CollapseItemsByImportanceVariant> (сворачивание по важности; 27: DontUse 26/Use 1)
- форм-уровень <GroupList> (ссылка на группу списка, значение 2:<GUID>/имя; 30)
Все три — pass-through (захват «как есть», зеркало платформы). RefreshRequest — в Emit-Table
рядом с currentRowUse; форм-уровневые — через KNOWN_FORM_PROPS (decompile) + generic Emit-Properties
(авто-PascalCase, compile ps1+py).
Верификация: таргет-раундтрип 68 форм с этими тегами → три категории закрыты (0 LOST; остаток —
другие категории valueType/HorizontalSpacing). Регресс form-compile 43/43 (ps1+py); 1С-cert кейса
dynamic-list-form (все три тега, включая GroupList с GUID, грузятся в платформу). spec обновлён.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раундтрип терял префикс: оригинал <v8:Type>cfg:ConstantsSet</v8:Type>, regen — голый
<v8:Type>ConstantsSet</v8:Type> (напр. ПанельАдминистрированияБП/НастройкиРегистровУчета,
реквизит НаборКонстант). cfg:-regex компилятора требует точку (ConstantsSet.X), а голая
форма без .Имя уходила в default без префикса.
Корпус (acc+erp 8.3.24) — голые cfg-типы (без точки): DynamicList 5205 (уже обрабатывался),
ConstantsSet 103, ReportObject 10. Блок DynamicList расширен на все три. Дотированные формы
ConstantsSet.X/ReportObject.X по-прежнему ловит общий cfg:-regex. Декомпилятор не трогали —
он уже отдаёт голую форму (Decompile-Type снимает cfg:).
compile (ps1+py). Верификация: таргет-раундтрип формы → match (было 2 → 0); регресс
form-compile 43/43 (ps1+py); 1С-cert кейса attributes-types (реквизиты ConstantsSet/ReportObject
грузятся в платформу). spec обновлён.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PreserveWhitespace=false стрипает <v8:content> </v8:content> → "" (неотличимо от суппресса).
Хелпер Get-LangTextWS восстанавливал пробел только для одиночной (ru-only) строки; для
мультиязычной мапы {ru:" ", en:" "} (напр. БольничныйЛист: LabelDecoration «Пробел1» с ru+en
пробелами) оба значения терялись → regen давал <v8:content/> вместо <v8:content> </v8:content>.
Get-LangTextWS расширен на map-случай (восстанавливает " " в каждом языке, где content-узел
есть, но текст пуст — платформа не эмитит пустой content). Get-MLFormattedValue (заголовок
LabelDecoration) зарефакторен на переиспользование Get-LangTextWS вместо собственного inline
single-string восстановления. Компилятор (Emit-MLItems) пробел уже эмитит корректно — правка
только в декомпиляторе.
Версия 1.0x → 0.103 (декомпилятор — draft, продолжаем 0.xx-схему).
Верификация: таргет-роундтрип формы → match (было 4 → 0).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раундтрип терял блок ограничения типов у поля ввода на составном/характеристика-типе:
<TypeDomainEnabled> + <AvailableTypes> (напр. ЯндексМаркетВитринаФулфилмент/РегламентноеЗадание —
поле ИмяПользователя с AvailableTypes=xs:string Length=0 Variable).
Корпус (acc+erp 8.3.24): AvailableTypes встречается в 18 местах, ВСЕ — на InputField (полное
покрытие scope). Содержимое — стандартный 1С type-description (<v8:Type>+qualifiers), тот же
формат, что у реквизитов → переиспользуем существующий механизм типов:
- decompile: Decompile-Type на узле <AvailableTypes> → компактная DSL-строка (одиночная/мультитип "a | b")
- compile (ps1+py): Emit-Type с tag='AvailableTypes' (сам разбирает мультитип); TypeDomainEnabled — bool pass-through
availableTypes — формат типа реквизита (§Типы): одиночный или составной через "|".
Верификация: таргет-раундтрип всех 17 форм с AvailableTypes → 15 match, остаток 6 строк в 2 формах —
ДРУГИЕ категории (ExtendedTooltip/Value), не AvailableTypes; целевая форма match (было 8 → 0).
Регресс form-compile 43/43 (ps1+py); 1С-cert кейса input-fields (поле с мультитип AvailableTypes
грузится в платформу). spec обновлён.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раундтрип додумывал <Title> команды из имени, когда в оригинале заголовка нет
(напр. ФормаРабочегоМеста_320х320: 126 строк ADDED — «Задания выбрать», «Сканирование
далее» и т.п. на ~30 командах-кнопках с одной картинкой).
Корпус (acc+erp 8.3.24): из 92040 команд форм 99.87% имеют <Title> (захват штатный),
лишь 121 (0.13%) — без заголовка. Значит авто-вывод как дефолт верен (помощь модели),
а для редкого хвоста нужен суппресс-маркер — ровно как уже сделано для элементов
(Emit-Title) и формы (autoTitle).
compile (ps1+py): Emit-Commands зеркалит Emit-Title — ключ title есть+непустой → эмитим;
есть+"" → суппресс (не эмитим, не додумываем); отсутствует → авто-вывод из имени.
decompile: нет <Title> у команды → title:"" (иначе компилятор додумает).
Верификация: таргет-раундтрип формы → match (было 126 → 0); регресс form-compile 43/43
(ps1+py); 1С-cert кейса commands (команда с title:"" грузится без <Title>). spec обновлён.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раундтрип терял 4 свойства (категория Table-скаляры + форм-уровень):
- Table <HeaderHeight>/<FooterHeight> (высота шапки/подвала в строках; ~35/~6 форм)
- Table <CurrentRowUse> (использование текущей строки; ≠ одноимённое свойство команды,
у которой свой путь захвата/эмиссии). Значения: DontUse/Use/SelectionPresentation/
SelectionPresentationAndChoice/Choice
- форм-уровень <ConversationsRepresentation> (Auto/Show/DontShow; редкое)
Все три Table-свойства были явно отложены в Emit-Table (комментарий о «строгом Table-XSD»).
Корпусные данные показывают, что 1С эмитит те же теги в РАЗНЫХ позициях у разных форм →
загрузчик толерантен к порядку детей Table (как и существующий компилятор с ранним DataPath).
Размещены pass-through в Emit-Table (height-теги рядом с UseAlternationRowColor, CurrentRowUse
у блока дин-списка); форм-уровень — generic Emit-Properties (авто-PascalCase).
decompile (ps1): захват headerHeight/footerHeight/currentRowUse на Table; ConversationsRepresentation
в KNOWN_FORM_PROPS. compile (ps1+py): эмиссия в emit_table.
Верификация: таргет-раундтрип 4 форм → match (TOTAL diff lines 0); регресс form-compile 43/43
(ps1+py); 1С-cert кейса table (форма с тремя тегами грузится в платформу). spec обновлён.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Роль в xr-флаге (userVisible/view/edit/use, объектная форма {common,roles}) может
ссылаться по GUID (<xr:Value name="<guid>"> без префикса Role. — заимствованная роль
или расширение), а не по имени. Emit-XrFlag всегда добавлял Role. → Role.<guid>
(форма Сотрудники/ВыплатыУчётЗатрат: 4 ADDED Role.GUID + 4 LOST). Фикс: ключ-роль,
совпадающий с GUID-паттерном, эмитится как есть (без Role.). Декомпилятор GUID и так
сохранял верно (нет префикса для снятия). Зеркало py.
Форма Сотрудники → match. Кейс attributes-types (+edit с ролью по GUID) сертифицирован
в 1С (платформа принимает неизвестную GUID-роль). Регресс 43/43 (ps1+py).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Маркер пустого значения "_" (Get-FilterValue для пустого <dcsset:right xsi:type="X"/>)
эмитился компилятором как литеральный `_` (<dcsset:right xsi:type="dcscor:Field">_</...>)
в объектной форме фильтра (когда форсится valueType/userSettingPresentation). Платформа
хранит self-closing пустой тег (напр. сравнение с незаданным полем dcscor:Field, или
пустой xs:string). Фикс: value=="_" → <dcsset:right xsi:type="$vt"/> (vt из valueType
или xs:string). Зеркало py.
Формы ОтправкиОтчетности/ФормаЭлемента (dcscor:Field) → match; чинит и Новости
(xs:string пустой в object-форме). Кейс input-fields (+CA фильтр с пустым dcscor:Field)
сертифицирован в 1С. Регресс 43/43 (ps1+py).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ExtendedTooltip (companion = LabelDecoration) может нести <Events> (напр.
URLProcessing у hyperlink-подсказки — ОбработкаНавигационнойСсылки). Декомпилятор
ловил own-content (layout/оформление/флаги/hyperlink), но НЕ события → весь блок
Events LOST (топ list-iter: ExtendedTooltip>Events 492 impact). Был отложенный хвост
кластера ExtendedTooltip own-content.
Переиспользован механизм событий элемента: декомпилятор Get-Events → etObj['events'];
компилятор Emit-Events (typeKey 'label', после Title) + 'events' в companionStructKeys
(чтобы text+events шёл структурной веткой). Зеркало py. Round-trip формы
НастройкиИнтеграцииМаркетплейс/ФормаЭлемента бит-в-бит (3 ExtendedTooltip с URLProcessing).
Кейс input-fields (extendedTooltip +hyperlink +events URLProcessing) сертифицирован
в 1С. Регресс 43/43 (ps1+py).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Декомпилятор ловил эти свойства (Add-CommonProps/Add-Appearance), но эмиттеры
компилятора их не выводили → LOST. Четыре подфикса (по выбору пользователя из топа
list-iter):
1. Page>BackColor/TitleTextColor/TitleFont (193+): Emit-Page не звал Emit-Appearance.
Добавлен (profile field, после ShowTitle перед компаньоном — порядок корпуса).
2. Popup>TitleTextColor/TitleFont (133/127): Emit-Popup не звал Emit-Appearance. Добавлен.
3. ColumnGroup>HeaderPicture (144): Emit-ColumnGroup не звал Emit-ColumnPics. Добавлен
(после ShowInHeader/Layout перед оформлением — порядок корпуса).
4. UsualGroup Title/ToolTip с whitespace-контентом: Add-CommonProps читал title/tooltip
через Get-LangText (PreserveWhitespace=false стрипал <v8:content> </> → "" →
компилятор подавлял). Новый Get-LangTextWS восстанавливает " " (как Get-MLFormattedValue).
1-пробельные tooltip'ы теперь матчатся; редкий N-пробельный → косметика числа пробелов.
Зеркало py. Выборка 40 форм с этими категориями: целевые потери 0 (match 21,
остаток — несвязанный хвост). Кейсы pages (+backColor/titleTextColor/titleFont),
column-group (+headerPicture), button-group (popup +titleTextColor/titleFont)
сертифицированы в 1С. Регресс 43/43 (ps1+py).
Раскрыто (отдельно): MultipleValuesBackColor (input) — другой appearance-ключ.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Дата-значение фильтра платформой почти всегда хранится как StandardBeginningDate
Custom, а не xs:dateTime (корпус 8.3.24: 268 SBD-Custom vs 2 xs:dateTime в
dcsset:right). Добавлен естественный шорткат: голая ISO-дата без valueType →
компилятор выводит SBD Custom+date. Работает и в shorthand-строке фильтра
("ДатаЗаказа > 2020-01-01T00:00:00").
Компилятор: Emit-FilterItem ловит дату без valueType → SBD Custom (раньше → xs:dateTime);
Parse-FilterShorthand больше не ставит valueType=xs:dateTime для даты (оставляет
вывод компилятору). Декомпилятор: SBD Custom+date → голая дата без valueType
(компилятор восстановит), именованный вариант → строка+valueType, SED/нетипичное →
объект+valueType. Escape для плоского xs:dateTime — явный valueType. Зеркало py.
Кейс input-fields (+date-фильтр голой датой объектно и shorthand-строкой, +именованный
вариант) сертифицирован в 1С, round-trip подтверждён (голые даты без valueType
возвращаются). Регресс 43/43, SBD-корпус (40 форм) без регрессий (match 28).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>