@prefix decision: <https://ontology.inferal.com/modules/decision/> .
@prefix prov: <http://www.w3.org/ns/prov#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .

decision:GoalShape
    a sh:NodeShape ;
    rdfs:label "goal shape"@en ;
    rdfs:comment "Validates that goal instances are RDF resources while leaving domain-specific goal content open."@en ;
    sh:targetClass decision:Goal ;
    sh:nodeKind sh:BlankNodeOrIRI .

decision:IssueShape
    a sh:NodeShape ;
    rdfs:label "issue shape"@en ;
    rdfs:comment "Validates that issue instances are RDF resources while leaving domain-specific issue content open."@en ;
    sh:targetClass decision:Issue ;
    sh:nodeKind sh:BlankNodeOrIRI .

decision:OptionShape
    a sh:NodeShape ;
    rdfs:label "option shape"@en ;
    rdfs:comment "Validates projected consequences attached to an option."@en ;
    sh:targetClass decision:Option ;
    sh:nodeKind sh:BlankNodeOrIRI ;
    sh:property [
        sh:path decision:anticipatesConsequence ;
        sh:class decision:AnticipatedConsequence ;
        sh:nodeKind sh:BlankNodeOrIRI ;
    ] .

decision:CriterionShape
    a sh:NodeShape ;
    rdfs:label "criterion shape"@en ;
    rdfs:comment "Validates that criterion instances are RDF resources while leaving their domain-specific scale open."@en ;
    sh:targetClass decision:Criterion ;
    sh:nodeKind sh:BlankNodeOrIRI .

decision:EvaluationShape
    a sh:NodeShape ;
    rdfs:label "evaluation shape"@en ;
    rdfs:comment "Requires an evaluation to assess exactly one option under exactly one criterion and validates optional evidence links."@en ;
    sh:targetClass decision:Evaluation ;
    sh:nodeKind sh:BlankNodeOrIRI ;
    sh:property [
        sh:path decision:evaluatesOption ;
        sh:class decision:Option ;
        sh:nodeKind sh:BlankNodeOrIRI ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
    ] ;
    sh:property [
        sh:path decision:appliesCriterion ;
        sh:class decision:Criterion ;
        sh:nodeKind sh:BlankNodeOrIRI ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
    ] ;
    sh:property [
        sh:path decision:basedOnEvidence ;
        sh:class prov:Entity ;
        sh:nodeKind sh:BlankNodeOrIRI ;
    ] .

decision:DeliberationShape
    a sh:NodeShape ;
    rdfs:label "deliberation shape"@en ;
    rdfs:comment "Requires a deliberation to address an issue, pursue a goal, and consider at least one option while validating optional evaluations, decisions, and feedback."@en ;
    sh:targetClass decision:Deliberation ;
    sh:nodeKind sh:BlankNodeOrIRI ;
    sh:property [
        sh:path decision:addressesIssue ;
        sh:class decision:Issue ;
        sh:nodeKind sh:BlankNodeOrIRI ;
        sh:minCount 1 ;
    ] ;
    sh:property [
        sh:path decision:pursuesGoal ;
        sh:class decision:Goal ;
        sh:nodeKind sh:BlankNodeOrIRI ;
        sh:minCount 1 ;
    ] ;
    sh:property [
        sh:path decision:considersOption ;
        sh:class decision:Option ;
        sh:nodeKind sh:BlankNodeOrIRI ;
        sh:minCount 1 ;
    ] ;
    sh:property [
        sh:path decision:hasEvaluation ;
        sh:class decision:Evaluation ;
        sh:nodeKind sh:BlankNodeOrIRI ;
    ] ;
    sh:property [
        sh:path decision:generatedDecision ;
        sh:class decision:Decision ;
        sh:nodeKind sh:BlankNodeOrIRI ;
    ] ;
    sh:property [
        sh:path decision:informedByConsequence ;
        sh:class decision:ObservedConsequence ;
        sh:nodeKind sh:BlankNodeOrIRI ;
    ] ;
    sh:sparql [
        sh:message "Every evaluation used by a deliberation must evaluate an option considered by that deliberation."@en ;
        sh:select """
            PREFIX decision: <https://ontology.inferal.com/modules/decision/>
            SELECT $this ?evaluation ?option WHERE {
                $this decision:hasEvaluation ?evaluation .
                ?evaluation decision:evaluatesOption ?option .
                FILTER NOT EXISTS { $this decision:considersOption ?option . }
            }
        """ ;
    ] .

