xml-structure-review — контур XML метаданных
Проверяет структуру выгрузки конфигурации и расширений. Применимость определяется не объёмом правки, а фактом: менялись ли 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.