xml-structure-review — контур XML метаданных

SkillFiles & storage

A check loop for 1C metadata XML structures: correctness of object files, forms, data composition schemas, roles, and templates; object registration within the configuration; two-way 'disk ↔ composition' reconciliation; object rights in extension roles. Invoked by the quality-gate orchestrator when

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the xml-structure-review — контур XML метаданных skill

What this skill tells your AI

The instructions your AI receives, as published by romandredan/1c-quality-gate in skills/xml-structure-review/SKILL.md and read by ahel’s review.

Проверяет структуру выгрузки конфигурации и расширений. Применимость определяется не объёмом правки, а фактом: менялись ли XML метаданных.

КлассГлубина
C0пропуск
C1не применим, если XML не менялся; иначе — валидация изменённых файлов
C2валидация изменённых объектов плюс проверка регистрации
C3полный проход: валидация, сверка диск↔состав в обе стороны, права в ролях

Прогон механики — субагент xml-runner

Запуск скриптов и разбор их вывода делегируй субагенту xml-runner, передав список изменённых файлов и каталог выгрузки. Он вернёт вердикт, находки с путями и строками, а также раздел «не проверено».

Причина в контексте: валидаторы печатают до тридцати ошибок на файл, и на правке класса C3 их вывод вытесняет всё остальное раньше, чем дело дойдёт до отчёта. Твоя работа начинается после его отчёта — триаж находок, привязка к типовым дефектам и решение, что чинить.

Субагента может не быть — тогда прогоняй скрипты сам по разделам ниже. Записи следа в обоих случаях формируешь ты: субагент возвращает факты и в формат следа их не оформляет.


1. Сверка «диск ↔ состав» — главная проверка контура

node "$QG/tools/xml/orphan-check.mjs" <каталог выгрузки>

Почему это первое, что нужно проверять. Объект метаданных, лежащий на диске, но не внесённый в секцию ChildObjects файла Configuration.xml, не попадает в собранный артефакт: сборка зелёная, валидаторы молчат, падение происходит в рантайме у пользователя. Это слепое пятно всей штатной цепочки, и закрывает его только явная сверка; почему молчит каждое звено — references/pipeline-blind-spots.md.

Обратное направление не менее важно: имя в составе без файла на диске ломает саму сборку.

Коды возврата: 0 — расхождений нет, 2 — есть сироты либо отсутствующие файлы.

Каталоги вне карты типов скрипт не додумывает, а выносит в раздел «не проверено»: молчаливый пропуск здесь означал бы ровно ту дыру, ради которой проверка и написана.

Как чинить

Найденную сироту регистрируют, а не пересоздают: добавляют строку <Тип>Имя</Тип> в нужную группу ChildObjects. Пересоздание объекта средствами генерации перезапишет его XML и может затереть уже описанные реквизиты, измерения и ресурсы.


2. Уникальность UUID — вторая проверка того же класса

node "$QG/tools/xml/uuid-unique.mjs" <каталог выгрузки>

Объект, скопированный вместе со своим uuid, и заглушка вида a1b2c3d4-… дают два разных объекта с одним идентификатором. Платформа при загрузке либо отвергает выгрузку, либо оставляет один из двух — второй исчезает бесшумно, ровно как файл-сирота. Валидаторы структуры совпадение между файлами не видят по устройству — разбор в references/pipeline-blind-spots.md.

Проверяются файлы с корневым элементом MetaDataObject; повтор внутри одного файла — тоже находка, продублированный блок реквизита уносит с собой uuid оригинала.

Графические схемы не читаются: точки карты маршрута бизнес-процесса платформа штатно копирует между процессами, и скан Ext/Flowchart.xml давал бы находку на каждой типовой конфигурации. Что это измерено на полной выгрузке, а не предположено, — там же, в справочнике.

Коды возврата: 0 — дублей нет, 2 — есть дубли либо каталог не прочитан.

Как чинить: менять UUID у нового объекта, а не у исходного. Правка идентификатора существующего объекта в рабочей базе равносильна его удалению и созданию заново — ссылки на него теряются.


3. Валидация структуры файлов

Путь передавай параметром -Path — он принимается всеми валидаторами без исключения:

python "$QG/tools/xml/meta-validate.py" -Path "<путь>"

У каждого скрипта есть ещё собственное имя параметра, и они разные (-ObjectPath, -FormPath, -RightsPath, -SubsystemPath, -TemplatePath, -CIPath, -ConfigPath, -ExtensionPath). Не подставляй имя от одного скрипта другому: allow_abbrev=False, и вызов упадёт с ошибкой разбора аргументов. -Path снимает вопрос целиком.