decision:DecisionShape
    a sh:NodeShape ;
    rdfs:label "decision shape"@en ;
    rdfs:comment "Requires a decision to result from exactly one deliberation and select at least one option considered by it."@en ;
    sh:targetClass decision:Decision ;
    sh:nodeKind sh:BlankNodeOrIRI ;
    sh:property [
        sh:path decision:resultedFromDeliberation ;
        sh:class decision:Deliberation ;
        sh:nodeKind sh:BlankNodeOrIRI ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
    ] ;
    sh:property [
        sh:path decision:selectedOption ;
        sh:class decision:Option ;
        sh:nodeKind sh:BlankNodeOrIRI ;
        sh:minCount 1 ;
    ] ;
    sh:property [
        sh:path decision:basedOnEvaluation ;
        sh:class decision:Evaluation ;
        sh:nodeKind sh:BlankNodeOrIRI ;
    ] ;
    sh:property [
        sh:path decision:supersedesDecision ;
        sh:class decision:Decision ;
        sh:nodeKind sh:BlankNodeOrIRI ;
    ] ;
    sh:sparql [
        sh:message "Every selected option must be among the options considered by the deliberation that generated the decision."@en ;
        sh:select """
            PREFIX decision: <https://ontology.inferal.com/modules/decision/>
            SELECT $this ?deliberation ?option WHERE {
                $this decision:resultedFromDeliberation ?deliberation ;
                      decision:selectedOption ?option .
                FILTER NOT EXISTS { ?deliberation decision:considersOption ?option . }
            }
        """ ;
    ] ;
    sh:sparql [
        sh:message "Every evaluation cited by a decision must belong to the deliberation that generated it."@en ;
        sh:select """
            PREFIX decision: <https://ontology.inferal.com/modules/decision/>
            SELECT $this ?deliberation ?evaluation WHERE {
                $this decision:resultedFromDeliberation ?deliberation ;
                      decision:basedOnEvaluation ?evaluation .
                FILTER NOT EXISTS { ?deliberation decision:hasEvaluation ?evaluation . }
            }
        """ ;
    ] ;
    sh:sparql [
        sh:message "A decision must not directly or transitively supersede itself."@en ;
        sh:select """
            PREFIX decision: <https://ontology.inferal.com/modules/decision/>
            SELECT $this WHERE {
                $this decision:supersedesDecision+ $this .
            }
        """ ;
    ] .

decision:DecisionRecordShape
    a sh:NodeShape ;
    rdfs:label "decision record shape"@en ;
    rdfs:comment "Requires a decision record to document at least one decision and validates optional rationale resources."@en ;
    sh:targetClass decision:DecisionRecord ;
    sh:nodeKind sh:BlankNodeOrIRI ;
    sh:property [
        sh:path decision:recordsDecision ;
        sh:class decision:Decision ;
        sh:nodeKind sh:BlankNodeOrIRI ;
        sh:minCount 1 ;
    ] ;
    sh:property [
        sh:path decision:hasRationale ;
        sh:class decision:Rationale ;
        sh:nodeKind sh:BlankNodeOrIRI ;
    ] .

decision:RationaleShape
    a sh:NodeShape ;
    rdfs:label "rationale shape"@en ;
    rdfs:comment "Validates that rationale instances are RDF resources while allowing domain-specific explanation structures."@en ;
    sh:targetClass decision:Rationale ;
    sh:nodeKind sh:BlankNodeOrIRI .

decision:ResultingActionShape
    a sh:NodeShape ;
    rdfs:label "resulting action shape"@en ;
    rdfs:comment "Requires a resulting action to implement at least one decision and validates any observed consequences it produces."@en ;
    sh:targetClass decision:ResultingAction ;
    sh:nodeKind sh:BlankNodeOrIRI ;
    sh:property [
        sh:path decision:implementsDecision ;
        sh:class decision:Decision ;
        sh:nodeKind sh:BlankNodeOrIRI ;
        sh:minCount 1 ;
    ] ;
    sh:property [
        sh:path decision:producedConsequence ;
        sh:class decision:ObservedConsequence ;
        sh:nodeKind sh:BlankNodeOrIRI ;
    ] .

decision:ConsequenceShape
    a sh:NodeShape ;
    rdfs:label "consequence shape"@en ;
    rdfs:comment "Validates that consequence instances are RDF resources while preserving their domain-specific content."@en ;
    sh:targetClass decision:Consequence ;
    sh:nodeKind sh:BlankNodeOrIRI .

decision:AnticipatedConsequenceShape
    a sh:NodeShape ;
    rdfs:label "anticipated consequence shape"@en ;
    rdfs:comment "Validates that anticipated consequences are RDF resources without treating them as observations."@en ;
    sh:targetClass decision:AnticipatedConsequence ;
    sh:nodeKind sh:BlankNodeOrIRI .

decision:ObservedConsequenceShape
    a sh:NodeShape ;
    rdfs:label "observed consequence shape"@en ;
    rdfs:comment "Requires every observed consequence to be linked from at least one resulting action and validates optional correspondence to prior anticipations."@en ;
    sh:targetClass decision:ObservedConsequence ;
    sh:nodeKind sh:BlankNodeOrIRI ;
    sh:property [
        sh:path [ sh:inversePath decision:producedConsequence ] ;
        sh:class decision:ResultingAction ;
        sh:nodeKind sh:BlankNodeOrIRI ;
        sh:minCount 1 ;
    ] ;
    sh:property [
        sh:path decision:correspondsToAnticipation ;
        sh:class decision:AnticipatedConsequence ;
        sh:nodeKind sh:BlankNodeOrIRI ;
    ] .
