xml-structure-review — контур XML метаданных
SkillFiles & storageA 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.
No other account needed.
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 без ExtendedConfigurationObject | cfe-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