@prefix augo: <https://w3id.org/augmanitai/ns/oversight#> .
@prefix dct: <http://purl.org/dc/terms/> .
@prefix mv: <https://w3id.org/augmanitai/ns/meaning-validity#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

mv:StatementShape a sh:NodeShape ;
    sh:property [ sh:class mv:Statement ;
            sh:message "supersededBy verweist per IRI auf eine andere Aussage, die im selben Graphen ausdrücklich als mv:Statement typisiert ist."@de,
                "supersededBy points by IRI to another statement that is explicitly typed mv:Statement in the same graph."@en ;
            sh:nodeKind sh:IRI ;
            sh:path mv:supersededBy ],
        [ sh:in ( augo:holds augo:doesNotHold augo:undetermined augo:notPerformed ) ;
            sh:maxCount 1 ;
            sh:message "Eine Aussage braucht genau einen Gültigkeitsstatus: holds, doesNotHold, undetermined oder notPerformed (augo-Werte)."@de,
                "A statement needs exactly one validity status: holds, doesNotHold, undetermined or notPerformed (augo values)."@en ;
            sh:minCount 1 ;
            sh:path mv:validityStatus ],
        [ sh:message "scope ist Text oder eine IRI."@de,
                "scope is text or an IRI."@en ;
            sh:or ( [ sh:nodeKind sh:IRI ] [ sh:datatype xsd:string ] [ sh:datatype rdf:langString ] ) ;
            sh:path mv:scope ],
        [ sh:datatype xsd:dateTime ;
            sh:maxCount 1 ;
            sh:message "Eine Aussage braucht genau ein statedAt (Datum und Uhrzeit mit Zeitzone)."@de,
                "A statement needs exactly one statedAt (date-time with timezone)."@en ;
            sh:minCount 1 ;
            sh:path mv:statedAt ;
            sh:pattern "(Z|[+-][0-9]{2}:[0-9]{2})$" ],
        [ sh:datatype xsd:dateTime ;
            sh:maxCount 1 ;
            sh:message "determinedAt ist höchstens ein Zeitpunkt (Datum und Uhrzeit mit Zeitzone)."@de,
                "determinedAt is at most one date-time with timezone."@en ;
            sh:path mv:determinedAt ;
            sh:pattern "(Z|[+-][0-9]{2}:[0-9]{2})$" ],
        [ sh:message "perspective muss eine IRI sein."@de,
                "perspective must be an IRI."@en ;
            sh:nodeKind sh:IRI ;
            sh:path mv:perspective ],
        [ sh:maxCount 1 ;
            sh:message "basedOnDefinition ist höchstens eine IRI einer versionierten Definition."@de,
                "basedOnDefinition is at most one IRI of a versioned definition."@en ;
            sh:nodeKind sh:IRI ;
            sh:path mv:basedOnDefinition ] ;
    sh:sparql [ a sh:SPARQLConstraint ;
            sh:message "determinedAt darf nicht vor statedAt liegen."@de,
                "determinedAt must not be earlier than statedAt."@en ;
            sh:select """PREFIX mv: <https://w3id.org/augmanitai/ns/meaning-validity#>
PREFIX augo: <https://w3id.org/augmanitai/ns/oversight#>
SELECT $this WHERE { $this mv:statedAt ?s ; mv:determinedAt ?d . FILTER (regex(str(?s), "(Z|[+-][0-9]{2}:[0-9]{2})$") && regex(str(?d), "(Z|[+-][0-9]{2}:[0-9]{2})$") && ?d < ?s) }""" ],
        [ a sh:SPARQLConstraint ;
            sh:message "Eine Aussage kann sich nicht selbst ersetzen."@de,
                "A statement cannot supersede itself."@en ;
            sh:select """PREFIX mv: <https://w3id.org/augmanitai/ns/meaning-validity#>
PREFIX augo: <https://w3id.org/augmanitai/ns/oversight#>
SELECT $this WHERE { $this mv:supersededBy $this }""" ],
        [ a sh:SPARQLConstraint ;
            sh:message "holds, doesNotHold oder undetermined verlangt determinedAt: ein Feststellungsergebnis ohne Feststellungszeit wird nicht angenommen."@de,
                "holds, doesNotHold or undetermined requires determinedAt: a determination result without a determination time is not accepted."@en ;
            sh:select """PREFIX mv: <https://w3id.org/augmanitai/ns/meaning-validity#>
PREFIX augo: <https://w3id.org/augmanitai/ns/oversight#>
SELECT $this WHERE { $this mv:validityStatus ?v . FILTER (?v IN (augo:holds, augo:doesNotHold, augo:undetermined)) FILTER NOT EXISTS { $this mv:determinedAt ?d } }""" ],
        [ a sh:SPARQLConstraint ;
            sh:message "notPerformed bedeutet, dass keine Feststellung stattfand; determinedAt muss fehlen (eine ausgelassene Prüfung wird nie wie eine durchgeführte erfasst)."@de,
                "notPerformed means no determination took place; determinedAt must be absent (a skipped check is never recorded like a performed one)."@en ;
            sh:select """PREFIX mv: <https://w3id.org/augmanitai/ns/meaning-validity#>
PREFIX augo: <https://w3id.org/augmanitai/ns/oversight#>
SELECT $this WHERE { $this mv:validityStatus augo:notPerformed ; mv:determinedAt ?d }""" ],
        [ a sh:SPARQLConstraint ;
            sh:message "Eine Aussage kann nur durch eine spätere ersetzt werden (statedAt der ersetzenden Aussage muss später liegen)."@de,
                "A statement can only be superseded by a later statement (statedAt of the replacing statement must be later)."@en ;
            sh:select """PREFIX mv: <https://w3id.org/augmanitai/ns/meaning-validity#>
PREFIX augo: <https://w3id.org/augmanitai/ns/oversight#>
SELECT $this WHERE { $this mv:supersededBy ?n . ?n mv:statedAt ?t2 . $this mv:statedAt ?t1 . FILTER (regex(str(?t1), "(Z|[+-][0-9]{2}:[0-9]{2})$") && regex(str(?t2), "(Z|[+-][0-9]{2}:[0-9]{2})$") && ?t2 <= ?t1) }""" ] ;
    sh:targetClass mv:Statement ;
    sh:targetSubjectsOf mv:basedOnDefinition,
        mv:determinedAt,
        mv:perspective,
        mv:scope,
        mv:statedAt,
        mv:supersededBy,
        mv:validityStatus .

<https://w3id.org/augmanitai/ns/meaning-validity-shapes.ttl> a owl:Ontology ;
    dct:creator <https://orcid.org/0009-0006-3773-7796> ;
    dct:license <https://creativecommons.org/licenses/by/4.0/> ;
    dct:source <https://w3id.org/augmanitai/ns/meaning-validity/0.1> ;
    dct:title "SHACL-Formen für mv 0.1"@de,
        "SHACL shapes for mv 0.1"@en ;
    owl:versionInfo "0.1" .

