# MRK-2.0 SHACL shapes (DRAFT) - the L4 gate.
# Validates the graph a corpus PROJECTS into (via mrk-1.1.context.jsonld), catching
# integrity errors JSON Schema structurally cannot see across a corpus: dangling
# references, mistyped nodes, and missing per-type structure. Run with pyshacl:
#   pyshacl -s shapes.ttl -df turtle graph.ttl

@prefix sh:      <http://www.w3.org/ns/shacl#> .
@prefix mrk:     <https://machinereadyknowledge.com/ns#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix xsd:     <http://www.w3.org/2001/XMLSchema#> .

mrk:ArticleShape a sh:NodeShape ;
    sh:targetClass mrk:Article ;
    sh:property [ sh:path dcterms:title ; sh:minCount 1 ; sh:maxCount 1 ] ;
    sh:property [ sh:path mrk:verified ; sh:minCount 1 ; sh:datatype xsd:date ] ;
    sh:property [ sh:path mrk:lifecycle ; sh:minCount 1 ;
                  sh:in ( "draft" "unreleased" "current" "superseded" "retired" "expired" ) ] ;
    sh:property [ sh:path mrk:visibility ;
                  sh:in ( "public" "internal" "confidential" ) ] ;
    sh:property [ sh:path mrk:hasSection ; sh:minCount 1 ; sh:class mrk:Section ] .

mrk:SectionShape a sh:NodeShape ;
    sh:targetClass mrk:Section ;
    sh:property [ sh:path mrk:sectionRole ; sh:minCount 1 ; sh:maxCount 1 ;
                  sh:in ( "context" "symptom" "cause" "resolution" "procedure"
                          "verification" "concept" "reference" "prerequisite"
                          "result" "caveat" "example" ) ] ;
    sh:property [ sh:path mrk:selfContained ; sh:minCount 1 ; sh:datatype xsd:boolean ] .

# Referential integrity: every edge target must be a real node of the right kind.
# A dangling `requires`/`dependsOn`/`supersedes` (typo, retired-and-purged id) fails
# here - the check JSON Schema cannot make because it never sees the other file.
mrk:RequiresIntegrityShape a sh:NodeShape ;
    sh:targetObjectsOf mrk:requires ;
    sh:class mrk:Section ;
    sh:message "requires: target section does not exist in the corpus graph" .

mrk:DependsOnIntegrityShape a sh:NodeShape ;
    sh:targetObjectsOf mrk:dependsOn ;
    sh:class mrk:Article ;
    sh:message "depends_on: target article does not exist in the corpus graph" .

mrk:SupersedesIntegrityShape a sh:NodeShape ;
    sh:targetObjectsOf dcterms:replaces ;
    sh:class mrk:Article ;
    sh:message "supersedes: target article does not exist in the corpus graph" .
