Files
romanett f061c2d7da Merge Master to Release/2.0 (#4676)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Klaus Landsdorf <kl@iniationware.com>
Co-authored-by: Marc Schier <marcschier@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: marcschier <11168470+marcschier@users.noreply.github.com>
Co-authored-by: romanett <7413710+romanett@users.noreply.github.com>
2026-10-06 09:35:42 +00:00
..
2026-10-06 09:35:42 +00:00

NodeSet vendoring helpers

derive-identifier-table.py

Derives a source-generator-compatible identifier table (*.NodeIds.csv) from a vendored NodeSet2 document and the OPC Foundation's published table.

The published table's numeric ids and node classes are authoritative, but its symbolic names follow the UA-ModelCompiler's conventions, which differ from the ones this repository's model source generator derives in NodeSetToModelDesign.ImportSymbolicName / BuildSymbolicId. Feeding the published table to the generator as a ModelSourceGeneratorIdentifierFile therefore fails with MODELGEN025. Four differences occur in practice:

Published Generated Why
Server_Namespaces_http___…_ http___…_ the publication qualifies the namespace-metadata object with its server path; the NodeSet's own SymbolicName does not
X_ControlChannel X_ControlChannel_Placeholder a <Placeholder> BrowseName maps to Name_Placeholder
DefaultBinary RGBWDataType_Encoding_DefaultBinary encoding nodes are qualified with the data type they encode
Aliases_Assets_AssetsByAssetId AssetsByAssetId the publication prefixes a top-level instance with the path of the objects organizing it, down from a base-namespace object (OPC 10000-110 AMB: 0:Aliases, 0:Locations); the generator starts the symbolic id at the instance, because organized nodes are no children

The table guards the symbols the generator derives, not the identifier constants it emits. Two kinds of valid rows have no constant in Variables / VariableIds: the entries of the type dictionaries (TypeDictionary_BinarySchema_<DataType>), and the children of a top-level instance that its type does not declare mandatory, such as a child the NodeSet adds to an instance on its own (AMB's AssetsByProductInstanceUri_NodeVersion).

Run it once per vendored model and keep both files:

python3 tools/nodesets/derive-identifier-table.py \
    src/Opc.Ua.IA/Model/Opc.Ua.IA.NodeSet2.xml \
    src/Opc.Ua.IA/Model/Opc.Ua.IA.Upstream.NodeIds.csv \
    src/Opc.Ua.IA/Model/Opc.Ua.IA.NodeIds.csv

*.Upstream.NodeIds.csv is the unmodified publication and is deliberately kept out of <AdditionalFiles>, so the two can be diffed to review exactly what the derivation changed — the same convention src/Opc.Ua.ISA95 uses.

The script exits non-zero when a published row disagrees with the NodeSet on the numeric id or node class. That is an upstream defect rather than a naming convention and needs a documented repair in the vendored NodeSet, not a silent rewrite of the table.