From 35314d4484e17c19cb7762d7f0cab1dabbb84da6 Mon Sep 17 00:00:00 2001 From: Jacobus Geluk Date: Wed, 18 Feb 2026 17:40:09 +0000 Subject: [PATCH 01/11] fix(ns): add dprod-shapes prefix to normative namespaces table Add the dprod-shapes namespace (https://ekgf.github.io/dprod/shapes/) to the spec's normative namespaces section and remove unused sdo prefix from dprod-shapes.ttl. Resolves: DPROD-16, #29 Co-Authored-By: Claude Opus 4.6 --- ontology/dprod/dprod-shapes.ttl | 1 - respec/template.html | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ontology/dprod/dprod-shapes.ttl b/ontology/dprod/dprod-shapes.ttl index fe50f71..e267078 100644 --- a/ontology/dprod/dprod-shapes.ttl +++ b/ontology/dprod/dprod-shapes.ttl @@ -17,7 +17,6 @@ @prefix rdfs: . @prefix sh: . @prefix xsd: . -@prefix sdo: . dprod-shapes: a owl:Ontology ; diff --git a/respec/template.html b/respec/template.html index c7008a6..eff0e75 100644 --- a/respec/template.html +++ b/respec/template.html @@ -597,6 +597,15 @@

Normative namespaces

[[dprod]] + + + dprod-shapes + + + https://ekgf.github.io/dprod/shapes/ + + [[dprod]] + dcat From c37a608d2a651c98042c9e248378768f1079cdaa Mon Sep 17 00:00:00 2001 From: Jacobus Geluk Date: Wed, 18 Feb 2026 17:49:58 +0000 Subject: [PATCH 02/11] fix(spec-gen): prevent SHACL shape labels from leaking into spec Add RDFS.label to IGNORED_NODE_SHAPE_PREDICATES so that shape labels (ending in " shape") no longer overwrite OWL class labels in the generated specification. Also remove a stale merge conflict marker in main.py. Resolves: DPROD-18, #79 Co-Authored-By: Claude Opus 4.6 --- spec-generator/globals.py | 1 + spec-generator/main.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/spec-generator/globals.py b/spec-generator/globals.py index 030da5b..ed83677 100644 --- a/spec-generator/globals.py +++ b/spec-generator/globals.py @@ -13,6 +13,7 @@ IGNORED_NODE_SHAPE_PREDICATES = ( RDF.type, + RDFS.label, RDFS.isDefinedBy, SKOS.altLabel, SKOS.changeNote, diff --git a/spec-generator/main.py b/spec-generator/main.py index 806335f..21757b3 100644 --- a/spec-generator/main.py +++ b/spec-generator/main.py @@ -64,7 +64,6 @@ def main(): g_shapes = load_dprod_shapes() jsonld_context_ontology = { -<<<<<<< HEAD "@version": 1.1, "dprod": ontology_namespace_iri, "xsd": str(XSD), From 0b7fb24cca22015dd86295fce82a3ead93b8b70b Mon Sep 17 00:00:00 2001 From: Jacobus Geluk Date: Wed, 18 Feb 2026 17:53:52 +0000 Subject: [PATCH 03/11] fix(ontology): add Retire to DataProductLifecycleStatus enumeration Add "Retire" as a terminal lifecycle status for obsolete data products, aligning with the CDMC source document. Resolves: DPROD-17, #28 Co-Authored-By: Claude Opus 4.6 --- ontology/dprod/dprod-ontology.ttl | 2 +- ontology/dprod/dprod-shapes.ttl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ontology/dprod/dprod-ontology.ttl b/ontology/dprod/dprod-ontology.ttl index 1db2f38..fe0eb37 100644 --- a/ontology/dprod/dprod-ontology.ttl +++ b/ontology/dprod/dprod-ontology.ttl @@ -54,7 +54,7 @@ dprod:DataProduct dprod:DataProductLifecycleStatus a owl:Class, rdfs:Class ; dct:description - "The development status of the data product taken from a controlled list (e.g. Ideation, Design, Build, Deploy, Consume)."@en ; + "The development status of the data product taken from a controlled list (e.g. Ideation, Design, Build, Deploy, Consume, Retire)."@en ; rdfs:comment "The lifecycle of the data product as defined by EDM Council CDMC"@en ; rdfs:isDefinedBy dprod: ; rdfs:label "data product lifecycle status" ; diff --git a/ontology/dprod/dprod-shapes.ttl b/ontology/dprod/dprod-shapes.ttl index fe50f71..dfb8bc1 100644 --- a/ontology/dprod/dprod-shapes.ttl +++ b/ontology/dprod/dprod-shapes.ttl @@ -125,7 +125,7 @@ dprod-shapes:InformationSensitivityClassificationShape dprod-shapes:DataProductLifecycleStatusShape a sh:NodeShape; rdfs:label "data product lifecycle status shape" ; - dct:description "The development status of the data product taken from a controlled list (e.g. Ideation, Design, Build, Deploy, Consume)."@en ; + dct:description "The development status of the data product taken from a controlled list (e.g. Ideation, Design, Build, Deploy, Consume, Retire)."@en ; sh:targetClass dprod:DataProductLifecycleStatus; rdfs:isDefinedBy dprod-shapes:; . From a51d9d3355d7fc6256db17b8cf6dcf2c6449318f Mon Sep 17 00:00:00 2001 From: Jacobus Geluk Date: Wed, 18 Feb 2026 18:00:26 +0000 Subject: [PATCH 04/11] fix(examples): correct ODRL modeling in data-rights example Apply the ODRL fixes described in #83: - Change policy type from Offer to Agreement (required to have assignee) - Add assignee as PartyCollection with spatial refinement - Move spatial constraint from permission constraint to assignee refinement - Change action from odrl:read to odrl:use (read is not an ODRL term) - Update README.md inline example to match Resolves: DPROD-20, #83 Co-Authored-By: Claude Opus 4.6 --- examples/data-rights/README.md | 19 ++++++++++-------- examples/data-rights/example.jsonld | 30 +++++++++++++++-------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/examples/data-rights/README.md b/examples/data-rights/README.md index 638c1d2..23ab16f 100644 --- a/examples/data-rights/README.md +++ b/examples/data-rights/README.md @@ -12,18 +12,21 @@ examplePolicyA odrl:target exampleProduct:ProductA . examplePolicyB odrl:target exampleDataset:DatasetA1 . ``` -An example of a policy follows, that describes permission to distribute the data only within a specific geographic region: +An example of an agreement follows, that describes permission to use all the datasets of the product if the user is working inside EMEA or APAC: ```json examplePolicyA odrl:permission { - "action": "odrl:distribute", - "constraint": [ - {"leftOperand": "spatial", - "operator": "eq", - "rightOperator": "region:EMEA" - } - ] + "action": "odrl:use", + "assignee": { + "@type": "odrl:PartyCollection", + "refinement": [ + {"leftOperand": "odrl:spatial", + "operator": "odrl:isAnyOf", + "rightOperand": ["reg:EMEA", "reg:APAC"] + } + ] } + } ``` diff --git a/examples/data-rights/example.jsonld b/examples/data-rights/example.jsonld index f1c4e4b..d3a2a35 100644 --- a/examples/data-rights/example.jsonld +++ b/examples/data-rights/example.jsonld @@ -1,5 +1,5 @@ { - "@type": "Offer", + "@type": "Agreement", "@context": [ { "odrl": "http://www.w3.org/ns/odrl/2/", @@ -12,19 +12,21 @@ "permission": [ { - "action": "odrl:read", - "constraint": [ - { - "@type": "odrl:Constraint", - "leftOperand": "odrl:spatial", - "operator": "odrl:isAnyOf", - "rightOperand": [ - "reg:EMEA", - "reg:APAC" - ], - "description": " Permission to read all the datasets of the product if user is working inside EMEA or APAC" - } - ] + "action": "odrl:use", + "assignee": { + "@type": "odrl:PartyCollection", + "refinement": [ + { + "@type": "odrl:Constraint", + "leftOperand": "odrl:spatial", + "operator": "odrl:isAnyOf", + "rightOperand": [ + "reg:EMEA", + "reg:APAC" + ] + } + ] + } } ] } From fcadb0085a168af4e1aab125d33df8c30d566031 Mon Sep 17 00:00:00 2001 From: Jacobus Geluk Date: Wed, 18 Feb 2026 20:24:56 +0000 Subject: [PATCH 05/11] fix(examples): incorporate improvements from PR #132 Move assigner/target inside permission and add source to PartyCollection, as suggested by @joshcornejo. Co-Authored-By: Josh Cornejo <10956002+joshcornejo@users.noreply.github.com> Co-Authored-By: Claude Opus 4.6 --- examples/data-rights/example.jsonld | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/data-rights/example.jsonld b/examples/data-rights/example.jsonld index d3a2a35..9d3a08c 100644 --- a/examples/data-rights/example.jsonld +++ b/examples/data-rights/example.jsonld @@ -7,14 +7,14 @@ } ], "uid": "56456df-dfg-34535345-5545", - "assigner": "https://schema.org/person/AdamSmith", - "target": "https://data.org/data-product/equity-trade-xxx", "permission": [ { - "action": "odrl:use", + "target": "https://data.org/data-product/equity-trade-xxx", + "assigner": "https://schema.org/person/AdamSmith", "assignee": { "@type": "odrl:PartyCollection", + "source": "https://example.org/DataDepartment", "refinement": [ { "@type": "odrl:Constraint", @@ -26,7 +26,8 @@ ] } ] - } + }, + "action": "odrl:use" } ] } From 3185d9553284b3c94bec829b306e108c77e9657d Mon Sep 17 00:00:00 2001 From: Jacobus Geluk Date: Wed, 25 Feb 2026 16:44:06 +0000 Subject: [PATCH 06/11] chore: ballot 4 base for consolidation PRs Co-authored-by: Cursor From a01065049cfcf9de2fe109038eb32a6d775de055 Mon Sep 17 00:00:00 2001 From: Jacobus Geluk Date: Wed, 25 Feb 2026 16:52:09 +0000 Subject: [PATCH 07/11] fix: typo DataProductagreement -> DataProductAgreement in Example 2 (DPROD-23, Closes #101) Co-authored-by: Cursor --- examples/core-data-product-extensions/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/core-data-product-extensions/README.md b/examples/core-data-product-extensions/README.md index 82e4e7f..ba7dd1b 100644 --- a/examples/core-data-product-extensions/README.md +++ b/examples/core-data-product-extensions/README.md @@ -78,7 +78,7 @@ Below is an example of a Data Product with an associated Data Product Agreement }, "ex:iSubjectToAgreement": { "@id": "ex:VVSimpleAgreement", - "@type": "ex:DataProductagreement" + "@type": "ex:DataProductAgreement" } } ], From 25c0ae3763432ec436fd5a50b6eeea4d58d07610 Mon Sep 17 00:00:00 2001 From: Jacobus Geluk Date: Wed, 25 Feb 2026 16:56:35 +0000 Subject: [PATCH 08/11] fix(ontology,shapes): protocol/securitySchemaType use dprod classes; rdfs:label on securitySchemaType (DPROD-24, Closes #98, #141, #139) Co-authored-by: Cursor --- ontology/dprod/dprod-ontology.ttl | 2 +- ontology/dprod/dprod-shapes.ttl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ontology/dprod/dprod-ontology.ttl b/ontology/dprod/dprod-ontology.ttl index 051bc2d..76424f0 100644 --- a/ontology/dprod/dprod-ontology.ttl +++ b/ontology/dprod/dprod-ontology.ttl @@ -221,5 +221,5 @@ dprod:securitySchemaType rdfs:isDefinedBy dprod: ; rdfs:domain dcat:DataService ; # rdfs:range rdf:resource ; # better let user decide whether they want SecuritySchemaType class or own class or skos - rdf:label "security schema type" ; + rdfs:label "security schema type" ; . diff --git a/ontology/dprod/dprod-shapes.ttl b/ontology/dprod/dprod-shapes.ttl index 26727ab..ff2af7e 100644 --- a/ontology/dprod/dprod-shapes.ttl +++ b/ontology/dprod/dprod-shapes.ttl @@ -362,7 +362,7 @@ dprod-shapes:DataService-protocol a sh:PropertyShape; rdfs:isDefinedBy dprod-shapes:; sh:path dprod:protocol; - sh:class dcat:Protocol; + sh:class dprod:Protocol; dct:description "A protocol (possibly one of many options) used to communicate with this data service."@en ; rdfs:label "data service protocol shape" ; . @@ -371,7 +371,7 @@ dprod-shapes:DataService-securitySchemaType a sh:PropertyShape; rdfs:isDefinedBy dprod-shapes:; sh:path dprod:securitySchemaType; - sh:class dcat:SecuritySchemaType; + sh:class dprod:SecuritySchemaType; dct:description "The security schema type used for authentication and communication with this Data Service."@en ; rdfs:label "data service security schema type shape" ; . From 31a05ee26296b87cf9052db28de9236bb18789d9 Mon Sep 17 00:00:00 2001 From: Jacobus Geluk Date: Wed, 4 Mar 2026 17:39:57 +0000 Subject: [PATCH 09/11] fix(examples): apply #165 data-rights JSON-LD variant on ballot/4 --- examples/data-rights/example.jsonld | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/examples/data-rights/example.jsonld b/examples/data-rights/example.jsonld index 9d3a08c..6a03398 100644 --- a/examples/data-rights/example.jsonld +++ b/examples/data-rights/example.jsonld @@ -13,21 +13,19 @@ "target": "https://data.org/data-product/equity-trade-xxx", "assigner": "https://schema.org/person/AdamSmith", "assignee": { - "@type": "odrl:PartyCollection", - "source": "https://example.org/DataDepartment", - "refinement": [ - { - "@type": "odrl:Constraint", - "leftOperand": "odrl:spatial", - "operator": "odrl:isAnyOf", - "rightOperand": [ - "reg:EMEA", - "reg:APAC" - ] - } - ] + "@type": "PartyCollection", + "source": "https://example.org/DataDepartment", + "refinement": [{ + "leftOperand": "odrl:spatial", + "operator": "odrl:isAnyOf", + "rightOperand": [ + "reg:EMEA", + "reg:APAC" + ], + "description": " Permission to read all the datasets of the product if user is working inside EMEA or APAC" + }] }, - "action": "odrl:use" + "action": "odrl:use", } ] } From d4ca3c742248f6b1e6af067186f1be8a6c859daa Mon Sep 17 00:00:00 2001 From: Jacobus Geluk Date: Mon, 13 Apr 2026 16:02:02 +0100 Subject: [PATCH 10/11] Ballot 4: show class identifier in generated spec (DPROD-21, #97) (#173) ## Summary - Each class section in the generated spec now renders an `Identifier:` row, mirroring the existing property layout. - Readers can immediately see the prefixed name (e.g. `dcat:DataService`) and click through to the defining vocabulary for external classes; DPROD-local classes self-link to their in-page section. - Addresses Vladimir Alexiev's feedback in #97 that `DataService` alone is ambiguous about whether DPROD is redefining `dcat:DataService` or reusing it. Resolves: DPROD-21, Closes #97 ## Test plan - [x] `bash build.sh` / `python spec-generator/main.py` succeeds - [x] `dist/index.html` shows `Identifier: dprod:DataProduct` at `#dataproductshape` - [x] `dist/index.html` shows `Identifier: dcat:DataService` linking to `http://www.w3.org/ns/dcat#DataService` at `#dataserviceshape` - [ ] Visual review of all class sections in the rendered spec Co-authored-by: Claude Opus 4.6 (1M context) --- respec/template.html | 11 +++++++++++ spec-generator/node_shape.py | 12 +++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/respec/template.html b/respec/template.html index d973f80..de270e9 100644 --- a/respec/template.html +++ b/respec/template.html @@ -816,6 +816,17 @@

Data Product (DPROD) Model

{% for cls in classes %}

{{cls.name}}

+ + + + + + + +
Identifier: + + {{cls.axiom_iri_normalized}} +
{% if cls.description is not none %}

{{cls.description}}

{% endif %} diff --git a/spec-generator/node_shape.py b/spec-generator/node_shape.py index 3f913af..06ad82c 100644 --- a/spec-generator/node_shape.py +++ b/spec-generator/node_shape.py @@ -3,7 +3,7 @@ from rdflib import URIRef, Graph, SH, DCTERMS, Literal, RDFS from functions import short_name, null_html_string, cast_to_uri_ref -from globals import IGNORED_NODE_SHAPE_PREDICATES, shapes_graph_ns_iri +from globals import IGNORED_NODE_SHAPE_PREDICATES, ontology_namespace_iri, shapes_graph_ns_iri @dataclass(init=False) @@ -25,6 +25,7 @@ def __init__(self, g: Graph, **kwargs): self.axiom_iri = cast_to_uri_ref(g.value(self.shape_iri, SH.targetClass)) if self.axiom_iri is None: raise ValueError("No sh:axiom_iri provided for NodeShape") + self.axiom_iri_normalized = g.namespace_manager.normalizeUri(self.axiom_iri) # First load the properties of the OWL target class for rdf_predicate, rdf_object in g.predicate_objects(self.axiom_iri): self._set_prop(g, rdf_predicate, rdf_object, 'OWL') @@ -85,3 +86,12 @@ def html_id(self) -> str | None: if self.shape_iri.__contains__(shapes_graph_ns_iri): return self.shape_iri.replace(shapes_graph_ns_iri, '').lower() return self.name.lower() + + def href(self) -> str: + """Return the href value for the class's canonical identifier. + For DPROD-local classes this points back to the in-page section + (consistent with PropertyShape.href); for external classes such as + dcat:DataService it points to the defining vocabulary.""" + if self.axiom_iri.__contains__(ontology_namespace_iri): + return f"#{self.html_id()}" + return str(self.axiom_iri) From bf2eec01ea01f4fa4ced8c16b861a0c547df2eed Mon Sep 17 00:00:00 2001 From: Jacobus Geluk Date: Thu, 7 May 2026 13:10:59 +0100 Subject: [PATCH 11/11] Ballot 4: remove dprod:Protocol class (DPROD-33, #143) (#172) ## Summary - Removes the `dprod:Protocol` OWL class, resolving the modeling question in #143 (part of #98). - `dprod:protocol` now points to a URI / SKOS concept rather than an under-specified class. Resolves: DPROD-33, Closes #143 ## Test plan - [ ] `bash build.sh` succeeds - [ ] Generated spec in `dist/index.html` no longer references `dprod:Protocol` - [ ] Examples still validate against updated shapes Co-authored-by: Claude Opus 4.6 (1M context) --- ontology/dprod/dprod-ontology.ttl | 9 +-------- ontology/dprod/dprod-shapes.ttl | 9 --------- spec-generator/main.py | 1 - 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/ontology/dprod/dprod-ontology.ttl b/ontology/dprod/dprod-ontology.ttl index af8226a..6b5289d 100644 --- a/ontology/dprod/dprod-ontology.ttl +++ b/ontology/dprod/dprod-ontology.ttl @@ -78,13 +78,6 @@ dprod:Enumeration rdfs:label "enumeration" ; . -dprod:Protocol - a owl:Class, rdfs:Class ; - dct:description "A detailed specification, possibly including a specific version, for how to communicate with a service."@en ; - rdfs:isDefinedBy dprod: ; - rdfs:label "protocol" ; -. - dprod:SecuritySchemaType a owl:Class, rdfs:Class ; dct:description "A classification encompassing a set of rules used for authentication and communication."@en ; @@ -211,7 +204,7 @@ dprod:protocol dct:description "A protocol (possibly one of many options) used to communicate with this data service."@en ; rdfs:isDefinedBy dprod: ; rdfs:domain dcat:DataService ; -# rdfs:range rdf:resource ; # better let user decide whether they want Protocol class or own class or skos +# rdfs:range not specified; users reference external URIs or SKOS concepts (DPROD-33) rdfs:label "protocol" ; . diff --git a/ontology/dprod/dprod-shapes.ttl b/ontology/dprod/dprod-shapes.ttl index d552f31..2ac1704 100644 --- a/ontology/dprod/dprod-shapes.ttl +++ b/ontology/dprod/dprod-shapes.ttl @@ -129,14 +129,6 @@ dprod-shapes:DataProductLifecycleStatusShape rdfs:isDefinedBy dprod-shapes:; . -dprod-shapes:ProtocolShape - a sh:NodeShape; - rdfs:label "protocol shape" ; - dct:description "A detailed specification, possibly including a specific version, for how to communicate with a service."@en ; - rdfs:isDefinedBy dprod-shapes:; - sh:targetClass dprod:Protocol; -. - dprod-shapes:SecuritySchemaTypeShape a sh:NodeShape; rdfs:label "security schema type shape" ; @@ -361,7 +353,6 @@ dprod-shapes:DataService-protocol a sh:PropertyShape; rdfs:isDefinedBy dprod-shapes:; sh:path dprod:protocol; - sh:class dprod:Protocol; dct:description "A protocol (possibly one of many options) used to communicate with this data service."@en ; rdfs:label "data service protocol shape" ; . diff --git a/spec-generator/main.py b/spec-generator/main.py index d952f33..52d4821 100644 --- a/spec-generator/main.py +++ b/spec-generator/main.py @@ -47,7 +47,6 @@ def main(): 'Dataset', 'DataProductLifecycleStatus', 'InformationSensitivityClassification', - 'Protocol', 'SecuritySchemaType', 'Enumeration' ])