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
@@ -15,6 +15,19 @@ param(
)
$ErrorActionPreference = "Stop"
# Эти пространства имён предоставляет сама платформа — пакетов в конфигурации
# для них нет и быть не должно (выведено по корпусу: импортируются, но
# targetNamespace с таким значением ни у одного пакета нет)
$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"
)
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$XDTO_NS = "http://v8.1c.ru/8.1/xdto"
@@ -446,8 +459,18 @@ function Build-Property([System.Xml.XmlElement]$el, [bool]$isAttribute) {
Add-Attr $p "nillable" (XA $el "nillable")
}
Add-Attr $p "fixed" (XA $el "fixed")
Add-Attr $p "default" (XA $el "default")
# XSD-шный fixed="V" несёт значение, в модели это fixed="true" + default="V".
# Прощающий ввод: модельная форма через зеркало xdto:fixed тоже принимается.
$mFixed = MA $el "fixed"
if ($null -ne $mFixed) {
Add-Attr $p "fixed" $mFixed
Add-Attr $p "default" (XA $el "default")
} elseif ($null -ne (XA $el "fixed")) {
Add-Attr $p "fixed" "true"
Add-Attr $p "default" (XA $el "fixed")
} else {
Add-Attr $p "default" (XA $el "default")
}
if ($isAttribute) {
Add-Attr $p "form" "Attribute"
@@ -839,6 +862,28 @@ M "`t</XDTOPackage>"
# --- Register in Configuration.xml ---
# Ранняя диагностика: отказ платформы при db-update дешевле поймать на сборке
$xdtoRootDir = Join-Path $OutputDir "XDTOPackages"
$declaredImports = @()
foreach ($c in $pkgNode.Children) { if ($c.Tag -eq "import") { foreach ($a in $c.Attrs) { if ($a.Name -eq "namespace") { $declaredImports += $a.Value } } } }
if ($declaredImports.Count -gt 0 -and (Test-Path $xdtoRootDir)) {
$knownNs = @{}
foreach ($other in (Get-ChildItem $xdtoRootDir -Directory -ErrorAction SilentlyContinue)) {
$ob = Join-Path (Join-Path $other.FullName "Ext") "Package.bin"
if (-not (Test-Path $ob)) { continue }
try {
$od = New-Object System.Xml.XmlDocument
$od.Load($ob)
$knownNs[$od.DocumentElement.GetAttribute("targetNamespace")] = $true
} catch {}
}
foreach ($imp in $declaredImports) {
if (-not $knownNs.ContainsKey($imp) -and $PLATFORM_NS -notcontains $imp) {
Warn "Импорт `"$imp`" не разрешается: пакета с таким namespace в конфигурации нет. Платформа отвергнет пакет при обновлении — соберите зависимость первой"
}
}
}
$configXmlPath = Join-Path $OutputDir "Configuration.xml"
$regResult = "no-config"
if (Test-Path $configXmlPath) {
@@ -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):