Commit Graph

223 Commits

Author SHA1 Message Date
Nick Shirokov bbed308c85 fix(skd-decompile): не сохранять valueType если auto-detect compile даст тот же тип
Для filter right values с типом dcscor:DesignTimeValue, чьё значение
соответствует ref-pattern (Перечисление.X.Y / Справочник.X.Y / ПланСчетов.X.Y
и др.), compile auto-detect-ит DesignTimeValue из значения. Раньше
decompile всё равно сохранял valueType явно — лишний шум в DSL.

Применено к single-right и multi-right. Эффект на diff нулевой (compile
эмитит то же самое), но decompiled JSON становится компактнее и читабельнее.
2026-05-24 21:17:03 +03:00
Nick Shirokov 11ddc2b5a2 fix(skd-compile): single-line эмиссия <DataCompositionSchema xmlns=...>
Раньше эмитили шапку схемы в 8 строк (каждый xmlns на отдельной строке).
Оригинал платформы пишет всё в одну строку. Был с самого начала
существования skd-compile — не регрессия, но косметика на каждый отчёт
давала 9 строк diff (1 LOST + 8 ADDED).

Sample30 total: 458 → 238 строк diff.
2026-05-24 21:09:34 +03:00
Nick Shirokov f642f673d9 fix(skd-compile): не пропускать Auto-items в top-level selection/order
Platform может содержать SelectedItemAuto/OrderItemAuto в top-level
<dcsset:selection>/<dcsset:order> (рядом с явными полями) — это валидно.
Раньше compile использовал -skipAuto на top-level, теряя эти items.

Снапшоты регенерированы.

sample30: −10 строк (942 → 932).
2026-05-23 22:06:03 +03:00
Nick Shirokov ad99f3db0b fix(skd-compile): startDate/endDate в StandardPeriod ТОЛЬКО для variant=Custom
Анализ корпуса ERP/БСП (671 отчёт): из 635 StandardPeriod values только
93 (все Custom) имели <v8:startDate>/<v8:endDate>. Остальные 542 варианта
(ThisMonth, LastYear, Today, ThisQuarter, FromBeginningOfThisYear и т.д.)
эмитятся БЕЗ дат — это canonical platform-pattern.

Раньше compile добавлял boilerplate 0001-01-01 даты ко всем вариантам
независимо от типа. Снапшоты регенерированы.

sample30: −138 строк (1330 → 1192).
2026-05-23 21:24:42 +03:00
Nick Shirokov 0466ae8fd8 feat(skd-compile): @autoDates companions использует type=dateTime (канон БСП)
Раньше @autoDates генерировал НачалоПериода/КонецПериода с type=date →
DateFractions=Date. Реальный БСП паттерн использует DateTime (платформа сама
приводит конец периода к 23:59:59 для дат без времени, но DateTime более
явное и матчит шаблоны БСП).

Снапшоты регенерированы.
2026-05-23 20:54:48 +03:00
Nick Shirokov 5ca8ce2b64 fix(skd-compile): widths-unwrap и indent в template cell appearance
Две bug-фиксы для шаблонов:

1. PS-quirk: \$widths = if (\$t.widths) { @(\$t.widths) } else { @() }
   разворачивал одно-элементный массив в строку, после чего \$widths[0]
   возвращал первый Char (например '1' для "15.625"), а [double][Char]'1'=49.
   Заменил if-expression на обычный if-statement.

2. Indent в <dcsat:appearance>: компайлер ставил 4 таба вместо 5
   (и 5 вместо 6 у items внутри). Поправлено в обоих рантаймах.

sample30: −552 строки (2666 → 2114).
2026-05-23 17:18:50 +03:00
Nick Shirokov 0846740db7 feat(skd-compile): пустой <dcsset:filter/> на conditionalAppearance item
Платформа эмитит <dcsset:filter/> (self-closing, без условий) на
каждом condApp item, где фильтр не задан — это нормальная форма
"правило применяется ко всем строкам без дополнительных условий".

Compile теперь эмитит пустой тег если filter отсутствует/пуст.
Decompile-side уже корректно игнорировал пустой filter (Build-CondApp
читает items только если они есть).

Эффект на sample30: −252 строки diff.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 21:51:49 +03:00
Nick Shirokov 65a2b5870d feat(skd-compile): типизация appearance/outputParameters значений
Реальные платформенные значения имеют конкретные xsi:type, которые
compile терял в roundtrip:

Output параметры (расширена таблица OUTPUT_PARAM_TYPES):
- РасположениеОбщихИтогов, РасположениеИтогов → DataCompositionTotalPlacement
- РасположениеГруппировки → DataCompositionFieldGroupPlacement
- РасположениеРесурсов → DataCompositionResourcesPlacement
- ТипМакета → DataCompositionGroupTemplateType

Appearance keys (новая key-type карта в Emit-AppearanceValue):
- Размещение → DataCompositionTextPlacementType
- ГоризонтальноеПоложение/ВертикальноеПоложение → v8ui:HorizontalAlign/VerticalAlign
- ОриентацияТекста, РасположениеИтогов, ТипМакета

Auto-detect расширения:
- Числовые строки (МинимальнаяШирина=40 и др.) → xs:decimal
- ЦветТекста/ЦветФона/ЦветГраницы без префикса style:/web:/win: → v8ui:Color
  (для значений "auto", "#FFC8C8" и т.п.)

Эффект на sample30: −1122 строки diff.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 20:45:18 +03:00
Nick Shirokov 32e06cbc56 fix(skd-compile): всегда эмитить useRestriction для параметра
Платформа эмитит <useRestriction>true|false</useRestriction> у каждого
параметра безусловно. Раньше compile эмитил только если =true, что
приводило к LOST <useRestriction>false</useRestriction> в roundtrip.

Эффект на sample30: −84 строки diff.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 19:27:36 +03:00
Nick Shirokov 38b5445f15 fix(skd): откат implicit viewMode=Normal — сохраняем точное присутствие
Реальные отчёты непоследовательны: одни filter/item имеют
<viewMode>Normal</viewMode> с userSettingID, другие — нет (зависит от
момента редактирования через UI). Стратегия "compile добавляет implicit
Normal когда есть userSettingID" даёт ложные ADDED строки в bit-perfect.

