fix(meta-validate,meta-edit): sync HierarchyType allowlist + анти-дрейф тул (Фаза 0)

Продублированные enum-allowlist-ы meta-validate/meta-edit дрейфнули от meta-compile:
HierarchyType содержал фантом HierarchyItemsOnly вместо HierarchyOfItems (кампания
enum-allowlist подтвердила: ItemsOnly не существует). Валидатор давал неверный вердикт.
Сведено к meta-compile (ps1+py обоих навыков).

tests/skills/check-enum-drift.mjs — гард от повторного дрейфа: сверяет validEnumValues
meta-compile (авторитет) с valid_property_values (validate) и validEnumValues (edit),
выход 1 при расхождении значений. Навыки остаются автономными (allowlist-ы копируются),
тул ловит рассинхрон. Сейчас: OK, дрейфа нет.

meta-validate v1.6, meta-edit v1.11. Тесты 13/13 + 11/11 ps1+py.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-07-11 20:05:59 +03:00
parent 700ede1df7
commit ca1c80e164
5 changed files with 64 additions and 8 deletions
@@ -1,4 +1,4 @@
# meta-edit v1.10 — Edit existing 1C metadata object XML (inline mode + complex properties + TS attribute ops + modify-ts)
# meta-edit v1.11 — Edit existing 1C metadata object XML (inline mode + complex properties + TS attribute ops + modify-ts)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$DefinitionFile,
@@ -78,7 +78,7 @@ $script:validEnumValues = @{
"Posting" = @("Allow","Deny")
"RealTimePosting" = @("Allow","Deny")
"EditType" = @("InDialog","InList","BothWays")
"HierarchyType" = @("HierarchyFoldersAndItems","HierarchyItemsOnly")
"HierarchyType" = @("HierarchyFoldersAndItems","HierarchyOfItems")
"CodeType" = @("String","Number")
"CodeAllowedLength" = @("Variable","Fixed")
"NumberType" = @("String","Number")
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# meta-edit v1.10 — Edit existing 1C metadata object XML (inline mode + complex properties + TS attribute ops + modify-ts)
# meta-edit v1.11 — Edit existing 1C metadata object XML (inline mode + complex properties + TS attribute ops + modify-ts)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -285,7 +285,7 @@ valid_enum_values = {
'Posting': ['Allow', 'Deny'],
'RealTimePosting': ['Allow', 'Deny'],
'EditType': ['InDialog', 'InList', 'BothWays'],
'HierarchyType': ['HierarchyFoldersAndItems', 'HierarchyItemsOnly'],
'HierarchyType': ['HierarchyFoldersAndItems', 'HierarchyOfItems'],
'CodeType': ['String', 'Number'],
'CodeAllowedLength': ['Variable', 'Fixed'],
'NumberType': ['String', 'Number'],
@@ -1,4 +1,4 @@
# meta-validate v1.5 — Validate 1C metadata object structure
# meta-validate v1.6 — Validate 1C metadata object structure
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -253,7 +253,7 @@ $validPropertyValues = @{
"DataLockControlMode" = @("Automatic","Managed")
"FullTextSearch" = @("Use","DontUse")
"DefaultPresentation" = @("AsDescription","AsCode")
"HierarchyType" = @("HierarchyFoldersAndItems","HierarchyItemsOnly")
"HierarchyType" = @("HierarchyFoldersAndItems","HierarchyOfItems")
"EditType" = @("InDialog","InList","BothWays")
"WriteMode" = @("Independent","RecorderSubordinate")
"InformationRegisterPeriodicity" = @("Nonperiodical","Second","Day","Month","Quarter","Year","RecorderPosition")
@@ -1,4 +1,4 @@
# meta-validate v1.5 — Validate 1C metadata object structure (Python port)
# meta-validate v1.6 — Validate 1C metadata object structure (Python port)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import os
@@ -253,7 +253,7 @@ valid_property_values = {
"DataLockControlMode": ["Automatic", "Managed"],
"FullTextSearch": ["Use", "DontUse"],
"DefaultPresentation": ["AsDescription", "AsCode"],
"HierarchyType": ["HierarchyFoldersAndItems", "HierarchyItemsOnly"],
"HierarchyType": ["HierarchyFoldersAndItems", "HierarchyOfItems"],
"EditType": ["InDialog", "InList", "BothWays"],
"WriteMode": ["Independent", "RecorderSubordinate"],
"InformationRegisterPeriodicity": ["Nonperiodical", "Second", "Day", "Month", "Quarter", "Year", "RecorderPosition"],
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env node
// Анти-дрейф enum-allowlist-ов: сверяет продублированные списки допустимых значений перечислений
// meta-compile (АВТОРИТЕТ) ↔ meta-validate ↔ meta-edit. Навыки автономны (allowlist-ы копируются
// намеренно), поэтому нужен гард от расхождений значений (напр. HierarchyItemsOnly vs HierarchyOfItems).
// Парсит .ps1 (канонический порт). Выход 1 при дрейфе. Запуск: node tests/skills/check-enum-drift.mjs
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
// Извлечь PS1-хэштейбл по имени переменной, распарсить "Prop" = @("v1","v2", ...)
function parsePs1EnumMap(file, varName) {
const text = readFileSync(join(ROOT, file), 'utf8');
const at = text.indexOf(varName);
if (at < 0) throw new Error(`${varName} not found in ${file}`);
let i = text.indexOf('@{', at) + 2, depth = 1, end = i;
while (i < text.length && depth > 0) {
const c = text[i];
if (c === '{') depth++;
else if (c === '}') { depth--; if (depth === 0) { end = i; break; } }
i++;
}
const block = text.slice(text.indexOf('@{', at) + 2, end);
const map = {};
const re = /"([\wА-Яа-яЁё]+)"\s*=\s*@\(([^)]*)\)/g;
let m;
while ((m = re.exec(block)) !== null) {
map[m[1]] = [...m[2].matchAll(/"([^"]*)"/g)].map(v => v[1]);
}
return map;
}
const compile = parsePs1EnumMap('.claude/skills/meta-compile/scripts/meta-compile.ps1', '$script:validEnumValues');
const validate = parsePs1EnumMap('.claude/skills/meta-validate/scripts/meta-validate.ps1', '$validPropertyValues');
const edit = parsePs1EnumMap('.claude/skills/meta-edit/scripts/meta-edit.ps1', '$script:validEnumValues');
const eq = (a, b) => a.length === b.length && [...a].sort().join('|') === [...b].sort().join('|');
let drift = 0;
for (const [name, map] of [['meta-validate', validate], ['meta-edit', edit]]) {
for (const prop of Object.keys(map)) {
if (compile[prop] && !eq(map[prop], compile[prop])) {
console.log(`DRIFT ${name}.${prop}: [${map[prop].join(', ')}] != meta-compile [${compile[prop].join(', ')}]`);
drift++;
}
}
}
// Информационно: свойства в валидаторе/редакторе, которых НЕТ в авторитете (возможен опечатка-ключ или устаревшее)
for (const [name, map] of [['meta-validate', validate], ['meta-edit', edit]]) {
for (const prop of Object.keys(map)) {
if (!compile[prop]) console.log(`INFO ${name}.${prop} нет в meta-compile.validEnumValues (проверьте ключ)`);
}
}
console.log(drift === 0 ? 'OK — нет дрейфа значений enum-allowlist vs meta-compile' : `\n${drift} DRIFT(s) — свести к meta-compile.`);
process.exit(drift ? 1 : 0);