@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix uco-core: <https://ontology.unifiedcyberontology.org/uco/core/> .
@prefix cacontology-undercover: <https://cacontology.projectvic.org/undercover#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix dcterms: <http://purl.org/dc/terms/> .

# Ontology Declaration
<https://cacontology.projectvic.org/undercover/shapes/3.0.0> rdf:type owl:Ontology ;
    rdfs:label "CAC Undercover Operations SHACL Shapes"@en ;
    rdfs:comment "SHACL validation shapes for the CAC Undercover Operations Ontology, providing validation for undercover identities, infiltration tactics, surveillance operations, and evidence collection through covert means."@en ;
    owl:versionIRI <https://cacontology.projectvic.org/undercover/shapes/3.0.0> ;
    owl:versionInfo "3.0.0" ;
    dcterms:creator "CAC Ontology Team" ;
    dcterms:modified "2026-01-01"^^xsd:date ;
    owl:imports <https://cacontology.projectvic.org/undercover/3.0.0> ,
                <http://purl.org/nemo/gufo#> ,
                <https://ontology.unifiedcyberontology.org/uco/core/> .

# =============================================================================
# UNDERCOVER OPERATION SHAPES
# =============================================================================

cacontology-undercover:UndercoverOperationShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:UndercoverOperation ;
    rdfs:label "Undercover Operation Shape"@en ;
    rdfs:comment "Validation shape for undercover operation instances."@en ;
    sh:property [
        sh:path cacontology-undercover:operationType ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "online_investigation" "physical_surveillance" "sting_operation" "long_term_infiltration" "reactive_investigation" "proactive_investigation" "joint_operation" ) ;
        sh:message "Undercover operation must specify operation type from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:operationStatus ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "planning" "active" "suspended" "completed" "terminated" "compromised" "under_review" ) ;
        sh:message "Undercover operation must specify operation status from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:riskLevel ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "low" "moderate" "high" "extreme" "critical" "unacceptable" ) ;
        sh:message "Undercover operation must specify risk level from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:operationDuration ;
        sh:datatype xsd:decimal ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:minInclusive 1.0 ;
        sh:maxInclusive 365.0 ;
        sh:message "Operation duration must be between 1 and 365 days."@en
    ] ;
    sh:property [
        sh:path uco-core:startTime ;
        sh:datatype xsd:dateTime ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "Undercover operation may have a start time."@en
    ] ;
    sh:property [
        sh:path uco-core:endTime ;
        sh:datatype xsd:dateTime ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "Undercover operation may have an end time."@en
    ] .

cacontology-undercover:OnlineUndercoverOperationShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:OnlineUndercoverOperation ;
    rdfs:label "Online Undercover Operation Shape"@en ;
    rdfs:comment "Validation shape for online undercover operation instances."@en ;
    sh:property [
        sh:path cacontology-undercover:platformsUsed ;
        sh:datatype xsd:nonNegativeInteger ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:minInclusive 1 ;
        sh:maxInclusive 20 ;
        sh:message "Online undercover operation must use between 1 and 20 platforms."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:digitalFootprintManagement ;
        sh:datatype xsd:boolean ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "Online undercover operation must specify digital footprint management."@en
    ] .

# =============================================================================
# UNDERCOVER IDENTITY SHAPES
# =============================================================================

cacontology-undercover:UndercoverIdentityShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:UndercoverIdentity ;
    rdfs:label "Undercover Identity Shape"@en ;
    rdfs:comment "Validation shape for undercover identity instances."@en ;
    sh:property [
        sh:path cacontology-undercover:identityType ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "complete_fabrication" "partial_legend" "borrowed_identity" "enhanced_real_identity" "digital_only" "physical_and_digital" ) ;
        sh:message "Undercover identity must specify identity type from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:identityComplexity ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "basic" "intermediate" "advanced" "comprehensive" "deep_cover" ) ;
        sh:message "Undercover identity must specify identity complexity from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:backstoryDepth ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "minimal" "basic" "detailed" "comprehensive" "extensive" ) ;
        sh:message "Undercover identity must specify backstory depth from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:documentationLevel ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "none" "basic" "standard" "enhanced" "complete" "official" ) ;
        sh:message "Undercover identity must specify documentation level from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:identityLifespan ;
        sh:datatype xsd:decimal ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:minInclusive 1.0 ;
        sh:maxInclusive 1095.0 ;
        sh:message "Identity lifespan must be between 1 and 1095 days (3 years)."@en
    ] .