Меняю на корректную модель:
- decompile сохраняет viewMode даже = 'Normal' если node физически
  присутствует в XML (object form переходит автоматически)
- compile эмитит viewMode только если явно задан в JSON

Применено к: filter (item + group), dataParameters, conditionalAppearance,
selection items, order items.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 18:01:09 +03:00
Nick Shirokov f9774d799c feat(skd-compile): implicit viewMode=Normal + user-settings на FilterItemGroup и axis
Платформа эмитит <viewMode>Normal</viewMode> автоматически когда у
элемента есть <userSettingID> (это сигнал пользовательской настройки).
Теперь compile делает то же:
- filter item, dataParameters item, conditionalAppearance item, table
  axis (column/row/point/series) — все эмитят Normal если userSettingID
  задан и явный viewMode не указан

Кроме того: FilterItemGroup теперь поддерживает свой viewMode /
userSettingID / presentation / userSettingPresentation (наравне с
обычными filter items).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 17:45:15 +03:00
Nick Shirokov eac0ae5a02 fix(skd-compile): DataSetUnion inner items оборачиваются как <item>
Платформенный 1С пишет вложенные dataSets внутри DataSetUnion как
<item xsi:type="DataSetQuery">, а наш compile эмитил <dataSet xsi:type=...>.
Это вело к двум проблемам:
- сгенерированный XML отличался от платформенного (косметика для bit-perfect)
- skd-decompile симметрично искал <dataSet> и пропускал inner items
  при чтении реальных схем — теряя все вложенные fields/titles

Эталон: upload/erf/ПроверкаЭкранирования/.../Templates/СКД_Объединение
показывает что Designer всегда пишет <item xsi:type="..."> внутри Union.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 16:00:59 +03:00
Nick Shirokov a46d5a166b feat(skd-decompile): сохранение viewMode/itemsViewMode для round-trip
Decompile теперь читает viewMode/itemsViewMode из XML и сохраняет в JSON
точно как было — даже Normal-значения (платформа эмитит эти теги
контекстно, и для bit-perfect нам важно наличие, а не сам режим).

Чтение:
- item-level: selection item, order item (новая object form)
- block-level: selection/filter/order/conditionalAppearance →
  XViewMode на settings
- structure group: viewMode + itemsViewMode на самом item
- settings: itemsViewMode

Дополнительно:
- Убран shorthand @normal из filter/condApp/dataParam (Normal — default,
  шум в JSON)
- Структурный shorthand "A > B > details" не сворачивается если есть
  viewMode/itemsViewMode на элементе
- Selection/order на structure-item сохраняются даже = [Auto] —
  compile теперь не дефолтит, поэтому наличие важно для bit-perfect

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 15:38:42 +03:00
Nick Shirokov bf4005bf76 feat(skd-compile): viewMode/itemsViewMode на блоках и structure items
DSL расширения (item-level — паттерн object form расширен):
- selection: {field, viewMode}
- order: {field, direction, viewMode} (новая object form)
- structure group: {type:group, viewMode, itemsViewMode}

DSL расширения (block-level на settings):
- selectionViewMode, filterViewMode, orderViewMode
- conditionalAppearanceViewMode
- itemsViewMode (на самих settings)

Compile эмитит viewMode/itemsViewMode только если явно задано в JSON —
это позволяет decompile сохранить точное наличие/отсутствие из XML и
получить bit-perfect round-trip (платформа эмитит эти теги
контекстно — на ABCXYZ-стиле для каждого блока, а в простых отчётах
без пользовательских настроек — не эмитит).

Дополнительно:
- Пустой LocalStringType теперь эмитится как self-closing (как платформа)
- Убран default order/selection=["Auto"] на StructureItemGroup
  (раньше compile дефолтил, теперь эмитит только если задано)

В SKILL.md не упоминаем — фича редкая. Полное описание в spec.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 15:38:29 +03:00
Nick Shirokov c3a8a9c874 fix(skd): multilang в calcField appearance и selection lwsTitle + hidden combo
Найдено через новый debug-tool debug/skd-decompile/verify-roundtrip.ps1
(XML→decompile→compile→diff на сэмпле 30 ERP).

1. Emit-CalcFields appearance: третий дубликат-emitter с тем же
   multilang-багом как был в Emit-AppearanceValue для field/cond. Унифи-
   цирован через Emit-AppearanceValue. (compile.ps1+py)

2. Emit-SelectionItem: lwsTitle для folder + field-with-title
   эмитили "$($item.folder)" — для hashtable получали "@{ru=X; en=Y}".
   Унифицирован через Emit-MLText с новой опцией -NoXsiType
   (lwsTitle в оригинале без xsi:type, в отличие от <title> в fields).
   (compile.ps1+py)

3. Build-Parameter hidden detection: combo availableAsField=false +
   useRestriction=true. Только availableAsField=false (без
   useRestriction) → object form `availableAsField: false`.

На сэмпле 30 ERP roundtrip-diff: ADDED <content> 667 → 129
(multilang-потери в selection закрыты). Остаточные LOST <item> ~10k —
другие потери (attributeUseRestriction и проч.) — отдельная задача.

Versions: compile v1.35→v1.36, decompile v0.20→v0.21.
2026-05-21 21:50:46 +03:00
Nick Shirokov 8b71054478 feat(skd-decompile): query file префикс + inline объекты/массивы по lineLimit
1. Внешний .sql теперь именуется <outputBasename>-<datasetName>.sql
   (раньше просто <datasetName>.sql). Защищает от коллизий при
   batch-decompile нескольких отчётов в одну папку: имена dataset'ов
   часто совпадают ("НаборДанных1" — почти везде).
   В JSON: "query": "@<outputBasename>-<datasetName>.sql".

2. ConvertTo-CompactJson: Try-InlineJson — пытается сериализовать
   container на одну строку. Если результат + текущий indent ≤120
   chars → inline; иначе multi-line. Применяется и к объектам и к
   массивам (включая массивы из примитивов — раньше они всегда были
   inline, что давало гигантские строки на длинных fields).

   Примеры inline (объекты ≤120 chars):
   - { "value": "B", "style": "header" }
   - { "name": "Имя", "expression": "Имя" }
   Длинные объекты и массивы — multi-line как раньше.

