feat(skills): порядок объектов метаданных в ChildObjects

Навыки-создатели дописывали новый объект в конец группы своего вида, а стандарт
требует порядка по имени (АПК:1108). Замеры на 8 боевых выгрузках: 103 385 объектов
лежат по алфавиту, нарушают его ровно дописки в хвост. Стенд подтвердил, что
беспорядок вечен: платформа нормализует порядок ВИДОВ (возвращает канонический),
но порядок имён внутри вида не трогает.

Настройка newObjectPosition в .v8-project.json (end по умолчанию | byName) —
решение проекта, а не вызова: читают её meta-compile, role-compile, xdto-compile,
cfe-borrow и cf-edit add-childObject. Компаратор при этом константа, моделирующая
дерево Конфигуратора: ключ «ранг+символ» без культурных таблиц, одинаковый в обоих
портах на любой ОС. На корпусе он даёт 4 нарушения на 125 088 пар против 2866 у
ordinal-сравнения, которым cf-edit и cfe-borrow сортировали до сих пор.

Subsystem не упорядочивается автоматически нигде: пока подсистемы не перечислены
в <SubsystemsOrder>, порядок дерева задаёт порядок разделов в панели, а платформа
этот список сама не заводит.

Настройка не чинит накопленное, поэтому cf-edit получил операцию sort-childObjects
(вся конфигурация или названные виды). Она переставляет значения узлов, а не узлы,
поэтому диф — чистая перестановка строк. Имя вида принимается в любом регистре,
во множественном числе и по-русски; неизвестный вид — отказ со списком допустимых.

Попутно:
- PS-порты создателей переведены с DOM-сериализации на текстовую вставку: на
  выгрузке не в каноне Конфигуратора они переписывали заголовок без просьбы;
- PS-сторона семьи detect_xml_style/finalize_xml_bytes закрыта в cf-edit и
  cfe-borrow — правка чужого файла наследует его BOM/EOL/заголовок;
- xdto-compile присоединён к семье Register-InChildObjects вместо инлайн-копии;
- закрыт ложный успех в py subsystem-compile: <ChildObjects /> с пробелом ET
  разбирает, а текстовые ветки не находили — файл писался без вставки;
- cfe-borrow py не импортировал json, из-за чего резолвер молча возвращал end;
- cf-edit add-childObject ставил объект в конец блока, за пределы своей группы,
  когда видов старше в файле не было.

Проверки: 906/906 на PowerShell и 903/906 на Python, 10 гардов, верификация
эталонов платформой без падений, раундтрип отсортированной конфигурации на
8.3.24 и 8.3.27, сортировка боевой выгрузки ACC (1,4 МБ) и расширения из корпуса.

Задачу принёс PR #85; часть кода взята оттуда.