Что проверяетсяВалидаторЧто передавать
Объект метаданных (справочник, документ, регистр, перечисление)meta-validate.pyфайл Объект.xml
Управляемая формаform-validate.pyфайл Form.xml
Схема компоновки данныхskd-validate.pyфайл макета СКД
Роль и праваrole-validate.pyлюбое из трёх: Roles/Имя.xml, каталог Roles/Имя, Roles/Имя/Ext/Rights.xml
Подсистемаsubsystem-validate.pyфайл подсистемы
Макет табличного документаmxl-validate.pyфайл макета
Командный интерфейсinterface-validate.pyфайл командного интерфейса
Конфигурация целикомcf-validate.pyкорень выгрузки
Расширение конфигурацииcfe-validate.pyкорень расширения
Внешняя обработка или отчётepf-validate.pyкорень исходников обработки

Роль — единственный объект, где проверяется не файл объекта, а Rights.xml; валидатор приводит к нему любую из трёх форм пути сам.

Флаги: -Detailed — подробный вывод, -MaxErrors N — ограничение числа сообщений, -OutFile <путь> — вывод в файл.

Если Python недоступен — запиши [qg skipped: layer=xml, scope=structure-validation, reason=python_unavailable] и всё равно выполни пункт 1: сверка диск↔состав работает на Node и от Python не зависит. Она же и есть самая ценная часть контура.

Если валидатор упал с ModuleNotFoundError: No module named 'lxml' — это не находка в проверяемом коде, а недоступность инструмента: все валидаторы разбирают XML через lxml. Запиши [qg skipped: layer=xml, scope=structure-validation, reason=lxml_unavailable], назови лечение (pip install lxml) и так же выполни пункт 1. Молча выдать это за ошибку файла — худший исход: правка пойдёт в исправный XML.


4. Права на объекты в ролях расширения

Для расширений, содержащих собственные роли: собственный объект расширения без явно выданных прав невидим пользователю, и ни сборка, ни валидаторы этого не показывают.

Проверяй, что для каждого нового объекта расширения права заданы в файле прав роли. Симптом пропуска — объект существует, механизм работает, но у пользователя пустой список или отсутствующая команда.

Контр-сигналы — где отсутствие прав законно. Прежде чем выпускать находку, сверься с references/role-rights-model.md:

  • у Перечисление и РегламентноеЗадание объектных прав не существует — пустой набор здесь никогда не находка, а запись о правах в роли, наоборот, дефект;
  • право Use у HTTP- и веб-сервисов выдаётся точке вызова (HTTPService.<Имя>.URLTemplate.<Шаблон>.Method.<Метод>, WebService.<Имя>.Operation.<Имя>), а не сервису целиком;
  • отсутствующий Ext/Rights.xml — валидное состояние пустой роли, а не потерянный файл.

Собственное против заимствованного. Права требуются собственным объектам и собственным реквизитам расширения; у заимствованных они наследуются от конфигурации. Признак принадлежности задан отсутствием тега, а не пометкой — разбор в references/cfe-object-belonging.md.


5. Дефекты, которые проходят валидацию

Валидаторы разбирают XML по схеме формата и молчат о конструкциях, законных по схеме, но ломающих платформу. Такой дефект опаснее обычного: отчёт зелёный, а артефакт не собирается.

AutoCommandBar таблицы с Autofill и вложенным ExtendedTooltip. Загрузка внешней обработки или отчёта уходит в бесконечный цикл со 100% CPU — не ошибка и не диалог, а зависание; form-validate.py при этом даёт «OK». Контр-сигнал: у CommandBar та же конструкция штатна — признак действует только внутри AutoCommandBar таблицы. Законные формы разметки и второй кандидат, снятый тем же разбором, но не изолированный, — references/pipeline-blind-spots.md.

Правило времени вместо ожидания. Загрузка обработки на пустой базе — секунды. Прогон дольше трёх-пяти минут на пустой базе означает зацикливание: процесс снимают и бисектят форму по группам элементов, а не ждут. Почему порог действует только на пустой базе — в том же справочнике.

Тип поля схемы компоновки на объект вне состава расширения. Ссылка вида CatalogRef.Пользователи на незаимствованный объект теряется при загрузке в базу целиком и молча: файл на диске тип содержит, а в базе поле остаётся без типа, и форма отчёта не открывается — падают все варианты, включая типовые. Ловится пунктом 14 cfe-validate.py (qg:CFE-TYPE-REF-NOT-ADOPTED). Контр-сигнал: макет, побайтово равный вендорному, тип сохраняет — расширение не хранит свою копию. Измерения и разбор — в references/pipeline-blind-spots.md.

Спорить надо с базой, а не с файлом. Когда поведение платформы противоречит содержимому исходника, сверяют выгрузку из базы (DESIGNER /DumpConfigToFiles <каталог> -Extension <имя>), а не файл на диске: загрузка — не побайтовый перенос, часть конструкций она отбрасывает.


6. Типовые дефекты структуры

