diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1 index e4e16bfb..dd310970 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.ps1 +++ b/.claude/skills/meta-compile/scripts/meta-compile.ps1 @@ -345,9 +345,20 @@ function Parse-AttributeShorthand { # Object form $name = "$($val.name)" + # Build type string combining type + length/precision from separate JSON fields + $typeStr = if ($val.type) { "$($val.type)" } else { "" } + if ($typeStr -and -not $typeStr.Contains('(')) { + if ($typeStr -eq "String" -and $val.length) { + $typeStr = "String($($val.length))" + } elseif ($typeStr -eq "Number" -and $val.length) { + $prec = if ($val.precision) { $val.precision } else { 0 } + $nn = if ($val.nonneg -or $val.nonnegative) { ",nonneg" } else { "" } + $typeStr = "Number($($val.length),$prec$nn)" + } + } return @{ name = $name - type = if ($val.type) { "$($val.type)" } else { "" } + type = $typeStr synonym = if ($val.synonym) { "$($val.synonym)" } else { Split-CamelCase $name } comment = if ($val.comment) { "$($val.comment)" } else { "" } flags = @(if ($val.flags) { $val.flags } else { @() }) @@ -1078,7 +1089,7 @@ function Emit-DocumentProperties { if ($regRecords.Count -gt 0) { X "$i" foreach ($rr in $regRecords) { - X "$i`t$rr" + X "$i`t$rr" } X "$i" } else { @@ -1139,8 +1150,17 @@ function Emit-ConstantProperties { Emit-MLText $i "Synonym" $synonym X "$i" - # Type + # Type — combine valueType + length/precision from separate JSON fields $valueType = if ($def.valueType) { "$($def.valueType)" } else { "String" } + if ($valueType -and -not $valueType.Contains('(')) { + if ($valueType -eq "String" -and $def.length) { + $valueType = "String($($def.length))" + } elseif ($valueType -eq "Number" -and $def.length) { + $p = if ($def.precision) { $def.precision } else { 0 } + $nn = if ($def.nonneg -or $def.nonnegative) { ",nonneg" } else { "" } + $valueType = "Number($($def.length),$p$nn)" + } + } Emit-ValueType $i $valueType X "$itrue" @@ -1265,10 +1285,12 @@ function Emit-DefinedTypeProperties { Emit-MLText $i "Synonym" $synonym X "$i" - # Type — composite type with multiple v8:Type entries + # Type — composite type with multiple v8:Type entries (accept both valueType and valueTypes) $valueTypes = @() if ($def.valueTypes) { $valueTypes = @($def.valueTypes) + } elseif ($def.valueType) { + $valueTypes = @($def.valueType) } if ($valueTypes.Count -gt 0) { X "$i" @@ -1345,6 +1367,10 @@ function Emit-ScheduledJobProperties { X "$i" $methodName = if ($def.methodName) { "$($def.methodName)" } else { "" } + # Ensure CommonModule. prefix + if ($methodName -and -not $methodName.StartsWith("CommonModule.")) { + $methodName = "CommonModule.$methodName" + } X "$i$(Esc-Xml $methodName)" $description = if ($def.description) { "$($def.description)" } else { $synonym } @@ -1391,6 +1417,10 @@ function Emit-EventSubscriptionProperties { X "$i$event" $handler = if ($def.handler) { "$($def.handler)" } else { "" } + # Ensure CommonModule. prefix + if ($handler -and -not $handler.StartsWith("CommonModule.")) { + $handler = "CommonModule.$handler" + } X "$i$(Esc-Xml $handler)" } @@ -1556,7 +1586,7 @@ function Emit-ChartOfCharacteristicTypesProperties { X "$i`txs:boolean" X "$i`txs:string" X "$i`t" - X "$i`t`t0" + X "$i`t`t100" X "$i`t`tVariable" X "$i`t" X "$i`txs:decimal" diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py index 7529563e..f422955f 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.py +++ b/.claude/skills/meta-compile/scripts/meta-compile.py @@ -320,9 +320,18 @@ def parse_attribute_shorthand(val): return parsed # Object form name = str(val.get('name', '')) + # Build type string combining type + length/precision from separate JSON fields + type_str = str(val['type']) if val.get('type') else '' + if type_str and '(' not in type_str: + if type_str == 'String' and val.get('length'): + type_str = f"String({val['length']})" + elif type_str == 'Number' and val.get('length'): + prec = val.get('precision', 0) + nn = ',nonneg' if val.get('nonneg') or val.get('nonnegative') else '' + type_str = f"Number({val['length']},{prec}{nn})" return { 'name': name, - 'type': str(val['type']) if val.get('type') else '', + 'type': type_str, 'synonym': str(val['synonym']) if val.get('synonym') else split_camel_case(name), 'comment': str(val['comment']) if val.get('comment') else '', 'flags': list(val.get('flags', [])), @@ -968,7 +977,7 @@ def emit_document_properties(indent): if reg_records: X(f'{i}') for rr in reg_records: - X(f'{i}\t{rr}') + X(f'{i}\t{rr}') X(f'{i}') else: X(f'{i}') @@ -1014,7 +1023,15 @@ def emit_constant_properties(indent): X(f'{i}{esc_xml(obj_name)}') emit_mltext(i, 'Synonym', synonym) X(f'{i}') + # Type — combine valueType + length/precision from separate JSON fields value_type = str(defn['valueType']) if defn.get('valueType') else 'String' + if value_type and '(' not in value_type: + if value_type == 'String' and defn.get('length'): + value_type = f"String({defn['length']})" + elif value_type == 'Number' and defn.get('length'): + prec = defn.get('precision', 0) + nn = ',nonneg' if defn.get('nonneg') or defn.get('nonnegative') else '' + value_type = f"Number({defn['length']},{prec}{nn})" emit_value_type(i, value_type) X(f'{i}true') X(f'{i}') @@ -1111,7 +1128,11 @@ def emit_defined_type_properties(indent): X(f'{i}{esc_xml(obj_name)}') emit_mltext(i, 'Synonym', synonym) X(f'{i}') + # Accept both valueType and valueTypes value_types = list(defn.get('valueTypes', [])) + if not value_types and defn.get('valueType'): + vt_raw = defn['valueType'] + value_types = list(vt_raw) if isinstance(vt_raw, list) else [vt_raw] if value_types: X(f'{i}') for vt in value_types: @@ -1182,6 +1203,9 @@ def emit_scheduled_job_properties(indent): emit_mltext(i, 'Synonym', synonym) X(f'{i}') method_name = str(defn['methodName']) if defn.get('methodName') else '' + # Ensure CommonModule. prefix + if method_name and not method_name.startswith('CommonModule.'): + method_name = f'CommonModule.{method_name}' X(f'{i}{esc_xml(method_name)}') description = str(defn['description']) if defn.get('description') else synonym X(f'{i}{esc_xml(description)}') @@ -1213,6 +1237,9 @@ def emit_event_subscription_properties(indent): event = str(defn['event']) if defn.get('event') else 'BeforeWrite' X(f'{i}{event}') handler = str(defn['handler']) if defn.get('handler') else '' + # Ensure CommonModule. prefix + if handler and not handler.startswith('CommonModule.'): + handler = f'CommonModule.{handler}' X(f'{i}{esc_xml(handler)}') # --- 13b. Report, DataProcessor --- @@ -1366,7 +1393,7 @@ def emit_chart_of_characteristic_types_properties(indent): X(f'{i}\txs:boolean') X(f'{i}\txs:string') X(f'{i}\t') - X(f'{i}\t\t0') + X(f'{i}\t\t100') X(f'{i}\t\tVariable') X(f'{i}\t') X(f'{i}\txs:decimal') diff --git a/.claude/skills/meta-validate/scripts/meta-validate.ps1 b/.claude/skills/meta-validate/scripts/meta-validate.ps1 index a161fb9a..05257e55 100644 --- a/.claude/skills/meta-validate/scripts/meta-validate.ps1 +++ b/.claude/skills/meta-validate/scripts/meta-validate.ps1 @@ -1181,12 +1181,20 @@ if ($propsNode -and $mdType -in @("EventSubscription","ScheduledJob") -and $scri if ($methodRef) { $parts = $methodRef.Split('.') - if ($parts.Count -ne 2) { - Report-Error "13. ${mdType}.${propLabel} = '$methodRef': expected format 'CommonModuleName.ProcedureName'" - $check13Ok = $false - } else { + # Format: CommonModule.ModuleName.ProcedureName (3 parts) or ModuleName.ProcedureName (2 parts, legacy) + if ($parts.Count -eq 3 -and $parts[0] -eq "CommonModule") { + $cmName = $parts[1] + $procName = $parts[2] + } elseif ($parts.Count -eq 2) { $cmName = $parts[0] $procName = $parts[1] + } else { + Report-Error "13. ${mdType}.${propLabel} = '$methodRef': expected format 'CommonModule.ModuleName.ProcedureName'" + $check13Ok = $false + $cmName = $null + $procName = $null + } + if ($cmName) { $cmXml = Join-Path (Join-Path $script:configDir "CommonModules") "$cmName.xml" if (-not (Test-Path $cmXml)) { Report-Error "13. ${mdType}.${propLabel}: CommonModule '$cmName' not found (expected $cmXml)" diff --git a/.claude/skills/meta-validate/scripts/meta-validate.py b/.claude/skills/meta-validate/scripts/meta-validate.py index e0d59234..adf42731 100644 --- a/.claude/skills/meta-validate/scripts/meta-validate.py +++ b/.claude/skills/meta-validate/scripts/meta-validate.py @@ -1106,12 +1106,19 @@ if props_node is not None and md_type in ("EventSubscription", "ScheduledJob") a if method_ref: parts = method_ref.split(".") - if len(parts) != 2: - report_error(f"13. {md_type}.{prop_label} = '{method_ref}': expected format 'CommonModuleName.ProcedureName'") - check13_ok = False - else: + # Format: CommonModule.ModuleName.ProcedureName (3 parts) or ModuleName.ProcedureName (2 parts, legacy) + if len(parts) == 3 and parts[0] == "CommonModule": + cm_name = parts[1] + proc_name = parts[2] + elif len(parts) == 2: cm_name = parts[0] proc_name = parts[1] + else: + report_error(f"13. {md_type}.{prop_label} = '{method_ref}': expected format 'CommonModule.ModuleName.ProcedureName'") + check13_ok = False + cm_name = None + proc_name = None + if cm_name: cm_xml = os.path.join(config_dir, "CommonModules", f"{cm_name}.xml") if not os.path.exists(cm_xml): report_error(f"13. {md_type}.{prop_label}: CommonModule '{cm_name}' not found (expected {cm_xml})")