v0.19 → v0.20.
2026-05-21 21:04:21 +03:00
Nick Shirokov 55b80fdc08 feat(skd-decompile): компактный JSON-сериализатор + расширенный shorthand totalFields
Заменил ConvertTo-Json (PS5.1) на собственный ConvertTo-CompactJson:
- 2-пробельный indent (вместо 4 + выравнивание keys по длине)
- Массивы примитивов (string/number/bool/null) — inline `[a, b, c]`
- Массивы с объектами/nested arrays — multi-line как раньше
- Кириллица в UTF-8 (без \uXXXX-escapes)
- Корректный escape строк (\\", \\, \n, \r, \t, \uXXXX для control chars)

Build-TotalField: shorthand "name: expr" для любого однострочного
expression. Раньше object form применялась когда expression не Func(arg).
Теперь — только когда есть group или expression многострочный.
Compile принимает любой shorthand вида "dataPath: expression" (Parse-
TotalShorthand делает split по первому ":").

Save-UserStyles тоже использует новый сериализатор.

Все 16 декомпиляционных snapshot'ов обновлены (косметика — JSON
структурно тот же, тесты round-trip проходят).

На реальном отчёте (целевой корпус): 405 → 264 строк (-35%).
v0.18 → v0.19.
2026-05-21 20:50:34 +03:00
Nick Shirokov e0ee927156 feat(skd-decompile): externalize multi-line queries в отдельные .sql файлы
Если query ≥3 строк и указан -OutputPath, decompile выносит SQL в
<datasetName>.sql рядом с decompiled.json. В JSON эмитится "@<name>.sql"
вместо inline-строки.

- Имя файла: dataset name (sanitized — non-word chars → _), коллизии
  разрешаются суффиксом _2/_3/...
- compile уже поддерживает синтаксис @file.sql (Resolve-QueryValue)
  — round-trip симметричен.
- Тесты не изменились: все тестовые queries по 1 строке (порог не
  срабатывает).
- На реальных отчётах (ERP/ACC main DCS — 10-50 строк query типично)
  даёт значительно более компактный JSON + читаемый .sql с подсветкой
  синтаксиса в IDE.

Новый тест dataset-query-multiline (round-trip с внешним .sql).
v0.17 → v0.18.
2026-05-21 20:37:15 +03:00
Nick Shirokov a1131965cc feat(skd): DataSetFieldFolder + GroupItemAuto + empty-field selection
Закрывает три gap'a, выявленных при полном прогоне ERP+ACC:

1. DataSetFieldFolder — поле-папка для UI-группировки полей в композиторе
   настроек. Только dataPath + title, без valueType/role.
   - DSL: object form поля с `folder: true`.
   - Compile: при folder=true → <field xsi:type="DataSetFieldFolder">.
   - Decompile: распознать xsi:type, эмитить object form.

2. GroupItemAuto — пустой <item xsi:type="GroupItemAuto"/> в groupItems
   (auto-grouping, аналогично "Auto" в selection).
   - DSL: строка "Auto" в groupFields.
   - Compile/decompile: round-trip.

3. Empty <field/> в conditionalAppearance/selection (wildcard — apply
   to all). Раньше — SelectionItem: sentinel. Теперь эмитим как "Auto"
   (семантический эквивалент через SelectedItemAuto).

Новый тест dataset-folder-and-auto-group (round-trip).
Versions: compile v1.34→v1.35, decompile v0.16→v0.17.

На предыдущем прогоне ERP+ACC: 227 sentinel'ов (218 DataSetFieldFolder
+ 7 GroupItemAuto + 2 SelectionItem). После — 0.
2026-05-21 20:28:45 +03:00
Nick Shirokov be9ebedf14 fix(skd-compile): multilang appearance value (Формат={ru,en} и др.)
Emit-AppearanceValue / emit_appearance_value: hashtable/PSCustomObject/dict
значение → LocalStringType независимо от ключа. Раньше для значения
{ru: "ДЛФ=D", en: "DLF=D"} compile эмитил xs:string "@{ru=ДЛФ=D; en=DLF=D}"
(строковое представление PS hashtable) — потеря структуры и неверный XML.

Wrapper {use: false, value: ...} распознаётся точечно (требуются оба ключа,
чтобы не путать с multilang dict без 'use').

Унификация field-level appearance: parse сохраняет значение как есть
(а не str(v)), emit использует Emit-AppearanceValue вместо дублированной
mini-логики. Side-effect: "true"/"false" в field appearance теперь эмитятся
как xs:boolean (раньше — xs:string). Корректнее для 1С; обновлён один
snapshot теста compile.

Новый тест appearance-multilang-value (поле + conditionalAppearance с
multilang Формат — round-trip bit-perfect).
Versions: compile v1.33→v1.34.

Закрывает п.2 из handoff («известный баг с multilang appearance values»).
2026-05-21 20:01:31 +03:00
Nick Shirokov 7f3a8861ad feat(skd): inline cell style override + закрытие категории C
Cell в rows теперь может быть либо string ("text"/"{param}"/"|"/">"/null),
либо объектом {value, style: "presetName"}. Object form применяется когда
стиль ячейки отличается от template default.

compile (ps1+py): helpers _get_cell_value / _get_cell_style_or_default.
Emit-AreaTemplateDSL / _emit_area_template_dsl используют per-cell style
для appearance вместо единого template style.

decompile: refactor Build-Template. Первый pass — собрать style name per
cell в cellStyleMap. Второй pass — выбрать template default как most
frequent style. Третий pass — обернуть в {value, style} ячейки, чьи
стили отличаются от default. TemplateStyleMismatch sentinel удалён —
теперь все случаи покрываются через inline override.

Дедуп при обоих pass'ах (Match-PresetByShape) работает через
effectivePresets (built-in + user + ранее аллоцированные customN), так
что одинаковые shape'ы получают одно имя.

Новый тест template-inline-cell-style (round-trip bit-perfect).
Versions: compile v1.32→v1.33, decompile v0.15→v0.16.

Метрики на момент коммита:
- ERP-сэмпл 30: 30/30 clean, 0 sentinel'ов
- Корпус из 40 отчётов целевого класса: 40/40 clean, 0 sentinel'ов

Закрывает категории A, B, C полностью на обоих корпусах.
2026-05-21 19:53:41 +03:00
Nick Shirokov 3119700c71 feat(skd-decompile): авто-генерация skd-styles.json для custom appearance
Категория C — закрыта для однородных шаблонов с custom appearance.

