fix(cfe-borrow,form-*,interface-edit,meta-compile,role-compile,subsystem-compile,template-add): длина среза Configuration.xml

Detect-FormatVersion читает префикс Configuration.xml как
ReadAllText(...).Substring(0, Min(2000, (Get-Item).Length)). Размер файла — в
БАЙТАХ, Substring считает СИМВОЛЫ: на кириллице байт больше, и если файл
короче 2000 символов, длина среза выходит за строку и навык падает
исключением. Проявлялось на маленьких конфигурациях — например на фикстуре
EPF внутри конфигурации на поддержке.

Функция расходится копиями по навыкам, поэтому правка одинаковая в восьми:
длина берётся по самой строке. В help-add так было изначально; в
meta-compile рядом (Detect-CompatibilityMode) уже стоял верный вариант.

py-порты иммунны: там f.read(2000) в текстовом режиме — читает символы и не
бросает исключение. Зеркалить нечего, версии выровнены по обоим портам.

Заодно tests/skills/verify-snapshots.mjs: outputPath кейса читался только из
params, тогда как runner.mjs берёт его с верхнего уровня — из-за расхождения
харнесс искал результат не там, где навык его написал, и это маскировало
падение как «выход не создан».

Проверка: 1С-сертификация mxl-compile 13/13 (кейс guard-allow-external падал
с начала кампании), полная сюита 630/630 на PowerShell и 627+3 skipped на python.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-02 15:35:17 +03:00
co-authored by Claude Opus 5
parent 919d49fe14
commit fae22435d4
17 changed files with 53 additions and 26 deletions
+5 -2
View File
@@ -907,7 +907,9 @@ async function verifyCase(skillName, caseName, skillConfig, caseData, opts) {
log('platform-load', true, 'skipped (no v8 context)');
return result;
}
const tplName = caseData.params?.templatePath || caseData.params?.outputPath || 'Template.xml';
// outputPath у кейса бывает на ВЕРХНЕМ уровне (так его читает runner.mjs) и в params.
// Порядок должен совпадать с раннером, иначе файл ищется не там, где навык его написал.
const tplName = caseData.params?.templatePath || caseData.outputPath || caseData.params?.outputPath || 'Template.xml';
const tplPath = join(workDir, tplName);
if (!existsSync(tplPath)) {
result.errors.push(`Output not produced at ${tplPath}`);
@@ -944,7 +946,8 @@ async function verifyCase(skillName, caseName, skillConfig, caseData, opts) {
}
if (MXL_PLATFORM_VERIFY.has(skillName)) {
const tplName = caseData.params?.outputPath || 'Template.xml';
// См. выше: top-level outputPath имеет приоритет — так же, как в runner.mjs.
const tplName = caseData.outputPath || caseData.params?.outputPath || 'Template.xml';
const tplPath = join(workDir, tplName);
if (!existsSync(tplPath)) {
result.errors.push(`Output not produced at ${tplPath}`);