cacontology-undercover:DigitalIdentityShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:DigitalIdentity ;
    rdfs:label "Digital Identity Shape"@en ;
    rdfs:comment "Validation shape for digital identity instances."@en ;
    sh:property [
        sh:path cacontology-undercover:socialMediaProfiles ;
        sh:datatype xsd:nonNegativeInteger ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:minInclusive 0 ;
        sh:maxInclusive 15 ;
        sh:message "Digital identity may have between 0 and 15 social media profiles."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:emailAccounts ;
        sh:datatype xsd:nonNegativeInteger ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:minInclusive 1 ;
        sh:maxInclusive 10 ;
        sh:message "Digital identity must have between 1 and 10 email accounts."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:digitalHistoryDepth ;
        sh:datatype xsd:decimal ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:minInclusive 30.0 ;
        sh:maxInclusive 1095.0 ;
        sh:message "Digital history depth must be between 30 and 1095 days."@en
    ] .

# =============================================================================
# OPERATION PLANNING SHAPES
# =============================================================================

cacontology-undercover:OperationPlanShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:OperationPlan ;
    rdfs:label "Operation Plan Shape"@en ;
    rdfs:comment "Validation shape for operation plan instances."@en ;
    sh:property [
        sh:path cacontology-undercover:planningPhase ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "initial" "detailed" "tactical" "operational" "contingency" "final" ) ;
        sh:message "Operation plan must specify planning phase from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:approvalLevel ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "supervisor" "unit_commander" "division_chief" "agency_head" "multi_agency" "federal" ) ;
        sh:message "Operation plan must specify approval level from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:riskAssessmentCompleted ;
        sh:datatype xsd:boolean ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "Operation plan must specify if risk assessment is completed."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:legalReviewCompleted ;
        sh:datatype xsd:boolean ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "Operation plan must specify if legal review is completed."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:planRevision ;
        sh:datatype xsd:nonNegativeInteger ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:minInclusive 0 ;
        sh:maxInclusive 20 ;
        sh:message "Plan revision must be between 0 and 20."@en
    ] .

cacontology-undercover:RiskAssessmentShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:RiskAssessment ;
    rdfs:label "Risk Assessment Shape"@en ;
    rdfs:comment "Validation shape for risk assessment instances."@en ;
    sh:property [
        sh:path cacontology-undercover:riskCategory ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "officer_safety" "operation_security" "legal_liability" "public_safety" "evidence_integrity" "agency_reputation" ) ;
        sh:message "Risk assessment must specify risk category from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:riskProbability ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "very_low" "low" "moderate" "high" "very_high" "certain" ) ;
        sh:message "Risk assessment must specify risk probability from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:riskImpact ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "negligible" "minor" "moderate" "major" "severe" "catastrophic" ) ;
        sh:message "Risk assessment must specify risk impact from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:mitigationStrategy ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "avoidance" "mitigation" "transfer" "acceptance" "monitoring" "contingency" ) ;
        sh:message "Risk assessment must specify mitigation strategy from the allowed list."@en
    ] .

# =============================================================================
# EVIDENCE COLLECTION SHAPES
# =============================================================================

