Skip to content

[WotCon] Add the WoT Connectivity 1.1 information model - #4139

Open
marcschier wants to merge 16 commits into
marcschier/wot-09-xregistry-clientfrom
marcschier/wot-10-wotcon-model
Open

[WotCon] Add the WoT Connectivity 1.1 information model#4139
marcschier wants to merge 16 commits into
marcschier/wot-09-xregistry-clientfrom
marcschier/wot-10-wotcon-model

Conversation

@marcschier

Copy link
Copy Markdown
Collaborator

This is PR 10 of the stacked split of integration PR #4093 into independently reviewable pieces.

Stack/dependency shape:

The #4132 dependency is functional, not cosmetic. Without #4132, building the WoT Connectivity model on #4134 alone fails with duplicate generated declarations, for example:

CS0102: The type 'Methods' already contains a definition for 'CreateAssetMethodType'

That occurs because the combined WoT-Con NodeSet ships the 1.02 CreateAssetMethodType node explicitly; without #4132's NodeSet-to-ModelDesign fix, the generator synthesizes a second declaration with the same name.

Once #4132 and #4134 land, the extra diff from those dependencies disappears and this PR reduces to the three WoT Connectivity model files:

  • src\Opc.Ua.WotCon\Design\Opc.Ua.WotCon.NodeSet2.xml
  • src\Opc.Ua.WotCon\Design\Opc.Ua.WotCon.NodeSet2.csv
  • src\Opc.Ua.WotCon\Opc.Ua.WotCon.csproj

The generated C# is produced from the pinned NodeSet2 at build time. I verified it builds from clean after deleting the WotCon bin/obj, the source-generation tool bin/obj directories, and shutting down dotnet build servers.

marcschier and others added 2 commits July 31, 2026 08:00
Pins the combined WoT Connectivity 1.1 NodeSet2 and its NodeId companion file
into the project and generates the model from them.

The combined NodeSet contains the complete published OPC 10100-1 v1.02 model
alongside the additive registry nodes in a single namespace, emitted under the
same prefix, name and model URI the standalone 1.02 model used. Every existing
1.02 generated constant, NodeState and proxy therefore keeps its exact NodeId,
so the model is additive rather than a replacement.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
The combined WoT Connectivity model generates DataTypeIds and the other identifier classes into the Opc.Ua.WotCon namespace, so an unqualified DataTypeIds in a file that imports that namespace now resolves to the generated class rather than to the standard one and the core identifiers stop resolving.

Qualifies the affected references in the WoT Connectivity server so it keeps building against the new model. No behaviour changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
Copilot AI review requested due to automatic review settings July 31, 2026 09:41
@marcschier

marcschier commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator Author

The combined WoT Connectivity model generates identifier classes in the Opc.Ua.WotCon namespace, which shadows core Opc.Ua classes such as DataTypeIds, so the affected server/test references are qualified. The model swap also required registering the xRegistry namespace and partitioning the combined predefined-node table so WotConnectivityNodeManager keeps only the v1.02 asset surface; otherwise the master asset-management tests fail at runtime when the table resolves xRegistry references.

The combined WoT Connectivity model includes the deprecated 1.02 asset surface and the additive registry nodes that reference xRegistry base types. Register the xRegistry namespace before creating the combined table, then retain only the legacy node slice for WotConnectivityNodeManager.

This keeps the existing asset-management NodeManager from claiming registry nodes or failing when xRegistry NodeIds are resolved. No behavior change outside the model partitioning needed by the combined NodeSet.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Adds the WoT Connectivity 1.1 information model while updating the source-generation pipeline to correctly handle combined NodeSets, placeholder names, method-argument identifiers, and structured argument decoding.

Changes:

  • Introduces a combined WoT Connectivity 1.1 NodeSet (plus CSV) and wires it into the Opc.Ua.WotCon project (including Opc.Ua.XRegistry base model consumption).
  • Improves source-generation correctness for placeholder browse names, DataTypeEncoding parenting, explicit method-type reuse, and stable/unique method-argument code identifiers.
  • Extends generators/templates to decode structured argument values with message context and adds fluent builder support for variables discovered by DataTypeId.