Refactor fingerprint → preset shape (11 полей: font/fontSize/bold/italic/
hAlign/vAlign/wrap/bgColor/textColor/borderColor/borders). vAlign теперь
учитывается в matching (раньше игнорировался).

Алгоритм:
1. При -OutputPath загружается existing skd-styles.json рядом (если есть);
   user presets накладываются на built-in по той же логике что и compile.
2. Каждая ячейка → Extract-CellPreset → Match-PresetByShape против
   effectivePresets (built-in + user).
3. Если не match — Allocate-CustomStyle: новый customN, регистрируется
   в effectivePresets и accumulator.
4. По окончании Save-UserStyles пишет skd-styles.json рядом с outputPath
   (preserved existing + новые customN).
5. Compile подхватит файл по своим search-путям (cwd/dirname/scan-up).

В SKILL.md не добавляем (custom стили — для round-trip, не для написания
модель с нуля; built-in `data/header/subheader/total/none` остаются
основным интерфейсом для модели).

- runner.mjs: новый preRun step `writeFile` для подготовки fixture-файлов
  в workDir (нужен для теста с предзаписанным skd-styles.json).
- Новый тест template-custom-style: preRun пишет myHeader preset,
  скомпилирует темплейт, decompile reverse'ит → переиспользует имя
  myHeader (не создаёт customN).
- v0.14 → v0.15.

Метрики:
- ERP-сэмпл 30: 24 → 0 sentinel'ов, clean 26 → 30/30
- Целевой корпус 40 отчётов: 39 → 25 sentinel'ов (часть закрыта), clean
  19 → 20/40. Остаточные — шаблоны с разными стилями в разных ячейках
  одного шаблона (нужно per-cell style override — отдельная задача).
2026-05-21 19:32:17 +03:00
Nick Shirokov 4bd8f27dec feat(skd): preset style=none + детект пустого fingerprint в decompile
Закрывает простую часть категории C: шаблоны где у ячеек appearance
содержит только per-cell атрибуты (МинимальнаяШирина и др.) без font/
borders/colors. Раньше такие шаблоны попадали в TemplateStyleMismatch.

- skd-compile (ps1+py): новый preset 'none' со всеми стилевыми полями
  null/false. Emit-CellAppearance / _emit_cell_appearance пропускают
  Font-элемент когда style.font=null.
- skd-decompile: пустой fingerprint (после отсева per-cell ключей) не
  считается за стиль ячейки; если все non-merge ячейки шаблона имели
  пустой fp — эмитим style="none" вместо sentinel.
- Новый тест template-no-style (round-trip bit-perfect).
- Versions: compile v1.31→v1.32, decompile v0.13→v0.14.

Метрики:
- ERP-сэмпл 30: 32 → 24 sentinel'ов, clean 24→26/30
- Корпус из 40 отчётов целевого класса: 45 → 39 sentinel'ов, 19/40 clean

Остаточные sentinel'ы — реальный custom appearance (нестандартный шрифт/
выравнивание/цвет вне built-in пресетов). Требует расширения DSL под
hashtable-style — отдельная задача.
2026-05-21 18:38:34 +03:00
Nick Shirokov a73517ee07 feat(skd): nested folder + nestedObject + groupItem object form (round-trip)
Закрывает категорию B полностью на ERP-корпусе:
- selection.folder теперь рекурсивный: внутри items могут быть string,
  {field, title}, или ещё одна {folder, items: [...]}. Compile/decompile
  обходят дерево рекурсивно (Emit-SelectionItem / Build-SelectionItem).
- structure: новая ветка type=nestedObject с {objectID, settings:
  {selection, filter, order, conditionalAppearance, outputParameters}}.
- groupFields теперь объектная форма {field, groupType?, periodAdditionType?}
  когда не дефолт (Items / None). Compile уже принимал; decompile перестаёт
  ставить warning GroupItemDetails. Try-StructureShorthand игнорирует
  object-form поля при сворачивании в строку.
- Refactor: Build-Structure для StructureItemGroup теперь использует
  общий Get-GroupFields вместо дублированного inline-кода.

В SKILL.md не добавляем (формы редкие/сложные, модель не пишет с нуля).

Новый тест structure-nested-and-folder покрывает все три случая bit-perfect.
Versions: compile v1.30→v1.31, decompile v0.12→v0.13.

На сэмпле 30 ERP-отчётов: 754 → 32 sentinel'ов (-96%), clean 4 → 24/30.
Остаточные 32 — все TemplateStyleMismatch (категория C, диагностика).
2026-05-21 18:19:49 +03:00
Nick Shirokov cbc9f0cf61 feat(skd): inputParameters — ChoiceParameters/Links + typed values (round-trip)
DSL: object-form ключ inputParameters — массив элементов, каждый типизирован
по форме value:
- choiceParameters: [{name, values: [...]}] — параметры выбора (DesignTimeValue)
- choiceParameterLinks: [{name, value, mode}] — связи параметров выбора
- value (+ optional use=false) — простое типизированное значение (bool/string/number)

Compile: Emit-InputParameters / emit_input_parameters → <r:inputParameters>...
Decompile: Read-InputParameters читает любой xsi:type, без SilentDrop warnings.
Build-Parameter — убран вызов несуществующего Check-InputParameters.

В SKILL.md не добавляем (форма сложная — модель не пишет с нуля, но при
декомпиляции из реального отчёта получает корректно и compile примет назад).

Новый тест field-input-parameters (3 типа элементов, bit-perfect round-trip).
Versions: compile v1.29→v1.30, decompile v0.11→v0.12.

На сэмпле 30 ERP-отчётов: SilentDrop:ChoiceParameters/Links 51 → 0,
clean reports 8 → 21, total sentinel'ы 109 → 58.
2026-05-21 18:07:59 +03:00
Nick Shirokov 4413a06c49 feat(skd): orderExpression — сортировка поля по выражению (round-trip)
- skd-compile (ps1+py): object-form ключ orderExpression{expression,orderType,autoOrder}
  → <r:orderExpression><dcscom:expression/><dcscom:orderType/><dcscom:autoOrder/>