cacontology-undercover:UndercoverEvidenceShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:UndercoverEvidence ;
    rdfs:label "Undercover Evidence Shape"@en ;
    rdfs:comment "Validation shape for undercover evidence instances."@en ;
    sh:property [
        sh:path cacontology-undercover:evidenceType ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "digital_communication" "audio_recording" "video_recording" "photographic" "documentary" "physical_evidence" "testimonial" ) ;
        sh:message "Undercover evidence must specify evidence type from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:collectionMethod ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "covert_recording" "screen_capture" "digital_preservation" "physical_seizure" "witness_statement" "surveillance" ) ;
        sh:message "Undercover evidence must specify collection method from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:chainOfCustodyMaintained ;
        sh:datatype xsd:boolean ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "Undercover evidence must specify if chain of custody is maintained."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:evidenceAuthenticity ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "verified" "authenticated" "questionable" "compromised" "inadmissible" ) ;
        sh:message "Undercover evidence must specify evidence authenticity from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:collectionDate ;
        sh:datatype xsd:dateTime ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "Undercover evidence must specify collection date."@en
    ] .

cacontology-undercover:CovertRecordingShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:CovertRecording ;
    rdfs:label "Covert Recording Shape"@en ;
    rdfs:comment "Validation shape for covert recording instances."@en ;
    sh:property [
        sh:path cacontology-undercover:recordingType ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "audio_only" "video_only" "audio_video" "screen_recording" "call_recording" "meeting_recording" ) ;
        sh:message "Covert recording must specify recording type from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:recordingQuality ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "poor" "fair" "good" "excellent" "professional" ) ;
        sh:message "Covert recording must specify recording quality from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:recordingDuration ;
        sh:datatype xsd:decimal ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:minInclusive 0.1 ;
        sh:maxInclusive 480.0 ;
        sh:message "Recording duration must be between 0.1 and 480 minutes (8 hours)."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:consentRequired ;
        sh:datatype xsd:boolean ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "Covert recording must specify if consent is required."@en
    ] .

# =============================================================================
# OPERATION MONITORING SHAPES
# =============================================================================

cacontology-undercover:OperationMonitoringShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:OperationMonitoring ;
    rdfs:label "Operation Monitoring Shape"@en ;
    rdfs:comment "Validation shape for operation monitoring instances."@en ;
    sh:property [
        sh:path cacontology-undercover:monitoringType ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "real_time" "periodic" "event_driven" "continuous" "scheduled" "emergency" ) ;
        sh:message "Operation monitoring must specify monitoring type from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:monitoringFrequency ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "constant" "hourly" "daily" "weekly" "as_needed" "critical_events" ) ;
        sh:message "Operation monitoring must specify monitoring frequency from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:supervisorInvolved ;
        sh:datatype xsd:boolean ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "Operation monitoring must specify if supervisor is involved."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:escalationProtocol ;
        sh:datatype xsd:boolean ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "Operation monitoring must specify if escalation protocol exists."@en
    ] .

cacontology-undercover:SafetyProtocolShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:SafetyProtocol ;
    rdfs:label "Safety Protocol Shape"@en ;
    rdfs:comment "Validation shape for safety protocol instances."@en ;
    sh:property [
        sh:path cacontology-undercover:protocolType ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "emergency_extraction" "panic_signal" "check_in_schedule" "backup_team" "medical_standby" "communication_protocol" ) ;
        sh:message "Safety protocol must specify protocol type from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:activationTrigger ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "officer_request" "missed_check_in" "threat_detected" "operation_compromise" "medical_emergency" "automatic_trigger" ) ;
        sh:message "Safety protocol must specify activation trigger from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:responseTime ;
        sh:datatype xsd:decimal ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:minInclusive 1.0 ;
        sh:maxInclusive 60.0 ;
        sh:message "Safety protocol response time must be between 1 and 60 minutes."@en
    ] .

# =============================================================================
# OPERATION TERMINATION SHAPES
# =============================================================================

