diff --git a/.claude/skills/meta-edit/SKILL.md b/.claude/skills/meta-edit/SKILL.md
index fcd485283..3ae1505bf 100644
--- a/.claude/skills/meta-edit/SKILL.md
+++ b/.claude/skills/meta-edit/SKILL.md
@@ -33,7 +33,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/meta-edit.ps1" -Def
| Operation | Inline-операция (альтернатива DefinitionFile) |
| Value | Значение для inline-операции |
| DefinitionFile | JSON-файл с операциями (альтернатива Operation) |
-| NoValidate | Не запускать meta-validate после правки |
+| NoValidate | Не запускать валидацию после правки |
## Частые операции
diff --git a/.claude/skills/meta-edit/scripts/meta-edit.ps1 b/.claude/skills/meta-edit/scripts/meta-edit.ps1
index 1c9a1baa1..5f6db278a 100644
--- a/.claude/skills/meta-edit/scripts/meta-edit.ps1
+++ b/.claude/skills/meta-edit/scripts/meta-edit.ps1
@@ -1,4 +1,4 @@
-# meta-edit v1.53 — Edit existing 1C metadata object XML
+# meta-edit v1.54 — Edit existing 1C metadata object XML
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
[CmdletBinding(PositionalBinding=$false)]
param(
@@ -3897,15 +3897,17 @@ Info "Saved: $resolvedPath"
# ============================================================
if (-not $NoValidate) {
- $validateScript = Join-Path (Join-Path $PSScriptRoot "..\..\meta-validate") "scripts\meta-validate.ps1"
+ # Внешняя обработка/отчёт — автономный объект, meta-validate его не знает (#108).
+ $validateSkill = if (@('ExternalDataProcessor','ExternalReport') -contains $script:objType) { "epf-validate" } else { "meta-validate" }
+ $validateScript = Join-Path (Join-Path $PSScriptRoot "..\..\$validateSkill") "scripts\$validateSkill.ps1"
$validateScript = [System.IO.Path]::GetFullPath($validateScript)
if (Test-Path $validateScript) {
Write-Host ""
- Write-Host "--- Running meta-validate ---" -ForegroundColor DarkGray
+ Write-Host "--- Running $validateSkill ---" -ForegroundColor DarkGray
& powershell.exe -NoProfile -File $validateScript -ObjectPath $resolvedPath
} else {
Write-Host ""
- Write-Host "[SKIP] meta-validate not found at: $validateScript" -ForegroundColor DarkGray
+ Write-Host "[SKIP] $validateSkill not found at: $validateScript" -ForegroundColor DarkGray
}
}
diff --git a/.claude/skills/meta-edit/scripts/meta-edit.py b/.claude/skills/meta-edit/scripts/meta-edit.py
index b4c0971ab..ff918a758 100644
--- a/.claude/skills/meta-edit/scripts/meta-edit.py
+++ b/.claude/skills/meta-edit/scripts/meta-edit.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# meta-edit v1.53 — Edit existing 1C metadata object XML
+# meta-edit v1.54 — Edit existing 1C metadata object XML
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -3985,16 +3985,20 @@ def main():
# --- Auto-validate ---
if not args.NoValidate:
+ # Внешняя обработка/отчёт — автономный объект, meta-validate его не знает (#108).
+ validate_skill = "epf-validate" if obj_type in ("ExternalDataProcessor", "ExternalReport") else "meta-validate"
script_dir = os.path.dirname(os.path.abspath(__file__))
- validate_script = os.path.normpath(os.path.join(script_dir, "..", "..", "meta-validate", "scripts", "meta-validate.py"))
+ validate_script = os.path.normpath(os.path.join(script_dir, "..", "..", validate_skill, "scripts", f"{validate_skill}.py"))
if os.path.exists(validate_script):
print()
- print("--- Running meta-validate ---")
+ print(f"--- Running {validate_skill} ---")
python_exe = sys.executable
+ # Буфер stdout сбросить до запуска: иначе вывод дочернего процесса обгоняет наш.
+ sys.stdout.flush()
subprocess.run([python_exe, validate_script, "-ObjectPath", resolved_path])
else:
print()
- print(f"[SKIP] meta-validate not found at: {validate_script}")
+ print(f"[SKIP] {validate_skill} not found at: {validate_script}")
# --- Summary ---
print()
diff --git a/tests/skills/cases/meta-edit/epf-autovalidate.json b/tests/skills/cases/meta-edit/epf-autovalidate.json
new file mode 100644
index 000000000..c4bfa26a6
--- /dev/null
+++ b/tests/skills/cases/meta-edit/epf-autovalidate.json
@@ -0,0 +1,24 @@
+{
+ "name": "Внешняя обработка: автопроверка через epf-validate, не meta-validate (#108)",
+ "setup": "none",
+ "skipValidation": true,
+ "preRun": [
+ {
+ "script": "epf-init/scripts/init",
+ "args": { "-Name": "Проба", "-SrcDir": "{workDir}" }
+ }
+ ],
+ "params": { "objectPath": "Проба.xml", "objectName": "Проба" },
+ "input": {
+ "add": {
+ "attributes": ["Текст: String(50)"],
+ "tabularSections": [
+ { "name": "Строки", "attrs": ["Сумма: Number(15,2)"] }
+ ]
+ }
+ },
+ "expect": {
+ "stdoutContains": ["--- Running epf-validate ---", "Validation OK"],
+ "stdoutNotContains": ["Unrecognized metadata type", "meta-validate"]
+ }
+}
diff --git a/tests/skills/cases/meta-edit/erf-autovalidate.json b/tests/skills/cases/meta-edit/erf-autovalidate.json
new file mode 100644
index 000000000..0bf903018
--- /dev/null
+++ b/tests/skills/cases/meta-edit/erf-autovalidate.json
@@ -0,0 +1,24 @@
+{
+ "name": "Внешний отчёт: автопроверка через epf-validate, не meta-validate (#108)",
+ "setup": "none",
+ "skipValidation": true,
+ "preRun": [
+ {
+ "script": "erf-init/scripts/init",
+ "args": { "-Name": "ПробаОтчёт", "-SrcDir": "{workDir}" }
+ }
+ ],
+ "params": { "objectPath": "ПробаОтчёт.xml", "objectName": "ПробаОтчёт" },
+ "input": {
+ "add": {
+ "attributes": ["Текст: String(50)"],
+ "tabularSections": [
+ { "name": "Строки", "attrs": ["Сумма: Number(15,2)"] }
+ ]
+ }
+ },
+ "expect": {
+ "stdoutContains": ["--- Running epf-validate ---", "Validation OK"],
+ "stdoutNotContains": ["Unrecognized metadata type", "meta-validate"]
+ }
+}
diff --git a/tests/skills/cases/meta-edit/snapshots/epf-autovalidate/Проба.xml b/tests/skills/cases/meta-edit/snapshots/epf-autovalidate/Проба.xml
new file mode 100644
index 000000000..b0b097bb8
--- /dev/null
+++ b/tests/skills/cases/meta-edit/snapshots/epf-autovalidate/Проба.xml
@@ -0,0 +1,162 @@
+
+
+
+
+
+ UUID-002
+ UUID-003
+
+
+ UUID-004
+ UUID-005
+
+
+
+ Проба
+
+
+ ru
+ Проба
+
+
+
+
+
+
+
+
+
+ Текст
+
+
+ ru
+ Текст
+
+
+
+
+ xs:string
+
+ 50
+ Variable
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ UUID-008
+ UUID-009
+
+
+ UUID-010
+ UUID-011
+
+
+
+ Строки
+
+
+ ru
+ Строки
+
+
+
+
+ DontCheck
+
+
+
+ DontCheck
+ false
+ false
+ Auto
+
+
+ false
+
+
+ Auto
+ Auto
+
+ false
+ Use
+ false
+
+
+
+ Use
+
+
+
+
+
+
+
+
+
+
+ Сумма
+
+
+ ru
+ Сумма
+
+
+
+
+ xs:decimal
+
+ 15
+ 2
+ Any
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+ 0
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/meta-edit/snapshots/epf-autovalidate/Проба/Ext/ObjectModule.bsl b/tests/skills/cases/meta-edit/snapshots/epf-autovalidate/Проба/Ext/ObjectModule.bsl
new file mode 100644
index 000000000..15543d277
--- /dev/null
+++ b/tests/skills/cases/meta-edit/snapshots/epf-autovalidate/Проба/Ext/ObjectModule.bsl
@@ -0,0 +1,11 @@
+#Область ОписаниеПеременных
+
+#КонецОбласти
+
+#Область ПрограммныйИнтерфейс
+
+#КонецОбласти
+
+#Область СлужебныеПроцедурыИФункции
+
+#КонецОбласти
\ No newline at end of file
diff --git a/tests/skills/cases/meta-edit/snapshots/erf-autovalidate/ПробаОтчёт.xml b/tests/skills/cases/meta-edit/snapshots/erf-autovalidate/ПробаОтчёт.xml
new file mode 100644
index 000000000..f27ccdb50
--- /dev/null
+++ b/tests/skills/cases/meta-edit/snapshots/erf-autovalidate/ПробаОтчёт.xml
@@ -0,0 +1,168 @@
+
+
+
+
+
+ UUID-002
+ UUID-003
+
+
+ UUID-004
+ UUID-005
+
+
+
+ ПробаОтчёт
+
+
+ ru
+ ПробаОтчёт
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Текст
+
+
+ ru
+ Текст
+
+
+
+
+ xs:string
+
+ 50
+ Variable
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+ UUID-008
+ UUID-009
+
+
+ UUID-010
+ UUID-011
+
+
+
+ Строки
+
+
+ ru
+ Строки
+
+
+
+
+ DontCheck
+
+
+
+ DontCheck
+ false
+ false
+ Auto
+
+
+ false
+
+
+ Auto
+ Auto
+
+ false
+ Use
+ false
+
+
+
+ Use
+
+
+
+
+
+
+
+
+
+
+ Сумма
+
+
+ ru
+ Сумма
+
+
+
+
+ xs:decimal
+
+ 15
+ 2
+ Any
+
+
+ false
+
+
+
+ false
+
+ false
+ false
+
+
+ false
+ 0
+ DontCheck
+ Items
+
+
+ Auto
+ Auto
+
+
+ Auto
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/skills/cases/meta-edit/snapshots/erf-autovalidate/ПробаОтчёт/Ext/ObjectModule.bsl b/tests/skills/cases/meta-edit/snapshots/erf-autovalidate/ПробаОтчёт/Ext/ObjectModule.bsl
new file mode 100644
index 000000000..15543d277
--- /dev/null
+++ b/tests/skills/cases/meta-edit/snapshots/erf-autovalidate/ПробаОтчёт/Ext/ObjectModule.bsl
@@ -0,0 +1,11 @@
+#Область ОписаниеПеременных
+
+#КонецОбласти
+
+#Область ПрограммныйИнтерфейс
+
+#КонецОбласти
+
+#Область СлужебныеПроцедурыИФункции
+
+#КонецОбласти
\ No newline at end of file
diff --git a/tests/skills/verify-snapshots.mjs b/tests/skills/verify-snapshots.mjs
index ce021829d..89c732773 100644
--- a/tests/skills/verify-snapshots.mjs
+++ b/tests/skills/verify-snapshots.mjs
@@ -713,7 +713,7 @@ const EPF_SKILLS = new Map([
// Skills that produce either an EPF/ERF source or a full Configuration —
// route is auto-detected after the main script runs.
-const EPF_OR_CONFIG_SKILLS = new Set(['template-add', 'help-add']);
+const EPF_OR_CONFIG_SKILLS = new Set(['template-add', 'help-add', 'meta-edit']);
// Диагностика падения навыка. Оба потока вместе: ps1 печатает строку ошибки в stdout, py — в
// stderr, а лог платформы оба кладут в stdout. Читать только `stderr || stdout` значило на
@@ -918,8 +918,12 @@ async function verifyCase(skillName, caseName, skillConfig, caseData, opts) {
// setup кейса перекрывает setup навыка — как в runner.mjs. Без этого кейсы с гейтом по версии
// формата (empty-config-218/220/221) проверялись на конфигурации 2.17, то есть платформа не
// видела ровно того поведения, ради которого кейс написан.
+ // Кейс навыка «EPF или конфигурация» с setup `none` правит внешнюю обработку: пустая конфигурация
+ // вокруг неё — ложный PASS (корневой XML обработки платформа при загрузке конфигурации не видит).
const caseSetup = typeof caseData.setup === 'string' ? caseData.setup : null;
- const setupType = (caseSetup && caseSetup.startsWith('empty-config')) ? caseSetup : (skillConfig.setup || 'empty-config');
+ const caseSetupWins = caseSetup && (caseSetup.startsWith('empty-config') ||
+ (caseSetup === 'none' && EPF_OR_CONFIG_SKILLS.has(skillName)));
+ const setupType = caseSetupWins ? caseSetup : (skillConfig.setup || 'empty-config');
const isStandalone = STANDALONE_SKILLS.has(skillName);
let epfExt = EPF_SKILLS.get(skillName);
let isEpf = !!epfExt;