wot-specs: revise WoT Binding and add registry-first Connectivity 1.1 - #17
Merged
Conversation
- WoT Connectivity generator: mark InputArguments, OutputArguments, and EnumStrings as namespace-0 BrowseNames using the existing _ns0bn mechanism, covering both type declarations and well-known instance methods. Regenerated NodeSet2.xml accordingly (no NodeId churn). - Strengthen wot-specs/WoT-Connectivity/tools/validate_local.py to reject well-known Properties (InputArguments/OutputArguments/ EnumStrings) that carry a namespace-2 BrowseName instead of ns=0. - Correct the WoT Binding spec's normative modelling-rule NodeIds: MandatoryPlaceholder i=11510, OptionalPlaceholder i=11508 (previously swapped/incorrect). Add a validator assertion in wot-specs/WoT-Binding/tools/validate_local.py to prevent regression.
marcschier
commented
Jul 22, 2026
…1.02) + WoT Binding revisions Resolves all 14 unresolved review threads on PR #17. WoT Binding (OPC-UA-WoT-Binding.md): - Remove the ADR-informed paragraph; add "1.1 Differences from OPC 10101 v1.00" (preserved terms, event mapping, model/platform vocabulary, exact NodeSet roundtrip/preservation, implementer guidance). [thread 1] - Address-space example: add a left-to-right figure (WoT sample -> OPC UA nodes/references) with explanation. [thread 2] - Move the ADR->uav crosswalk out of the spec into wot-specs/extras/WoT-Binding/adr-to-uav-crosswalk.md; link only from extras/README and the WoT-Binding README. [thread 3] - Expand every S6 vocabulary subsection: concept, when/why it is an OPC UA model fact, normative usage, a short JSON example, and its explanation. [thread 4] - Add "Annex D — Implementer walkthrough": TM->types, TD->instances, and the reverse AddressSpace/NodeSet->TM/TD, using concise snippets. [thread 5] - Allow rel: uav:componentOf as a parent link (S6.2 + validation table + direction rule); demonstrate it in examples/01. [thread 10, Binding side] WoT Connectivity (OPC-UA-WoT-Connectivity.md): - Use the companion-spec header (title, Release, Namespace, publication date, WG-draft status, hr, numbered clauses); state intended submission to the OPC Foundation WoT WG. [thread 6] - Stop using "V2": additive revision 1.1 in the existing namespace http://opcfoundation.org/UA/WoT-Con/; incorporate the full OPC 10100-1 v1.02 model into one combined NodeSet preserving every published NodeId (1..172), type, method signature and the well-known WoTAssetConnectionManagement; add registry nodes in 64000+; mark the legacy surface Deprecated (OPC 11030); rename artifacts to Opc.Ua.WoTCon.*; drop separate-namespace/dual-profile claims. [thread 7] - Replace remaining V2 architecture prose with contextual language. [thread 8] - Expand S6 concepts into what/where/why/how subsections, each type linked to its Annex anchor, with short examples. [thread 9] - No-flat-root: remove the "A server MAY ..." convenience-folder paragraph; define parent selection via WoT links (rel: uav:componentOf), the link direction and how the materializer resolves the parent and creates the HasComponent Reference. [thread 10] - Add the explicit link to the WoT Binding spec in S7.2 projection mapping. [thread 11] - Expand S7.4-7.8 into implementer-ready normative shall/should/may prose (dependency graph + errors, closure atomicity, invalid desired versions, shadow prepare/switch/drain/retire state diagram, refresh/idempotence, version switch/unload/delete/federation) with examples. [thread 12] - Expand S9 Refresh (purpose/use cases, caller workflow, validate/plan/apply algorithm, concurrency/generation, outcomes/errors, implementer responsibilities) with a Mermaid sequence diagram. [thread 13] - Replace S12's link-only example list with shown, discussed snippets from the TM, TD, invalid TD and refresh-results files. [thread 14] Model / generator: - Pin the OPC 10100-1 v1.02 sources under legacy/ (WotConnection.xml/.csv) as a parsed source input (not hand-copied); build_model.py deterministically emits one combined NodeSet: ns order Core 0, xRegistry 1, own 2; legacy nodes remap ns=1 -> ns=2 with numeric ids unchanged; new nodes stay 64000+ (no churn). - NamespaceMetadata carries the 1.1 version at stable NodeIds; deprecation is machine-readable via ReleaseStatus="Deprecated". - validate_local.py proves legacy id/class preservation vs the pinned CSV, no duplicate ids, single namespace at model version 1.1.0, xRegistry references, deprecation markers, callable well-known WoTAssetConnectionManagement, and Annex A embedding, plus all previous structural checks. Validation: xRegistry + both WoT validators 0 errors/0 warnings; internal links OK; JSON parses; 5 Mermaid diagrams compile; markdownlint scoped to wot-specs 0 errors; git diff --check clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
koepalex
reviewed
Jul 22, 2026
koepalex
reviewed
Jul 22, 2026
koepalex
reviewed
Jul 22, 2026
…deId identity, HasComponent subtypes WoT Binding revisions responding to three review threads on OPC-UA-WoT-Binding.md: - uav:eventType (thread PRRT_kwDOTKTzys6S4F6O): add an explicit @type annotation for WoT event affordances / Thing Models that project OPC UA EventTypes (BaseEventType subtypes). Define its domain, the mapping, its relation to the uav:isEvent flag, and reverse conversion. Update the JSON-LD context, JSON Schema (eventType/@type vs uav:isEvent consistency), pump event examples (Binding + Connectivity), Section 5.2/6.1/8/9.1/1.1 tables and the Annex D walkthrough, and validator term coverage. - Portable identity (thread PRRT_kwDOTKTzys6S4IHC): make ExpandedNodeId normative. uav:id, uav:hasComponent, uav:componentOf, uav:mapToNodeId, uav:mapToType and any NodeId-valued uav:refType shall use the OPC 10000-6 nsu=<NamespaceUri>;... form (or namespace-0 canonical i=...), never the session-local ns=<index> form, so documents survive namespace-table reordering. Add Section 5.1.1, update URI/base/href rules (preserving percent-encoding), fix example hrefs, tighten the schema, and add validator checks that reject ns= in portable fields and validate ExpandedNodeId syntax. Wording explicitly excludes the qualified BrowseName form and the NodeSet2 preservation envelope so it does not contradict the exact roundtrip. - Component subtypes (thread PRRT_kwDOTKTzys6S4JsF): clarify that uav:hasComponent/uav:componentOf cover HasComponent and all subtypes for parent-child discovery, and that exact subtype semantics (e.g. HasOrderedComponent) are pinned by a uav:typedReference link (refType = ReferenceType ExpandedNodeId, plus uav:refName); reverse conversion recreates the subtype, otherwise plain HasComponent is used. Add a HasOrderedComponent example (i=49) and cover it in the walkthrough. Validated: WoT Binding + WoT Connectivity local validators, internal links, JSON/YAML well-formedness, scoped markdownlint, and git diff --check all clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
marcschier
commented
Jul 22, 2026
marcschier
commented
Jul 24, 2026
marcschier
commented
Jul 24, 2026
marcschier
commented
Jul 24, 2026
marcschier
commented
Jul 24, 2026
marcschier
added a commit
that referenced
this pull request
Jul 27, 2026
…atrix validation, per-DataSet SchemaId (#20) * Avro spec: encoder derives schema from type model; clarify publish/version lifecycle Correct the encoder/decoder/schema roles and the schema-change publish protocol in the Avro DataEncoding, its Part 14 mapping, and the Schema Registry PubSub profile: - Encoding PRODUCES a schema from the OPC UA type model; the encoder is never handed one. The schema's CRC-64-AVRO fingerprint is the SchemaId. The decoder needs the schema (registry/announcement or AddressSpace re-derivation). Fixes 5.1, 6 intro, 6.1, 7, and the ExtensionObject known-struct wording (5.9) so branch order is derived from the type model's subtype hierarchy, not consulted from an external registry. - S1: on a schema change the publisher shall PUBLISH to subscribers by BOTH registering the new schema in the Schema Registry AND announcing it (6.4 step 4, 8.4.5 encoder change tracking, SReg Annex C.2). - S2: a publisher shall advance ConfigurationVersion when the produced schema changes (MinorVersion append / MajorVersion reset); decoders stay SchemaId-authoritative and still decode if a publisher misbehaves (8.4.8). Applies to standalone OPC-UA-Avro-Encoding.md and the errata Part 6/Part 14 plus the Schema Registry. Arrow parallel pass tracked separately. * Reflect implementation learnings into Avro/Arrow specs Capture two normative rules discovered while implementing, so another implementer makes the right decisions: - Matrix dimension validation (finding #17): a matrix has at least two dimensions and the product of dimensions equals the element count; a decoder shall reject a violating matrix with Bad_DecodingError. Removes the contradictory 'empty dimensions vector' claim in Avro 5.5 (the implementation requires >=2 dimensions). Applied to Avro Part 6 5.5 and Arrow Part 6 matrix, standalone + errata. - Per-DataSet SchemaId (finding #20): the SchemaId identifies a single DataSet's schema; a NetworkMessage-level SchemaId is valid only when all its DataSetMessages share one schema, otherwise each DataSetMessage carries its own SchemaId. A producer computes/tracks the SchemaId and advances the DataSet ConfigurationVersion per DataSet, not per NetworkMessage. Applied to Avro Part 14 framing and Arrow Part 14 5.2.1, standalone + errata. markdownlint clean; check_links OK. * Avro spec: address PR #20 feedback (schema-gen inputs, decoder resolution, fixed NM envelope) Applies the three PR #20 review threads to the standalone Avro spec and mirrors the normative changes to the Part 6 / Part 14 errata specs: - T1 (schema-gen inputs): a grown schema also takes the previous schema of the lineage as an input (append new Variant body form / ExtObj concrete type as an additional union branch, existing branch indices preserved); no previous schema supplied = reset = new MajorVersion. Softened "never handed one". - T2 (decoder resolution): primary use case is a subscriber/downstream consumer that does NOT have the OPC UA type model at decode time, so it obtains the shared schema by SchemaId; "computed" -> "are using". - T3 (NetworkMessage envelope): the NM is a fixed, specification-defined envelope whose schema never changes; payload is an array of { schemaId, dataSetMessage:bytes } entries carrying each DataSetMessage opaquely, decoded via its per-DataSet schema. Added single-DataSet and un-enveloped-batch models; updated carrier table and common-header SchemaId identification. markdownlint (target files) + check_links (514) clean. * Avro spec: address PR #20 round-2 feedback (schema-gen wording, style, NetworkMessage schema artifacts) Standalone Avro spec + Part 6/14 errata: - T1 (§5.1): reconcile "encoder is not handed a schema" with §6.1 - the encoder GROWS its own previous schema (appending a Variant/ExtObj branch) when a form evolves, and creates a new schema from scratch (a new MajorVersion) only when no previous schema exists. Removed the unexplained "Neither side may substitute alternate branches" sentence. - T2 (§5.8/§5.9 and §8.1): broke the dense Variant/ExtensionObject paragraphs into logical paragraphs of full sentences; removed semicolon-joined clauses. - T3 (§7): "does not have" -> "likely does not have" the type model at consumption time. - T4 (§8.1): the fixed NetworkMessage envelope is now a published artifact - generated AvroNetworkMessage.avsc + AvroDataSetPayloadEntry.avsc (via message_types.py), linked from §8.1 and reproduced in Annex B. - T5 (§8.1): the un-enveloped batch schema AvroDataSetMessageBatch.avsc likewise generated, linked and added to Annex B. - T6: mirrored T1/T2/T3 into Part 6 and the NetworkMessage envelope/batch artifact links into Part 14. markdownlint (target files: only pre-existing MD011 false positives in generated annex blocks) and check_links (514) clean. * Arrow specs: parity with the Avro PR #20 model (encoder role, S1/S2, columnar envelope rationale) Brings the Arrow standalone spec and the Part 6/14 Arrow errata up to the model applied to Avro in PR #20. The Arrow specs already carried the per-DataSet SchemaId and the advance-MinorVersion lifecycle; this fills the remaining gaps: - Encoder role (Part 6 §5.6.9): the encoder is not handed a foreign schema - it PRODUCES the Arrow Schema from the type model and GROWS its own previous schema (appending a dense-union child, existing children and type codes unchanged); no previous schema = new MajorVersion. - Decoder framing (§5.6.10): the primary consumer LIKELY does not have the type model at consumption time, so it obtains the schema by SchemaId; only an AddressSpace-holding decoder re-derives. - S1 (§6.9.2.5 / Part 14 §5.2.5): publishing a changed schema is ONE rule with two channels - register in the Schema Registry AND announce (announce-only when no registry is reachable). - S2 (§5.6.12 step 4, §6.9.2.7 / Part 14 §5.2.7): the publisher SHALL advance the DataSet ConfigurationVersion on schema growth; decoders stay SchemaId-authoritative. - Columnar envelope rationale (§6.9.2.1 / Part 14 §5.2.1) - reflecting the reference implementation: an Arrow NetworkMessage is one homogeneous RecordBatch whose schema IS the DataSet schema, so the per-DataSet SchemaId is inherent and Arrow deliberately does NOT adopt Avro's fixed envelope with opaque per-DataSet entries. Implementers shall not add one. - Style: broke the dense semicolon paragraphs into full sentences; linked the generated struct-ArrowSchemaAnnouncement / struct-ArrowSchemaRequest artifacts. markdownlint clean on the Arrow specs; check_links OK (514). * Drafts cleanup: retire dead pubsub-binding NodeSet references and stop destructive regeneration The pubsub-binding NodeSet was renamed to scenario-binding and then rewritten as observability-export, but five tool/doc references still pointed at the deleted path: - avro/arrow tools/build_schemas.py + xregistry-catalog/tools/build_catalog.py: repoint the default source NodeSet to the current successor, core-specs/observability-export/Opc.Ua.ObservabilityExport.NodeSet2.xml (it still defines BoundItemDataType/BoundItemKindEnum and the model's successor DataTypes). - extras/validate_all.py + avro-encoding/README.md: fix the stale example/default path. Also fixes a destructive failure mode in the Avro generator: it used to shutil.rmtree() the committed schema directory and only THEN fail on the missing NodeSet, leaving the artifacts deleted (hit for real while generating the PR #20 NetworkMessage schemas). It now validates the NodeSet path first and exits 2 with a usage hint, leaving the output directory untouched. Verified: missing NodeSet -> clear error, exit 2, all 31 artifacts intact. Generated artifacts are intentionally NOT regenerated here. The committed schemas still derive from the old scenario-binding model, so regenerating would churn schema files, schemaids and the Annex type-reference tables; that refresh is a separate, deliberate change (it is why avro/arrow validate_local still report type-reference drift, a pre-existing staleness). check_links OK (514).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR changes or proposes
Adds a dedicated top-level
wot-specs/area with two complete, standalone specification drafts:uavprotocol/security vocabulary, adds collision-safe model/platform terms, defines event mapping, and specifies bidirectional NodeSet2 ↔ WoT conversion. The semantic/readable mapping is primary; the completeuav:nodesprojection is added only for source facts not yet expressible by the vocabulary, anduav:nodeSetis reserved for explicit byte archival or a demonstrated final fallback.http://opcfoundation.org/UA/WoT-Con/namespace. It incorporates the complete published 1.02 model with every numeric NodeId and signature retained, marks the superseded management/upload surface as deprecated, and adds an xRegistry-backed TD/TM registry underServer. Thing Models materialize as types, Thing Descriptions as instances, and forms compile into injectable binder plans with dependency-closureRefresh, validation/load/binding events, model/semantic-change behavior, registry-scoped federation and selectable graceful/immediate retirement.The existing OPC 10100-1 v1.02 namespace, NodeIds, methods and workflows remain directly present and callable in the combined 1.1 model.
The PR also adds:
wot-specs/structure.The review follow-ups also:
InputArguments,OutputArguments, andEnumStringsBrowseNames to namespace 0 and fix the canonical placeholder ModellingRule NodeIds;uav:eventType, portablensu=ExpandedNodeIds, and exactHasComponentsubtype preservation;uav:nodesconversion the default and require completeness tests to forbid the envelope;observable/observepropertyadvertises binding support rather than defining OPC UA Variable monitorability.relwithuav:refIdas identifier. The non-publisheduav:typedReferencedraft term was removed.uav:refId; prefer@context-qualified BrowseNames/paths while retaining OPC 10000-6 URI-qualified QualifiedNames as an alternative; clarify thatmapToNodeIdis instance mapping whilemapToTypeis definitive DataType mapping accompanied bymapToTypeName; retain and explain WoTactionGroups.BadNodeIdUnknowninvalidation.Why
OPC 10101 currently describes an OPC UA endpoint in WoT but does not provide an exact, generic two-way NodeSet representation or the model vocabulary needed to retain type composition, references, modelling rules and external semantics.
OPC 10100-1 v1.02 stores uploaded TDs behind a fixed flat asset-management surface. WoT Connectivity 1.1 retains that API for compatibility while adding a preferred registry model that can represent authored Thing Models, generated type definitions, arbitrary TD hierarchy/references, versioned documents and dynamic protocol code-behind.
The registry-first design makes TD/TM documents the versioned source of truth and the AddressSpace a derived projection, while preserving every current 1.02 scenario in the same namespace and model.
Type
Validation
uavterms, model-name, native-profile and archival digest/XML checks — OKwot-specs/: 0 errorsgit diff --check: cleanStack proof
The dependent draft implementation is available at OPCFoundation/UA-.NETStandard#4093. It depends on OPCFoundation/UA-.NETStandard#4094 (the upstream-owned successor to #4015) and proves conversion, source generation, selectable live retirement, registry materialization, legacy compatibility and protocol binders.
Checklist
python core-specs/extras/validate_all.pyand/or the extension'svalidate_local.py)