Repository navigation
Conversation
There was a problem hiding this comment.
QDJVMC found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
0c9c3c7 to
e075cd4
Compare
| | GenerateSerializationByIds | GET | /serialization | READ | "/serialization" | ||
| | GetAllEvents | GET | /events | READ | "/events" | ||
| | GetAllEvents-ValueOnly | GET | /events/$value | READ | "/events/$value" | ||
| | GetAllEvents-Reference | GET | /events/$reference | READ | "/events/$reference" |
There was a problem hiding this comment.
question: Why are this endpoints needed? There is no benefit to have only $reference structure in the events. If you need one you can design own types that represent them but generally you only want 1 event to store for one action. Not 3. If you have thousands of events, this is not acceptable and makes nothing better, than polling the REST resources directly. The only thing to manipulate the result is to have more or less details. of an event. but this can be solved by having different kinds of types and filtering by type.
There was a problem hiding this comment.
There is only one event. This is just the representation (same way as in the standard service endpoints). The benefit here is flexibility. The consumer can decide which representation is needed for the use case.
There was a problem hiding this comment.
I also have a problem with all this serialization formats. I understand the approach of keeping it consistent with the existing spec, but it’s already extremely time-consuming today for companies that don’t have an AAS server -but instead use AAS only as a facade layer - to maintain all those serialization formats. That’s why companies usually just don’t implement them and only offer the standard serialization. This makes it virtually impossible to have clear contracts between clients and servers regarding what can and cannot be delivered, and it greatly increases the complexity of the spec, which is already quite complex. That’s why nobody uses profiles either.
This is probably a fundamental debate: whether, in cases of doubt, decisions made in the past, which lead to major challenges during production implementation in the field, must absolutely be carried over to new features.
But from a productive solution perspective it would be a lot better to have defined payloads that solve actual use cases than having just a list of serilizations that you need to figure out by yourself not knowing the side effects (e.g. request with payload for very large submodels).
There was a problem hiding this comment.
It is a fundamental debate, and I feel you on that point. But two points basically dictate that this is probably the only viable solution right now:
- We need different representations for the use cases we wrote down
- Introducing a new approach to achieve the same solution would make the problem even bigger
Maybe AAS v4.0 could resolve such problems. Additionally, I don't see any harm if companies decide not to implement all endpoints of a profile as long as there is a way to tell the client what is supported.
There was a problem hiding this comment.
Additionally, I don't see any harm if companies decide not to implement all endpoints of a profile as long as there is a way to tell the client what is supported.
And that is the point: there is no way. Which means everything is discussed between people instead of clear contracting between systems. And the more options you introduce, the more cases you have to deal with on client side. We (as a company) have a large network of partners with whom we want to exchange data and this is currently already becoming a nightmare to handle for the existing standard.
There was a problem hiding this comment.
I get that but that can't be solved in the eventing feature alone. Adding deviations from the already existing approach here would just make it worse
There was a problem hiding this comment.
Why is it not an option, to skip the representation until someone really needs it? In the spec it also comes later and there is a way to skip it.
Events != Submodel and the events are not meta model based. So the representations won't work, because they are solving the complexity of the meta model (this is why everyone uses $value in demonstrators). It only works on the meta model endpoints. If you think further: if you have custom events, than the representation options based on meta model structures makes no sense any more.
There is no law that treat us to put bad concepts from the AAS spec to the eventing. So if someone outside of the "event"-Team wants to have this representations they are free to argument to add it. Currently it makes a good concept worse.
There was a problem hiding this comment.
I understand the motivation, since we offer this option for many other resources as well. The behavior, however, would be different. As I understand it, this would only affect the content of data in the CloudEvent payload, right? The other attributes of the payload would remain unchanged.
There was a problem hiding this comment.
TF Meeting 2026/10/21
- Preference to have
$referenceas mandatory for all servers - Other serialization formats should be defined
$value,$normalbut remain optional for a server to implement - Custom payload formats should be allowed
- Some form of description/capabilities operation is needed for the client to discover what the server offers/supports
| |GetAllEvents |GET |/events a| | ||
| path-suffix= $value/$reference or no suffix for normal | ||
|
|
||
| ?type=, ?id=, ?idShortPath=, ?globalAssetId=, ?semanticId=, ?submodelSemanticId=, ?since=, ?lastEventId= |
There was a problem hiding this comment.
Why you have Query parameters that are not in the response of the API? This breaks every API convention. There should only be query parameters of the headers of Cloud events. (Subject etc). What is "id"? No one will understand this. What if you want more than one type? Or more than one semanticId?
There was a reason to use a "SQL"-Like Query-Language that gives all this capabilities.
There was a problem hiding this comment.
- Why you have Query parameters that are not in the response of the API? This breaks every API convention.
Not uncommon and already exists in multiple places here in the API spec (e.g. in getAllSubmodels)
Also mostly incorrect anyway:
typeandsincefilter directly on the CloudEvent attributestypeandtime.lastEventIdworks likecursor: it’s a position, not a filter, and refers toid.globalAssetIdandsubmodelSemanticIdfilter on fields that are in the data (globalAssetIds,submodel.referredSemanticId).
- Only filter on CloudEvents attributes
This contradicts our requirements and use cases that we discussed during the workshop and agreed on. Filtering by semanticId and asset was an explicit requirement, including in the EPLAN use cases.
- What is "id"? No one will understand this.
id and idShortPath follow the way objects are addressed everywhere else in the API ({aasIdentifier}, {submodelIdentifier}, {idShortPath}) and the existing convention to filter on model attributes (?semanticId=, ?idShort=, ?assetIds=). A client that wants to observe a Submodel or SubmodelElement already has its identifier and idShortPath, so it does not need to construct encoded paths for filtering.
Fair point regarding the name, though: in a CloudEvent, id is the event id. I will rename it to aasIdentifier, submodelIdentifier, and cdIdentifier, so that submodelIdentifier together with idShortPath reads exactly like /submodels/{submodelIdentifier}/submodel-elements/{idShortPath}.
- What if you want more than one type? Or more than one semanticId?
Already supported: these parameters have the cardinality 0..* and are repeatable in the OpenAPI (?type=a&type=b). I will make this more explicit in the HTTP mapping.
There was a problem hiding this comment.
I miss some parameters based on our discussion in the workshop, namely dataSchema, limit, and cursor.
There was a problem hiding this comment.
TF Meeting 2026/10/21
-
Options
- Option 1
- Only
GETwith complex parameters base64Url-encoded in query string - Not a good idea because we already deprecated similar calls in the past, e.g.,
GET /lookup/shells
- Only
- Option 2
- Only
POST
- Only
- Option 3
GETwith only primitive parameters +POSTwith all parameters
- Note: Additional query can be implemented to offer more complex filter functionality
- Option 1
-
Things to consider
- need to define semantics regarding
AND/ORacross different parameters (probablyAND) and across multiple appearances of the same parameter (probablyOR, may be parameter-specific)
- need to define semantics regarding
I miss some parameters based on our discussion in the workshop, namely dataSchema, limit, and cursor.
dataSchema is addressed via other parameters, e.g., idShortPath. limit and cursor are define but in different file (using something similar to inheritance).
| e|specversion a|CloudEvents version; value `1.0` |string |1 | ||
| e|id a|Identifier of the event, unique within the scope of `source`, e.g. a UUID xref:bibliography.adoc#bib19[[19\]] |string |1 | ||
| e|source a|Base URL of the service, see xref:eventing.adoc#eventing-source-subject[Source and Subject] |string (URI-reference) |1 | ||
| e|subject a|Path of the modified object relative to `source`, see xref:eventing.adoc#eventing-source-subject[Source and Subject] |string |1 |
There was a problem hiding this comment.
In the examples: it is not useful to add here the path of the API with an base64-encoded ID. So no one will be able to route the event to the correct place, that is interested to update of some assets, AAS or submodels. You mixing here constraints that comes from the REST-API design and constraints that some has, who want to have events. I would agree if you put this path to the source field.
The subject needs to have only the ID of the resource that has changed. AASId, AssetId and SubmodelId (also for submodel elements event or define a pattern like "submodelid#path-to-element" ),. All systems before and after the AAS world has only the ID in clear not the base64-encoding. And what when the encoding changes? Then every event is broken. The same when the API has changed. Best example: the lookup endpoint changed in the last months. This is the reason why there are noch API specification details in source and subject. And you do not need it, because the AAS API itself tells the client if you have an submodel Id you have to follow the patterns of the Submodel-Repository-API to get the resources. There is no need to repeat the API again. also the prefix for submode/shells etc. is not needed, because the event-type tells the consumer which part of the API to use.
There was a problem hiding this comment.
Agreed. Coupling the subject to the REST API layout and especially its encoding contradicts the goal that events are independent of the protocol, and the event type already tells the consumer which kind of resource is affected. I will change the subject to the plain identifier: the AAS id, Submodel id, Concept Description id, or globalAssetId.
Two remarks:
- Moving the path to
sourcewould only move the same coupling there and would create a separate source per Submodel.sourceshould stay the base URL of the service. - A pattern like
submodelId#pathdoes not work, because AAS identifiers may contain#(e.g. IRDIs like0173-1#01-AHE582#003). For SubmodelElement events, I suggest using the text serialization of the ModelReference as defined in Part 1, e.g.(Submodel)urn:example:sm:1, (SubmodelElementCollection)Measurements, (Property)temperature. It contains the plain identifier, is defined by the metamodel instead of the API, and still allows selecting all events of a Submodel by prefix.
There was a problem hiding this comment.
Regarding source being the URL of the service I want to add that a server is not required to have an HTTP/REST endpoint but could also just have an OPC UA endpoint. Therefore, it would be best to use the Endpoint class instead. However, I assume that would conflict with the CloudEvent spec, wouldn't it?
| This would allow filters that the input parameters cannot express, e.g. a negation: | ||
|
|
||
| [source,json] | ||
| ---- |
There was a problem hiding this comment.
How should this be passed to a query parameter in a URL?
There was a problem hiding this comment.
It is not meant to be passed as a query parameter. Like the existing query operations (e.g. QuerySubmodels with POST /query/submodels), the query would be sent as JSON in the request body of a dedicated operation, e.g. QueryEvents with POST /query/events. The sentence describing this got lost in a revision of the chapter; I will add it again.
There was a problem hiding this comment.
If you use POST /query/events, then this endpoint has also to fulfil the since, lastEvent and pagination capabilities as the normal /event endpoint do. You cannot tell someone to use GET /events for events without Query-Requirements and POST /query/events when you have complex query requirements. That will not work. Sorry but RSQL fits better. Is it not better to create a query-parameter-scoped version of that query language, that is similar to RSQL to support complex query parameter queries? This will help in multiple places. (e.g. GetAllShells). It is not so hard. We can use the same field-specification and apply just new operators for query-parameter-usage.
Again: There is no law that treat us to put bad concepts from the AAS spec to the eventing.
There was a problem hiding this comment.
Why wouldn't having both GET and POST not work? We have this approach in multiple places in the API already and it works fine.
In totally understand your reasoning for a purely URL-based query language. While design of the AAS query language we also discussed this option but it has been rejected by the majority. We now have the following options
- Create a new URL-based query language just for eventing
- Define a URL-based query language that is consistent across all API parts
- Use the approach/style of the current API also for eventing (as suggested by Aaron)
Option 1 is not viable in my opinion because it not only introduces a second, completely different query language which further complicates the API but also it is unclear whether this will get replaced in v4.0 when trying to unify query languages again.
Option 2 would address this problem by making sure we introduce something that can be used throughout the whole API in an upcoming v4.0 but has the downside that we would need quite some time to properly design this which would delay the introduction of events.
Therefore, Option 3 seems the most sensible solution to me to both get eventing published in a timely manner and not introduce additional complexity by adding a new query language. When working an v4.0 we can then talk about updating/changing the query language to be URL-based across all aspects of the API.
There was a problem hiding this comment.
Thanks for the explanation, @mjacoby. That was exactly the thought process I had when writing my proposal. I never claimed that the specification I proposed would be the best approach if starting from scratch. In fact, I would probably have done many things differently. However, the proposal I made involves the least friction and can be implemented and specified in a timely manner.
We can't forget that some have already implemented things like the query language because that's what was agreed upon. For those companies, introducing alternatives that conflict with the agreed specifications could be very costly. If I understand correctly, this even involves your use case's implementation partners, @gataka.
| The normative filters are the input parameters of xref:specification/interfaces.adoc#GetAllEvents[GetAllEvents]. | ||
| ==== | ||
|
|
||
| The xref:query-language.adoc[AAS Query Language] could be extended by a root element `$event` for FieldIdentifiers, e.g. `$event#type`, `$event#subject`, `$event#time`, `$event#globalAssetIds[]`, `$event#semanticId`, and `$event#submodelSemanticId`. |
There was a problem hiding this comment.
It might also be necessary to filter based on data fields related to event types. like event#globalAssetId (not in ever event type) or the submodelSemanticId are type specific filters. So if you combine them with the wrong event-type you would never get an answer. So if the field is part of the data it should be marked as it like $event#data.globalAssetIds or $event#data.semanticId. A the filter fields should match 1:1 to the fields in the event and data object. Otherwise the complete filter is useless.
There was a problem hiding this comment.
Agreed for the Query Language proposal. This is also how FieldIdentifiers work for the other root elements, e.g. $aas#assetInformation.globalAssetId. I will change the proposal to $event#<attribute> for the CloudEvents attributes ($event#type, $event#subject, $event#time) and $event#data.<path> for the event data (e.g. $event#data.globalAssetIds[], $event#data.submodel.semanticId), referring to the event data with Content Normal.
Combining a data field with a different event type is not an issue: according to the evaluation semantics of the Query Language, a FieldIdentifier that does not exist for a candidate excludes it without an error, so such filters are typically combined with $event#type.
For the query parameters of GetAllEvents, I would keep the current approach, which follows the existing GetAll… operations (e.g. ?semanticId= in GetAllSubmodels, which also covers supplementalSemanticId).
…t profiles Add the chapter "Eventing" defining CloudEvents-based events for modifications of Asset Administration Shells, Submodels, SubmodelElements, Concept Descriptions, and asset links: event structure, source and subject, event types, event data with the Contents Normal, Value, and Reference, data schemas, the modifications that result in events including the derivation of SubmodelElement and asset events, event profiles, retrieval with GetAllEvents and transmission via message brokers, the relation to other concepts, and an informative proposal for filtering with the AAS Query Language. Add the Event Interface with the operation GetAllEvents, the Event and event data classes, the interface short name EVENT, the Event profiles AssetAdministrationShellRepositoryServiceSpecification/SSP-007, SubmodelRepositoryServiceSpecification/SSP-008, ConceptDescriptionRepositoryServiceSpecification/SSP-004, and DiscoveryServiceSpecification/SSP-003 with their OpenAPI documents, the schemas and query parameters in the Part 2 schemas, the operations in the combined OpenAPI document and the Operation to RIGHT mapping, the HTTP/REST mapping, the applicability of SerializationModifiers, the annex "Eventing Examples", terms, bibliography, navigation, and change notes.
e075cd4 to
bb2cdf8
Compare
Use the plain identifier as subject of AAS, Submodel, Concept Description, and asset events and the text serialization of the ModelReference for SubmodelElement events, so that the subject no longer depends on the paths and encoding of the HTTP/REST API. Replace the input parameter id of GetAllEvents with aasIdentifier, submodelIdentifier, and cdIdentifier, and state explicitly that parameters with several values are repeated. Let the FieldIdentifiers of the Query Language proposal follow the event structure ($event#<attribute> and $event#data.<path>) and describe the transmission of queries with QueryEvents (POST /query/events). Add Event to the model element names of the operation naming grammar and remove the no longer referenced RFC 8785.
bb2cdf8 to
1b2bf6f
Compare
| hide methods | ||
| left to right direction | ||
|
|
||
| class Event { |
There was a problem hiding this comment.
I suggest to use camel case for property names as in the rest of the specification, i.e.,
- specversion --> specVersion
- datacontenttype -> DataContentType
- dataschema --> dataSchema
| activate Client | ||
| Client -> EventService : GetAllEvents(submodelSemanticId, lastEventId) | ||
| activate EventService | ||
| Client <-- EventService : submodelelement.updated ("Measurements.temperature"),\nsubmodel.updated |
There was a problem hiding this comment.
Do I understand the diagram correctly that you expect to trigger both a SubmodelElement updated and Submodel updated event? If yes, I think this contradicts what we discussed at the workshop that only a single event should be triggered by one action.
| alt dataschema with Content Normal | ||
| Client -> Client : use SubmodelElement from event data | ||
| else dataschema with Content Reference | ||
| Client -> SMService : GetSubmodelVersionByIdAndDate(submodelId, time) |
There was a problem hiding this comment.
Would it make sense to allow the client to request just this exact event with normal/valueOnly serialization (e.g. by eventId) as an alterntive?
| [#eventing-general] | ||
| == General | ||
|
|
||
| Eventing enables clients to react to modifications of Asset Administration Shells, Submodels, SubmodelElements, Concept Descriptions, and asset links. |
| * *Synchronization:* systems such as engineering tools, product configurators, PLM, and ERP systems, as well as replicas, caches, and search indexes, keep their data consistent with a service. | ||
| * *Asset links:* a client detects that an Asset Administration Shell for an asset has become available or has been replaced. | ||
|
|
||
| In these use cases, one provider informs one or many receivers, within seconds or within the interval in which receivers retrieve events. |
There was a problem hiding this comment.
As we are talking about both pub/sub and pull-based "distribution" of events, I would rephrase this in passive voice, e.g., "the provider offers ways to receive events..." because in the HTTP case, the provider does not actively inform anyone but just provides the data for the client/consumer to fetch.
|
|
||
| In these use cases, one provider informs one or many receivers, within seconds or within the interval in which receivers retrieve events. | ||
|
|
||
| Events are represented according to CloudEvents xref:bibliography.adoc#bib16[[16\]] in the JSON event format xref:bibliography.adoc#bib17[[17\]]. |
There was a problem hiding this comment.
Not sure if using CloudEvents should be made on technology-agnostic level as some technologies could in the future could not be compatible with CloudEvents. Maybe change this to something along the lines of "CloudEvents should be used for any supported protocols".
|
|
||
| The following rules apply: | ||
|
|
||
| . All events resulting from the same modification shall have the same `time`. |
There was a problem hiding this comment.
What exactly should this time represent? I think we agreed on something like "time the changes have been presisted/stored"
| The following rules apply: | ||
|
|
||
| . All events resulting from the same modification shall have the same `time`. | ||
| . An event with a given `source` and `id` shall always have the same context attributes, except `dataschema`, and the same data for the same Content. |
There was a problem hiding this comment.
What are "context attributes"?
| [#eventing-source-subject] | ||
| === Source and Subject | ||
|
|
||
| The `source` of an event is the base URL of the HTTP/REST API of the service. |
There was a problem hiding this comment.
Not every AAS server implementation is required to have a REST API
| |Events of |subject | ||
| e|AssetAdministrationShell |Identifier of the Asset Administration Shell | ||
| e|Submodel |Identifier of the Submodel | ||
| e|SubmodelElement |ModelReference to the SubmodelElement in the link:https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.2/mappings/mappings.html#reference-serialization[text serialization of References] without _ReferenceType_ and _referredSemanticId_ |
There was a problem hiding this comment.
ReferenceType is mandatory according to metamodel, so I would rather enforce it to be ModelReference and enfore referredSemanticId to be empty via constraint
| == Event | ||
|
|
||
| [#eventing-event-structure] | ||
| === Event Structure |
There was a problem hiding this comment.
According to CloudEvents spec, the subject attribute is an optional attribute. Just trying to understand, are we deviating because AAS Events requires this as a mandatory attribute?
| . Every modification shall result in the events defined in this clause, regardless of whether it is caused by an API operation, an import of an AASX package or environment, or the service itself. | ||
| Unsuccessful operations and operations without any change of the content result in no events. | ||
| . A modification of an Asset Administration Shell, Submodel, or Concept Description results in exactly one event for this Identifiable, of type `created`, `updated`, or `deleted`. | ||
| . A modification of SubmodelElements additionally results in SubmodelElement events according to <<eventing-sme-events>>. |
There was a problem hiding this comment.
additionally here means that if any modification is done to SME, then an SME event + a Submodel event will be triggered, correct?
For example:
When SME is removed:
submodelelement.deleted + submodel.updated
Resolves #557. Related to #41, #297, and #600.
Rendered draft (PDF):
AAS-Part2-Eventing-Draft.pdf
Summary
This PR adds eventing to Part 2: services provide CloudEvents for every modification of their content, which clients retrieve with the new operation
GetAllEvents(GET /events) or receive via message brokers. The design follows the existing structure and conventions of the specification: the chapter defines the semantics, while the operation, the payload classes, the profiles, and the OpenAPI documents are placed where all other operations and classes are defined.Content of the chapter "Eventing"
sourceis the base URL of the service,subjectidentifies the modified object independently of the API: the plain identifier for AAS, Submodel, and Concept Description events, the globalAssetId for asset events, and the text serialization of the ModelReference from Part 1 for SubmodelElement events (e.g.(Submodel)urn:example:sm:1, (SubmodelElementCollection)Measurements, (Property)temperature).io.admin-shell.<object>.<modification>.v1foraas,submodel,submodelelement,conceptdescription, andassetwithcreated,updated,deleted.Normal,Value,Reference);dataschemaidentifies class and Content. Submodel and SubmodelElement events carry theglobalAssetIdsof the referencing AAS; references carryreferredSemanticId.GetAllEventswith filters (type,aasIdentifier,submodelIdentifier,cdIdentifier,idShortPath,globalAssetId,semanticId,submodelSemanticId,since,lastEventId; parameters with several values are repeated), standard pagination from the oldest to the most recent event, and continuation withlastEventId; transmission via message brokers (MQTT, Kafka, AMQP) using the CloudEvents protocol bindings with identical events.$event#type,$event#data.globalAssetIds[], …) and queries sent withQueryEvents(POST /query/events); it is not part of the specification.Further changes
GetAllEvents.Event,EventData, and the event data classes; interface short nameEVENT; Event profile identifiers for the ServiceDescription.GetAllEvents(/events,/events/$value,/events/$reference).V3.3_SSP-*.yaml), schemas and query parameters inPart2-API-Schemas/openapi.yaml, and the operations inEntire-API-Collection/V3.2.yaml.GetAllEvents,GetAllEvents-ValueOnly,GetAllEvents-Reference; new informative annex "Eventing Examples" with examples for all event types and Contents.Event.Points for review
GetAllEvents-ValueOnlyandGetAllEvents-Referenceare mapped to the RIGHTREAD, because the event data also containsglobalAssetIdsand asset links.explode: truelike the existing OpenAPI parameters; the Design Decisions text mentions comma-separated lists.V3.3_and profile identifiers…/3/3/…, while the combined OpenAPI document is stillEntire-API-Collection/V3.2.yaml.Validation
tools/validate_spec_artifacts.py,tools/validate_multipart_uploads.py, and the query unit tests pass.