xml-structure-review · git:20260831.d0275fb · 2026-08-31 · sha256 fabf5a8e7cba4f93
xml-structure-review git:20260831.d0275fbA
Immutable. This exact content is served forever at /api/v1/blob/fabf5a8e7cba4f93.
--- name: xml-structure-review description: >- Контур проверки XML-структур метаданных 1С: корректность файлов объектов, форм, схем компоновки, ролей и макетов; регистрация объекта в составе конфигурации; сверка «диск ↔ состав» в обе стороны; права на объекты в ролях расширения. Вызывается оркестратором quality-gate при изменении XML; напрямую — по запросу «проверь метаданные», «провалидируй расширение», «почему объект не попал в сборку». license: MIT --- # xml-structure-review — контур XML метаданных Проверяет структуру выгрузки конфигурации и расширений. Применимость определяется не объёмом правки, а фактом: **менялись ли XML метаданных**. | Класс | Глубина | |---|---| | C0 | пропуск | | C1 | не применим, если XML не менялся; иначе — валидация изменённых файлов | | C2 | валидация изменённых объектов **плюс проверка регистрации** | | C3 | полный проход: валидация, сверка диск↔состав в обе стороны, права в ролях | ## Прогон механики — субагент `xml-runner` Запуск скриптов и разбор их вывода делегируй субагенту `xml-runner`, передав список изменённых файлов и каталог выгрузки. Он вернёт вердикт, находки с путями и строками, а также раздел «не проверено». Причина в контексте: валидаторы печатают до тридцати ошибок на файл, и на правке класса C3 их вывод вытесняет всё остальное раньше, чем дело дойдёт до отчёта. Твоя работа начинается после его отчёта — триаж находок, привязка к типовым дефектам и решение, что чинить. Субагента может не быть — тогда прогоняй скрипты сам по разделам ниже. Записи следа в обоих случаях формируешь **ты**: субагент возвращает факты и в формат следа их не оформляет. --- ## 1. Сверка «диск ↔ состав» — главная проверка контура ```bash node "$QG/tools/xml/orphan-check.mjs" <каталог выгрузки> ``` **Почему это первое, что нужно проверять.** Объект метаданных, лежащий на диске, но не внесённый в секцию `ChildObjects` файла `Configuration.xml`, **не попадает в собранный артефакт**: сборка зелёная, валидаторы молчат, падение происходит в рантайме у пользователя. Это слепое пятно всей штатной цепочки, и закрывает его только явная сверка; почему молчит каждое звено — `references/pipeline-blind-spots.md`. Обратное направление не менее важно: имя в составе без файла на диске ломает саму сборку. **Коды возврата:** 0 — расхождений нет, 2 — есть сироты либо отсутствующие файлы. **Каталоги вне карты типов** скрипт не додумывает, а выносит в раздел «не проверено»: молчаливый пропуск здесь означал бы ровно ту дыру, ради которой проверка и написана. ### Как чинить Найденную сироту **регистрируют**, а не пересоздают: добавляют строку `<Тип>Имя</Тип>` в нужную группу `ChildObjects`. Пересоздание объекта средствами генерации перезапишет его XML и может затереть уже описанные реквизиты, измерения и ресурсы. --- ## 2. Уникальность UUID — вторая проверка того же класса ```bash node "$QG/tools/xml/uuid-unique.mjs" <каталог выгрузки> ``` Объект, скопированный вместе со своим `uuid`, и заглушка вида `a1b2c3d4-…` дают два разных объекта с одним идентификатором. Платформа при загрузке либо отвергает выгрузку, либо оставляет один из двух — второй исчезает бесшумно, ровно как файл-сирота. Валидаторы структуры совпадение между файлами не видят по устройству — разбор в `references/pipeline-blind-spots.md`. Проверяются файлы с корневым элементом `MetaDataObject`; повтор внутри одного файла — тоже находка, продублированный блок реквизита уносит с собой `uuid` оригинала. **Графические схемы не читаются:** точки карты маршрута бизнес-процесса платформа штатно копирует между процессами, и скан `Ext/Flowchart.xml` давал бы находку на каждой типовой конфигурации. Что это измерено на полной выгрузке, а не предположено, — там же, в справочнике. **Коды возврата:** 0 — дублей нет, 2 — есть дубли либо каталог не прочитан. **Как чинить:** менять UUID у **нового** объекта, а не у исходного. Правка идентификатора существующего объекта в рабочей базе равносильна его удалению и созданию заново — ссылки на него теряются. --- ## 3. Валидация структуры файлов **Путь передавай параметром `-Path`** — он принимается всеми валидаторами без исключения: ```bash 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`. **Правило времени вместо ожидания.** Загрузка обработки на пустой базе — секунды. Прогон дольше трёх-пяти минут **на пустой базе** означает зацикливание: процесс снимают и бисектят форму по группам элементов, а не ждут. Почему порог действует только на пустой базе — в том же справочнике. --- ## 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 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`.