- skd-decompile: читает <r:orderExpression> → object form поля, без SilentDrop warning
- SKILL.md skd-compile: одна строка в "Дополнительные ключи объектной формы"
- docs/skd-dsl-spec.md: пример в объектной форме поля
- Новый тест field-order-expression (round-trip bit-perfect)
- Versions: compile v1.28→v1.29, decompile v0.10→v0.11

На сэмпле 30 ERP-отчётов: SilentDrop:orderExpression 11 → 0.
2026-05-21 17:59:19 +03:00
Nick Shirokov 537adfd3f8 feat(skd-decompile): shorthand-render роли + extras без whitelist
- Get-RoleInfo: любой <dcscom:KEY> со строковым значением → extras; whitelist убран
- Render-Role: shorthand-строка "@flag K=V" когда все extras-значения простые
  (regex ^[\w\.\-]+$); иначе object form
- Build-Field: shorthand-роль встраивается в field-shorthand-строку
- v0.9 → v0.10

Новый тест-кейс field-roles-rich (балансовые поля с balanceGroupName/balanceType,
@dimension @required) — bit-perfect round-trip с compile.

На сэмпле 30 ERP-отчётов: 754 → 120 sentinel'ов (-84%), 8/30 clean.
ComplexRole 27 → 0.
2026-05-21 17:43:05 +03:00
Nick Shirokov 48b08d77e5 test(skd-decompile): 6 snapshot-based test cases по слоям
Кейсы создают исходник через preRun (skd-compile), декомпилируют его и
сравнивают workDir со снапшотом (Template.xml + decompiled.json):

- minimal-query — базовый DataSetQuery
- fields-types-and-restrictions — типы, роли, restrictions, multilang
  title, appearance, composite type, presentationExpression
- calc-total-params — calculatedFields, totalFields, parameters с
  autoDates/valueList/hidden/availableValues
- templates-with-style-merge-drilldown — built-in стили header/data,
  merge >/|, drilldown свёртка
- variant-full — selection с folder, filter Or, conditionalAppearance,
  outputParameters, dataParameters="auto", structure shorthand,
  groupTemplates
- dataset-types — DataSetQuery + DataSetObject + DataSetUnion

Все 6 passes на runtime=powershell. Готовая база для регрессии при
питон-порте (можно прогнать тот же набор через --runtime python).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 16:20:59 +03:00
Nick Shirokov 5ec21f24b4 feat(skd-decompile): scaffold — Ring 3 fail-fast, sentinel/warnings, query extraction
Layer 1 of the skd-decompile plan: SKILL.md with disable-model-invocation,
ps1 skeleton with XML→JSON pipeline, namespace probe for non-DCS root,
sentinel/warnings accumulator, and DataSetQuery extraction (query only).
Test case minimal-query demonstrates round-trip via skd-compile preRun.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 13:40:46 +03:00
Nick Shirokov 334241bea4 fix(skd-info): handle absolute -OutFile paths correctly
Раньше PS1-порт делал `Join-Path (Get-Location) $OutFile` без проверки,
что приводило к невалидным склейкам типа `C:\cwd\C:\abs\path.txt`, и
запись падала с «The given path's format is not supported».

Теперь: если путь абсолютный — нормализуется через `Path::GetFullPath`,
если относительный — резолвится против CWD. Python-порт уже был корректен,
только version bump.

Дополнительно: `args_extra` в runner.mjs теперь поддерживает подстановку
`{workDir}` — нужно для тестов с абсолютными путями внутри workspace.

Тесты: `skd-info/outfile-absolute-cyrillic` (PS + Python).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 10:19:20 +03:00
Nick Shirokov ce1ba0bab1 feat(skd-edit): normalize line endings + diagnostics on patch-query not-found
patch-query теперь нормализует CRLF/CR → LF в old/new/query перед поиском,
поэтому многострочные шаблоны с любым стилем переводов строк находятся
корректно (XmlDocument декодирует text-узлы как LF).

При not-found вместо сухого сообщения выводится воронка диагностики:
  1) cross-dataset probe — «Found in dataset 'Y' instead — wrong -DataSet?»
  2) tolerant probe (collapse whitespace + NBSP) — «would match with
     whitespace normalized» + точка расхождения
  3) prefix divergence — «matched N of M chars, expected 'X' (U+...) but
     got 'Y' (U+...)» + короткий контекст

Тесты: 4 новых кейса (positive CRLF-tolerant + 3 диагностических negative).
Регрессия 45/45 PS + 45/45 Python.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 19:53:24 +03:00
Nick Shirokov 6e14f2502e feat(skd-edit): empty parameter values, decimal/time/fix/composite
Brings skd-edit to parity with the skd-compile fixes from 449f814 / 0537410
/ ff2d851. Same helpers (Test-EmptyValue / Build-EmptyValueXml in ps1,
is_empty_value / build_empty_value_xml in py) shared by add-parameter,
modify-parameter (value=...), availableValues, add-dataParameter and
modify-dataParameter.

Behavior:
- Sentinel empty (null / "" / "_" / "null") serializes per declared type,
  matching what 1C Designer writes — ref/no-type → xsi:nil, string →
  xsi:type="xs:string" empty, date/time/decimal/boolean → typed zero,
  StandardPeriod → Custom + zero dates, dataParameters → dcscor:value
  xsi:nil="true". @valueList omits <value> entirely.
- Build-ValueTypeXml accepts bare decimal (10,2), decimal(N) (N,0),
  string(N,fix) (AllowedLength=Fixed), time (DateFractions=Time), and
  composite array of types.
- Parse-ParamShorthand / Parse-DataParamShorthand regex .+ → .* so a
  trailing `=` is treated as the empty-value sentinel. New @valueList flag.

New test cases: empty-param-values-add / -modify / empty-dataparam-values.
Three outdated skd-edit snapshots regenerated to reflect upstream skd-compile
empty-value emission (rename-parameter, reorder-parameters,
conditional-appearance-v2).

Regression: 41/41 ps1 + 41/41 py runner; 41/41 verify-snapshots ps1 + py
(live load into 1С 8.3.24). skd-compile 23/23 and skd-validate 15/15
unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 13:38:52 +03:00
Nick Shirokov ff2d8513c4 feat(skd-compile): time type, string(N,fix), and composite type parameters
Calibrated against live Designer output in upload/erf/ПроверкаЭкранирования.

