From 204a262746609bc41e1efcfd2ab3e8aa7d8a3d29 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sat, 25 Apr 2026 18:56:13 +0300 Subject: [PATCH] =?UTF-8?q?feat(verify-snapshots):=20=D1=80=D0=B5=D0=B0?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D0=B0=D1=8F=20=D0=BF=D0=BB=D0=B0=D1=82=D1=84?= =?UTF-8?q?=D0=BE=D1=80=D0=BC=D0=B5=D0=BD=D0=BD=D0=B0=D1=8F=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B0=20skd-compile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit До сих пор для skd-compile (как и других STANDALONE_SKILLS) verify-snapshots просто запускал скрипт и помечал PASS — без платформенной нагрузки. Опасный пробел: можно было закоммитить snapshot, который 1С Designer не примет. Теперь для skd-compile snapshot оборачивается во внешний отчёт (erf-init --WithSKD), Template.xml подменяется на сгенерированный кейсом, и запускается erf-build. Платформа парсит схему — если принимает, кейс PASS; если отклоняет, в errors попадает её stderr. Ссылочные типы (CatalogRef.X и т.п.) не требуют реальной базы: epf-build сам поднимает временную stub-конфигурацию. Если v8 недоступен — мягкий skip с пометкой "no v8 context". Замер: 21 кейс x ~5s avg = ~110s на полный verify-snapshots --skill skd-compile. Все 21 текущих кейса проходят — значит каждый snapshot гарантированно платформо-валиден. Аналогичная обёртка для mxl-compile / role-compile — отдельной задачей по образцу. Co-Authored-By: Claude Opus 4.7 (1M context) --- tests/skills/verify-snapshots.mjs | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/skills/verify-snapshots.mjs b/tests/skills/verify-snapshots.mjs index 6845c4e2..72a50e8d 100644 --- a/tests/skills/verify-snapshots.mjs +++ b/tests/skills/verify-snapshots.mjs @@ -320,6 +320,11 @@ const STANDALONE_SKILLS = new Set([ 'mxl-compile', 'mxl-decompile', 'mxl-info', 'mxl-validate', ]); +// Standalone skills that CAN be platform-verified by wrapping their output in +// an external report (ERF) and running erf-build — the platform parses the +// schema and we know if it's accepted. +const SKD_PLATFORM_VERIFY = new Set(['skd-compile']); + // EPF/ERF skills — need epf-build to verify, not LoadConfigFromFiles const EPF_SKILLS = new Set([ 'epf-init', 'erf-init', 'template-add', 'help-add', @@ -511,6 +516,50 @@ async function verifyCase(skillName, caseName, skillConfig, caseData, opts) { if (inputFile && existsSync(inputFile)) rmSync(inputFile); // ── Step 5: Determine verification strategy ── + if (SKD_PLATFORM_VERIFY.has(skillName)) { + // Wrap produced Template.xml in an external report (ERF) and try to build — + // platform either accepts the schema or rejects it with an error. + if (!opts.v8ctx) { + result.passed = true; + log('platform-load', true, 'skipped (no v8 context)'); + return result; + } + const tplName = caseData.params?.outputPath || 'Template.xml'; + const tplPath = join(workDir, tplName); + if (!existsSync(tplPath)) { + result.errors.push(`Output not produced at ${tplPath}`); + return result; + } + const erfDir = join(workDir, 'erf-src'); + const erfOutDir = join(workDir, 'erf-build'); + mkdirSync(erfOutDir, { recursive: true }); + try { + execSkill(opts.runtime, 'erf-init/scripts/init', ['-Name', 'TestReport', '-SrcDir', erfDir, '-WithSKD']); + log('erf-init', true); + } catch (e) { + const detail = (e.stderr || e.stdout || e.message).trim(); + log('erf-init', false, detail); + result.errors.push(`erf-init failed: ${detail.substring(0, 500)}`); + return result; + } + const dcsTpl = join(erfDir, 'TestReport', 'Templates', 'ОсновнаяСхемаКомпоновкиДанных', 'Ext', 'Template.xml'); + cpSync(tplPath, dcsTpl, { force: true }); + try { + execSkill(opts.runtime, 'epf-build/scripts/epf-build', [ + '-V8Path', opts.v8ctx.v8path, + '-SourceFile', join(erfDir, 'TestReport.xml'), + '-OutputFile', join(erfOutDir, 'TestReport.erf'), + ], 120_000); + log('erf-build', true, 'platform accepted schema'); + result.passed = true; + } catch (e) { + const detail = (e.stderr || e.stdout || e.message).trim(); + log('erf-build', false, detail); + result.errors.push(`erf-build rejected schema: ${detail.substring(0, 1000)}`); + } + return result; + } + if (isStandalone) { result.passed = true; log('platform-load', true, 'skipped (standalone file, not a config)');