From 358830c65bf2e1f98d757d5f921326ac8790ddf8 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 5 Apr 2026 20:24:08 +0300 Subject: [PATCH] =?UTF-8?q?feat(meta-validate):=20Check=2010=20=E2=80=94?= =?UTF-8?q?=20warn=20on=20empty=20registers=20and=20broken=20RegisterRecor?= =?UTF-8?q?ds=20refs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add two new validations found via platform snapshot verification: - Registers without any Dimensions/Resources/Attributes → platform rejects - Document.RegisterRecords referencing non-existent register objects Co-Authored-By: Claude Opus 4.6 (1M context) --- .../meta-validate/scripts/meta-validate.ps1 | 56 ++++++++++++++++++- .../meta-validate/scripts/meta-validate.py | 48 +++++++++++++++- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/.claude/skills/meta-validate/scripts/meta-validate.ps1 b/.claude/skills/meta-validate/scripts/meta-validate.ps1 index d30f210a..732d7670 100644 --- a/.claude/skills/meta-validate/scripts/meta-validate.ps1 +++ b/.claude/skills/meta-validate/scripts/meta-validate.ps1 @@ -1,4 +1,4 @@ -# meta-validate v1.2 — Validate 1C metadata object structure +# meta-validate v1.3 — Validate 1C metadata object structure # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -998,6 +998,18 @@ if ($propsNode) { } } + # CalculationRegister: ActionPeriod=true requires non-empty Schedule + if ($mdType -eq "CalculationRegister") { + $actionPeriod = $propsNode.SelectSingleNode("md:ActionPeriod", $ns) + if ($actionPeriod -and $actionPeriod.InnerText -eq "true") { + $schedule = $propsNode.SelectSingleNode("md:Schedule", $ns) + if (-not $schedule -or -not $schedule.InnerText.Trim()) { + Report-Warn "10. CalculationRegister: ActionPeriod=true but Schedule is empty — platform requires a schedule register" + $check10Issues++ + } + } + } + # DocumentJournal: RegisteredDocuments should not be empty if ($mdType -eq "DocumentJournal") { $regDocs = $propsNode.SelectSingleNode("md:RegisteredDocuments", $ns) @@ -1025,6 +1037,48 @@ if ($propsNode) { } } + # Register: must have at least one Dimension or Resource (platform rejects empty registers) + $regTypesAll = @("AccumulationRegister","AccountingRegister","CalculationRegister","InformationRegister") + if ($regTypesAll -contains $mdType -and $childObjNode) { + $dims = $childObjNode.SelectNodes("md:Dimension", $ns).Count + $ress = $childObjNode.SelectNodes("md:Resource", $ns).Count + $attrs = $childObjNode.SelectNodes("md:Attribute", $ns).Count + if (($dims + $ress + $attrs) -eq 0) { + Report-Warn "10. $mdType`: no Dimensions, Resources, or Attributes — platform will reject" + $check10Issues++ + } + } + + # Document: RegisterRecords references should point to existing objects in config + if ($mdType -eq "Document" -and $script:configDir) { + $regRecords = $propsNode.SelectSingleNode("md:RegisterRecords", $ns) + if ($regRecords) { + $items = $regRecords.SelectNodes("xr:Item", $ns) + foreach ($item in $items) { + $refVal = $item.InnerText.Trim() + if (-not $refVal) { continue } + # Parse "AccumulationRegister.Name" → dir AccumulationRegisters/Name + $parts = $refVal -split '\.',2 + if ($parts.Count -eq 2) { + $refType = $parts[0]; $refName = $parts[1] + $dirMap = @{ + "AccumulationRegister"="AccumulationRegisters"; "InformationRegister"="InformationRegisters" + "AccountingRegister"="AccountingRegisters"; "CalculationRegister"="CalculationRegisters" + } + $refDir = $dirMap[$refType] + if ($refDir) { + $refPath = Join-Path $script:configDir "$refDir/$refName" + $refXml = Join-Path $script:configDir "$refDir/$refName.xml" + if (-not (Test-Path $refPath) -and -not (Test-Path $refXml)) { + Report-Warn "10. Document.RegisterRecords references '$refVal' but object not found in config" + $check10Issues++ + } + } + } + } + } + } + # Register: must have at least one registrar document $registerTypes = @("AccumulationRegister","AccountingRegister","CalculationRegister","InformationRegister") if ($registerTypes -contains $mdType -and $script:configDir -and $objName -ne "(unknown)") { diff --git a/.claude/skills/meta-validate/scripts/meta-validate.py b/.claude/skills/meta-validate/scripts/meta-validate.py index c55ef8ae..45b92a38 100644 --- a/.claude/skills/meta-validate/scripts/meta-validate.py +++ b/.claude/skills/meta-validate/scripts/meta-validate.py @@ -1,4 +1,4 @@ -# meta-validate v1.2 — Validate 1C metadata object structure (Python port) +# meta-validate v1.3 — Validate 1C metadata object structure (Python port) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import os @@ -942,6 +942,15 @@ if props_node is not None: check10_issues += 1 print('[HINT] /meta-edit -Operation modify-property -Value "Task=Task.XXX"') + # CalculationRegister: ActionPeriod=true requires non-empty Schedule + if md_type == 'CalculationRegister': + action_period = find(props_node, 'md:ActionPeriod') + if action_period is not None and text_of(action_period) == 'true': + schedule = find(props_node, 'md:Schedule') + if schedule is None or not text_of(schedule): + report_warn('10. CalculationRegister: ActionPeriod=true but Schedule is empty — platform requires a schedule register') + check10_issues += 1 + # DocumentJournal: RegisteredDocuments should not be empty if md_type == 'DocumentJournal': reg_docs = find(props_node, 'md:RegisteredDocuments') @@ -969,6 +978,43 @@ if props_node is not None: check10_issues += 1 print('[HINT] /meta-edit -Operation modify-property -Value "ExtDimensionTypes=ChartOfCharacteristicTypes.XXX"') + # Register: must have at least one Dimension or Resource (platform rejects empty registers) + reg_types_all = ('AccumulationRegister', 'AccountingRegister', 'CalculationRegister', 'InformationRegister') + if md_type in reg_types_all and child_obj_node is not None: + dims = len(find_all(child_obj_node, 'md:Dimension')) + ress = len(find_all(child_obj_node, 'md:Resource')) + attrs = len(find_all(child_obj_node, 'md:Attribute')) + if dims + ress + attrs == 0: + report_warn(f"10. {md_type}: no Dimensions, Resources, or Attributes \u2014 platform will reject") + check10_issues += 1 + + # Document: RegisterRecords references should point to existing objects in config + if md_type == 'Document' and config_dir: + reg_records = find(props_node, 'md:RegisterRecords') + if reg_records is not None: + rr_items = find_all(reg_records, 'xr:Item') + for item in rr_items: + ref_val = (inner_text(item) or '').strip() + if not ref_val: + continue + # Parse "AccumulationRegister.Name" -> dir AccumulationRegisters/Name + parts = ref_val.split('.', 1) + if len(parts) == 2: + ref_type, ref_name = parts + dir_map = { + 'AccumulationRegister': 'AccumulationRegisters', + 'InformationRegister': 'InformationRegisters', + 'AccountingRegister': 'AccountingRegisters', + 'CalculationRegister': 'CalculationRegisters', + } + ref_dir = dir_map.get(ref_type) + if ref_dir: + ref_path = os.path.join(config_dir, ref_dir, ref_name) + ref_xml = os.path.join(config_dir, ref_dir, ref_name + '.xml') + if not os.path.exists(ref_path) and not os.path.exists(ref_xml): + report_warn(f"10. Document.RegisterRecords references '{ref_val}' but object not found in config") + check10_issues += 1 + # Register: must have at least one registrar document register_types = ('AccumulationRegister', 'AccountingRegister', 'CalculationRegister', 'InformationRegister') if md_type in register_types and config_dir and obj_name != '(unknown)':