From 8141452d3f86a3c2bff0047c0cbe3be6ddc8eb9c Mon Sep 17 00:00:00 2001 From: ektrah Date: Fri, 18 Sep 2026 09:19:11 +0200 Subject: [PATCH 1/5] add self-validation --- .github/workflows/experiment-a.yml | 19 ++++++++++++ experiments/a/ontology.ttl.md | 16 +++++++--- experiments/a/shapes.ttl | 48 ++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/experiment-a.yml create mode 100644 experiments/a/shapes.ttl diff --git a/.github/workflows/experiment-a.yml b/.github/workflows/experiment-a.yml new file mode 100644 index 0000000..4ce7ae3 --- /dev/null +++ b/.github/workflows/experiment-a.yml @@ -0,0 +1,19 @@ +name: Validate Experiment A + +on: + push: + pull_request: + +jobs: + validate: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install shifty-cli + run: cargo install shifty-cli + + - name: Validate + working-directory: experiments/a/ + run: shifty validate --shapes shapes.ttl --data ontology.ttl.md diff --git a/experiments/a/ontology.ttl.md b/experiments/a/ontology.ttl.md index 35d6b07..ca2df77 100644 --- a/experiments/a/ontology.ttl.md +++ b/experiments/a/ontology.ttl.md @@ -175,15 +175,23 @@ #. This can be used in conjunction with deprecations: mark a class as deprecated, define a replacement class, and make the two classes subclasses of each other, i.e., equivalent. Instances of the old class automatically become instances of the new class, and vice versa. -#. This is also useful without deprecations and can be used to define multiple alternative IRIs for the same class or property. However, then it is no longer obvious which is the recommended "main class" in the group of equivalent classes. +#. This is also useful without deprecations and can be used to define multiple alternative IRIs for the same class or property. However, then it is no longer obvious which is the canonical "main class" in the group of equivalent classes. -#. We use `bro:aliasOf` as a directed form of `owl:equivalentClass`: If `:x bro:aliasOf :y` then `:x owl:equivalentClass :y .`, `:x rdfs:subClassOf :y .`, `:y rdfs:subClassOf :x .`, and `:y` is the recommended "main class" in the group. +#. We use `bro:aliasClassOf` as a directed form of `owl:equivalentClass`: If `:x bro:aliasClassOf :y` then `:x owl:equivalentClass :y .` `:x rdfs:subClassOf :y .` `:y rdfs:subClassOf :x .`, and `:y` is the canonical class. + + bro:aliasClassOf + a owl:ObjectProperty ; + rdfs:subPropertyOf owl:equivalentClass ; + rdfs:label "alias of"@en ; + rdfs:comment "Relates an alias class to its canonical class."@en ; + rdfs:domain rdfs:Class ; + rdfs:range rdfs:Class . #. The change of aliasing statements is a non-breaking change as long as the new main class is already in the group. The addition of aliasing statements is a non-breaking change as long as the added group member is added to the ontology in the same version. Any other addition, change, or removal of aliasing statements is a breaking change. -#. When a node is an alias, any other statements about that node are removed from the ontology. This is considered a non-breaking change. As a consequence, users must be prepared to always follow aliasing statements to the main class first (e.g., `?x bro:aliasOf?/rdfs:label ?y` instead of `?x rdfs:label ?y`). +#. When a node is an alias, any other statements about that node are removed from the ontology. This is considered a non-breaking change. As a consequence, users must be prepared to always follow aliasing statements to the main class first (e.g., `?x bro:aliasClassOf?/rdfs:label ?y` instead of `?x rdfs:label ?y`). -#. In principle, aliasing statements could be defined as reflexive and transitive (e.g., if `:x bro:aliasOf :y` and `:y bro:aliasOf :z`, then it can be inferred that `:x bro:aliasOf :z`). However, to simplify things, if `?x bro:aliasOf ?y`, then there shall not be any `?y bro:aliasOf ?z`. +#. In principle, aliasing statements could be defined as reflexive and transitive (e.g., if `:x bro:aliasClassOf :y` and `:y bro:aliasClassOf :z`, then it can be inferred that `:x bro:aliasClassOf :z`). However, to simplify things, if `?x bro:aliasClassOf ?y`, then there shall not be any `?y bro:aliasClassOf ?z`. ## 7. Modeling Conventions diff --git a/experiments/a/shapes.ttl b/experiments/a/shapes.ttl new file mode 100644 index 0000000..e88571a --- /dev/null +++ b/experiments/a/shapes.ttl @@ -0,0 +1,48 @@ +@prefix rdfs: . +@prefix sh: . +@prefix bro: . + +bro:AliasClassOfShape + a sh:NodeShape ; + sh:targetSubjectsOf bro:aliasClassOf ; + + # x aliasClassOf y => x must be a class + sh:class rdfs:Class ; + + # x aliasClassOf y => y must be a class + sh:property [ + sh:path bro:aliasClassOf ; + sh:class rdfs:Class ; + sh:maxCount 1 ; + sh:message "bro:aliasClassOf must point to a class." ; + ] ; + + # x aliasClassOf y => x subClassOf y + sh:rule [ + a sh:TripleRule ; + sh:subject sh:this ; + sh:predicate rdfs:subClassOf ; + sh:object [ + sh:path bro:aliasClassOf + ] + ] ; + + # x aliasClassOf y => y subClassOf x + sh:rule [ + a sh:TripleRule ; + sh:subject [ + sh:path bro:aliasClassOf + ] ; + sh:predicate rdfs:subClassOf ; + sh:object sh:this + ] ; + + # x aliasClassOf y => y must not be an alias + sh:property [ + sh:path ( + bro:aliasClassOf + bro:aliasClassOf + ) ; + sh:maxCount 0 ; + sh:message "The canonical class of an aliasClassOf relation must not itself be an alias." ; + ] . From 72e9f917c323d6b535f1aaea5419136c5e9d8c2e Mon Sep 17 00:00:00 2001 From: ektrah Date: Fri, 18 Sep 2026 09:33:26 +0200 Subject: [PATCH 2/5] cache shifty-cli --- .github/workflows/experiment-a.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/experiment-a.yml b/.github/workflows/experiment-a.yml index 4ce7ae3..d69f704 100644 --- a/.github/workflows/experiment-a.yml +++ b/.github/workflows/experiment-a.yml @@ -8,11 +8,21 @@ jobs: validate: runs-on: ubuntu-latest + env: + SHIFTY_VERSION: "0.4.4" + steps: - uses: actions/checkout@v4 + - uses: actions/cache@v6 + id: shifty-cache + with: + path: ~/.cargo/bin + key: shifty-${{ runner.os }}-${{ env.SHIFTY_VERSION }} + - name: Install shifty-cli - run: cargo install shifty-cli + if: steps.shifty-cache.outputs.cache-hit != 'true' + run: cargo install shifty-cli --version "$SHIFTY_VERSION" - name: Validate working-directory: experiments/a/ From c7e0cdf660865ad5c9f221964c6a7a24134115de Mon Sep 17 00:00:00 2001 From: ektrah Date: Fri, 18 Sep 2026 09:37:08 +0200 Subject: [PATCH 3/5] update design notes --- experiments/a/ontology.ttl.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/experiments/a/ontology.ttl.md b/experiments/a/ontology.ttl.md index ca2df77..920155f 100644 --- a/experiments/a/ontology.ttl.md +++ b/experiments/a/ontology.ttl.md @@ -258,7 +258,7 @@ #. — Dynamic quantity with a last known value: `:x a brick:Motor ; brick:hasPoint [ a brick:Temperature_Sensor ; brick:lastKnownValue [ brick:timestamp "2026-09-17T12:00:00Z"^^xsd:dateTime ; brick:value 50 ] ] .` -#. — Dynamic quantity with an external reference: `:x a brick:Motor ; brick:hasPoint [ a brick:Temperature_Sensor ; rdf:hasExternalReference [ ..... ] ] .` +#. — Dynamic quantity with an external reference: `:x a brick:Motor ; brick:hasPoint [ a brick:Temperature_Sensor ; ref:hasExternalReference [ ..... ] ] .` #### RealEstateCore @@ -270,7 +270,7 @@ #### 223 -#. — Static quantity with a unit: `:x a s223:Motor ; s223:hasProperty [ a s223:QuantifiableObservableProperty ; qudt:hasQuantityKind qk:Temperature ; qudt:hasUnit unit:DEG_C ; qudt:quantityValue [ qudt:value 50 ] ] .` +#. — Static quantity with a unit: `:x a s223:Motor ; s223:hasProperty [ a s223:QuantifiableProperty ; s223:hasAspect s223:Aspect-Rated ; qudt:hasQuantityKind qk:Voltage ; qudt:hasUnit unit:V ; qudt:quantityValue [ qudt:value 240 ] ] .` #. — Dynamic quantity with an external reference: `:x a s223:Motor ; s223:hasProperty [ a s223:QuantifiableObservableProperty ; qudt:hasQuantityKind qk:Temperature ; qudt:hasUnit unit:DEG_C ; s223:hasExternalReference [ ..... ] ] .` From 2a94f9c758dee6054a2ab6db7c30d448800b9b9f Mon Sep 17 00:00:00 2001 From: ektrah Date: Fri, 18 Sep 2026 09:39:12 +0200 Subject: [PATCH 4/5] nit --- .github/workflows/experiment-a.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/experiment-a.yml b/.github/workflows/experiment-a.yml index d69f704..0b64f9d 100644 --- a/.github/workflows/experiment-a.yml +++ b/.github/workflows/experiment-a.yml @@ -12,7 +12,7 @@ jobs: SHIFTY_VERSION: "0.4.4" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: actions/cache@v6 id: shifty-cache From 5637fa699c5a064c8c605272f37d63881be42ad3 Mon Sep 17 00:00:00 2001 From: ektrah Date: Fri, 18 Sep 2026 09:45:16 +0200 Subject: [PATCH 5/5] create CODEOWNERS --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..2066f7b --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +/experiments/a/ @ektrah