feat(meta-compile,meta-validate): проверки на тип-множество там, где его не принимают

Запрет неочевидный, а отказ платформы приходит поздно и одной строкой из
Конфигуратора. Три уровня строгости, все замерены загрузкой в базу на
8.3.24.1691, а не выведены из документации:

- ОШИБКА — множество в составе определяемого типа. Платформа отвергает файл
  целиком («ОпределяемыйТип.<Имя> - Недопустимый тип»); проверено на
  ОпределяемыйТип, Характеристика, ЛюбаяСсылка и голых ссылках, контрольный
  вариант с обычным CatalogRef.<Имя> принят. Отсюда и ноль таких узлов в
  корпусе — это запрет, а не совпадение.
- ПРЕДУПРЕЖДЕНИЕ — голый метатип в типе значения ПВХ. Загрузка проходит, но
  Конфигуратор такой тип не предлагает: в дереве выбора СправочникСсылка и
  ДокументСсылка — папки без флажка, а ЛюбаяСсылки там нет вовсе. Плюс AnyRef
  раундтрипом возвращается как AnyIBRef, то есть молча меняется.
- ПРЕДУПРЕЖДЕНИЕ — определяемый тип одним из составного. Конфигуратор даёт
  выбрать его только единственным, но отказывать нельзя: в корпусе erp+acc
  6500 единственных против 1 составного, и этот один лежит в типовой ERP
  (Документ.НачислениеИСписаниеБонусныхБаллов.Баллы — два определяемых типа
  подряд). Навык не вправе отказаться собрать то, что поставляет 1С.

В meta-compile состав множеств берётся опросом самого эмиттера, а не второй
копией его регулярок: список видов живёт в Emit-TypeContent, и копия
разъехалась бы с ним молча.

Развёртка по 3428 объектам ERP: ровно 2 срабатывания, оба на том самом
реальном составном реквизите. Ложных нет.

Предупреждения пишутся прямо в stderr, а не через Write-Warning: в PS 5.1 тот
уходит не в тот поток (конвенция из cf-init), и до проверки они не доезжали.

Оба кейса-предупреждения проверены платформой — она эти конфигурации грузит,
что и подтверждает выбор «предупреждение, а не отказ».

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-09-20 18:45:16 +03:00
co-authored by Claude Opus 5
parent 079a177cf4
commit 1481e58bfc
67 changed files with 4022 additions and 9 deletions
@@ -1,4 +1,4 @@
# meta-validate v1.28 — Validate 1C metadata object structure (Python port)
# meta-validate v1.29 — Validate 1C metadata object structure (Python port)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import os
@@ -1666,6 +1666,38 @@ for uk in sorted(unknown_vocab):
if not bad_grammar and not not_storable and not unknown_vocab and types_seen:
report_ok(f"22. Type names: {types_seen} checked")
# ── Check 23: тип-множество там, где его не принимают ──
# Три уровня строгости, все замерены загрузкой в базу на 8.3.24.1691:
# ERROR — множество в составе определяемого типа: платформа отвергает файл целиком
# («ОпределяемыйТип.<Имя> - Недопустимый тип»), проверено на ОпределяемыйТип,
# Характеристика, ЛюбаяСсылка и голых ссылках;
# WARN — голый метатип в типе значения ПВХ: загрузка проходит, но Конфигуратор такой тип не
# предлагает (в дереве выбора это папка без флажка), а ЛюбаяСсылка на выгрузке
# возвращается как ЛюбаяСсылкаИБ;
# WARN — определяемый тип одним из составного: Конфигуратор даёт выбрать его только
# единственным. В корпусе erp+acc 6500 единственных против 1 составного — и этот один
# лежит в типовой ERP (Документ.НачислениеИСписаниеБонусныхБаллов.Баллы), поэтому не ошибка.
dt_sets_seen = 0
for tb in root.xpath("//md:Type | //md:ValueType", namespaces=NS):
sets = tb.xpath("v8:TypeSet", namespaces=NS)
if not sets:
continue
dt_sets_seen += 1
members = len(tb.xpath("v8:Type", namespaces=NS)) + len(sets)
owner = tb.getparent().getparent()
owner_kind = etree.QName(owner.tag).localname if owner is not None else ""
for st in sets:
raw = re.sub(r'^(?:cfg|d\d+p\d+):', '', (st.text or "").strip())
if owner_kind == "DefinedType":
report_error(f"23. Определяемый тип '{obj_name}': в составе тип-множество '{raw}' — платформа не загрузит такой файл («Недопустимый тип»). Состав определяемого типа — только конкретные типы")
continue
if owner_kind == "ChartOfCharacteristicTypes" and not re.match(r'^(DefinedType|Characteristic)[.]', raw):
report_warn(f"23. План видов характеристик '{obj_name}': тип значения '{raw}' Конфигуратор не предлагает (в дереве выбора это папка без флажка); ЛюбаяСсылка на выгрузке вернётся как ЛюбаяСсылкаИБ")
if members > 1 and re.match(r'^DefinedType[.]', raw):
report_warn(f"23. Составной тип содержит определяемый тип '{raw}' — Конфигуратор даёт выбрать его только единственным; платформа загрузит")
if dt_sets_seen:
report_ok(f"23. Type sets: {dt_sets_seen} block(s) checked")
# ── Check 18: свойства, появившиеся в новых версиях формата ──
# Реестр «тег → минимальная версия формата». Служит двум целям: (1) поймать свойство в файле со
# слишком старым штампом — при сборке на старой платформе оно будет молча отброшено (платформа