@prefix edu: <https://knobit.org/def/> .
@prefix kps: <https://knobit.org/def/shapes/knobit-profile#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix schema: <https://schema.org/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

kps:AppliedNotAlsoPrerequisiteShape a sh:NodeShape ;
    rdfs:label "Applied knowledge is not repeated as a prerequisite (KN-07)"@en ;
    sh:sparql [ a sh:SPARQLConstraint ;
            sh:message "The same knowledge is both applied and a prerequisite: direct application already implies it."@en ;
            sh:prefixes kps:prefixes ;
            sh:select "SELECT $this ?value WHERE { $this edu:appliesKnowledge ?value ; edu:dependsOnKnobit ?value . }" ;
            sh:severity sh:Warning ] ;
    sh:targetSubjectsOf edu:appliesKnowledge .

kps:AppliesKnowledgeTypingShape a sh:NodeShape ;
    rdfs:label "Applied knowledge runs from a skill to a knowledge knobit (KN-07)"@en ;
    sh:property [ sh:hasValue <https://knobit.org/def/knobitType/skill> ;
            sh:message "Only a skill knobit applies knowledge."@en ;
            sh:path edu:knobitType ],
        [ sh:in ( <https://knobit.org/def/knobitType/knowledge> ) ;
            sh:message "edu:appliesKnowledge must point to a knowledge knobit."@en ;
            sh:path ( edu:appliesKnowledge edu:knobitType ) ] ;
    sh:targetSubjectsOf edu:appliesKnowledge .

kps:ConformingKnobitShape a sh:NodeShape ;
    rdfs:label "A knobit claiming LCG-KNOBIT 0.1 carries the profile's description"@en ;
    sh:message "The knobit claims conformance to LCG-KNOBIT 0.1 but lacks part of the KN-06 description; validate it against kps:DescribedKnobitShape for the missing fields."@en ;
    sh:or ( kps:NoConformanceClaimShape kps:DeprecatedKnobitShape kps:DescribedKnobitShape ) ;
    sh:targetClass edu:Knobit .

kps:KnobitSetShape a sh:NodeShape ;
    rdfs:label "A knobit set that solves an item names at least one knobit"@en ;
    sh:property [ sh:class edu:Knobit ;
            sh:message "A knobit set names the knobits (at least one) that together solve the item."@en ;
            sh:minCount 1 ;
            sh:path edu:memberKnobit ] ;
    sh:targetClass edu:KnobitSet .

kps:MasteryImplicationAcyclicShape a sh:NodeShape ;
    rdfs:label "Mastery implications have no cycles (knowledge space theory)"@en ;
    sh:sparql [ a sh:SPARQLConstraint ;
            sh:message "Mastery implications (dependsOnKnobit, appliesKnowledge, hasPartKnobit) form a cycle: an assessment could not tell these knobits apart."@en ;
            sh:prefixes kps:prefixes ;
            sh:select "SELECT $this WHERE { $this (edu:dependsOnKnobit|edu:appliesKnowledge|edu:hasPartKnobit)+ $this . }" ] ;
    sh:targetSubjectsOf edu:appliesKnowledge,
        edu:dependsOnKnobit,
        edu:hasPartKnobit .

kps:SuccessionAcyclicShape a sh:NodeShape ;
    rdfs:label "Functional succession has no cycles except through feedback edges (KN-07)"@en ;
    sh:sparql [ a sh:SPARQLConstraint ;
            sh:message "Functional succession forms a cycle; an edge that sends the work back must be edu:feedsBackTo."@en ;
            sh:prefixes kps:prefixes ;
            sh:select "SELECT $this WHERE { $this edu:followedBy+ $this . }" ] ;
    sh:targetSubjectsOf edu:followedBy .

kps:DeprecatedKnobitShape a sh:NodeShape ;
    rdfs:comment "A superseded knobit keeps its URI and name but need not carry a description; it must say what replaced it."@en ;
    sh:property [ sh:minCount 1 ;
            sh:path schema:supersededBy ] .

kps:DescribedKnobitShape a sh:NodeShape ;
    rdfs:label "Knobit described to the LCG knobit profile (KN-06, KN-03)"@en ;
    sh:property [ sh:in ( <https://knobit.org/def/contextFunction/objectUnderstanding> <https://knobit.org/def/contextFunction/situationIdentification> <https://knobit.org/def/contextFunction/goalDefinition> <https://knobit.org/def/contextFunction/actionPlanning> <https://knobit.org/def/contextFunction/actionExecution> <https://knobit.org/def/contextFunction/resultEvaluation> <https://knobit.org/def/contextFunction/actionAdjustment> <https://knobit.org/def/contextFunction/valueRegulation> ) ;
            sh:maxCount 1 ;
            sh:message "A knobit has exactly one main context function."@en ;
            sh:minCount 1 ;
            sh:path edu:contextFunction ],
        [ sh:message "KN-06: the action is part of the minimum description."@en ;
            sh:minCount 1 ;
            sh:path edu:actionVerb ],
        [ sh:message "KN-06: the target object is part of the minimum description."@en ;
            sh:minCount 1 ;
            sh:path edu:targetObject ],
        [ sh:message "KN-06: the expected result is part of the minimum description."@en ;
            sh:minCount 1 ;
            sh:path edu:expectedResult ],
        [ sh:message "KN-03: the assessment criterion is part of the semantic fingerprint."@en ;
            sh:minCount 1 ;
            sh:path edu:assessmentCriterion ],
        [ sh:message "KN-06: a possible assessment method is part of the minimum description."@en ;
            sh:minCount 1 ;
            sh:path edu:assessmentMethod ],
        [ sh:message "KN-04: a knobit serves at least one LCG purpose."@en ;
            sh:minCount 1 ;
            sh:path edu:graphRelevance ],
        [ sh:message "A knobit has a name."@en ;
            sh:minCount 1 ;
            sh:path rdfs:label ],
        [ sh:in ( <https://knobit.org/def/knobitType/knowledge> <https://knobit.org/def/knobitType/skill> <https://knobit.org/def/knobitType/attitude> ) ;
            sh:maxCount 1 ;
            sh:message "A knobit has exactly one type: knowledge, skill or attitude."@en ;
            sh:minCount 1 ;
            sh:path edu:knobitType ] .

kps:NoConformanceClaimShape a sh:NodeShape ;
    sh:not [ a sh:NodeShape ;
            sh:property [ sh:path edu:conformsToProfile ] ] .

kps:prefixes sh:declare [ sh:namespace "https://knobit.org/def/"^^xsd:anyURI ;
            sh:prefix "edu" ] .

