Repository navigation
CTT: keep GeneratesEvent off Object instances and Views off non-hierarchical references; classify Deadband Err-006 as CTT defect - #4667
Conversation
…ical references; classify Deadband Err-006 - Source generator: an ObjectType's GeneratesEvent/AlwaysGeneratesEvent references were copied onto every Object/Variable built from the type (instance declarations such as the GDS AuthorizationServicesFolderType <ServiceName> placeholder, and CreateInstanceOf<Type>, hence the GDS AuthorizationServices/Default service). Part 3 §7.15 allows only an ObjectType, VariableType or Method as source. References declared on a type are now marked (HierarchyReference.DefinedOnType) and not emitted for Object/Variable nodes; types, Methods and references declared explicitly on an instance are unchanged. - Reference server sample: Views_Operations was the source of HasCause and HasEffect to Views_Engineering (test data for View Minimum Continuation Point 01 012.js / View Basic 2 018.js). Views shall not be the source of non-hierarchical references (Part 3 §5.4), so Views_Operations now Organizes Views_Engineering and a new View Views_Maintenance. - plans/ctt-issues.md: C54, Monitored Items Deadband Filter Err-006.js does not accept Bad_DeadbandFilterInvalid, which Part 8 §7.3.2 Table 61 defines for a PercentDeadband without EURange. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Variable instance behavior lacks regression coverage, and the CTT identifier range is now stale.
Review effort: Balanced
Findings: 1
Open (2)
What changed in this PR
Fixes CTT findings involving invalid inherited GeneratesEvent references and non-hierarchical View references, while documenting a deadband CTT defect.
Changes:
- Tracks and filters type-declared
GeneratesEventreferences from instances. - Reworks sample View relationships to use
Organizes. - Adds regression tests and records CTT issue C54.
| File | Description |
|---|---|
tools/Opc.Ua.SourceGeneration.Core/Schema/ModelDesignValidator.cs |
Marks type-declared references. |
tools/Opc.Ua.SourceGeneration.Core/Schema/ModelDesign.cs |
Clarifies reference metadata. |
tools/Opc.Ua.SourceGeneration.Core/Generators/NodeStateGenerator.cs |
Filters invalid inherited event references. |
tests/Opc.Ua.SourceGeneration.Core.Tests/Resources/TypeGeneratesEvent.ModelDesign.xml |
Adds generator test model. |
tests/Opc.Ua.SourceGeneration.Core.Tests/Generators/NodeStateGeneratorTests.cs |
Tests Object reference generation. |
tests/Opc.Ua.Server.Tests/ReferenceServerTest.cs |
Validates sample View references. |
samples/Quickstarts.Servers/ReferenceServer/Model/ReferenceServer.NodeSet2.xml |
Replaces invalid View relationships. |
plans/ctt-issues.md |
Records deadband test defect C54. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…54 in the CTT id range Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Code coverage✅ Coverage gate passed.
Uncovered changed lines
Coverage is above the recorded baseline - consider ratcheting Thresholds live in |
…generatesevent-deadband # Conflicts: # plans/ctt-issues.md
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #4667 +/- ##
=======================================
Coverage 82.60% 82.60%
=======================================
Files 2198 2198
Lines 337670 337692 +22
Branches 58834 58840 +6
=======================================
+ Hits 278921 278940 +19
+ Misses 39001 39000 -1
- Partials 19748 19752 +4
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
…generatesevent-deadband # Conflicts: # plans/ctt-issues.md
) Fixes #4669. OPC 10000-3 §7.15 says the SourceNode of `GeneratesEvent` "shall be an ObjectType, a VariableType or a Method". CTT `Base Info Core Structure 2 001.js` flags every Object that is the source of one. #4667 fixed this in the source generator. This PR fixes the three remaining WoT places. ### 1. WotCon asset registry - `AssetRegistry.BuildEventNode` / `RemoveEventTypes` no longer add or remove `GeneratesEvent` from the asset Object. Event delivery already relies on `EventNotifier = SubscribeToEvents` and root-notifier registration. - Tests now assert the reference is **absent** and the notifier bit is set. The re-apply test asserts that the old EventType node is gone. ### 2. WoT NodeSet converter (`src/Opc.Ua.Types/Wot`) - **TD → NodeSet:** a last pass (`RelocateInstanceGeneratesEvent`) moves forward `GeneratesEvent` references off an Object/Variable root: - An event the bound type already declares needs nothing more. Matching is by qualified BrowseName against the local context's declarations, the same rule as the declaration merge. - Any other event is declared by a synthesized non-abstract `<rootLocal>Type`. It derives from the bound type (or from `BaseObjectType` / `BaseDataVariableType` when the TD binds none) and becomes the instance's `HasTypeDefinition`. A Variable root gets a `UAVariableType` with the instance's DataType and ValueRank. - Thing Models are unchanged: the projected type keeps its `GeneratesEvent`. - **NodeSet → TD:** - An instance's event affordances are now collected from its type definition and that type's supertypes. Instance-level `GeneratesEvent` is still read for third-party NodeSets. - In a single readable document, a type that only carries one instance's events (only `HasSubtype` + `GeneratesEvent`, typing exactly one instance) is not chosen as root. It is folded back: its supertype becomes the type binding, and no link is written when that supertype is the default base type. The TD → NodeSet → TD round trip stays readable, with no `uav:nodes` fallback. - A document set gives the carrier its own Thing Model, and the instance TD binds to it. - **Archive check:** an event affordance is accepted when the root's type definition, or one of its supertypes, generates it. - `docs/WoTNodeSetConversion.md` documents the behaviour in a new "Event source" row. ### 3. Aggregation sample - `SamplePump.NodeSet2.xml`: each pump is typed by its own `PumpType` subtype, `ns=1;s=Pump1.Type` (`Pump_1Type`) and `Pump2.Type`, which declares its alarm EventTypes. - It is per pump because each pump owns its alarm EventTypes. `Pump2.Type` is cloned with the rest of Pump2. - The pumps keep `EventNotifier="1"` and no longer carry `GeneratesEvent`. - The checked-in documents are regenerated, adding `sample-pump-pump-1type.json` / `-2type.json`. The pump TDs still list the alarm event affordances. - The sample binding lookup ignores Thing Models, because the type's TM declares the same EventType as the pump TD. A declaration missing from the instance still fails as before. - Docs: `WoTConnectivity.md` (asset event affordances, §12.4.2) and `WotBindings.md`. The `GeneratesEvent` clause in the sample-limitation note was already stale, so I removed it. ### Runtime check `WotNativeOwnershipIndex` only uses `GeneratesEvent` in its alias table. Projected event routing takes the owner from `uav:componentOf` / `uav:id` and the notifier from Parent/`HasNotifier`. Nothing in `Opc.Ua.WotCon.Server` reads an instance-level `GeneratesEvent`. ### Tests (net10.0) - `Opc.Ua.Types.Tests`: 11446 passed, 1 skipped. New `WotInstanceEventSourceTests` covers object and variable roots, TMs, the TD with no events, the folded round trip, the legacy instance reference and the document set. Two bound-type cases were added to `WotDeclarationMergeBoundaryTests`. - `Opc.Ua.WotCon.Bindings.Tests`: 714 passed. - `Opc.Ua.WotCon.Tests`: 1496 passed, including the byte-exact sample regeneration tests. - net48 build of both test projects is clean, and `dotnet format whitespace` is clean. Not run: CTT `Base Info Core Structure 2 001.js` (p02-base-info) against a WotCon server. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Marc Schier <marcschier@users.noreply.github.com>