ДефектПризнакЧем ловится
Файл-сиротаобъект на диске вне составапункт 1
Отсутствующий файлимя в составе без файлапункт 1
Дубль UUIDдва объекта или реквизита с одним идентификаторомпункт 2
Нарушен порядок объектов в составенесоответствие каноническому порядку типовcfe-validate.py
Невалидные элементы формыэлементы вне схемы форматаform-validate.py
Рассогласованные версии форматаразные версии в связанных файлахmeta-validate.py
Обработчик формы без процедурыqg:XML-FORM-HANDLER-MISSING: <Event> называет имя, которого нет ни в модуле формы, ни в модуле базовой формы. Открытию формы это не мешает (проверено на платформе) — дефект спит до наступления события, отсюда 🟠, а не блокировкаform-validate.py
Действие команды без процедурыqg:XML-FORM-ACTION-MISSING: то же для <Action> команды формыform-validate.py
Отсутствие хранилища вариантов у отчётане задано хранилище настроекepf-validate.py
Права объекта не заданы в ролиобъект расширения не виден пользователюпункт 4
Права выданы типу, у которого их нетзапись Enum.* или ScheduledJob.* в файле правrole-validate.py, пункт 4
Неполное заимствованиеAdopted без ExtendedConfigurationObjectcfe-validate.py, пункт 4
Зависание загрузки на командной панелиAutofill и ExtendedTooltip внутри AutoCommandBar таблицыпункт 5, валидаторами не ловится
Параметр СКД против виртуальной таблицыqg:SKD-PARAM-VT-COLLISION: параметр Период/НачалоПериода/КонецПериода типа StandardPeriod при периодической ВТ без явных слотов — «Несоответствие типов» при формированииskd-validate.py
Недопустимое поле в выборке группировки СКДqg:SKD-GROUP-NONAGGREGATE-FIELD: поле — не поле группировки (с учётом родителей и реквизитов) и не ресурс — полный отказ формированияskd-validate.py
Группировка СКД без выбранных полейqg:SKD-GROUP-EMPTY-SELECTION: ни полей, ни Авто — запрос выполняется, отчёт молча пуст (предупреждение)skd-validate.py
Тип поля схемы компоновки на объект вне состава расширенияqg:CFE-TYPE-REF-NOT-ADOPTED: ссылка вида CatalogRef.Имя на незаимствованный объект — платформа молча выбрасывает <valueType> при загрузке, поле остаётся без типа, форма отчёта не открывается (предупреждение)cfe-validate.py, пункт 14

Записи следа

[qg applied: layer=xml, scope=registration-check, ids=[qg:XML-ORPHAN], verdict=violation:qg:XML-ORPHAN]
[qg applied: layer=xml, scope=uuid-uniqueness, ids=[qg:XML-UUID-DUP], verdict=clean]
[qg applied: layer=xml, scope=structure-validation, ids=[qg:XML-STRUCT], verdict=clean]
[qg applied: layer=xml, scope=form-binding, ids=[qg:XML-FORM-HANDLER-MISSING,qg:XML-FORM-ACTION-MISSING], verdict=clean]
[qg skipped: layer=xml, reason=not_applicable]

Первые три строки печатают сами инструменты — переноси их вывод дословно. Запись structure-validation печатает любой из валидаторов XML (meta-, form-, role-, skd- и остальные семь): проверка структуры называется одним именем независимо от вида файла. Каждый инструмент отмечается в журнале прогонов, и валидатор следа сверяет: запись applied по проверке, инструмент которой не запускался, снятие гейта не пройдёт.

Семантические находки СКД (qg:SKD-PARAM-VT-COLLISION, qg:SKD-GROUP-NONAGGREGATE-FIELD, qg:SKD-GROUP-EMPTY-SELECTION) печатает тот же skd-validate.py внутри прогона structure-validation — отдельного вызова для них нет. Тексты запросов в <query> схемы он не разбирает — их проверяет query-lint.mjs контура code, которому изменённые XML передаются наравне с .bsl.

Формат — ../quality-gate/references/evidence-format.md.

Валидность структуры не означает компилируемость. Валидаторы разбирают XML и не компилируют тела модулей; синтаксическая ошибка внутри процедуры проходит их все. Если проверка конфигурации платформой не запускалась, нужна запись [qg not_verified: dimension=compilation, reason=no_platform].


Принципы

  • Регистрация проверяется раньше структуры. Идеально валидный XML вне состава бесполезен.
  • Сверка идёт в обе стороны. Сирота ломает рантайм, отсутствующий файл ломает сборку.
  • Зелёная сборка ничего не доказывает. Загрузка конфигурации из файлов игнорирует незарегистрированное молча.
  • Сироту регистрируют, а не пересоздают — пересоздание затирает содержимое объекта.
  • Отсутствие прав — не всегда упущение. У части типов объектных прав не существует, и требование выдать их отправляет искать несуществующую настройку.
  • Валидатор молчит и о законном, и о неразобранном. «OK» на форме, которая вешает загрузку, — не вердикт о работоспособности, а граница схемы формата.

$QG — каталог установленного плагина. Как его разрешить (переменная CLAUDE_PLUGIN_ROOT в оболочке пуста) — см. раздел «Путь к инструментам плагина» в навыке quality-gate.

Signals

GitHub stars
25
Forks
6
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
xml-structure-review
Source
github.com/romandredan/1c-quality-gate