cacontology-undercover:OperationTerminationShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:OperationTermination ;
    rdfs:label "Operation Termination Shape"@en ;
    rdfs:comment "Validation shape for operation termination instances."@en ;
    sh:property [
        sh:path cacontology-undercover:terminationReason ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "objective_achieved" "evidence_sufficient" "operation_compromised" "safety_concern" "legal_issue" "resource_constraint" "time_limit" ) ;
        sh:message "Operation termination must specify termination reason from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:terminationType ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:in ( "planned" "emergency" "gradual" "immediate" "phased" "suspended" ) ;
        sh:message "Operation termination must specify termination type from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:evidenceSecured ;
        sh:datatype xsd:boolean ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "Operation termination must specify if evidence is secured."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:identityRetirement ;
        sh:datatype xsd:boolean ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "Operation termination must specify if identity is retired."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:terminationDate ;
        sh:datatype xsd:dateTime ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "Operation termination must specify termination date."@en
    ] .

# =============================================================================
# OBJECT PROPERTY SHAPES
# =============================================================================

cacontology-undercover:UsesIdentityShape rdf:type sh:PropertyShape ;
    sh:path cacontology-undercover:usesIdentity ;
    sh:name "uses identity" ;
    sh:description "Links operation to undercover identity used" ;
    sh:class cacontology-undercover:UndercoverIdentity ;
    sh:minCount 1 .

cacontology-undercover:FollowsPlanShape rdf:type sh:PropertyShape ;
    sh:path cacontology-undercover:followsPlan ;
    sh:name "follows plan" ;
    sh:description "Links operation to operation plan followed" ;
    sh:class cacontology-undercover:OperationPlan ;
    sh:minCount 1 ;
    sh:maxCount 1 .

cacontology-undercover:CollectsEvidenceShape rdf:type sh:PropertyShape ;
    sh:path cacontology-undercover:collectsEvidence ;
    sh:name "collects evidence" ;
    sh:description "Links operation to evidence collected" ;
    sh:class cacontology-undercover:UndercoverEvidence ;
    sh:minCount 0 .

cacontology-undercover:ImplementsMonitoringShape rdf:type sh:PropertyShape ;
    sh:path cacontology-undercover:implementsMonitoring ;
    sh:name "implements monitoring" ;
    sh:description "Links operation to monitoring protocols" ;
    sh:class cacontology-undercover:OperationMonitoring ;
    sh:minCount 1 .

cacontology-undercover:ImplementsSafetyShape rdf:type sh:PropertyShape ;
    sh:path cacontology-undercover:implementsSafety ;
    sh:name "implements safety" ;
    sh:description "Links operation to safety protocols" ;
    sh:class cacontology-undercover:SafetyProtocol ;
    sh:minCount 1 .

cacontology-undercover:ResultsInTerminationShape rdf:type sh:PropertyShape ;
    sh:path cacontology-undercover:resultsInTermination ;
    sh:name "results in termination" ;
    sh:description "Links operation to termination details" ;
    sh:class cacontology-undercover:OperationTermination ;
    sh:minCount 0 ;
    sh:maxCount 1 .

# =============================================================================
# CROSS-REFERENCE VALIDATION SHAPES
# =============================================================================

cacontology-undercover:OperationCrossReferenceShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:UndercoverOperation ;
    rdfs:label "Operation Cross Reference Shape"@en ;
    rdfs:comment "Validates cross-references between operation and related entities."@en ;
    sh:sparql [
        sh:message "Undercover operation must use at least one identity and follow a plan."@en ;
        sh:select """
            SELECT $this
            WHERE {
                $this a cacontology-undercover:UndercoverOperation .
                FILTER NOT EXISTS {
                    $this cacontology-undercover:usesIdentity ?identity ;
                          cacontology-undercover:followsPlan ?plan .
                }
            }
        """
    ] .

