From 24b1aa9ee1dbfb5ffb30a3857f2efc0d6f587c8b Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 20 Sep 2026 19:28:46 +0300 Subject: [PATCH] =?UTF-8?q?fix(meta-compile,meta-validate):=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BA=D0=B8=20=D0=BF=D0=BE=20=D0=B2=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=BE=D0=BC=D1=83=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Три находки, все воспроизведены: 1. Счётчик членов составного типа не видел форму с локальной xmlns: тип из чужого пространства имён пишется как , а регулярка требовала '>' сразу за именем тега. В итоге на одном и том же файле meta-compile молчал, а meta-validate предупреждал — навыки расходились в оценке одного содержимого. Радиус: оба порта. 2. Report-OK проверки 23 печатался безусловно — то есть сразу после собственного ERROR, и раздувал счётчик проверок в итоговой строке. Соседние проверки (21, 22) так не делают. 3. ToString() копировал весь буфер вывода на каждый реквизит: O(n^2) на крупном объекте. В файле уже есть ranged-перегрузка ровно для этого (Emit-TypeContent). py-порт был изначально корректен — он режет список. Добавлен кейс на тип с локальной xmlns: без него находка 1 вернулась бы незамеченной, потому что обычный составной тип её не показывает. Co-Authored-By: Claude Opus 5 (1M context) --- .../meta-compile/scripts/meta-compile.ps1 | 10 +- .../meta-compile/scripts/meta-compile.py | 4 +- .../meta-validate/scripts/meta-validate.ps1 | 6 +- .../meta-validate/scripts/meta-validate.py | 6 +- .../Configuration.xml | 252 ++++++++++++++++++ .../DataProcessors/Обработка.xml | 68 +++++ .../Обработка/Ext/ManagerModule.bsl | 0 .../Обработка/Ext/ObjectModule.bsl | 0 .../Ext/ClientApplicationInterface.xml | 18 ++ .../Languages/Русский.xml | 16 ++ .../warn-composite-defined-type-ns.json | 15 ++ 11 files changed, 389 insertions(+), 6 deletions(-) create mode 100644 tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/Configuration.xml create mode 100644 tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/DataProcessors/Обработка.xml create mode 100644 tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/DataProcessors/Обработка/Ext/ManagerModule.bsl create mode 100644 tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/DataProcessors/Обработка/Ext/ObjectModule.bsl create mode 100644 tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/Ext/ClientApplicationInterface.xml create mode 100644 tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/Languages/Русский.xml create mode 100644 tests/skills/cases/meta-compile/warn-composite-defined-type-ns.json diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1 index f9259f1d7..26f8d61d1 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.ps1 +++ b/.claude/skills/meta-compile/scripts/meta-compile.ps1 @@ -994,8 +994,10 @@ function Emit-ValueType { # предупреждение, а не отказ: иначе навык не собрал бы того, что поставляет 1С. Соотношение в # корпусе erp+acc — 6500 единственных против 1 составного. function Warn-DefinedTypeInComposite([int]$fromLength) { - $frag = $script:xml.ToString().Substring($fromLength) - $members = [regex]::Matches($frag, '').Count + $frag = $script:xml.ToString($fromLength, $script:xml.Length - $fromLength) + # После имени тега — либо '>', либо пробел: тип из чужого пространства имён несёт локальную + # xmlns прямо в теге (), и без пробела в классе он не считался членом. + $members = [regex]::Matches($frag, ']').Count if ($members -lt 2) { return } $dts = @() foreach ($m in [regex]::Matches($frag, 'cfg:(DefinedType\.[^<]+)')) { $dts += $m.Groups[1].Value } @@ -1012,7 +1014,9 @@ function Warn-DefinedTypeInComposite([int]$fromLength) { # разъехалась бы с ним молча — ровно тот класс отказа, от которого держим гарды. function Get-EmittedTypeSets([int]$fromLength) { $sets = @() - $frag = $script:xml.ToString().Substring($fromLength) + # Ranged-перегрузка, как в Emit-TypeContent: ToString() целиком копировал бы весь буфер + # на каждый реквизит — это O(n^2) на крупном объекте. + $frag = $script:xml.ToString($fromLength, $script:xml.Length - $fromLength) foreach ($m in [regex]::Matches($frag, 'cfg:([^<]+)')) { $sets += $m.Groups[1].Value } return $sets } diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py index 4671e7464..8fda99dfc 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.py +++ b/.claude/skills/meta-compile/scripts/meta-compile.py @@ -1103,7 +1103,9 @@ def emit_value_type(indent, type_str): # корпусе erp+acc — 6500 единственных против 1 составного. def warn_defined_type_in_composite(from_index): frag = chr(10).join(lines[from_index:]) - if len(re.findall(r'', frag)) < 2: + # После имени тега — либо '>', либо пробел: тип из чужого пространства имён несёт локальную + # xmlns прямо в теге (), и без пробела в классе он не считался членом. + if len(re.findall(r']', frag)) < 2: return dts = re.findall(r'cfg:(DefinedType[.][^<]+)', frag) if dts: diff --git a/.claude/skills/meta-validate/scripts/meta-validate.ps1 b/.claude/skills/meta-validate/scripts/meta-validate.ps1 index c6fd1a751..45712d662 100644 --- a/.claude/skills/meta-validate/scripts/meta-validate.ps1 +++ b/.claude/skills/meta-validate/scripts/meta-validate.ps1 @@ -1738,6 +1738,7 @@ if ($badGrammar.Count -eq 0 -and $notStorable.Count -eq 0 -and $unknownVocab.Cou # лежит в типовой ERP (Документ.НачислениеИСписаниеБонусныхБаллов.Баллы), поэтому не ошибка. $typeBlocks23 = @($xmlDoc.SelectNodes("//md:Type | //md:ValueType", $ns)) $dtSetsSeen = 0 +$dtSetsBad = $false foreach ($tb in $typeBlocks23) { $sets = @($tb.SelectNodes("v8:TypeSet", $ns)) if ($sets.Count -eq 0) { continue } @@ -1747,18 +1748,21 @@ foreach ($tb in $typeBlocks23) { foreach ($st in $sets) { $raw = $st.InnerText.Trim() -replace '^(?:cfg|d\d+p\d+):', '' if ($ownerKind -eq "DefinedType") { + $dtSetsBad = $true Report-Error "23. Определяемый тип '$objName': в составе тип-множество '$raw' — платформа не загрузит такой файл («Недопустимый тип»). Состав определяемого типа — только конкретные типы" continue } if ($ownerKind -eq "ChartOfCharacteristicTypes" -and $raw -notmatch '^(DefinedType|Characteristic)\.') { + $dtSetsBad = $true Report-Warn "23. План видов характеристик '$objName': тип значения '$raw' Конфигуратор не предлагает (в дереве выбора это папка без флажка); ЛюбаяСсылка на выгрузке вернётся как ЛюбаяСсылкаИБ" } if ($members -gt 1 -and $raw -match '^DefinedType\.') { + $dtSetsBad = $true Report-Warn "23. Составной тип содержит определяемый тип '$raw' — Конфигуратор даёт выбрать его только единственным; платформа загрузит" } } } -if ($dtSetsSeen -gt 0) { Report-OK "23. Type sets: $dtSetsSeen block(s) checked" } +if ($dtSetsSeen -gt 0 -and -not $dtSetsBad) { Report-OK "23. Type sets: $dtSetsSeen block(s) checked" } # --- Check 18: свойства, появившиеся в новых версиях формата --- # Реестр «тег → минимальная версия формата». Служит двум целям: (1) поймать свойство в файле со diff --git a/.claude/skills/meta-validate/scripts/meta-validate.py b/.claude/skills/meta-validate/scripts/meta-validate.py index b01fb29d9..412ac4dd9 100644 --- a/.claude/skills/meta-validate/scripts/meta-validate.py +++ b/.claude/skills/meta-validate/scripts/meta-validate.py @@ -1678,6 +1678,7 @@ if not bad_grammar and not not_storable and not unknown_vocab and types_seen: # единственным. В корпусе erp+acc 6500 единственных против 1 составного — и этот один # лежит в типовой ERP (Документ.НачислениеИСписаниеБонусныхБаллов.Баллы), поэтому не ошибка. dt_sets_seen = 0 +dt_sets_bad = False for tb in root.xpath("//md:Type | //md:ValueType", namespaces=NS): sets = tb.xpath("v8:TypeSet", namespaces=NS) if not sets: @@ -1689,13 +1690,16 @@ for tb in root.xpath("//md:Type | //md:ValueType", namespaces=NS): for st in sets: raw = re.sub(r'^(?:cfg|d\d+p\d+):', '', (st.text or "").strip()) if owner_kind == "DefinedType": + dt_sets_bad = True report_error(f"23. Определяемый тип '{obj_name}': в составе тип-множество '{raw}' — платформа не загрузит такой файл («Недопустимый тип»). Состав определяемого типа — только конкретные типы") continue if owner_kind == "ChartOfCharacteristicTypes" and not re.match(r'^(DefinedType|Characteristic)[.]', raw): + dt_sets_bad = True report_warn(f"23. План видов характеристик '{obj_name}': тип значения '{raw}' Конфигуратор не предлагает (в дереве выбора это папка без флажка); ЛюбаяСсылка на выгрузке вернётся как ЛюбаяСсылкаИБ") if members > 1 and re.match(r'^DefinedType[.]', raw): + dt_sets_bad = True report_warn(f"23. Составной тип содержит определяемый тип '{raw}' — Конфигуратор даёт выбрать его только единственным; платформа загрузит") -if dt_sets_seen: +if dt_sets_seen and not dt_sets_bad: report_ok(f"23. Type sets: {dt_sets_seen} block(s) checked") # ── Check 18: свойства, появившиеся в новых версиях формата ── diff --git a/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/Configuration.xml b/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/Configuration.xml new file mode 100644 index 000000000..4b777ca49 --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/Configuration.xml @@ -0,0 +1,252 @@ + + + + + + UUID-002 + UUID-003 + + + UUID-004 + UUID-005 + + + UUID-006 + UUID-007 + + + UUID-008 + UUID-009 + + + UUID-010 + UUID-011 + + + UUID-012 + UUID-013 + + + UUID-014 + UUID-015 + + + + TestConfig + + + ru + TestConfig + + + + + Version8_3_24 + ManagedApplication + + PlatformApplication + + Russian + + + + + false + false + false + + + + + + + + + + + + + + + + + + + + + + Biometrics + true + + + Location + false + + + BackgroundLocation + false + + + BluetoothPrinters + false + + + WiFiPrinters + false + + + Contacts + false + + + Calendars + false + + + PushNotifications + false + + + LocalNotifications + false + + + InAppPurchases + false + + + PersonalComputerFileExchange + false + + + Ads + false + + + NumberDialing + false + + + CallProcessing + false + + + CallLog + false + + + AutoSendSMS + false + + + ReceiveSMS + false + + + SMSLog + false + + + Camera + false + + + Microphone + false + + + MusicLibrary + false + + + PictureAndVideoLibraries + false + + + AudioPlaybackAndVibration + false + + + BackgroundAudioPlaybackAndVibration + false + + + InstallPackages + false + + + OSBackup + true + + + ApplicationUsageStatistics + false + + + BarcodeScanning + false + + + BackgroundAudioRecording + false + + + AllFilesAccess + false + + + Videoconferences + false + + + NFC + false + + + DocumentScanning + false + + + SpeechToText + false + + + Geofences + false + + + IncomingShareRequests + false + + + AllIncomingShareRequestsTypesProcessing + false + + + + + + Normal + + + Language.Русский + + + + + + Managed + NotAutoFree + DontUse + DontUse + TaxiEnableVersion8_2 + DontUse + Version8_3_24 + + + + Русский + Обработка + + + \ No newline at end of file diff --git a/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/DataProcessors/Обработка.xml b/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/DataProcessors/Обработка.xml new file mode 100644 index 000000000..4ee86ca13 --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/DataProcessors/Обработка.xml @@ -0,0 +1,68 @@ + + + + + + UUID-002 + UUID-003 + + + UUID-004 + UUID-005 + + + + Обработка + + + ru + Обработка + + + + true + + + false + + + + + + + Макет + + + ru + Макет + + + + + cfg:DefinedType.Сумма + mxl:SpreadsheetDocument + + false + + + + false + + false + false + + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + \ No newline at end of file diff --git a/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/DataProcessors/Обработка/Ext/ManagerModule.bsl b/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/DataProcessors/Обработка/Ext/ManagerModule.bsl new file mode 100644 index 000000000..e69de29bb diff --git a/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/DataProcessors/Обработка/Ext/ObjectModule.bsl b/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/DataProcessors/Обработка/Ext/ObjectModule.bsl new file mode 100644 index 000000000..e69de29bb diff --git a/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/Ext/ClientApplicationInterface.xml b/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/Ext/ClientApplicationInterface.xml new file mode 100644 index 000000000..3c1161b2d --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/Ext/ClientApplicationInterface.xml @@ -0,0 +1,18 @@ + + + + + UUID-002 + + + + + UUID-004 + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/Languages/Русский.xml b/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/Languages/Русский.xml new file mode 100644 index 000000000..37c60d786 --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/warn-composite-defined-type-ns/Languages/Русский.xml @@ -0,0 +1,16 @@ + + + + + Русский + + + ru + Русский + + + + ru + + + \ No newline at end of file diff --git a/tests/skills/cases/meta-compile/warn-composite-defined-type-ns.json b/tests/skills/cases/meta-compile/warn-composite-defined-type-ns.json new file mode 100644 index 000000000..7d6727162 --- /dev/null +++ b/tests/skills/cases/meta-compile/warn-composite-defined-type-ns.json @@ -0,0 +1,15 @@ +{ + "name": "Предупреждение о составном ловит и тип с локальной xmlns (мимо счётчика членов он не проходит)", + "input": { + "type": "DataProcessor", + "name": "Обработка", + "attributes": [ + "Макет: DefinedType.Сумма + SpreadsheetDocument" + ] + }, + "expect": { + "stderrContains": [ + "Составной тип содержит определяемый тип (DefinedType.Сумма)" + ] + } +}