Description
Three findings from the 2026-10-03 CTT run with the patched 1.05.513 scripts. Two are server/model defects and are fixed here. The third is a CTT script defect, recorded as C56 in
plans/ctt-issues.md.1. Monitored Items Deadband Filter
Err-006.js: CTT defect (C56, no server change)The script modifies a MonitoredItem on the first static numeric scalar (a plain BaseDataVariable with no EURange) to use a PercentDeadband. It accepts only
GoodorBad_MonitoredItemFilterUnsupported. Since #4629 the server returnsBad_DeadbandFilterInvalid, and that is the code the spec defines for this case:Bad_DeadbandFilterInvalidis returned when "a PercentDeadband is not supported, since an EURange is not configured".CreateMonitoredItems and ModifyMonitoredItems both go through
ValidateMonitoringFilterAsyncand return the same code. Monitor BasicErr-022.jsalready acceptsBad_FilterNotAllowedfor non-analog items, so the scripts disagree with each other here.Draft Mantis note (not filed yet):
2. GeneratesEvent on Objects (Base Info Core Structure 2
001.js): source generator defectThe CTT reported
ns=9;i=234(the<ServiceName>placeholder of AuthorizationServicesFolderType) andns=9;s=AuthorizationServices/Defaultas Objects that are the source of GeneratesEvent references. OPC 10000-3 §7.15 says: "The SourceNode of References of this type shall be an ObjectType, a VariableType or a Method".OpcUaGdsModel.xmldeclares both references (AccessTokenRequested/Issued audit events) correctly, onAuthorizationServiceType. The source generator copied the type's own non-hierarchical references onto every Object or Variable built from the type: onto instance declarations (the placeholder) and intoCreateInstanceOf<Type>, whichAuthorizationServiceStateinitialises from, and that is how theDefaultservice gets them. UA-ModelCompiler does the same thing, so the officialOpc.Ua.Gds.NodeSet2.xmlin UA-Nodeset has the same two references onns=1;i=234.Fix:
TranslateReferencesnow marks references declared on a type (HierarchyReference.DefinedOnType, which already existed but was never set).NodeStateGenerator.GetReferencesdrops forward GeneratesEvent references (including subtypes such as AlwaysGeneratesEvent) for Object and Variable nodes when the reference came from the type.3. View targeted by HasCause/HasEffect (Base Info Core Structure 2
001.js): sample model defect#4485 added
Views_Operations HasCause/HasEffect Views_Engineeringso that View Minimum Continuation Point 01012.jsand View Basic 2018.jshave at least two references to View nodes on the configured View (/Server Test/NodeIds/NodeClasses/View=Views_Operations). OPC 10000-3 §5.4 says Views "can be the SourceNode of any hierarchical Reference. They shall not be the SourceNode of any NonHierarchical Reference."Views_Operationsnow OrganizesViews_Engineeringand a new View,Views_Maintenance, which organizesDataAccess. This keeps two View-class references and adds no loops (ContainsNoLoops stays true).Tests
NodeStateGeneratorTests.TypeGeneratesEventReferencesAreNotCopiedToObjectInstances: covers the type, the placeholder, the instance,CreateInstanceOf, Methods and an explicit instance reference. It fails without the fix.ReferenceServerTest.SampleViewsHaveNoNonHierarchicalReferencesAsync. The existingNodeClassSampleNodesReferenceTheirOwnNodeClassAsyncstill passes.ReferenceServerTest: 56 passed, 0 failedUA.slnxbuilds with net10.0. The changed test projects build with net48.CTT (patched 1.05.513 scripts, compared with the 2026-10-03 patched baseline)
001.js: Error → Skipped. The GeneratesEvent and View errors are gone; the remaining skips are the CTT's own "type not defined within the test-script" notes. No other change.018.jsand View Minimum Continuation Point 01012.jsstill pass.Err-006.jsstill Error (C56). With the script fix it passes. Monitor Basic007.jsgave a response-timestamp delay warning (>200 ms) caused by machine load; it also appears in the 2026-09-29 base run.🤖 Generated with Claude Code