From 0c7902cbb329a166d6f7352babcc0cfe0889dbe9 Mon Sep 17 00:00:00 2001 From: Niko Stotz Date: Sun, 4 Feb 2024 17:22:39 +0100 Subject: [PATCH 1/9] first sketch on derived models --- derived/derivation.adoc | 355 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 355 insertions(+) create mode 100644 derived/derivation.adoc diff --git a/derived/derivation.adoc b/derived/derivation.adoc new file mode 100644 index 00000000..d84547fc --- /dev/null +++ b/derived/derivation.adoc @@ -0,0 +1,355 @@ +include::../shared/issue-footnotes.adoc[] +:serialization: ../serialization/serialization +:m3: ../metametamodel/metametamodel +:bulk: ../bulk/repo-access-api +:chunk: <<{serialization}.adoc#SerializationChunk, SerializationChunk>> + += Derived Models +:toc: preamble +:toclevels: 2 + +Derived models are calculated from other (original or derived) models without direct human interaction. +They are usually some form of analysis result, such as one related to a type system. +Nodes in derived models are typically associated with an original node -- e.g., the type computed for an AST node. +The repository manages this association. +Derived models may be persisted or be recalculated on the fly. + +== Terminology +original node:: +A node CRUDed by users (mediated by tools). + +derived node:: +A node implementing `IDerived` that can be calculated from one or more _base_ nodes. ++ +NOTE: A derived node is still a node with all its capabilities. +Thus, a derived node MUST be (indirectly) contained by a partition. + +base node:: +A node that has _derived_ nodes. +The base node can be an _original_ or _derived_ node. + +ava:: +A <<{m3}.adoc#Language, Language>> that defines the requested contents of a _derived_ model. +The _derived nodes_ are instances of ava. ++ +Example: We request ava `com.example.validation`. +This language defines interface `Warning`. +Another language `org.compiler.validation` _dependsOn_ `com.example.validation`, +and defines classifiers `ParserWarning implements IDerived, Warning` and `LinkerWarning implements IDerived, Warning`. ++ +[plantuml, avaExample, svg] +---- +package "com.example.validation" as ex { + interface Warning +} + +package "org.compiler.validation" as comp { + class ParserWarning implements .IDerived, ex.Warning + class LinkerWarning implements .IDerived, ex.Warning +} + +comp .> ex: dependsOn +---- ++ +The derived model contains instances of `ParserWarning` and `LinkerWarning`. ++ +NOTE: The name "ava" is a sufficiently meaningless placeholder until we think of a good name. + +derivation:: +The _derived_ nodes referencing a _base_ node. +Can be specified by the _derived_ node's _ava_. + +original model:: +A model that cannot be (re-)computed from other models. ++ +It contains mainly _original_ nodes, but MAY contain _derived_ nodes. +Example: A processor uses the repository to store its derivation result. + +derived model:: +A model that can be calculated from _base_ models. +Its partition, and possibly many other nodes, are _derived_ nodes. ++ +However, a derived model MAY contain nodes that do not implement `IDerived`. +Example: A derived richtext description contains `Word` concepts. +`Word` is reused in many contexts, and does not implement `IDerived`. + +base model:: +A model that has _derived_ models. +A base model can be an _original_ or _derived_ model. + +== New builtin interface `IDerived` +[plantuml, iderived, svg] +---- +interface "builtins::Node" as Node + +interface IDerived + +IDerived "0..*" -> "1..*" Node: base +---- + +Each derived node references one or more base nodes. +Any (base) node can have none or more derived nodes. + +== Client use cases: +* "Which validation issues have been found on this partition?" + +* "What are the types of all nodes in this partition?" + +* "What's the type of this node I reached via reference, i.e. I don't know its partition?" + +* "Update me any time the validation of this node changes" + +* "Give me this partition including validation and typing info" + +* "Give me this partition FAST, I don't care about validation and typing info" + +== Client Bulk API +=== retrieveDerivation +Retrieves derivations of subtrees of listed node ids, according to listed languages. + +==== Parameters +[[retrieveDerivation.nodeIds]] +`nodeIds`:: List of node ids we want to retrieve derivations about from the repository. + +[[retrieveDerivation.languages]] +`languages`:: List of _avas_ to specify the kind of derivations. +Optional parameter, defaults to _all derivations_. +If present, MUST be a list of (language key, language version) pairs. + +[[retrieveDerivation.depthLimit]] +`depthLimit`:: Limit the depth of retrieved subtrees. +Optional parameter, defaults to _infinite_. +If present, MUST be an integer >= 0, with ++ +-- +* 0 meaning "return only the nodes with ids listed in `nodeIds` parameter", +* 1 meaning "return the nodes with id listed in the `nodeIds` parameter and their direct children/annotations", +* 2 meaning "return the nodes with id listed in the `nodeIds` parameter, their direct children/annotations, and the direct children/annotations of these", +* etc. +-- ++ +NOTE: There's no _magic value_ of `depthLimit` to express _infinite_ depth. +We need to omit the parameter if we don't want to limit the depth. + +==== Result +{chunk} containing all derived nodes according to `nodeIds`, `languages`, and `depthLimit` parameters. + +First, we find all _base_ nodes according to `nodeIds` and `depthLimit` parameter (see <<{bulk}.adoc#retrieve, Bulk retrieve>>). +Then, we find all _derivations_ according to `languages`. +The result contains all derivations and all their descendants. + +Does NOT include the base nodes mentioned in `nodeIds`, or their descendants. +Does NOT include the definition of <<{serialization}.adoc#UsedLanguage, UsedLanguages>>, only their <<{serialization}.adoc#MetaPointer, MetaPointers>>. + + +== Possible derivation backends + +[[permanent-repo, permanently stored in repository]] +Permanently stored in repository:: +_Example: Information about import source._ +We don't want to use annotations, as it's a lot of data, and we rarely need it. +So we don't want to burden the original model with it. +We create this derived model once, store it in the repository, and only change it on re-import. +Thus, derived node ids are stable. ++ +NOTE: This implements option G in #13{fn-org13}. + +[[permanent-external, permanently stored externally]] +Permanently stored externally (with identity):: +_Example: Extended personnel data._ +We relate original model nodes to persons in active directory. +All external data has its own identity (a GUID). +We derive node ids from external identity. + +[[temp-repo, temporarily stored in repository]] +Temporarily stored in repository:: +_Example: Recalculation-expensive validation results._ +We run potentially expensive validators on model change, and store their result in the repository. +As soon as we re-execute a validator, we delete all previous results of that validator from the repository. +Thus, derived node ids of the same validation result are stable, but once we re-calculate it, the node id changes +(even if it's semantically the same validation result). + +[[internal, internally stored]] +Internally stored:: +_Example: Complex type calculation engine with in-memory representation of its results._ +We update in-memory type information on model change. +We build the derived model from in-memory representation. +We store derived node ids also in memory, so they are stable for the lifetime of the in-memory representation. + +[[live, live-calculated]] +Live-calculated:: +_Example: Simple programming language where the type is always explicitly mentioned._ +We never infer any type, just look up a few references. +Thus, we always calculate the type on-the-fly, and never persist it. +Derived node ids change on every request. + +== Backend implementation of `retrieveDerivation` +A processor can `register` or `unregister` itself for one or more _ava_. +Only <>, <>, and <> backends would register. + +On a call to `retrieveDerivation`, we forward the request to the registered processors. +We also check the repository for partitions that implement `IDerived` and are instances of a classifier of one of the _ava_ languages. + +=== Example +Assume a _base_ model with nodes `a`,`b`,`bb`,`c`. +`a` is a partition containing `b` and `c`. +`b` contains `bb`. + +[plantuml, retrieveDerivationExample, svg] +---- +hide empty members + +object a +object b +object bb +object c + +a *-- b +a *-- c +b *-- bb +---- + +.Languages + +* `ValidationLang`, defines +** `IViolation` +* `M2Validation` _dependsOn_ `ValidationLang`, defines +** `PropertyViolation` implements `IDerived`, `IViolation` +** `MultiplicityViolation` implements `IDerived`, `IViolation` +* `DomainValidation` _dependsOn_ `ValidationLang`, defines +** `DomainValidationPartition` implements `IDerived` +** `InvalidNameViolation` implements `IDerived`, `IViolation` +* `TypeLang`, defines +** `StringType` implements `IDerived` +** `IntType` implements `IDerived` +** `EnumType` implements `IDerived` +** `UnkonwnType` implements `IDerived` + +[plantuml, retrieveDerivationLanguages, svg] +---- +hide empty members + +'interface IDerived + +package ValidationLang { + interface IViolation +} + +package M2Validation { + class PropertyViolation implements ValidationLang.IViolation + ', .IDerived + PropertyViolation --> .M3.Property: property + class MultiplicityViolation implements ValidationLang.IViolation + ', .IDerived + MultiplicityViolation --> .M3.Feature: feature +} +'M2Validation .> ValidationLang: dependsOn + +package DomainValidation { + class DomainValidationPartition<> + 'implements .IDerived + class InvalidNameViolation implements ValidationLang.IViolation + ', .IDerived + { + message: string + } + DomainValidationPartition *-- InvalidNameViolation +} +'DomainValidation .> ValidationLang: dependsOn + +package TypeLang { + class StringType + class IntType + class EnumType + class UnknownType +} + +package M3 { + interface Feature + class Property implements Feature +} +---- + +.Available backends +* <> Domain validator providing `ValidationLang` _ava_ +* <> Typesystem calculator providing `TypeLang` _ava_ +* <> M2 validator providing `ValidationLang` _ava_ + +.Description +1. [registration] M2 validator and Typesystem calculator processors register themselves with their _ava_. +2. [prebuild] Domain validator processor creates its temporary _derived_ partition `x`, containing one node with id `xx`, and stores it to repository. +Domain validator retrieved these free node ids from repository. +3. Typesystem calculator calculates the types of all original nodes. +It requests free node ids `ff`, `fg`, `fh`, `fi` for the resulting derived nodes and stores them in its internal representation. +4. [model update] Typesystem calculator is notified that node `c` changed. +It recalculates the type, but doesn't succeed, resulting in an _unknown type_. +Typesystem calculator requests a free node id for the resulting derived node `UnknownType` and stores the node id in its internal representation. +5. [request] A client asks to retrieve a derivation for nodes `a`, `b`, `c` with infinite depth for _avas_ `ValidationLang` and `TypeLang`. +6. Backend asks Typesystem validator to provide `TypeLang` derivations. +7. Typesystem validator returns nodes `ff`, `fg`, `fh`, `gg` according to its internal representation. +Note that node `fi` is replaced by `gg` (from model update). +8. Backend asks M2 validator to provide `ValidationLang` derivations. +9. M2 validator replies with two new nodes `eef` and `csa`. +M2 validator got the node ids for the new nodes from repository. +10. Backend asks Repository for all fitting partitions, and retrieves each partition's contents. +11. Repository returns `x` and `xx`. +12. Backend concatenates all results and returns them to client. + +[plantuml, retrieveDerivationImpl, svg] +---- +actor client +participant "retrieveDerivation\nbackend" as backend +participant "Domain\nvalidator" as domval +participant "Typesystem\ncalculator" as typer +participant "M2 validator" as langval +participant repository + +== registration == +autonumber 1 +langval ->> backend: register(ValidationLang) +autonumber stop +typer ->> backend: register(TypeLang) + +== prebuild == +autonumber resume +domval<<-] ++ +autonumber stop + domval -> repository ++: ids(count=1) + return [x] + domval ->> repository: store([\n DomainValidationPartition:x()\n InvalidNameViolation:xx(base[b], message="no space name")\n]) +deactivate domval + +autonumber resume +typer<<-] ++ +autonumber stop + typer -> typer ++: typeAll() + typer -> repository ++: ids(count=4) + return [ff, fg, fh, fi] + deactivate typer +deactivate typer + +== model update == +autonumber resume +typer<<-] ++: modelChange(c) +autonumber stop + typer -> typer ++: type(c) + typer -> repository ++: ids(count=1) + return [gg] + deactivate typer +deactivate typer + +== request == +autonumber resume +client -> backend ++: retrieveDerivation(\n baseNodeIds=[a,b,c]\n languages=[ValidationLang, TypeLang]\n) + backend ->> typer ++: provideDerivation(baseNodeIds=[a,b,c]) + return [\n StringType:ff(base=[a])\n IntType:fg(base=[b])\n EnumType:fh(base=[bb,myEnum])\n UnknownType:gg(base=[c])\n] + backend ->> langval ++: provideDerivation(baseNodeIds=[a,b,c]) +autonumber stop + langval -> repository ++: ids(count=2) + return [eef, csa] +autonumber resume + return [\n PropertyValueViolation:eef(base=[a], property=x)\n MultiplicityViolation:csa(base=[bb], feature=age)\n] + backend ->> repository ++: listPartitions().where(\n [ValidationLang, TypeLang].contains(\n it.classifer.allSpecializedLanguages()\n )\n)\n.retrieve() + return [\n DomainValidationPartition:x()\n InvalidNameViolation:xx(base[b], message="no space name")\n] +return [\n StringType:ff)\n IntType:fg\n EnumType:fh\n UnknownType:gg\n PropertyValueViolation:eef\n MultiplicityViolation:csa\n DomainValidationPartition:x\n InvalidNameViolation:xx\n] +---- From 1b02ab20e3df104fc465c9d6609f070697af3f3d Mon Sep 17 00:00:00 2001 From: Niko Stotz Date: Sun, 11 Feb 2024 17:29:21 +0100 Subject: [PATCH 2/9] updated with latest decisions --- bulk/repo-access-api.adoc | 72 ++++++++------------------------------- 1 file changed, 14 insertions(+), 58 deletions(-) diff --git a/bulk/repo-access-api.adoc b/bulk/repo-access-api.adoc index 6abe2db3..a5b43ec5 100644 --- a/bulk/repo-access-api.adoc +++ b/bulk/repo-access-api.adoc @@ -49,7 +49,19 @@ We enforce conformance to{fn-org223} * No unresolvable containment/annotation ids * No unresolvable parent ids -For now, we do not support paging, as paging tree nodes is non-trivial{fn-org204} +For now, we do not support paging, as paging tree nodes is non-trivial.{fn-org204} + +== Deleted nodes +We don't have an explicit delete API.{fn-org221} +We don't support [[orphan, orphans]]_orphans_ for now. + +Deleted nodes don't exist anymore in the repository from the client's point of view. +They might still exist in other contexts (e.g. another branch), or physically within the repository for internal reasons (e.g. storage optimization, concurrent editing support). +A deleted node MUST NOT appear in any responses according to this API.{fn-org220} + +A repository MAY consider the deleted node's id to be _unused_, and thus allow to re-use it. +A repository also MAY disallow re-using previously deleted node ids. + [[apis]] == APIs @@ -78,8 +90,7 @@ Creates new partitions in the repository.{fn-org216} Each sent node is its own partition. Thus, we cannot send the contents (i.e. (indirect) annotations/containments) of a partition; We can send them in a later <> call. We also MUST NOT mention any annotation/containment node ids in the partition nodes, as they cannot be part of the same request, and we don't allow moving nodes in this operation. - -We MAY send properties and references #TODO correct?#{fn-org225} +We MAY send properties and references{fn-org225} Each partition node id MUST NOT exist in the repository, and the sending client MUST use node ids allocated to it via <>. @@ -189,21 +200,6 @@ Also, we assume no knowledge of the metamodel. #TODO do we support changes to classifier? What about changes in metapointer.version? Migration use cases?#{fn-org69} - -[[orphan]] -.Orphans -An _orphan_ node is a node present in the repository that is not mentioned in any other node as containment or annotation, and is not a partition.{fn-org219} -We cannot create orphans explicitly. -A node becomes an orphan if it already exists in the repository, but the node's id is removed from its parent containment/annotation, -and the node is not moved to another parent. - -#TODO: What about references to orphans? Do they resolve?# - -A repository MAY immediately <> orphans, or keep them in a <<{trash}.adoc, trash>>. - -The repository MUST NOT update/change references to orphan nodes. -Rationale: We in general do support unresolved or unresolvable references. - .How to handle unknown ids? * If requested by this client via <>: Create new node @@ -227,46 +223,6 @@ Rationale: We in general do support unresolved or unresolvable references. // ---- -[[delete, delete]] -=== delete: Delete nodes from repository -Deletes nodes from the repository.{fn-org221} - -Deleted nodes don't exist anymore in the repository from the client's point of view. -They might still exist in other contexts (e.g. another branch), or physically within the repository for internal reasons (e.g. storage optimization, concurrent editing support). -After this call succeeds, the deleted nodes MUST NOT appear in any responses according to this API.{fn-org220} - -If we delete a node, we implicitly remove it from its parent's containment/annotation. - -(Transitively) contained/annotation nodes of deleted nodes that are not explicitly mentioned in the call are deleted. - -After this call succeeds, a repository MAY consider the deleted node's id to be _unused_, and thus allow to re-use it. -A repository also MAY disallow re-using previously deleted node ids. - -The whole call fails, without any changes to the repository, if any of the provided node ids does not exist in the repository, or any of the provided node ids is a <<{m3}.adoc#predefined-builtins-keys, built-in id>>. - -==== Parameters -[[delete.nodeIds]] -`nodeIds`:: List of node ids we want to delete from the repository. - -==== Result -#TODO# - -==== Example request -[source, httprequest] ----- -DELETE /bulk/delete?nodes=["first-node-id","13123123","c2Vjb25kIG5vZGUgaWQ"] ----- - -[NOTE] -==== -link:https://www.rfc-editor.org/rfc/rfc9110.html#name-delete[RFC 9110: HTTP Semantics] states about the request body of a DELETE method: - -> An origin server SHOULD NOT rely on private agreements to receive content, since participants in HTTP communication are often unaware of intermediaries along the request chain. - -Thus, this example sends the node ids via URL query. - -==== - [[ids, ids]] === ids: Get available ids Provides unused <<{m3}.adoc#identifiers, valid ids>>. From f391c34ada90a233287987aad4c41da869037a49 Mon Sep 17 00:00:00 2001 From: Niko Stotz Date: Sun, 11 Feb 2024 17:47:05 +0100 Subject: [PATCH 3/9] added error cases --- bulk/repo-access-api.adoc | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/bulk/repo-access-api.adoc b/bulk/repo-access-api.adoc index a5b43ec5..76a0c197 100644 --- a/bulk/repo-access-api.adoc +++ b/bulk/repo-access-api.adoc @@ -53,7 +53,9 @@ For now, we do not support paging, as paging tree nodes is non-trivial.{fn-org20 == Deleted nodes We don't have an explicit delete API.{fn-org221} + We don't support [[orphan, orphans]]_orphans_ for now. +They are immediately deleted.{fn-org219} Deleted nodes don't exist anymore in the repository from the client's point of view. They might still exist in other contexts (e.g. another branch), or physically within the repository for internal reasons (e.g. storage optimization, concurrent editing support). @@ -62,6 +64,9 @@ A deleted node MUST NOT appear in any responses according to this API.{fn-org220 A repository MAY consider the deleted node's id to be _unused_, and thus allow to re-use it. A repository also MAY disallow re-using previously deleted node ids. +== Error cases for all SerializationChunks +=== Node with same id sent more than once + [[apis]] == APIs @@ -83,6 +88,9 @@ None. The partitions are sent as complete nodes.{fn-org202} Does NOT include <<{m3}.adoc#Language, Languages>> or partition children. +==== Error cases +None. + [[createPartitions, createPartitions]] === createPartitions: Create new partitions Creates new partitions in the repository.{fn-org216} @@ -101,6 +109,11 @@ Each partition node id MUST NOT exist in the repository, and the sending client ==== Result #TODO# +==== Error cases +===== Partition node id already exists +===== Partition node id not reserved for this client +===== Partition node lists contained or annotated nodes + [[deletePartitions, deletePartitions]] === deletePartitions: Delete partitions and all their contents Deletes all mentioned partitions, including all (transitive) annotations and children. @@ -116,6 +129,9 @@ All (transitive) annotations and children become <>. ==== Result #TODO# +==== Error cases +===== Node with that id is not a partition +===== Node with that id does not exist [[retrieve, retrieve]] === retrieve: Get nodes from repository @@ -148,6 +164,9 @@ We need to omit the parameter if we don't want to limit the depth. {chunk} containing all nodes according to `nodeIds` and `depthLimit` parameters. Does NOT include the definition of <<{serialization}.adoc#UsedLanguage, UsedLanguages>>, only their <<{serialization}.adoc#MetaPointer, MetaPointers>>. +==== Error cases +===== Node with requested id does not exist + ==== Example request [source, httprequest] ---- @@ -222,6 +241,13 @@ Also, we assume no knowledge of the metamodel. // include::partitions.json[] // ---- +==== Error cases +===== Node id mentioned as annotation/child in more than one parent +===== Move would create loop in tree +===== Parent / child / annotation node id unknown +===== Parent doesn't match child/annotation +===== New node id not reserved for this client + [[ids, ids]] === ids: Get available ids @@ -254,6 +280,9 @@ It MAY return less than `count` ids. ==== Result List of ids guaranteed to be free. +==== Error cases +None. + ==== Example request [source, httprequest] ---- @@ -277,7 +306,7 @@ create:: <> for partitions, <> that sends a update:: <> that sends a node (both partitions and other nodes) with an _existing id_, including all its features (both updated and unchanged). -delete:: <> for partitions (including all descendants), <> for other nodes +delete:: <> for partitions (including all descendants), for others <> of the parent node without mentioning the deleted node. move:: Assume we want to move node `N` from its current parent `S` to its new parent `T`. + From 10d53c7e1c123650ba4e3857aca3deab3717c2fa Mon Sep 17 00:00:00 2001 From: Niko Stotz Date: Sun, 11 Feb 2024 20:32:03 +0100 Subject: [PATCH 4/9] added more error cases --- bulk/repo-access-api.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bulk/repo-access-api.adoc b/bulk/repo-access-api.adoc index 76a0c197..35ffed1a 100644 --- a/bulk/repo-access-api.adoc +++ b/bulk/repo-access-api.adoc @@ -132,6 +132,7 @@ All (transitive) annotations and children become <>. ==== Error cases ===== Node with that id is not a partition ===== Node with that id does not exist +===== Invalid node id [[retrieve, retrieve]] === retrieve: Get nodes from repository @@ -166,6 +167,8 @@ Does NOT include the definition of <<{serialization}.adoc#UsedLanguage, UsedLang ==== Error cases ===== Node with requested id does not exist +===== Invalid depthLimit +===== Invalid node id ==== Example request [source, httprequest] From db531f33c2f9064ba35d965f42b565d7ce2f4d70 Mon Sep 17 00:00:00 2001 From: Jos Warmer Date: Mon, 11 Mar 2024 17:06:34 +0100 Subject: [PATCH 5/9] Added some question to the derivation document. --- derived/derivation.adoc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/derived/derivation.adoc b/derived/derivation.adoc index d84547fc..b4624e08 100644 --- a/derived/derivation.adoc +++ b/derived/derivation.adoc @@ -90,6 +90,11 @@ IDerived "0..*" -> "1..*" Node: base Each derived node references one or more base nodes. Any (base) node can have none or more derived nodes. +[horizontal,labelwidth=12] +QUESTION:: Should a derived node also be able to refer to features inside a node? Or do we leave that for specific classes implementing `IDerived`? +QUESTION:: The assumption is that derived nodes can have children that are not derived nodes. +Of course children could also be derived nodes. + == Client use cases: * "Which validation issues have been found on this partition?" @@ -134,6 +139,9 @@ We need to omit the parameter if we don't want to limit the depth. ==== Result {chunk} containing all derived nodes according to `nodeIds`, `languages`, and `depthLimit` parameters. +[horizontal,labelwidth=12] +QUESTION:: The `depth:Limit` describes the depth of the retrieved nodes (derived nodes may be full trees), the next line suggests that `depthLimit` applies to the node id's sent. Needs clarification. + First, we find all _base_ nodes according to `nodeIds` and `depthLimit` parameter (see <<{bulk}.adoc#retrieve, Bulk retrieve>>). Then, we find all _derivations_ according to `languages`. The result contains all derivations and all their descendants. @@ -143,6 +151,8 @@ Does NOT include the definition of <<{serialization}.adoc#UsedLanguage, UsedLang == Possible derivation backends +[horizontal,labelwidth=12] +QUESTION:: The repository that is referred to is this always the repository where the opriginal model is stored, or could oit be a different (i.e. derivation processor specific) repository? [[permanent-repo, permanently stored in repository]] Permanently stored in repository:: @@ -270,6 +280,9 @@ package M3 { } ---- +[horizontal,labelwidth=12] +QUESTION:: Should the `PropertyValidation` also point to the Property instance in the M2 model being validated, and not just to the node that contains the property? + .Available backends * <> Domain validator providing `ValidationLang` _ava_ * <> Typesystem calculator providing `TypeLang` _ava_ From 688e692e188f02d6874ddb6b1ba75e03a01cb23a Mon Sep 17 00:00:00 2001 From: Jos Warmer Date: Tue, 2 Apr 2024 16:41:09 +0200 Subject: [PATCH 6/9] Definitions and questions about Processors and Derived Models --- derived/processors.adoc | 134 ++++++++++++++++++++++++++++++++++++++++ derived/processors.png | Bin 0 -> 52604 bytes derived/processors.pptx | Bin 0 -> 48060 bytes 3 files changed, 134 insertions(+) create mode 100644 derived/processors.adoc create mode 100644 derived/processors.png create mode 100644 derived/processors.pptx diff --git a/derived/processors.adoc b/derived/processors.adoc new file mode 100644 index 00000000..715d7af0 --- /dev/null +++ b/derived/processors.adoc @@ -0,0 +1,134 @@ +:serialization: ../serialization/serialization +:m3: ../metametamodel/metametamodel +:bulk: ../bulk/repo-access-api +:chunk: <<{serialization}.adoc#SerializationChunk, SerializationChunk>> + += Processors and Derived Models +:toc: preamble +:toclevels: 2 + +== Terminology + +repository:: +A _repository_ is the "world". +- A repository is the scope in which id's are unique. +- A repository is the scope in which referred nodes can be resolved. +- A repository is a collection of partitions. + +original node:: +A node CRUDed by users (mediated by tools). + +derived node:: +A node implementing `IDerived` that is attached (by reference) to one base node and +that can be calculated from its base node and (optionally) other nodes. + +calculated node:: A node that is (automatically) calculated from other nodes. +A derived node is a calculated node, but not vice versa. + +model:: +A _model_ is a subset of a repository. +- A model is a collection of partitions (from the same repository). + +original model:: +An _original model_ is a model where all nodes are original nodes. +- An original model cannot be (re-)computed from other models. + +derived model:: +A _derived model_ is a model that can be calculated from _base_ models. +- A derived model has no original nodes. +- In a derived model all nodes are created (automatically) by a processor. + It contains derived nodes and calculated nodes. + ++ +However, a derived model MAY contain nodes that do not implement `IDerived`. +Example: A derived richtext description contains `Word` concepts. +`Word` is reused in many contexts, and does not implement `IDerived`. +In this case `Word` is a calculated node, but *not* a derived node. + +NOTE: A repository always contains exactly one original model and any number of derived models. + +NOTE: As defined here, nodes that are calculated by a processor can never be children or annotations of an original node. + +base model:: +A model that has _derived_ models. +A base model can be an _original_ or a _derived_ model. + +processor:: +A _processor_ is a component that provides/calculates derived nodes for nodes in a base model. +- A processor is always directly associated with exactly one _base model_. +- A processor creates (derived and calculated) nodes in exactly one _derived model_. +- A processor may use nodes (derived, calculated or original) from any model to calculate it's derived model. + +NOTE: Note that multiple processors may use the same language in their derived models. +E.g. a _model validation_ processor and a _type errors_ processor and a _deadlock detection_ processor may all use the same _Findings_ language. +Because of this derived models cannot be identified by their used languages. + +== Getting a derived node +Assume a client has base nodes _BaseA_, _BaseB_ and _BaseC_. +To ask for a derived node the client needs: + +- The node id of BaseN. +- The identification of the processor/derived model. + +Given processors _Red_, _Yellow_ and _Blue_ (don't be afraid of them :-) the client can ask: + + Get derived node Blue for BaseA.id + +or + + Get derived node Orange for BaseA.id and BaseB.id + +Note that _Processor Blue_ and _Derived Model Blue_ are conceptually the same +from the point of view of the client. + +NOTE: In this approach the language(s) used by a derived model play no role at all. +The response chunk containing the derived nodes (and their children etc.) will contain `usedLanguages`. + +The picture below shows an actual instantiation of the above described structure. + +.Repository with models and processors +image::processors.png[width=100%] + + +== Client Confusion +In general, there are (possibly) derived models in a repository, therefore requesting all +partitions will result in getting both original partitions and all derived partitions. +In many cases this might not be what the client needs. + +- How can a client see the difference? +- How can we ensure a client does not start editing / changing derived models? + +*=> Do we need to formalize Models (see definition above) in the repository?* + +== Repository Confusion +Assuming that processors use the existing bulk or delta API to store/retrieve nodes. + +- How does the repository know which nodes/partitions are derived or calculated? + * The repository should be able to work without knowing the language(s), + therefore the repository cannot consult a language definition to know which nodes are derived. + * For calculated nodes this is even harder as there is no information in the language + to deduce whether a node is calculated. +- If the previous point is solved, how does the repository know to which processor they belong? +- The repsotiory should be able to work without knowing the language(s), + +== Processors +There is a number of questions that needs to be answered about processors: + +- A processor is related to exactly one base model, this relationship needs to be defined somewhere. + * As there is one original model in a repository, connecting a processor to an original base model is + identical to connecting / registering a processor to a repository. + * The relationship to the derived model of the processor is less easy as + there might be many derived models in a repository. +- A processor typically expects nodes from one or more specific languages. + * E.g a type processor needs to understand the nodes for which it is calculating the types, while a scoping processor needs to understand the scoping rules of the specific language(s). + * +- Processors are attached to a repository, because they need access to their base model and + the repository is the only place where this can be found. +- Who and when will a processor be started? + * We do not want the client to explicitly start (and/or stop) processors. + A client should simply ask for a derived node for a certain processor/derived model. + The processor may already be running, or it will be started. + Except for maybe the performance, this should be invisible to the client. +- Can a processor create multiple derived nodes for one base node? + * E.g. a type processor may not only calculate types, but also type errors for a node. + Do we want to allow this? diff --git a/derived/processors.png b/derived/processors.png new file mode 100644 index 0000000000000000000000000000000000000000..b98e70bb609e700084685c0c503741af4683b2b3 GIT binary patch literal 52604 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 EKVoE*`2YX_ literal 0 HcmV?d00001 From 0db9eb8f2f062621fbe7401b0cfad148c192494e Mon Sep 17 00:00:00 2001 From: Jos Warmer Date: Tue, 2 Apr 2024 16:48:07 +0200 Subject: [PATCH 7/9] Typos --- derived/processors.adoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/derived/processors.adoc b/derived/processors.adoc index 715d7af0..89c6f5e9 100644 --- a/derived/processors.adoc +++ b/derived/processors.adoc @@ -98,7 +98,7 @@ In many cases this might not be what the client needs. - How can a client see the difference? - How can we ensure a client does not start editing / changing derived models? -*=> Do we need to formalize Models (see definition above) in the repository?* +*=> Do we need to formalize the notion of Models (see definition above) in the repository?* == Repository Confusion Assuming that processors use the existing bulk or delta API to store/retrieve nodes. @@ -109,7 +109,6 @@ Assuming that processors use the existing bulk or delta API to store/retrieve no * For calculated nodes this is even harder as there is no information in the language to deduce whether a node is calculated. - If the previous point is solved, how does the repository know to which processor they belong? -- The repsotiory should be able to work without knowing the language(s), == Processors There is a number of questions that needs to be answered about processors: From 433a2a5e530607d3faee973bd0b4c5f64653de8a Mon Sep 17 00:00:00 2001 From: Niko Stotz Date: Tue, 7 May 2024 13:45:21 +0200 Subject: [PATCH 8/9] completeness scenario as sequence diagram --- derived/completeness.adoc | 156 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 derived/completeness.adoc diff --git a/derived/completeness.adoc b/derived/completeness.adoc new file mode 100644 index 00000000..40d010e1 --- /dev/null +++ b/derived/completeness.adoc @@ -0,0 +1,156 @@ += Completeness Scenario + +"complete" means "a processor has finished all its work _up to the point in time at which we asked it_" + +Same as in https://github.com/LionWeb-io/specification/issues/248#issuecomment-2079730360[#248] + +== Assumptions + +* processors use the same APIs as other clients to retrieve their base models (and any other nodes they might need). + +* There is a central authority `derivationBackend` within a repository that handles requests for derivations. + +* `derivationBackend` has a special API to ask processors for a _complete_ derivation. +(Note that this only contains the derived nodes from this processor -- `derivationBackend` aggregates the results of all processors that contribute to the same derivation). + +[plantuml,scenario,svg] +---- +!pragma teoz true + +actor generator as gen +participant derivationBackend as db +participant ScopeProcessor as scope<> +participant ValidationProcessor as val<> +participant DomainValidator as dom<> +database repository as repo + +autonumber 1 + +repo <<-]: change1 +activate repo #red +autonumber 1 +repo ->> scope: change1 +activate scope +autonumber 1 +scope -> scope: queue +[-[hidden]>scope +deactivate scope + +autonumber 1 +repo ->> dom: change1 +deactivate repo +activate dom +autonumber 1 +dom -> dom: queue +[-[hidden]>dom +deactivate dom + +autonumber 1 +repo <<-]: change2 +activate repo #red +autonumber 1 +repo ->> scope: change2 +autonumber 1 +repo ->> dom: change2 +deactivate repo + +autonumber 1 +repo <<-]: change3 +activate repo #red +autonumber 1 +repo ->> scope: change3 +autonumber 1 +repo ->> dom: change3 +deactivate repo + +== global state: aa == + +autonumber 2 + +gen -> db: get validation\nderivation +activate db + autonumber 3 + db ->> scope + activate scope + + autonumber 3 + db ->> val + activate val + + autonumber 3 + db ->> dom + activate dom + + autonumber 13 + & dom -> repo ++: get persisted derived model + return + + autonumber 4 + scope -> scope: process change1 + autonumber 10 + & val -> repo++: get original model + return + + + autonumber 5 + scope -> scope: process change2 + + + autonumber 14 + & dom -> dom: process change1\nno change + autonumber 15 + dom -> dom ++: process change2 + autonumber stop + dom -> repo ++ #red: update persisted derived model + return + +== global state: ab == + + return + + autonumber 12 + val -> val: calculate + autonumber 12 + val -->> db: validations + deactivate val + + + autonumber 6 + repo <<-]: newChange + activate repo #red + autonumber 7 + repo ->> scope: newChange + autonumber 16 + repo ->> dom: newChange + deactivate repo + +== global state: bb == + + autonumber 7 + scope -> scope: process change3 + autonumber 8 + scope -->> db: validations + deactivate scope + + autonumber 17 + dom -> dom: process change3\nno change + autonumber 18 + dom -->> db: validations + deactivate dom + +autonumber 20 +gen <-- db +deactivate db + +activate scope +autonumber 9 +scope -> scope: process newChange +[-[hidden]>scope +deactivate scope + +activate dom +autonumber 19 +dom -> dom: process newChange\nno change +[-[hidden]>dom +deactivate dom +---- From 3d5a879eaeafa47423134194911f06025a9bf3b2 Mon Sep 17 00:00:00 2001 From: Niko Stotz Date: Tue, 7 May 2024 13:59:02 +0200 Subject: [PATCH 9/9] added inboxes --- derived/completeness.adoc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/derived/completeness.adoc b/derived/completeness.adoc index 40d010e1..6408d083 100644 --- a/derived/completeness.adoc +++ b/derived/completeness.adoc @@ -13,6 +13,9 @@ Same as in https://github.com/LionWeb-io/specification/issues/248#issuecomment-2 * `derivationBackend` has a special API to ask processors for a _complete_ derivation. (Note that this only contains the derived nodes from this processor -- `derivationBackend` aggregates the results of all processors that contribute to the same derivation). +NOTE: Red activity lines for repository are updates. + +Yellow boxes are the incoming, unprocessed changes. + [plantuml,scenario,svg] ---- !pragma teoz true @@ -33,6 +36,7 @@ repo ->> scope: change1 activate scope autonumber 1 scope -> scope: queue +note over scope: inbox:\nchange1 [-[hidden]>scope deactivate scope @@ -42,6 +46,7 @@ deactivate repo activate dom autonumber 1 dom -> dom: queue +note over dom: inbox:\nchange1 [-[hidden]>dom deactivate dom @@ -50,8 +55,10 @@ repo <<-]: change2 activate repo #red autonumber 1 repo ->> scope: change2 +note over scope: inbox:\nchange1\nchange2 autonumber 1 repo ->> dom: change2 +note over dom: inbox:\nchange1\nchange2 deactivate repo autonumber 1 @@ -59,8 +66,10 @@ repo <<-]: change3 activate repo #red autonumber 1 repo ->> scope: change3 +note over scope: inbox:\nchange1\nchange2\nchange3 autonumber 1 repo ->> dom: change3 +note over dom: inbox:\nchange1\nchange2\nchange3 deactivate repo == global state: aa == @@ -87,6 +96,7 @@ activate db autonumber 4 scope -> scope: process change1 + note over scope: inbox:\nchange2\nchange3 autonumber 10 & val -> repo++: get original model return @@ -94,10 +104,12 @@ activate db autonumber 5 scope -> scope: process change2 + note over scope: inbox:\nchange3 autonumber 14 & dom -> dom: process change1\nno change + note over dom: inbox:\nchange2\nchange3 autonumber 15 dom -> dom ++: process change2 autonumber stop @@ -107,6 +119,7 @@ activate db == global state: ab == return + note over dom: inbox:\nchange3 autonumber 12 val -> val: calculate @@ -120,23 +133,29 @@ activate db activate repo #red autonumber 7 repo ->> scope: newChange + note over scope: inbox:\nchange3\ndelayed inbox:\nnewChange autonumber 16 repo ->> dom: newChange + note over dom: inbox:\nchange3\ndelayed inbox:\nnewChange deactivate repo == global state: bb == autonumber 7 scope -> scope: process change3 + note over scope: inbox:\nempty\ndelayed inbox:\nnewChange autonumber 8 scope -->> db: validations deactivate scope + note over scope: inbox:\nnewChange autonumber 17 dom -> dom: process change3\nno change + note over dom: inbox:\nempty\ndelayed inbox:\nnewChange autonumber 18 dom -->> db: validations deactivate dom + note over dom: inbox:\nnewChange autonumber 20 gen <-- db