@prefix op: <https://ontology.inferal.com/mappings/relay-advertising-operation-inputs/> .
@prefix ior: <https://ontology.inferal.com/mappings/relay-operation-input-roles/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

op:SlotShape a sh:NodeShape ; sh:targetClass ior:Slot ;
  rdfs:label "complete contextualized input slot" ;
  rdfs:comment "Each represented path has six independent decisions and belongs to one ordered invocation item." ;
  sh:property [ sh:path op:invocation ; sh:minCount 1 ; sh:maxCount 1 ; sh:class ior:Invocation ] ;
  sh:property [ sh:path op:itemIndex ; sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:integer ; sh:minInclusive 0 ] ;
  sh:property [ sh:path ior:wirePath ; sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ] ;
  sh:property [ sh:path [ sh:inversePath ior:slot ] ; sh:minCount 6 ; sh:maxCount 6 ; sh:class ior:Decision ] ;
  sh:sparql [ sh:message "Every slot requires exactly one decision for each axis." ; sh:select """
    PREFIX ior: <https://ontology.inferal.com/mappings/relay-operation-input-roles/>
    SELECT $this WHERE {
      FILTER(NOT EXISTS { ?d ior:slot $this ; ior:axis ior:role } ||
             NOT EXISTS { ?d ior:slot $this ; ior:axis ior:inputPolicy } ||
             NOT EXISTS { ?d ior:slot $this ; ior:axis ior:requiredness } ||
             NOT EXISTS { ?d ior:slot $this ; ior:axis ior:omission } ||
             NOT EXISTS { ?d ior:slot $this ; ior:axis ior:suppliedBehavior } ||
             NOT EXISTS { ?d ior:slot $this ; ior:axis ior:execution })
    }
  """ ] .

op:DecisionShape a sh:NodeShape ; sh:targetClass ior:Decision ;
  rdfs:label "source policy decision" ;
  rdfs:comment "Only a resolved decision selects one source-supported value. No prospective input assessment establishes execution success." ;
  sh:property [ sh:path ior:slot ; sh:minCount 1 ; sh:maxCount 1 ; sh:class ior:Slot ] ;
  sh:property [ sh:path ior:axis ; sh:minCount 1 ; sh:maxCount 1 ; sh:in (ior:role ior:inputPolicy ior:requiredness ior:omission ior:suppliedBehavior ior:execution) ] ;
  sh:property [ sh:path ior:state ; sh:minCount 1 ; sh:maxCount 1 ; sh:in (ior:Resolved ior:Unassessed ior:Conditional ior:Conflicted) ] ;
  sh:property [ sh:path ior:selectedValue ; sh:maxCount 1 ; sh:nodeKind sh:IRI ] ;
  sh:sparql [ sh:message "A resolved decision selects its preserved source claim; other decisions select nothing. Execution is always unassessed." ; sh:select """
    PREFIX ior: <https://ontology.inferal.com/mappings/relay-operation-input-roles/>
    PREFIX ss: <https://ontology.inferal.com/modules/scoped-statements/>
    SELECT $this WHERE {
      $this ior:state ?state ; ior:axis ?axis .
      FILTER((?axis = ior:execution && (?state != ior:Unassessed || EXISTS { $this ior:selectedValue ?v })) ||
        (?state != ior:Resolved && EXISTS { $this ior:selectedValue ?v }) ||
        (?state = ior:Resolved && NOT EXISTS {
          $this ior:selectedValue ?v ; ior:sourceClaim ?c . ?c ss:claimValue ?v ; ior:axis ?axis ; ior:sourceBinding ?source
        }))
    }
  """ ] .

op:CandidateShape a sh:NodeShape ; sh:targetClass ior:Candidate ;
  rdfs:label "traceable input policy evidence" ;
  rdfs:comment "Candidates retain a source record and the independent caller context used to select applicability." ;
  sh:property [ sh:path ior:sourceBinding ; sh:minCount 1 ; sh:nodeKind sh:IRI ] ;
  sh:property [ sh:path op:declaredContext ; sh:minCount 1 ; sh:maxCount 1 ; sh:nodeKind sh:IRI ] .
