fix(xdto): три дефекта, найденных платформенной верификацией снэпшотов

verify-snapshots загружает результат каждого кейса в 1С. Раньше навыки xdto
через него не проходили вовсе; первый прогон дал 5 из 9. Ни корпусная сверка,
ни валидатор такого не ловили: корпус состоит из заведомо валидных пакетов,
а синтетические кейсы до сих пор в базу не грузились.

1. fixed. В модели XDTO это булев флаг, значение лежит в default; в XSD наоборот —
   fixed="V" несёт значение. Компилятор писал значение прямо в fixed, и платформа
   отвергала пакет («Отсутствует фиксированное значение свойства»). Перевод сделан
   в обе стороны; по принципу прощающего ввода принимается и модельная форма через
   зеркало xdto:fixed. Отображение выведено по корпусу: fixed встречается только
   вместе с default, значений всего два.

2. Импорт на несуществующий пакет платформа отвергает («xdto-package-3.3 …
   не определен»), а у нас проверки не было. Добавлена ошибка валидатора и,
   что важнее, предупреждение прямо на сборке — отказ при db-update дешевле
   поймать на шаг раньше. Правило пришлось калибровать корпусом: сначала оно
   дало 67 ложных срабатываний на платформенных пространствах имён, их список
   выведен и исключён.

3. localName проверяется как NCName — фикстура с пробелом в имени была негодной,
   заменена на реалистичный дефис (name="alpha_3" localName="alpha-3").

Харнесс получил skipPlatformVerify с обязательной причиной: результат
set-namespace невалиден by design, операция намеренно оставляет висящий импорт
у зависящего пакета.

Итог: 9/9 компилятора, 9/10 + 1 осознанный пропуск у edit, round-trip 760/760,
валидатор 0 ложных, 40 тестов на обоих рантаймах.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-07-26 14:51:08 +03:00
co-authored by Claude Opus 5
parent 3eb805f7b0
commit 5d5a1bc36a
33 changed files with 344 additions and 29 deletions
@@ -9,6 +9,18 @@ import uuid
from lxml import etree
# Эти пространства имён предоставляет сама платформа — пакетов в конфигурации
# для них нет и быть не должно (выведено по корпусу)
PLATFORM_NS = {
"http://v8.1c.ru/8.1/data/core",
"http://v8.1c.ru/8.1/data/enterprise",
"http://v8.1c.ru/8.1/data/enterprise/current-config",
"http://v8.1c.ru/8.1/data-composition-system/settings",
"http://v8.1c.ru/8.3/data/ext",
"http://www.w3.org/2001/XMLSchema",
}
sys.stdout.reconfigure(encoding="utf-8")
sys.stderr.reconfigure(encoding="utf-8")
@@ -498,8 +510,17 @@ def build_property(el, is_attribute):
add_attr(p, "upperBound", "-1" if max_occ == "unbounded" else max_occ)
add_attr(p, "nillable", el.get("nillable"))
add_attr(p, "fixed", el.get("fixed"))
add_attr(p, "default", el.get("default"))
# XSD-шный fixed="V" несёт значение, в модели это fixed="true" + default="V".
# Прощающий ввод: модельная форма через зеркало xdto:fixed тоже принимается.
m_fixed = MA(el, "fixed")
if m_fixed is not None:
add_attr(p, "fixed", m_fixed)
add_attr(p, "default", el.get("default"))
elif el.get("fixed") is not None:
add_attr(p, "fixed", "true")
add_attr(p, "default", el.get("fixed"))
else:
add_attr(p, "default", el.get("default"))
if is_attribute:
add_attr(p, "form", "Attribute")
@@ -869,6 +890,25 @@ with open(md_file, "wb") as f:
# ── register in Configuration.xml ────────────────────────────
# Ранняя диагностика: отказ платформы при db-update дешевле поймать на сборке
xdto_root_dir = os.path.join(args.OutputDir, "XDTOPackages")
declared_imports = [a["value"] for c in pkg_node.children if c.tag == "import"
for a in c.attrs if a["name"] == "namespace"]
if declared_imports and os.path.isdir(xdto_root_dir):
known_ns = set()
for other in sorted(os.listdir(xdto_root_dir)):
ob = os.path.join(xdto_root_dir, other, "Ext", "Package.bin")
if not os.path.exists(ob):
continue
try:
known_ns.add(_parse_xml(ob).getroot().get("targetNamespace"))
except Exception: # noqa: BLE001
pass
for imp in declared_imports:
if imp not in known_ns and imp not in PLATFORM_NS:
warn(f'Импорт "{imp}" не разрешается: пакета с таким namespace в конфигурации нет. '
"Платформа отвергнет пакет при обновлении — соберите зависимость первой")
config_xml = os.path.join(args.OutputDir, "Configuration.xml")
reg_result = "no-config"
if os.path.exists(config_xml):