- New type 'time' (synonym 'время'): xs:dateTime with DateFractions=Time
  for time-of-day values. Designer uses the same xs:dateTime XSD type as
  date/dateTime — only DateFractions differs. Empty value: typed-zero
  0001-01-01T00:00:00 (same as dateTime).

- Extended string regex to accept (N,fix) → AllowedLength=Fixed (was
  Variable-only). Non-empty fixed-string values are emitted as-given
  without space-padding to Length — the platform handles padding on save.

- Composite types in parameters (array of types in object form, e.g.
  ["string(10,fix)", "CatalogRef.X"]) now work end-to-end: valueType
  emits each type with its qualifiers, and empty composite values
  serialize as <value xsi:nil="true"/> matching Designer.

Test case empty-param-values extended with 5 new params covering all
three additions. Snapshot validated by skd-validate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 12:52:26 +03:00
Nick Shirokov a5a1636918 feat(skd-validate): catch broken XDTO in valueType and value
skd-validate was purely structural (names/refs/duplicates) and missed an
entire class of bugs that XDTO rejects at db-load-xml — exactly the
kinds of mistakes the LLM (or hand-edits) commonly introduce.

New section 16: valueType structural — each <v8:Type> must have a known
prefix (xs:/v8: or any prefix bound to enterprise/current-config),
qualifier blocks must match their preceding type, and qualifier
internals (Digits/FractionDigits/AllowedSign, Length/AllowedLength,
DateFractions) must use legal tokens.

New section 17: value content — <value xsi:type="dcscor:DesignTimeValue">
rejects literal placeholders ('_') and empty strings, since these are
the exact symptom of the titan team's BUG-2.

5 new fixtures cover: bare-decimal, missing-qualifiers,
qualifier/type mismatch, ref-literal '_', bad AllowedSign token.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 11:57:20 +03:00
Nick Shirokov 05374100c1 fix(skd-compile): accept bare decimal and decimal(N) with sensible defaults
Emit-SingleValueType / emit_single_value_type previously required full
decimal(D,F) — anything else fell through to a fallback that produced
invalid <v8:Type>decimal</v8:Type> (no xs: prefix, no qualifiers).

New regex `^decimal(\((\d+)(,(\d+))?(,nonneg)?\))?$` accepts:
- decimal                → 10,2,Any (money default — most common 1C intent)
- decimal(N)             → N,0,Any (integer)
- decimal(N,nonneg)      → N,0,Nonnegative
- decimal(N,M)           → as before
- decimal(N,M,nonneg)    → as before

Synonyms (число, число(N), etc.) inherit the same forms via Resolve-TypeStr.

Shared Emit-ValueType is called from fields, parameters, and output
parameters — one fix covers all three paths. 3 existing snapshots
regenerated with proper xs:decimal + qualifiers, plus new
decimal-qualifier-defaults test case covering all 5 forms × synonyms.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 11:45:23 +03:00
Nick Shirokov 449f814d16 fix(skd-compile): Designer-compatible empty parameter values
Centralized empty-value handling: shorthand `=`, `= _`, `= null` and
object-form `value: null` / `""` now serialize per type, matching what 1C
Designer writes:
- ref / no-type → <value xsi:nil="true"/>
- string → <value xsi:type="xs:string"/>
- date/decimal/boolean → typed zero (0001-01-01 / 0 / false)
- StandardPeriod → Custom variant with zero dates
- @valueList → omit <value> entirely

Closes BUG-1 (StandardPeriod @autoDates) and BUG-2 (CatalogRef.X = _
producing invalid <value>_</value>) reported by titan team. New helpers
Test-EmptyValue / Emit-EmptyValue (ps1) and is_empty_value /
emit_empty_value (py) shared by Emit-ParamValue, availableValues loop,
and explicit dataParameters emit. Shorthand regex .+ → .* so trailing
`=` parses as empty.

Reference: upload/erf/ПроверкаЭкранирования (live Designer dump).
New test case empty-param-values covers all 10 type×sentinel combos;
3 existing snapshots regenerated to include the now-correct <value>
tags.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 11:27:24 +03:00
Nick Shirokov 3eaa7ffa3b fix(skd-edit): drop unneeded " → &quot; in query/expression
Зеркалим решение из skd-compile: убираем .Replace('"','&quot;') из Esc-Xml
и удаляем post-process, который принудительно ставил &quot; внутри
<query>/<expression>. Реальный Конфигуратор так не пишет — экранирование
было анти-1С-стилем и портило round-trip diff.