cacontology-undercover:PlanApprovalValidationShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:OperationPlan ;
    rdfs:label "Plan Approval Validation Shape"@en ;
    rdfs:comment "Validates operation plan approval requirements."@en ;
    sh:sparql [
        sh:message "High-risk operations require higher approval levels."@en ;
        sh:select """
            SELECT $this
            WHERE {
                ?operation cacontology-undercover:followsPlan $this ;
                          cacontology-undercover:riskLevel ?risk .
                $this cacontology-undercover:approvalLevel ?approval .
                FILTER (?risk IN ("high", "extreme", "critical") && ?approval IN ("supervisor", "unit_commander"))
            }
        """
    ] .

cacontology-undercover:EvidenceChainValidationShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:UndercoverEvidence ;
    rdfs:label "Evidence Chain Validation Shape"@en ;
    rdfs:comment "Validates evidence chain of custody requirements."@en ;
    sh:sparql [
        sh:message "All undercover evidence must maintain chain of custody."@en ;
        sh:select """
            SELECT $this
            WHERE {
                $this a cacontology-undercover:UndercoverEvidence ;
                      cacontology-undercover:chainOfCustodyMaintained false .
            }
        """
    ] .

# =============================================================================
# TEMPORAL VALIDATION SHAPES
# =============================================================================

cacontology-undercover:TemporalValidationShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:UndercoverOperation ;
    rdfs:label "Temporal Validation Shape"@en ;
    rdfs:comment "Validates temporal consistency in undercover operations."@en ;
    sh:sparql [
        sh:message "Start time must be before end time when both are specified."@en ;
        sh:select """
            SELECT $this
            WHERE {
                $this uco-core:startTime ?start ;
                      uco-core:endTime ?end .
                FILTER (?start >= ?end)
            }
        """
    ] .

cacontology-undercover:CollectionDateValidationShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:UndercoverEvidence ;
    rdfs:label "Collection Date Validation Shape"@en ;
    rdfs:comment "Validates evidence collection date consistency."@en ;
    sh:sparql [
        sh:message "Evidence collection date should not be in the future."@en ;
        sh:select """
            SELECT $this
            WHERE {
                $this cacontology-undercover:collectionDate ?date .
                FILTER (?date > NOW())
            }
        """
    ] .

# =============================================================================
# DATA QUALITY SHAPES
# =============================================================================

cacontology-undercover:DataQualityShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:UndercoverOperation ;
    rdfs:label "Data Quality Shape"@en ;
    rdfs:comment "Validates data quality for undercover operations."@en ;
    sh:property [
        sh:path rdfs:label ;
        sh:nodeKind sh:Literal ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:minLength 5 ;
        sh:maxLength 200 ;
        sh:message "Label should be between 5 and 200 characters when provided."@en
    ] ;
    sh:property [
        sh:path rdfs:comment ;
        sh:nodeKind sh:Literal ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:minLength 10 ;
        sh:maxLength 1000 ;
        sh:message "Comment should be between 10 and 1000 characters when provided."@en
    ] .

# =============================================================================
# MEETING LOCATION SHAPES (Miami CAC Case Enhancement)
# =============================================================================

cacontology-undercover:MeetingLocationShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:MeetingLocation ;
    rdfs:label "Meeting Location Shape"@en ;
    rdfs:comment "Validation shape for meeting location instances used in undercover operations."@en ;
    sh:property [
        sh:path rdfs:label ;
        sh:datatype rdf:langString ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "Meeting location should have a label."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:locationName ;
        sh:datatype xsd:string ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:minLength 1 ;
        sh:maxLength 200 ;
        sh:message "Location name should be between 1 and 200 characters."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:roomNumber ;
        sh:datatype xsd:string ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "Meeting location may specify a room number."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:arrangedTime ;
        sh:datatype xsd:dateTime ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "Meeting location may specify an arranged meeting time."@en
    ] .

cacontology-undercover:MotelShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:Motel ;
    rdfs:label "Motel Shape"@en ;
    rdfs:comment "Validation shape for motel meeting location instances."@en ;
    sh:property [
        sh:path rdfs:label ;
        sh:datatype rdf:langString ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "Motel should have a label."@en
    ] .