Reviewed changes

Copilot reviewed 31 out of 32 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tools/Opc.Ua.SourceGeneration.Core/Shared/SourceGenerationUtils.cs Adds ToCSharpIdentifier and extends string literal escaping for Unicode line separators.
tools/Opc.Ua.SourceGeneration.Core/Schema/NodeSetToModelDesign.cs Fixes import edge cases (placeholders, DataTypeEncoding parent) and method-type synthesis/reuse.
tools/Opc.Ua.SourceGeneration.Core/Schema/ModelDesignValidator.cs Ensures method argument code names are assigned during import/validation.
tools/Opc.Ua.SourceGeneration.Core/Schema/ModelDesignExtensions.cs Introduces scoped, collision-aware generated identifiers for method arguments.
tools/Opc.Ua.SourceGeneration.Core/Generators/ObjectTypeProxyGenerator.cs Uses scoped argument identifiers; fixes structured output decoding and error message escaping.
tools/Opc.Ua.SourceGeneration.Core/Generators/NodeStateGenerator.cs Uses scoped argument identifiers; decodes structured values with message context; fixes Description assignment target.
tools/Opc.Ua.SourceGeneration.Core/Generators/NodeManagerTemplates.cs Adds a FindByDataTypeId traversal helper to support new fluent APIs.
tools/Opc.Ua.SourceGeneration.Core/Generators/MethodDesignArgumentResolver.cs Resolves both input/output args together and assigns generated identifiers.
tools/Opc.Ua.SourceGeneration.Core/Generators/FluentBuilderGenerator.cs Adds VariableFromDataTypeId pass-through methods; doc comment formatting tweak.
src/Opc.Ua.WotCon/Opc.Ua.WotCon.csproj Switches to NodeSet2-based generation, references Opc.Ua.XRegistry, and links its NodeSet as ignored input.
src/Opc.Ua.WotCon/Design/Opc.Ua.WotCon.NodeSet2.csv Adds NodeIds CSV for the combined WoT Connectivity model.
src/Opc.Ua.WotCon.Server/* Aligns DataTypeIds references to Ua.DataTypeIds in server code.
src/Opc.Ua.ISA95/Design/Common/Opc.ISA95.NodeIds.csv Renames placeholder nodes to *_Placeholder to match new placeholder naming convention.
tests/* Adds/updates regression tests and fixtures for new generator behaviors and naming rules.
Suppressed comments (1)

tools/Opc.Ua.SourceGeneration.Core/Shared/SourceGenerationUtils.cs:1

  • TrimStart('@') removes all leading '@' characters, which is potentially lossy if an authored UA name legitimately begins with multiple '@' characters (it will collapse them). If the intent is only to strip a single C# escape prefix, consider removing at most one leading '@' (e.g., StartsWith('@') ? name[1..] : name) to avoid changing authored semantics unexpectedly.

Comment thread tools/Opc.Ua.SourceGeneration.Core/Schema/ModelDesignExtensions.cs Outdated
Comment thread tools/Opc.Ua.SourceGeneration.Core/Generators/MethodDesignArgumentResolver.cs Outdated
The fluent builder generator emits calls to INodeManagerBuilder.VariableFromDataTypeId
and to a NodeManagerBuilder constructor overload that carries the data-type lookup, but
the runtime side of that API was missing, so every generated node manager failed to
compile with CS1729 and CS1061.

Adds the VariableFromDataTypeId resolution to the builder interface and implementation,
along with NodeStateLookupExtensions.FindByDataType, which is the lookup the builder
delegates to and has no other consumer.

Resolution reports BadNodeIdInvalid for a null data type, BadNodeIdUnknown when nothing
matches, BadBrowseNameDuplicated when the match is ambiguous, and BadTypeMismatch when
the resolved node is not a variable. An optional browse name disambiguates a data type
that is carried by more than one variable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
@marcschier

Copy link
Copy Markdown
Collaborator Author

Fixed the net10.0 solution build failure on this PR.

This branch carries the FluentBuilderGenerator change, which emits calls to
INodeManagerBuilder.VariableFromDataTypeId and to a NodeManagerBuilder constructor
overload carrying the data-type lookup. The runtime side of that API was not present on
any branch in the stack - it had been grouped into a later server PR that does not exist
yet - so every generated node manager failed to compile:

BoilerNodeManager.NodeManager.g.cs(97,31): CS1729: 'NodeManagerBuilder' does not
  contain a constructor that takes 7 arguments
BoilerNodeManager.FluentBuilders.g.cs(140,24): CS1061: 'INodeManagerBuilder' does not
  contain a definition for 'VariableFromDataTypeId'

The fix lands in #4132 (where the generator change belongs) and is cherry-picked here so
this branch builds standalone. It adds VariableFromDataTypeId to the builder interface
and implementation, NodeStateLookupExtensions.FindByDataType, and eight tests covering
the resolution rules.

Verified locally: MinimalBoilerServer - one of the two projects failing in CI - builds
clean on this branch.

DiNodeManager constructed NodeManagerBuilder without the data-type resolver, so
VariableFromDataTypeId reported BadNodeIdUnknown ("no predefined variable has DataType")
for every DI node manager - a misleading error, since the lookup had simply never
been supplied rather than the variable being absent.

Delegates to NodeStateLookupExtensions.FindByDataType rather than hand-rolling the
scan a fourth time in this file.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
@marcschier marcschier closed this Jul 31, 2026
@marcschier marcschier reopened this Jul 31, 2026
marcschier and others added 2 commits July 31, 2026 16:29
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
…-wotcon-model

# Conflicts:
#	src/Opc.Ua.Di.Server/DiNodeManager.cs
Guard generated method argument name state with System.Threading.Lock so concurrent generator runs cannot mutate the ConditionalWeakTable state at the same time. Make argument resolution pure and assign generated code names only at emission sites that need those names, preserving scope-specific reserved names deterministically.

Also suppress warnings for legacy-TFM no-op shell builds so generated consumer validation remains warning-free when CustomTestTarget points at a TFM the sample intentionally skips.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
@codecov

codecov Bot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.13251% with 38 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.08%. Comparing base (bdbdd9a) to head (66ccab9).

Files with missing lines Patch % Lines
...urceGeneration.Core/Schema/NodeSetToModelDesign.cs 67.64% 8 Missing and 3 partials ⚠️
src/Opc.Ua.WotCon.Server/WotConModelPartition.cs 52.63% 8 Missing and 1 partial ⚠️
...rceGeneration.Core/Schema/ModelDesignExtensions.cs 92.72% 1 Missing and 7 partials ⚠️
...rceGeneration.Core/Shared/SourceGenerationUtils.cs 88.09% 2 Missing and 3 partials ⚠️
...ceGeneration.Core/Generators/NodeStateGenerator.cs 96.80% 1 Missing and 2 partials ⚠️
...Ua.Server/NodeManager/NodeStateLookupExtensions.cs 75.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@                         Coverage Diff                         @@
##           marcschier/wot-04-generator-wot    #4139      +/-   ##
===================================================================
- Coverage                            80.09%   80.08%   -0.01%     
===================================================================
  Files                                 1539     1540       +1     
  Lines                               214557   214958     +401     
  Branches                             37070    37133      +63     
===================================================================
+ Hits                                171841   172159     +318     
- Misses                               29859    29921      +62     
- Partials                             12857    12878      +21     
Files with missing lines Coverage Δ
src/Opc.Ua.Di.Server/DiNodeManager.cs 69.65% <100.00%> (+0.09%) ⬆️
src/Opc.Ua.Server/Fluent/FluentNodeManagerBase.cs 63.82% <100.00%> (+0.78%) ⬆️
src/Opc.Ua.Server/Fluent/NodeManagerBuilder.cs 90.07% <100.00%> (+2.03%) ⬆️
src/Opc.Ua.WotCon.Server/Assets/AssetRegistry.cs 71.34% <100.00%> (ø)
...WotCon.Server/ThingDescriptions/WotActionMapper.cs 98.18% <100.00%> (ø)
...tCon.Server/ThingDescriptions/WotPropertyMapper.cs 86.95% <100.00%> (ø)
...Opc.Ua.WotCon.Server/WotConnectivityNodeManager.cs 47.03% <100.00%> (+0.59%) ⬆️
...c.Ua.WotCon.Server/WotConnectivityServerOptions.cs 100.00% <ø> (ø)
...neration.Core/Generators/FluentBuilderGenerator.cs 86.09% <100.00%> (+0.17%) ⬆️
...on.Core/Generators/MethodDesignArgumentResolver.cs 80.00% <100.00%> (+11.57%) ⬆️
... and 9 more

... and 23 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…-wotcon-model

# Conflicts:
#	tests/Opc.Ua.SourceGeneration.Core.Tests/Schema/NodeSetToModelDesignTests.cs
#	tools/Opc.Ua.SourceGeneration.Core/Generators/FluentBuilderGenerator.cs
#	tools/Opc.Ua.SourceGeneration.Core/Generators/MethodDesignArgumentResolver.cs
#	tools/Opc.Ua.SourceGeneration.Core/Generators/ObjectTypeProxyGenerator.cs
#	tools/Opc.Ua.SourceGeneration.Core/Schema/ModelDesignValidator.cs
#	tools/Opc.Ua.SourceGeneration.Core/Schema/NodeSetToModelDesign.cs
…-10-wotcon-model

# Conflicts:
#	tools/Opc.Ua.SourceGeneration.Core/Generators/NodeStateGenerator.cs
#	tools/Opc.Ua.SourceGeneration.Core/Schema/ModelDesignExtensions.cs
@marcschier
marcschier changed the base branch from marcschier/wot-04-generator-wot to marcschier/wot-09-xregistry-client August 1, 2026 11:55
@marcschier

Copy link
Copy Markdown
Collaborator Author

Flagging a net48-only build break in Opc.Ua.WotCon.Server that CI surfaced on #4140. It is
pre-existing, not caused by the restacking - I verified by building the commit before the
linearisation merge (abc2009e4), which fails identically.

Symptom

Opc.Ua.WotCon.Server compiles for net10.0 but not for net48:

Assets/WotAssetFileManager.cs(84,43): CS0029: Cannot implicitly convert type
  'Opc.Ua.WotCon.CloseAndUpdateMethodStateMethodCallHandler' to
  'Opc.Ua.WotCon.CloseAndUpdateIWoTAssetTypeWoTFileMethodStateMethodCallHandler'
WotConnectivityNodeManager.cs(405,51): CS0407: ... has the wrong return type   (x5)

The generator emits the disambiguated delegate type name
(CloseAndUpdateIWoTAssetTypeWoTFileMethodStateMethodCallHandler) when compiling for net48, but the
short name (CloseAndUpdateMethodStateMethodCallHandler) for net10.0. The hand-written code
references the short form, so only net48 fails.

What I ruled out

Generated argument names leaking between the two TFM compilations in one process.
AssignMethodArgumentCodeNames builds a fresh usedNames set and clears prior per-scope state on
every call, so that path is sound.

Remaining hypothesis

The collision/disambiguation decision for generated delegate type names appears to depend on the
iteration order of a hash-based collection, which differs between the two compilations. That is the
same class of defect the automated reviewer raised on this PR - generated output varying with
ordering - just reaching the type-name path rather than the argument-name path.

A deterministic ordering (sort the candidate set before deciding whether to disambiguate) is the
likely fix, and it would make the emitted names stable across TFMs by construction. Worth fixing at
the generator rather than by renaming the hand-written references, since the latter would just move
the breakage to the other TFM.

Not resolving; recording it here so it is not lost.

marcschier and others added 2 commits August 1, 2026 18:21
The generator now emits a distinct handler delegate and result type per declaring
type, so a method that appears on more than one type no longer shares a single
generic name. CloseAndUpdate on the WoT file and the five WoTAssetConnectionManagement
methods each have their own type now, and the server still referenced the generic
names, so it no longer compiled.

Points the asset file manager at the WoT file's CloseAndUpdate handler and the
connectivity node manager at the management type's result types.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
@marcschier
marcschier force-pushed the marcschier/wot-10-wotcon-model branch from 956f632 to 1ae01a3 Compare August 1, 2026 16:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants