@prefix rdf: . @prefix rdfs: . @prefix xsd: . @prefix sh: . @prefix pr: . @prefix prsh: . ################################################################# # PR Data Meta Model - SHACL Shapes v0.1.1 # Executable encoding of BLOCKING (sh:Violation) & MAJOR (sh:Warning) rules. # FIX v0.1.1 (2026-07-23): NR-002 uniqueness query now restricts ?cls to # LEAF classes (via FILTER ... IN) so that objects of different layers that # share a name (e.g. Sub-Domain "Sell Out" vs Concept "Sell Out") are NOT # reported as duplicates. Rule stays "unique WITHIN its class". # Run: python run_shacl_validation.py SODH_data.ttl pr_metamodel_shapes_v0.1.ttl pr_metamodel_v0.9.ttl ################################################################# prsh:MetaModelObjectShape a sh:NodeShape ; sh:targetClass pr:MetaModelObject ; sh:property [ sh:path pr:hasIdentifier ; sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ; sh:severity sh:Violation ; sh:message "DQ-001 (BLOCKING): exactly one hasIdentifier." ] ; sh:property [ sh:path pr:hasName ; sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ; sh:minLength 2 ; sh:severity sh:Violation ; sh:message "DQ-002 (BLOCKING): exactly one non-empty hasName." ] ; sh:property [ sh:path pr:ownedBy ; sh:minCount 1 ; sh:class pr:Actor ; sh:severity sh:Violation ; sh:message "OW-001 (BLOCKING): at least one owner (Actor)." ] ; sh:property [ sh:path pr:owningDomain ; sh:minCount 1 ; sh:maxCount 1 ; sh:class pr:DataDomain ; sh:severity sh:Violation ; sh:message "OW-001 (BLOCKING): exactly one owning Data Domain." ] ; sh:property [ sh:path pr:hasStatus ; sh:minCount 1 ; sh:in ( "DRAFT" "UNDER_REVIEW" "PUBLISHED" "DEPRECATED" ) ; sh:severity sh:Warning ; sh:message "DQ-012 (MAJOR): hasStatus in controlled list." ] ; sh:property [ sh:path pr:hasVersion ; sh:minCount 1 ; sh:severity sh:Warning ; sh:message "DQ-012 (MAJOR): hasVersion required." ] . prsh:BackDocSourceShape a sh:NodeShape ; sh:targetClass pr:MetaModelObject ; sh:sparql [ sh:severity sh:Violation ; sh:message "DQ-006 (BLOCKING): a DRAFT back-doc object MUST carry hasSource." ; sh:select """ PREFIX pr: SELECT $this WHERE { $this pr:hasStatus "DRAFT" . FILTER NOT EXISTS { $this pr:hasSource ?s } } """ ] . prsh:CanonicalNameShape a sh:NodeShape ; sh:targetClass pr:MetaModelObject ; sh:property [ sh:path pr:hasName ; sh:pattern "^(?!GL_)(?!ID_).*(? SELECT $this WHERE { $this a ?cls ; pr:hasName ?n ; pr:owningDomain ?d . ?other a ?cls ; pr:hasName ?n ; pr:owningDomain ?d . FILTER ( $this != ?other ) FILTER ( ?cls IN ( pr:DataDomain, pr:SubDomain, pr:BusinessObject, pr:BusinessConcept, pr:Metric, pr:KPI, pr:DataAsset, pr:DataObject, pr:DataElement, pr:DataContract, pr:DataProduct, pr:Table, pr:Field ) ) } """ ] . prsh:ArbitrationGateShape a sh:NodeShape ; sh:targetClass pr:MetaModelObject ; sh:sparql [ sh:severity sh:Violation ; sh:message "OW-007 (BLOCKING): a TO_ARBITRATE object MUST NOT be PUBLISHED." ; sh:select """ PREFIX pr: SELECT $this WHERE { $this pr:hasStatus "PUBLISHED" . $this pr:arbitrationStatus "TO_ARBITRATE" . } """ ] .