Снимок add-calculated-field-restrict обновлён под новый формат.
Кейс preserve-entities-modify-parameter-title удалён: его смысл
инвертировался (теперь проверял бы нормализацию, а не сохранение),
а часть про многострочный xmlns уже покрыта preserve-xmlns-multiline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 16:51:04 +03:00
Nick Shirokov 98ebb478ee fix(skd-compile): drop unneeded " → &quot; — matches Designer style
Конфигуратор внутри текстового контента <query>/<expression> оставляет " сырыми
(проверено на ERP DCS: 1504 raw " против 0 &quot;). Убираем .Replace('"','&quot;')
из esc_xml — теперь round-trip diff против типовых остаётся чистым.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 16:50:55 +03:00
Nick Shirokov fb67b1b80d fix(skd-edit): realistic multilang fixture (ERP-style appearance block)
multilang-base/Template.xml содержал <editFormat xsi:type="v8:LocalStringType">
на <field xsi:type="DataSetFieldField">, что нелегально по XDTO-схеме DCS —
1С Designer падал с "Исключение XDTO" при загрузке через
LoadExternalDataProcessorOrReportFromFiles. Snapshot-тесты этого не ловили
(только byte-equality), а platform-verify (tests/skills/verify-snapshots.mjs)
ронялся на трёх кейсах с этой фикстурой.

Заменил <editFormat> на реалистичный <appearance> блок с вложенным
<dcscor:item xsi:type="dcsset:SettingsParameterValue"> и многоязычным
<dcscor:value> (ru + en) — структура взята из типовой ERP-выгрузки. Это
даёт более правильный test для preserve-unknown-children: <appearance>
содержит вложенный multi-lang xsi:type-узел, который точно прошёл бы
через DOM round-trip с искажениями, если бы _unknownChildren не работал.

preserve-unknown-children-modify-field: shorthand изменён с
"@ignoreNullsInGroups" на "@dimension" (no-op по составу role, но
триггерит rebuild). Прежний @ignoreNullsInGroups без @dimension давал
комбинацию, которую Designer отвергает (ignoreNullsInGroups валиден
только в контексте resource-роли).

39/39 snapshot suite (PS+PY) + 39/39 platform verify через erf-build →
Designer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 15:19:13 +03:00
Nick Shirokov 79db5de6ee fix(skd-edit): preserve multi-lang title + unknown children in modify-*
В типовых конфигурациях (ERP, БП, ЗУП и т.д.) у полей и параметров обычно
есть мульти-язык title (ru + en, иногда + локализация). До этого modify-field /
modify-parameter / modify-dataParameter, перестраивая элемент через
Build-MLTextXml, оставляли только последнее найденное <v8:content> в ru —
en/uk/kk siblings молча терялись, и при следующей выгрузке Designer
ломал миграцию.

Read-FieldProperties сохраняет полный OuterXml <title> в _rawTitle и
коллекционирует OuterXml неизвестных дочерних элементов
(<editFormat>, <appearance>, кастомные расширения) в _unknownChildren.
Build-FieldFragment эмитит:
* _rawTitle как есть, если user не задал новый title;
* Patch-MLTextRu(_rawTitle, newRu) если user задал ru-override — патчит
  только <v8:content> в <v8:lang>ru</v8:lang>, остальные языки сохраняет;
* _unknownChildren в конце поля (после valueType).

modify-parameter аналогично: при title-override проверяет multi-lang
(>1 <v8:item>) и патчит ru через Patch-MLTextRu, иначе ребилдит ru-only.

set-field-role сохраняет нестандартные подэлементы <role> (например
<dcscom:addition>, <dcscom:groupFields>), не входящие в фиксированный
known-children set и не указанные через kv в shorthand.

xmlns-стрип на захваченных OuterXml — лишние декларации (которые сериализаторы
добавляют для standalone-фрагментов) убираются.

PY: lxml etree.tostring по умолчанию включает .tail (whitespace после
закрывающего тега), что приводило к non-idempotent ростy whitespace при
повторных прогонах. Везде добавлен with_tail=False.

Новые тесты с idempotent: true:
* preserve-multilang-modify-field (ru-override на multi-lang title);
* preserve-multilang-modify-parameter (то же для параметра);
* preserve-unknown-children-modify-field (role flag, проверяем что
  <editFormat> и en title не теряются).

Общая fixture: multilang-base/Template.xml с полем и параметром,
у каждого ru + en title; поле также имеет <editFormat>.

39/39 PS + 39/39 PY. skd-edit v1.20 -> v1.21.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 15:18:07 +03:00
Nick Shirokov 23d2cb42de fix(skd-edit): preserve <valueType>, detect line endings, drop CRLF leak
Targeted follow-ups к round-trip фиксу:

* modify-field больше не теряет <valueType> при перестройке поля —
  Read-FieldProperties сохраняет полный OuterXml элемента (StringQualifiers,
  NumberQualifiers, DateQualifiers и т.п.), Build-FieldFragment отдаёт его
  обратно. Лишние xmlns-декларации, добавляемые сериализатором при
  выгрузке поддерева, стрипаются регексом.
* Line-ending convention теперь определяется при load (CRLF vs LF) и
  единообразно применяется в финале save. Раньше CreateWhitespace и
  Build-*Fragment везде использовали CRLF, что приводило к смешанным
  переносам в LF-исходниках (и наоборот) и к non-idempotent выходу
  modify-parameter title (run 1 → \n\t\t<title>\r\n... → run 2 →
  \r\n\t\t<title>\r\n...).
* PS Insert-BeforeElement переведён на LF; все -join "`r`n" → "`n";
  py "\r\n".join → "\n". Конечная нормализация переносов делается в
  save в соответствии со script:LineEnding.
* preserve-entities-modify-parameter-title.json теперь idempotent: true
  (после фикса CRLF leak'а двойной прогон byte-identical).

На реальной схеме diff после modify-field составил 30 строк: целевая
вставка title плюс полезная одноразовая коррекция ранее повреждённых
&quot; в text-content <dcsat:expression>. modify-field идемпотентен.

skd-edit v1.19 -> v1.20.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 15:18:07 +03:00
Nick Shirokov 511bfe7fdf fix(skd-edit): NO-OP skip + format-preserve post-process (round-trip)
XmlDocument round-trip искажал Template.xml даже при отсутствии правок:
декодировал &quot; в <query>/<expression>, схлопывал многострочный xmlns
корня, добавлял пробел перед /> и записывал файл при [WARN] not found.

Дирти-флаг ($script:Dirty / dirty) ставится только на успешной мутации;
финальный save пропускается с [INFO] No changes -- file untouched, если
ни одна операция в batch ничего не изменила. Post-process после OuterXml
восстанавливает raw-форматирование корневого xmlns из исходного файла,
re-escape `"` в текстах <query>/<expression> с anchored regex (не задевая
xsi:type="..."), и нормализует <foo .../> к <foo.../>.

Замеры на реальной схеме после modify-field: diff упал с 423 строк до 37
(94% шума устранено), повторный прогон byte-identical.

В runner.mjs добавлен caseData.idempotent: re-run + byte-equality на всех
файлах workDir. Три новых кейса (NO-OP, entity-preserve, xmlns-multiline)
+ общий fixture roundtrip-base. Все 33 ранее существовавших snapshot
перегенерированы под корректное форматирование (восстанавливают то, что
старый skd-edit ломал).

skd-edit v1.18 -> v1.19. PS и PY порты синхронизированы.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 15:17:42 +03:00
Nick Shirokov 7fa279c354 feat(skd-edit): clear-conditionalAppearance + multiline patch-query (доки)
- Новая операция clear-conditionalAppearance в стиле clear-selection/
  order/filter. Закрывает потребность "заменить набор правил оформления"
  через clear + re-add.
- patch-query: многострочные подстроки уже работали (string.Replace
  корректно обрабатывает \n). Зафиксировано в SKILL.md.
- add-total: shorthand-шаблон с тремя случаями (Func, Func(expr),
  identity-выражение) — после fix Bug 6 поведение нужно явно объяснить.
- Косметика: убрана утечка XML-внутренностей в комментарии примера
  set-field-role @period.
- Пример patch-query @once заменён на более типовой случай уникальной
  подстроки (КАК ВТ_СтароеИмя вместо ЛЕВОЕ СОЕДИНЕНИЕ).

Регресс: 33/33 PS, 33/33 PY, 33/33 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 17:39:24 +03:00
Nick Shirokov 28a2a34c84 fix(skd-edit): add-total identity expression для не-аггрегатных функций
Раньше "DataPath: X" всегда заворачивалось в X(DataPath). Если X не
аггрегатная функция (например, имя другого ресурса или сам DataPath),
получалось некорректное выражение типа Проверка(Проверка).

Зеркалю логику из skd-compile: whitelist аггрегатных функций
(Сумма, Количество, Минимум, Максимум, Среднее + EN-варианты).
Для остального — identity (использовать funcPart как есть).

Сообщение [OK] теперь показывает фактически записанный expression.

Регресс: 32/32 PS, 32/32 PY, 32/32 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:16:27 +03:00
Nick Shirokov f0f1e88aaa feat(skd-edit): patch-query @once — assert ровно одно вхождение
Защищает от случайных замен в комментариях/совпадениях имён:

  "ЛЕВОЕ СОЕДИНЕНИЕ => ВНУТРЕННЕЕ СОЕДИНЕНИЕ @once"
  # fail, если в запросе 0 или 2+ вхождений

Без флага default — replace-all (как раньше, обратная совместимость).

При успехе сообщение содержит фактическое число вхождений
"(N occurrence(s))", помогает заметить неожиданную множественность
без явного @once.

Регресс: 31/31 PS, 31/31 PY, 31/31 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:00:55 +03:00
Nick Shirokov e7cbf306a0 feat(skd-edit): availableValue — список с replace-семантикой и в add-parameter
- Единый list-синтаксис: availableValue=v1[: p1], v2[: p2], ...
  Элементы через запятую, представление после двоеточия.
- Запятые/двоеточия внутри значений и представлений — в одинарных кавычках:
  availableValue=Окр1: 'руб., коп.', Окр1000: руб.
- add-parameter теперь принимает availableValue= и создаёт начальный список
  в одном вызове (раньше требовался последующий modify-parameter).
- modify-parameter availableValue=... ЗАМЕНЯЕТ весь список (раньше
  append). Согласуется с остальными modify-* для одиночных свойств.
- SKILL.md: добавлен shorthand-шаблон для modify-parameter,
  расширен для add-parameter [availableValue=список].

Существующие тесты мигрированы со старого ;;-batch на новый list-синтаксис.
Снапшоты сохранились (тесты стартовали с пустого списка — semantics
совпадает для greenfield).

Регресс: 29/29 PS, 29/29 PY, 29/29 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 15:37:56 +03:00
Nick Shirokov 5090deb5bc feat(skd-edit): set-field-role — управление ролями поля
Новая операция: полная замена <role>-блока поля dataSet.

- Shorthand: "<dataPath> [@флаги] [kv=значение]"
- Флаги (зеркало skd-compile): @balance, @dimension, @account, @period,
  @required, @autoOrder, @ignoreNullValues
- KV: balanceGroupName, balanceType, parentDimension, accountTypeExpression,
  orderType, expression, periodNumber, periodType
- Пустой spec (только dataPath) — снимает роль целиком
- Поддерживает пакетный режим

Закрывает потребность временного toggle off/on роли при отладке
(было: ручной Edit XML), а также корректировку balance/dimension
после add-total.

Регресс: 27/27 PS, 27/27 PY, 27/27 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:53:55 +03:00
Nick Shirokov 8b0bcf0194 feat(skd-edit): флаги @hidden и @always для параметров
- @hidden — скрывает параметр от пользовательских настроек
  (useRestriction=true + availableAsField=false). Для констант-параметров.
- @always — параметр всегда подставляется в запрос (use=Always).
  Используется самостоятельно для видимых обязательных параметров.
- Композируются: @hidden @always одной строкой даёт типовой паттерн
  "скрытая константа всегда применяется".
- Поддержка в add-parameter и modify-parameter, идемпотентны.

Регресс: 25/25 PS, 25/25 PY, 25/25 платформенный verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:14:19 +03:00
Nick Shirokov 529a5cacae feat(skd-edit): modify-structure + фиксы set-structure/parameter/patch-query
- modify-structure: новая операция, меняет groupItems группы по @name=,
  сохраняя Selection/order/filter/conditionalAppearance (Bug 1)
- set-structure: shorthand поддерживает запятую для нескольких полей
  в одном уровне группировки (Bug 2)
- set-structure: @name= с обрамляющими кавычками (двойными/одинарными)
  снимает их при записи в <dcsset:name> (Bug 3)
- add-parameter: ссылочные типы (CatalogRef, ChartOfAccountsRef, …)
  пишут <value xsi:type="dcscor:DesignTimeValue">, не xs:string (Bug 4a)
- modify-parameter: namespace-aware lookup существующих свойств
  — обновляет inplace, не плодит дубли (Bug 4b)
- modify-parameter value=…: пересборка <value> с корректным xsi:type
  из <valueType> (попутно лечит ранее битый XML)
- patch-query: батч ;;-сегментов триммится по краям (Bug 5)
- skd-compile: симметричный фикс ссылочных типов в emit_value

Регресс: 23/23 PS, 23/23 PY (skd-edit), 21/21 PS+PY (skd-compile),
23/23 платформенный verify-snapshots.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 13:40:49 +03:00
Nick Shirokov 8b0f55f1cc feat(form-validate): silent-skip числовых и UUID-DataPath в Check 5
В реальных выгрузках ERP/БП встречаются непрозрачные платформенные
DataPath, которые невозможно проверить из одного Form.xml:
- bare numeric ("10", "1000003") — внутренние индексы платформы
- "N/M:<uuid>" — ссылка на метаданные по UUID

Раньше Check 5 ругался на них "attribute not found". Теперь такие
пути пропускаются без счёта в paths checked и без ошибки.

Реалистичные пользовательские опечатки (кириллица в имени атрибута)
продолжают ловиться обычной проверкой attrMap.

Добавлен тест-кейс datapath-opaque-refs, версия v1.5 → v1.6.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 11:40:27 +03:00