cacontology-undercover:HotelShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:Hotel ;
    rdfs:label "Hotel Shape"@en ;
    rdfs:comment "Validation shape for hotel meeting location instances."@en ;
    sh:property [
        sh:path rdfs:label ;
        sh:datatype rdf:langString ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "Hotel should have a label."@en
    ] .

cacontology-undercover:ShortTermRentalShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:ShortTermRental ;
    rdfs:label "Short Term Rental Shape"@en ;
    rdfs:comment "Validation shape for short-term rental meeting location instances."@en ;
    sh:property [
        sh:path rdfs:label ;
        sh:datatype rdf:langString ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "Short-term rental should have a label."@en
    ] .

# =============================================================================
# MULTIPLE PERSONA OPERATION SHAPES (Miami CAC Case Enhancement)
# =============================================================================

cacontology-undercover:MultiplePersonaOperationShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:MultiplePersonaOperation ;
    rdfs:label "Multiple Persona Operation Shape"@en ;
    rdfs:comment "Validation shape for undercover operations using multiple minor personas."@en ;
    sh:property [
        sh:path cacontology-undercover:personaCount ;
        sh:datatype xsd:nonNegativeInteger ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:minInclusive 2 ;
        sh:maxInclusive 10 ;
        sh:message "Multiple persona operation must use between 2 and 10 personas."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:primaryPersonaAge ;
        sh:datatype xsd:nonNegativeInteger ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:minInclusive 10 ;
        sh:maxInclusive 17 ;
        sh:message "Primary persona age must be between 10 and 17 years old."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:secondaryPersonaAge ;
        sh:datatype xsd:nonNegativeInteger ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:minInclusive 8 ;
        sh:maxInclusive 17 ;
        sh:message "Secondary persona age must be between 8 and 17 years old."@en
    ] .

cacontology-undercover:SiblingPersonaOperationShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:SiblingPersonaOperation ;
    rdfs:label "Sibling Persona Operation Shape"@en ;
    rdfs:comment "Validation shape for undercover operations using related sibling personas."@en ;
    sh:property [
        sh:path cacontology-undercover:siblingRelationship ;
        sh:datatype xsd:string ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:in ( "sisters" "brothers" "brother_sister" "sister_brother" ) ;
        sh:message "Sibling relationship must be from the allowed list."@en
    ] .

# =============================================================================
# SUSPECT COMMUNICATION ACTION SHAPES (Miami CAC Case Enhancement)
# =============================================================================

cacontology-undercover:SuspectCommunicationActionShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:SuspectCommunicationAction ;
    rdfs:label "Suspect Communication Action Shape"@en ;
    rdfs:comment "Validation shape for criminal communication actions by suspects."@en ;
    sh:property [
        sh:path rdfs:label ;
        sh:datatype rdf:langString ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "Suspect communication action should have a label."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:occurredDuringOperation ;
        sh:class cacontology-undercover:UndercoverOperation ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "Suspect communication action should link to an undercover operation."@en
    ] .

cacontology-undercover:ExplicitMessageRequestActionShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:ExplicitMessageRequestAction ;
    rdfs:label "Explicit Message Request Action Shape"@en ;
    rdfs:comment "Validation shape for suspect requests for explicit content."@en ;
    sh:property [
        sh:path cacontology-undercover:requestType ;
        sh:datatype xsd:string ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:in ( "images" "videos" "video_call" "live_stream" ) ;
        sh:message "Request type must be from the allowed list."@en
    ] .

cacontology-undercover:VideoCallRequestActionShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:VideoCallRequestAction ;
    rdfs:label "Video Call Request Action Shape"@en ;
    rdfs:comment "Validation shape for suspect requests for video calls."@en ;
    sh:property [
        sh:path cacontology-undercover:whenParentAbsent ;
        sh:datatype xsd:boolean ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "May specify if request was conditional on parent being absent."@en
    ] .

