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})")