Co-Authored-By: Sergei Pleshanov <72200277+Abacadabras@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QoAJmoNbgWKobA7JGgN5S3
This commit is contained in:
Nick Shirokov
2026-08-29 17:34:09 +03:00
co-authored by Sergei Pleshanov Claude Opus 5
parent 7409bacd47
commit c7b0dce151
302 changed files with 13595 additions and 388 deletions
+38 -12
View File
@@ -71,7 +71,7 @@ const FAMILIES = [
// вверх. Группа db-* использует её же, чтобы найти запись базы и взять реквизиты
// хранилища — задача одна, поэтому семья общая, а не вторая с тем же телом.
{ id: 'full', authority: 'cf-edit',
consumers: ['db-dump-xml', 'db-load-git', 'db-load-xml', 'db-repo', 'db-update',
consumers: ['cfe-borrow', 'db-dump-xml', 'db-load-git', 'db-load-xml', 'db-repo', 'db-update',
'form-add', 'form-compile', 'form-edit', 'help-add', 'interface-edit', 'meta-compile',
'meta-edit', 'meta-remove', 'mxl-compile', 'role-compile', 'skd-compile', 'skd-edit',
'subsystem-compile', 'subsystem-edit', 'template-add', 'xdto-compile', 'xdto-edit'] },
@@ -145,7 +145,7 @@ const FAMILIES = [
{ id: 'base', authority: 'cf-init',
consumers: ['cfe-borrow', 'cfe-init', 'epf-init', 'erf-init', 'form-add', 'form-compile',
'help-add', 'meta-compile', 'mxl-compile', 'role-compile', 'skd-compile',
'subsystem-compile', 'subsystem-edit', 'template-add'] },
'subsystem-compile', 'subsystem-edit', 'template-add', 'xdto-compile'] },
],
},
@@ -213,24 +213,30 @@ const FAMILIES = [
{ id: 'text-no-quot', authority: 'meta-compile',
consumers: ['cf-init', 'cfe-init', 'epf-init', 'erf-init', 'form-compile', 'form-edit',
'meta-edit', 'mxl-compile', 'role-compile', 'skd-compile', 'skd-edit',
'subsystem-compile', 'subsystem-edit'] },
'subsystem-compile', 'subsystem-edit', 'xdto-compile'] },
],
},
// ─── Сохранение стиля XML при round-trip (#44/#46/#47) ───────────────────
{
name: 'detect_xml_style', py: '_detect_xml_style', ps1: null,
name: 'detect_xml_style', py: '_detect_xml_style', ps1: 'Detect-XmlStyle',
variants: [
{ id: 'base', authority: 'cf-edit',
consumers: ['cfe-borrow', 'form-add', 'form-remove', 'help-add', 'interface-edit', 'meta-edit',
'meta-remove', 'subsystem-edit', 'template-add', 'template-remove'] },
{ id: 'base', authority: 'cf-edit', consumers: [],
// PS-сторона семьи пока закрыта только в радиусе задачи про порядок объектов;
// в остальных навыках та же канонизация лежит инлайном — отдельная волна.
consumersPy: ['cfe-borrow', 'form-add', 'form-remove', 'help-add', 'interface-edit', 'meta-edit',
'meta-remove', 'subsystem-edit', 'template-add', 'template-remove'],
consumersPs1: ['cfe-borrow'] },
],
},
{
name: 'finalize_xml_bytes', py: '_finalize_xml_bytes', ps1: null,
name: 'finalize_xml_bytes', py: '_finalize_xml_bytes', ps1: 'Finalize-XmlText',
variants: [
{ id: 'base', authority: 'cf-edit',
consumers: ['cfe-borrow', 'form-add', 'form-remove', 'help-add', 'interface-edit', 'meta-edit',
'meta-remove', 'subsystem-edit', 'template-add', 'template-remove'] },
{ id: 'base', authority: 'cf-edit', consumers: [],
// PS-сторона семьи пока закрыта только в радиусе задачи про порядок объектов;
// в остальных навыках та же канонизация лежит инлайном — отдельная волна.
consumersPy: ['cfe-borrow', 'form-add', 'form-remove', 'help-add', 'interface-edit', 'meta-edit',
'meta-remove', 'subsystem-edit', 'template-add', 'template-remove'],
consumersPs1: ['cfe-borrow'] },
],
},
@@ -420,7 +426,7 @@ const FAMILIES = [
name: 'ChildObjects: регистрация объекта в составе',
py: 'register_in_childobjects', ps1: 'Register-InChildObjects',
variants: [
{ id: 'grouped', authority: 'meta-compile', consumers: ['role-compile'] },
{ id: 'grouped', authority: 'meta-compile', consumers: ['role-compile', 'xdto-compile'] },
{ id: 'nested-parent', authority: 'subsystem-compile', consumers: [],
why: 'родителем бывает вложенный Subsystem.xml произвольной глубины: отступ берётся из документа, а запись дописывается в конец блока — фиксированные три табуляции там неверны, и группировать по типу нечего' },
],
@@ -447,6 +453,26 @@ const FAMILIES = [
],
},
// ─── Порядок объектов метаданных в <ChildObjects> ────────────────────────
// Куда встаёт новая запись — решение проекта (newObjectPosition в .v8-project.json),
// а не навыка. Компаратор при этом константа: он моделирует дерево Конфигуратора и
// одинаков для всех проектов, поэтому команда сортировки cf-edit настройку не читает.
{
name: 'ChildObjects: настройка newObjectPosition',
py: 'get_new_object_position', ps1: 'Get-NewObjectPosition',
variants: [
{ id: 'base', authority: 'meta-compile',
consumers: ['cf-edit', 'cfe-borrow', 'role-compile', 'xdto-compile'] },
],
},
{
name: 'ChildObjects: порядок имён объектов',
py: 'compare_metadata_names', ps1: 'Compare-MetadataNames',
variants: [
{ id: 'base', authority: 'meta-compile',
consumers: ['cf-edit', 'cfe-borrow', 'role-compile', 'xdto-compile'] },
],
},
];
// ─── Семьи, разъехавшиеся целиком ───────────────────────────────────────────