cacontology-undercover:DisguiseRequestActionShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:DisguiseRequestAction ;
    rdfs:label "Disguise Request Action Shape"@en ;
    rdfs:comment "Validation shape for suspect requests for victim to wear disguise items."@en ;
    sh:property [
        sh:path cacontology-undercover:disguiseItemRequested ;
        sh:datatype xsd:string ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "May specify the disguise item requested."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:disguisePurpose ;
        sh:datatype xsd:string ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:in ( "avoid_detection" "conceal_identity" "evade_witnesses" "other" ) ;
        sh:message "Disguise purpose must be from the allowed list."@en
    ] .

cacontology-undercover:CriminalItemAgreementActionShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:CriminalItemAgreementAction ;
    rdfs:label "Criminal Item Agreement Action Shape"@en ;
    rdfs:comment "Validation shape for suspect agreements to bring items for abuse."@en ;
    sh:property [
        sh:path cacontology-undercover:itemsAgreedToBring ;
        sh:datatype xsd:string ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "May specify items suspect agreed to bring."@en
    ] .

cacontology-undercover:MeetingLocationArrangementShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:MeetingLocationArrangement ;
    rdfs:label "Meeting Location Arrangement Shape"@en ;
    rdfs:comment "Validation shape for suspect arrangements of meeting locations."@en ;
    sh:property [
        sh:path cacontology-undercover:meetingLocationType ;
        sh:datatype xsd:string ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:in ( "motel" "hotel" "residence" "vehicle" "outdoor" "short_term_rental" "other" ) ;
        sh:message "Meeting location type must be from the allowed list."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:meetingLocationName ;
        sh:datatype xsd:string ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "May specify the name of the meeting location."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:arrangedForMeeting ;
        sh:class cacontology-undercover:MeetingLocation ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "May link to the specific meeting location."@en
    ] .

cacontology-undercover:AgeAcknowledgmentShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:AgeAcknowledgment ;
    rdfs:label "Age Acknowledgment Shape"@en ;
    rdfs:comment "Validation shape for suspect acknowledgments of minor's age."@en ;
    sh:property [
        sh:path cacontology-undercover:ageStatedToSuspect ;
        sh:datatype xsd:nonNegativeInteger ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:minInclusive 1 ;
        sh:maxInclusive 17 ;
        sh:message "Age stated to suspect must be between 1 and 17."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:acknowledgedCount ;
        sh:datatype xsd:nonNegativeInteger ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:minInclusive 1 ;
        sh:maxInclusive 100 ;
        sh:message "Acknowledged count must be between 1 and 100."@en
    ] .

cacontology-undercover:SexualIntentStatementShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:SexualIntentStatement ;
    rdfs:label "Sexual Intent Statement Shape"@en ;
    rdfs:comment "Validation shape for explicit sexual intent statements by suspects."@en ;
    sh:property [
        sh:path cacontology-undercover:sexualActsIntended ;
        sh:datatype xsd:string ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "May specify types of sexual acts intended."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:targetedBothPersonas ;
        sh:datatype xsd:boolean ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "May specify if suspect targeted both personas in sibling operation."@en
    ] .

cacontology-undercover:TransportArrangementActionShape rdf:type sh:NodeShape ;
    sh:targetClass cacontology-undercover:TransportArrangementAction ;
    rdfs:label "Transport Arrangement Action Shape"@en ;
    rdfs:comment "Validation shape for suspect arrangements to transport alleged minor."@en ;
    sh:property [
        sh:path cacontology-undercover:pickupLocation ;
        sh:datatype xsd:string ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "May specify the pickup location."@en
    ] ;
    sh:property [
        sh:path cacontology-undercover:destinationLocation ;
        sh:datatype xsd:string ;
        sh:minCount 0 ;
        sh:maxCount 1 ;
        sh:message "May specify the destination location."@en
    ] . 