diff --git a/.claude/skills/form-info/scripts/form-info.py b/.claude/skills/form-info/scripts/form-info.py index 0cab83b8..6c61579c 100644 --- a/.claude/skills/form-info/scripts/form-info.py +++ b/.claude/skills/form-info/scripts/form-info.py @@ -353,7 +353,7 @@ def get_support_status_for_path(target_path): except Exception: pass return None - def is_external_root(xml_path): + def _sg_is_external_root(xml_path): if not os.path.isfile(xml_path): return False try: @@ -367,14 +367,14 @@ def get_support_status_for_path(target_path): rp = os.path.abspath(target_path) # The target file itself may be the element meta-xml (e.g. Subsystems/X.xml). elem_uuid = root_uuid(rp) - if is_external_root(rp): + if _sg_is_external_root(rp): return None bin_path = None d = os.path.dirname(rp) for _ in range(12): if not d: break - if is_external_root(d + ".xml"): + if _sg_is_external_root(d + ".xml"): return None if not elem_uuid: elem_uuid = root_uuid(d + ".xml") diff --git a/.claude/skills/interface-validate/scripts/interface-validate.ps1 b/.claude/skills/interface-validate/scripts/interface-validate.ps1 index 5737589c..f0c8acb2 100644 --- a/.claude/skills/interface-validate/scripts/interface-validate.ps1 +++ b/.claude/skills/interface-validate/scripts/interface-validate.ps1 @@ -51,7 +51,8 @@ $script:output = New-Object System.Text.StringBuilder 8192 $script:allCommandNames = @() function Out-Line([string]$msg) { $script:output.AppendLine($msg) | Out-Null } -function Report-OK([string]$msg) { +function Report-OK { + param([string]$msg) $script:okCount++ if ($Detailed) { Out-Line "[OK] $msg" } } diff --git a/.claude/skills/meta-info/scripts/meta-info.py b/.claude/skills/meta-info/scripts/meta-info.py index 02ef735c..806d29da 100644 --- a/.claude/skills/meta-info/scripts/meta-info.py +++ b/.claude/skills/meta-info/scripts/meta-info.py @@ -674,7 +674,7 @@ def get_ws_operations(child_objs): # ── Support status of this object (Ext/ParentConfigurations.bin) ── # See docs/1c-support-state-spec.md. Walks up to the config root, decodes the # object's support rule. Never throws — degrades to "не на поддержке". -def _meta_is_external_root(xml_path): +def _sg_is_external_root(xml_path): if not os.path.isfile(xml_path): return False try: @@ -689,7 +689,7 @@ def _meta_is_external_root(xml_path): def get_object_support_status(obj_uuid): try: - if _meta_is_external_root(object_path): + if _sg_is_external_root(object_path): return None d = os.path.dirname(object_path) bin_path = None diff --git a/.claude/skills/mxl-info/scripts/mxl-info.py b/.claude/skills/mxl-info/scripts/mxl-info.py index f606f8c7..809ce4cd 100644 --- a/.claude/skills/mxl-info/scripts/mxl-info.py +++ b/.claude/skills/mxl-info/scripts/mxl-info.py @@ -321,7 +321,7 @@ def get_support_status_for_path(target_path): except Exception: pass return None - def is_external_root(xml_path): + def _sg_is_external_root(xml_path): if not os.path.isfile(xml_path): return False try: @@ -335,14 +335,14 @@ def get_support_status_for_path(target_path): rp = os.path.abspath(target_path) # The target file itself may be the element meta-xml (e.g. Subsystems/X.xml). elem_uuid = root_uuid(rp) - if is_external_root(rp): + if _sg_is_external_root(rp): return None bin_path = None d = os.path.dirname(rp) for _ in range(12): if not d: break - if is_external_root(d + ".xml"): + if _sg_is_external_root(d + ".xml"): return None if not elem_uuid: elem_uuid = root_uuid(d + ".xml") diff --git a/.claude/skills/role-info/scripts/role-info.py b/.claude/skills/role-info/scripts/role-info.py index fa70ce6c..660fc9ef 100644 --- a/.claude/skills/role-info/scripts/role-info.py +++ b/.claude/skills/role-info/scripts/role-info.py @@ -161,7 +161,7 @@ def get_support_status_for_path(target_path): except Exception: pass return None - def is_external_root(xml_path): + def _sg_is_external_root(xml_path): if not os.path.isfile(xml_path): return False try: @@ -175,14 +175,14 @@ def get_support_status_for_path(target_path): rp = os.path.abspath(target_path) # The target file itself may be the element meta-xml (e.g. Subsystems/X.xml). elem_uuid = root_uuid(rp) - if is_external_root(rp): + if _sg_is_external_root(rp): return None bin_path = None d = os.path.dirname(rp) for _ in range(12): if not d: break - if is_external_root(d + ".xml"): + if _sg_is_external_root(d + ".xml"): return None if not elem_uuid: elem_uuid = root_uuid(d + ".xml") diff --git a/.claude/skills/skd-info/scripts/skd-info.py b/.claude/skills/skd-info/scripts/skd-info.py index a537618a..d22a880e 100644 --- a/.claude/skills/skd-info/scripts/skd-info.py +++ b/.claude/skills/skd-info/scripts/skd-info.py @@ -278,7 +278,7 @@ def get_support_status_for_path(target_path): except Exception: pass return None - def is_external_root(xml_path): + def _sg_is_external_root(xml_path): if not os.path.isfile(xml_path): return False try: @@ -292,14 +292,14 @@ def get_support_status_for_path(target_path): rp = os.path.abspath(target_path) # The target file itself may be the element meta-xml (e.g. Subsystems/X.xml). elem_uuid = root_uuid(rp) - if is_external_root(rp): + if _sg_is_external_root(rp): return None bin_path = None d = os.path.dirname(rp) for _ in range(12): if not d: break - if is_external_root(d + ".xml"): + if _sg_is_external_root(d + ".xml"): return None if not elem_uuid: elem_uuid = root_uuid(d + ".xml") diff --git a/.claude/skills/subsystem-info/scripts/subsystem-info.py b/.claude/skills/subsystem-info/scripts/subsystem-info.py index 6be82ca1..489baa44 100644 --- a/.claude/skills/subsystem-info/scripts/subsystem-info.py +++ b/.claude/skills/subsystem-info/scripts/subsystem-info.py @@ -150,7 +150,7 @@ def get_support_status_for_path(target_path): except Exception: pass return None - def is_external_root(xml_path): + def _sg_is_external_root(xml_path): if not os.path.isfile(xml_path): return False try: @@ -164,14 +164,14 @@ def get_support_status_for_path(target_path): rp = os.path.abspath(target_path) # The target file itself may be the element meta-xml (e.g. Subsystems/X.xml). elem_uuid = root_uuid(rp) - if is_external_root(rp): + if _sg_is_external_root(rp): return None bin_path = None d = os.path.dirname(rp) for _ in range(12): if not d: break - if is_external_root(d + ".xml"): + if _sg_is_external_root(d + ".xml"): return None if not elem_uuid: elem_uuid = root_uuid(d + ".xml") diff --git a/.claude/skills/subsystem-validate/scripts/subsystem-validate.ps1 b/.claude/skills/subsystem-validate/scripts/subsystem-validate.ps1 index 473d46d7..1a479919 100644 --- a/.claude/skills/subsystem-validate/scripts/subsystem-validate.ps1 +++ b/.claude/skills/subsystem-validate/scripts/subsystem-validate.ps1 @@ -48,7 +48,8 @@ $script:okCount = 0 $script:output = New-Object System.Text.StringBuilder 8192 function Out-Line([string]$msg) { $script:output.AppendLine($msg) | Out-Null } -function Report-OK([string]$msg) { +function Report-OK { + param([string]$msg) $script:okCount++ if ($Detailed) { Out-Line "[OK] $msg" } } diff --git a/.claude/skills/xdto-validate/scripts/xdto-validate.ps1 b/.claude/skills/xdto-validate/scripts/xdto-validate.ps1 index ea519b0d..6f589b86 100644 --- a/.claude/skills/xdto-validate/scripts/xdto-validate.ps1 +++ b/.claude/skills/xdto-validate/scripts/xdto-validate.ps1 @@ -43,7 +43,8 @@ $script:stopped = $false $script:output = New-Object System.Text.StringBuilder function Out-Line([string]$s) { [void]$script:output.AppendLine($s) } -function Report-OK([string]$msg) { +function Report-OK { + param([string]$msg) $script:okCount++ if ($Detailed) { Out-Line "[OK] $msg" } } diff --git a/tests/skills/check-inline-drift.mjs b/tests/skills/check-inline-drift.mjs index 9a38f02a..cf5b7c35 100644 --- a/tests/skills/check-inline-drift.mjs +++ b/tests/skills/check-inline-drift.mjs @@ -56,9 +56,10 @@ const FAMILIES = [ { id: 'full', authority: 'cf-edit', consumers: ['form-add', 'form-compile', 'form-edit', 'help-add', 'interface-edit', 'meta-compile', 'meta-edit', 'meta-remove', 'mxl-compile', 'role-compile', 'skd-compile', 'skd-edit', - 'subsystem-compile', 'subsystem-edit', 'template-add', 'xdto-compile', 'xdto-edit'], - // *-info навыки несут хелпер только в PS1-порте — см. debug/inline-utils/FINDINGS.md. - consumersPs1: ['form-info', 'meta-info', 'mxl-info', 'role-info', 'skd-info'] }, + 'subsystem-compile', 'subsystem-edit', 'template-add', 'xdto-compile', 'xdto-edit', + // *-info навыки читают тем же хелпером СОСТОЯНИЕ поддержки для вывода, а не запрещают + // правку. Тело то же, поэтому семья общая. + 'form-info', 'meta-info', 'mxl-info', 'role-info', 'skd-info', 'subsystem-info'] }, ], }, { @@ -77,7 +78,9 @@ const FAMILIES = [ consumers: ['form-add', 'form-compile', 'form-edit', 'help-add', 'interface-edit', 'meta-compile', 'meta-edit', 'meta-remove', 'mxl-compile', 'role-compile', 'skd-compile', 'skd-edit', 'subsystem-compile', 'subsystem-edit', 'template-add', 'xdto-compile', 'xdto-edit'], - consumersPs1: ['support-edit'] }, + // support-edit и *-info читают uuid для ОТОБРАЖЕНИЯ состояния поддержки; в PY-портах + // *-info пользуются другим путём, поэтому копия только в PS1. + consumersPs1: ['form-info', 'mxl-info', 'role-info', 'skd-info', 'subsystem-info', 'support-edit'] }, ], }, @@ -151,7 +154,8 @@ const FAMILIES = [ name: 'validate: report_ok', py: null, ps1: 'Report-OK', variants: [ { id: 'buffered', authority: 'cf-validate', - consumers: ['cfe-validate', 'epf-validate', 'meta-validate', 'role-validate', 'skd-validate'] }, + consumers: ['cfe-validate', 'epf-validate', 'interface-validate', 'meta-validate', + 'role-validate', 'skd-validate', 'subsystem-validate', 'xdto-validate'] }, { id: 'streamed', authority: 'form-validate', consumers: ['mxl-validate'], why: 'потоковый вывод вместо буферизованного — эти навыки не поддерживают -OutFile' }, ], @@ -295,17 +299,22 @@ function extractPy(text) { const lines = text.split('\n'); const out = new Map(); for (let i = 0; i < lines.length; i++) { - const m = /^def ([A-Za-z_]\w*)\(/.exec(lines[i]); + // Определение бывает вложенным: *-info объявляют is_external_root внутри другой функции. + // Поиск только по `^def` делал такие копии невидимыми для гарда — то есть давал ложное «OK». + const m = /^(\s*)def ([A-Za-z_]\w*)\(/.exec(lines[i]); if (!m) continue; + const indent = m[1].length; const body = [lines[i]]; let j = i + 1; for (; j < lines.length; j++) { const l = lines[j]; - if (l.trim() === '' || l[0] === ' ' || l[0] === '\t') { body.push(l); continue; } + if (l.trim() === '') { body.push(l); continue; } + const li = l.length - l.trimStart().length; + if (li > indent) { body.push(l); continue; } break; } - out.set(m[1], body); - i = j - 1; + if (!out.has(m[2])) out.set(m[2], body); + // НЕ перескакиваем через тело: иначе вложенные определения внутри него остались бы невидимыми. } return out; } @@ -318,6 +327,15 @@ function extractPs1(text) { // поэтому конец ищем по закрывающей скобке НА ТОМ ЖЕ отступе, что и слово function. const m = /^(\s*)function\s+([A-Za-z][\w-]*)/.exec(lines[i]); if (!m) continue; + // Однострочное определение (`function Out(...) { ... }`) закрывается на своей же строке. + // Без этой ветки «телом» такой функции становилось всё до следующей одиночной `}` — то есть + // следующая функция проглатывалась и была невидима для гарда. + const opens = (lines[i].match(/\{/g) || []).length; + const closes = (lines[i].match(/\}/g) || []).length; + if (opens > 0 && opens === closes) { + if (!out.has(m[2])) out.set(m[2], [lines[i]]); + continue; + } const closing = m[1] + '}'; const body = [lines[i]]; let j = i + 1; @@ -326,7 +344,6 @@ function extractPs1(text) { if (lines[j].replace(/\s+$/, '') === closing) break; } if (!out.has(m[2])) out.set(m[2], body); - i = j; } return out; }