# TOP Core — OWL classes and SHACL contract
#
# Companion to taxonomy/taxonomy.ttl (the SKOS view). This file is the
# OWL/SHACL view: the same concepts as the SKOS taxonomy, expressed as
# owl:Class declarations with rdfs:subClassOf chains, plus the SHACL
# contract that enforces Universal DNA on every TOP entity.
#
# Mirrors taxonomy/taxonomy.ttl by URI: every concept here is the same
# IRI (top:Person, top:Document, …) carrying both views. SKOS-aware
# tools (TermBoard / PoolParty / Synaptica) load only the SKOS file;
# OWL reasoners and SHACL validators load this file (and may load both).
#
# WHAT THIS FILE DEFINES (per ADR-0012 and ADR-0013):
#
#   L0 — Root class (top:CommonEntity).
#        Every TOP entity is rdfs:subClassOf top:CommonEntity, by
#        construction. The root carries Universal DNA — the three
#        practitioner-grounded properties every entity answers:
#        identifier (what is this thing?), observedAt (when was it
#        captured?), status (is it current?).
#
#   L1 — Universal DNA properties (3).
#        top:identifier, top:observedAt, top:status. Domain
#        top:CommonEntity. Required (mandatory) per the SHACL contract
#        below.
#
#   L1 SHACL — top:UniversalDNAShape.
#        Targets top:CommonEntity. Requires identifier (xsd:anyURI,
#        exactly one), observedAt (xsd:dateTime, exactly one), status
#        (xsd:string, exactly one). The minimum every TOP entity must
#        carry.
#
#   L2 — Category-Level Object classes (8).
#        Agent, Location, Resource, Scope, Temporal, Evidence, Outcome,
#        Constraint. Each rdfs:subClassOf top:CommonEntity and
#        rdfs:subClassOf prov:Agent | prov:Activity | prov:Entity |
#        prov:Plan | prov:Location per the PROV-O alignment. Four
#        categories carry a light-edge BFO subClassOf for OBO interop
#        (Agent, Location, Temporal, Evidence); the other four
#        (Resource, Scope, Outcome, Constraint) are mixed-membership,
#        carry no category-level BFO peer, and declare the edge on
#        their leaves instead.
#
#   L2 — Category relational extensions (~24 properties).
#        The verbs each category brings to TOP. Agent gets
#        hasCredential / memberOf / authorizedBy. Location gets
#        withinLocation / geoSpatialData / accessRequirement. And so
#        on per ADR-0012. Domain pinned to the category; range pinned
#        where the target category is determinable.
#
#   L3 — Leaf classes (28).
#        The leaves under each category. Each rdfs:subClassOf its L2
#        category (which transitively pulls in top:CommonEntity and
#        the PROV-O alignment) plus its own PROV-O leaf alignment from
#        taxonomy/taxonomy.ttl (e.g., top:Document rdfs:subClassOf
#        prov:Entity; top:Log rdfs:subClassOf prov:Collection;
#        top:Person rdfs:subClassOf prov:Person).
#
# WHAT THIS FILE DOES NOT DEFINE:
#
#   - Workflow-extension classes. Clinical research / care delivery /
#     manufacturing / supply chain each live in their own file under
#     their workflow directory. TOP Core must serve every domain;
#     workflow-specific declarations belong in their workflow.
#   - Concrete instances. Walkthroughs (e.g., core/v1/walkthroughs/
#     person.ttl) carry single-instance examples of the pattern.
#   - Record-level metadata properties (creator, created, modified).
#     Per ADR-0013 those use Dublin Core (dcterms:creator,
#     dcterms:created, dcterms:modified) — clearly metadata, distinct
#     from Universal DNA which carries the practitioner shape.
#
# PROV-O ALIGNMENT (per ADR-0013):
#   Strict at the class level. Every category and every leaf with an
#   honest PROV-O peer carries rdfs:subClassOf prov:*. Workflows that
#   need PROV-O domain provenance (prov:wasAttributedTo on Entities,
#   prov:wasAssociatedWith on Activities) attach it directly with
#   proper PROV-O domain semantics. TOP Core does not invent a
#   record-level vs. domain-level fork — record-level metadata uses
#   Dublin Core; domain-level provenance uses PROV-O directly.
#
# BFO ALIGNMENT (per ADR-0013):
#   Light, edge-only — a single rdfs:subClassOf bfo:* for OBO Foundry
#   interop, never a heavy axiom set. Four L2 categories have clean BFO
#   peers and declare them at the category level:
#   Agent → IndependentContinuant, Location → Site, Temporal → Process,
#   Evidence → GenericallyDependentContinuant. Their 15 leaves inherit
#   that peer transitively and add no BFO triple of their own (a more
#   specific tag would be a modeling decision the category does not
#   license; an identical one would be redundant).
#   The other four categories (Resource, Scope, Outcome, Constraint)
#   are mixed-membership: no honest single peer exists at the category,
#   so the edge is declared on each of their 13 leaves:
#     Resource:   System → GenericallyDependentContinuant,
#                 Equipment → MaterialEntity, Material → MaterialEntity
#     Scope:      Portfolio / Program / Project → GenericallyDependentContinuant
#     Outcome:    Observation → GenericallyDependentContinuant,
#                 StatusChange → ProcessBoundary, Artifact → MaterialEntity,
#                 Conclusion → GenericallyDependentContinuant
#     Constraint: PhysicalLimit → Quality, RegulatoryLaw → GDC,
#                 SafetyGuardrail → GDC
#   Net: every one of the 28 leaves resolves to exactly one BFO
#   superclass (15 by inheritance, 13 declared). BFO classes use the
#   readable bfo: local-name convention already established above
#   (bfo:IndependentContinuant, bfo:Site, …); the SKOS view in
#   taxonomy/taxonomy.ttl intentionally carries no BFO crosswalk —
#   BFO lives here, parallel to PROV-O/schema.org living there.

@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl:   <http://www.w3.org/2002/07/owl#> .
@prefix xsd:   <http://www.w3.org/2001/XMLSchema#> .
@prefix sh:    <http://www.w3.org/ns/shacl#> .
@prefix prov:  <http://www.w3.org/ns/prov#> .
@prefix dct:   <http://purl.org/dc/terms/> .
@prefix bfo:   <http://purl.obolibrary.org/obo/bfo#> .

@prefix top:   <https://top.scientix.ai/v1#> .


# ====================================================================
# Ontology declaration
# ====================================================================

<https://top.scientix.ai/core/v1> a owl:Ontology ;
    dct:title "TOP Core — OWL classes and SHACL contract"@en ;
    dct:description "OWL/SHACL view of the SKOS taxonomy at taxonomy/taxonomy.ttl. Defines the root top:CommonEntity, the eight L2 categories, the 28 L3 leaves, the Universal DNA properties, the category relational extensions, and the SHACL UniversalDNAShape that enforces the three required practitioner-grounded properties on every TOP entity."@en ;
    dct:created "2026-05-10"^^xsd:date ;
    dct:license "Apache-2.0" ;
    rdfs:seeAlso <https://top.scientix.ai/v1#TaxonomyV1>,
                 <https://top.scientix.ai/core/v1/index.html>,
                 <https://top.scientix.ai/governance/decision-log.md> .


# ====================================================================
# L0 — Root class
# ====================================================================

top:CommonEntity a owl:Class ;
    rdfs:label "Common Entity"@en ;
    rdfs:comment "The root of every TOP entity. Carries Universal DNA — top:identifier, top:observedAt, top:status — that every Category and every Leaf inherits. Not directly instantiated; serves as the type lattice that lets queries reach across every Category."@en .


# ====================================================================
# Extensibility flavor annotation property (per ADR-0019)
# ====================================================================
# Every Core property declares one of three flavors:
#   "Invariant"   — semantics cannot drift; tightening allowed; redefinition forbidden
#   "Tightenable" — shape stays; downstream consumers may add SHACL constraints
#                   (require what's optional, narrow enums, bind value sets)
#   "Additive"    — designed for downstream addition (extends Core values, no replace)
# The full per-layer extension contract: governance/extension-contract.md
# Linter (forthcoming) enforces the contract at PR time.

top:flavor a owl:AnnotationProperty ;
    rdfs:label "flavor"@en ;
    rdfs:comment "Extensibility flavor per ADR-0019. Permitted values: 'Invariant', 'Tightenable', 'Additive'."@en .


# ====================================================================
# L1 — Universal DNA properties
# ====================================================================
# Three properties every TOP entity carries. Per ADR-0013 (practitioner-
# first), these are the three an operator universally encounters:
# what is this thing, when was it captured, is it current.

top:identifier a owl:DatatypeProperty , owl:FunctionalProperty ;
    rdfs:label "identifier"@en ;
    top:flavor "Invariant" ;
    rdfs:domain top:CommonEntity ;
    rdfs:range xsd:anyURI ;
    rdfs:comment "Globally unique URI / URN. The opaque, durable, system-of-record handle for the entity. Functional: every TOP entity has exactly one."@en .

top:observedAt a owl:DatatypeProperty ;
    rdfs:label "observed at"@en ;
    top:flavor "Invariant" ;
    rdfs:domain top:CommonEntity ;
    rdfs:range xsd:dateTime ;
    rdfs:comment "When the system recorded this entity-version — the transaction-time anchor (per ADR-0021), NGSI-LD-style. Distinct from valid time (top:validFrom / top:validUntil, the second clock, opt-in) and from intrinsic activity times (Temporal.startTime / endTime, domain-level)."@en .

top:status a owl:DatatypeProperty ;
    rdfs:label "status"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:CommonEntity ;
    rdfs:range xsd:string ;
    rdfs:comment "Current lifecycle / health state. Each Category narrows the enum at its layer; leaves narrow further. Universal at this layer because every entity has SOME state and the project-wide status query is operationally meaningful."@en .


# ====================================================================
# L1 SHACL — Universal DNA contract
# ====================================================================
# Enforces the three Universal DNA properties on every top:CommonEntity
# instance. Run with pyshacl --advanced (or equivalent SHACL validator).

top:UniversalDNAShape a sh:NodeShape ;
    rdfs:label "Universal DNA Shape"@en ;
    rdfs:comment "The minimum every TOP entity must carry: a unique identifier, an observation timestamp, and a current status."@en ;
    sh:targetClass top:CommonEntity ;
    sh:property [
        sh:path top:identifier ;
        sh:datatype xsd:anyURI ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "Every TOP entity must carry exactly one top:identifier (xsd:anyURI)." ;
    ] ;
    sh:property [
        sh:path top:observedAt ;
        sh:datatype xsd:dateTime ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "Every TOP entity must carry exactly one top:observedAt (xsd:dateTime)." ;
    ] ;
    sh:property [
        sh:path top:status ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "Every TOP entity must carry exactly one top:status (xsd:string)." ;
    ] .


# ====================================================================
# L2 — Category-Level Object classes (8)
# ====================================================================
# Each rdfs:subClassOf top:CommonEntity (carries Universal DNA) and
# rdfs:subClassOf prov:* (PROV-O class-level alignment per ADR-0013).
# Four carry a light-edge BFO subClassOf for OBO interop; four defer
# BFO to leaf level.

# --- Agent — authority ---

top:Agent a owl:Class ;
    rdfs:label "Agent"@en ;
    rdfs:subClassOf top:CommonEntity, prov:Agent, bfo:IndependentContinuant ;
    rdfs:comment "The entity that holds authority or bears responsibility for what is done: it signs, owns, authorizes, enforces, and can be attributed an action. Persons, Organizations, Groups, Autonomous Agents (software with delegated authority). Capacity to act is not sufficient. A thing that merely acts causally (a pathogen, a compound, a river) is not an Agent unless it can be held to account."@en .

top:hasCredential a owl:ObjectProperty ;
    rdfs:label "has credential"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Agent ;
    rdfs:range top:Credential ;
    rdfs:comment "Links the Agent to their proof of qualification or identity (license, certificate, training record, role assignment). Range pinned to top:Credential (an Evidence leaf) so audit queries follow uniform paths."@en .

top:memberOf a owl:ObjectProperty ;
    rdfs:label "member of"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Agent ;
    rdfs:range top:Agent ;
    rdfs:subPropertyOf prov:actedOnBehalfOf ;
    rdfs:comment "Organizational or group hierarchy the Agent belongs to. PROV-aligned: an Agent acting in their organizational capacity acts on behalf of the parent Agent."@en .

top:authorizedBy a owl:ObjectProperty ;
    rdfs:label "authorized by"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Agent ;
    rdfs:range top:Agent ;
    rdfs:comment "The authority that granted the Agent permission to act in a specific scope. Investigator authorizedBy IRB; contractor authorizedBy Sponsor; device operator authorizedBy QA Lead."@en .


# --- Location — space ---

top:Location a owl:Class ;
    rdfs:label "Location"@en ;
    rdfs:subClassOf top:CommonEntity, prov:Location, bfo:Site ;
    rdfs:comment "The spatial or logical context where an Activity occurs or a Resource resides. Physical (ward, manufacturing floor, depot) or logical (data warehouse, system zone, regulatory jurisdiction)."@en .

top:withinLocation a owl:ObjectProperty , owl:TransitiveProperty ;
    rdfs:label "within location"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Location ;
    rdfs:range top:Location ;
    rdfs:comment "Recursive parent location. Transitive: Room within Building within Campus is queryable as Room within Campus."@en .

top:geoSpatialData a owl:DatatypeProperty ;
    rdfs:label "geo-spatial data"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Location ;
    rdfs:range xsd:string ;
    rdfs:comment "Physical coordinates or digital path. WKT / GeoJSON for physical spaces; structured locator (URI, file path, network address) for logical spaces."@en .

top:accessRequirement a owl:ObjectProperty ;
    rdfs:label "access requirement"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Location ;
    rdfs:range top:Constraint ;
    rdfs:comment "Constraints required to enter this Location (clearance, training prerequisite, escort policy, biosafety level). Modeled via Constraint so authorization-failure events produce uniform Evidence."@en .


# --- Resource — tools ---
# BFO note: Resource is mixed-membership, so the category carries no BFO
# peer; the edge is declared per leaf instead. Equipment is a BFO
# MaterialEntity; System (software) is a GenericallyDependentContinuant;
# Material is a MaterialEntity (the leaf's substances/batches/stocks are
# physical — cf. its schema:Substance peer; a purely digital material
# would be the rare exception, not the rule).

top:Resource a owl:Class ;
    rdfs:label "Resource"@en ;
    rdfs:subClassOf top:CommonEntity, prov:Entity ;
    rdfs:comment "Physical or digital assets used to execute tasks or produce outcomes. Equipment, instruments, software systems, samples, kits, raw materials, consumables."@en .

top:ownedBy a owl:ObjectProperty ;
    rdfs:label "owned by"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Resource ;
    rdfs:range top:Agent ;
    rdfs:comment "The Agent (Person or Organization) that owns / has custody of the Resource. Chain-of-custody anchor."@en .

top:hasMaintenanceLog a owl:ObjectProperty ;
    rdfs:label "has maintenance log"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Resource ;
    rdfs:range top:Log ;
    rdfs:comment "Links the Resource to its history of maintenance / calibration / validation Log. Range pinned to top:Log (an Evidence leaf)."@en .

top:operationalState a owl:DatatypeProperty ;
    rdfs:label "operational state"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Resource ;
    rdfs:range xsd:string ;
    rdfs:comment "Hardware/software-specific readiness beyond top:status. CALIBRATED / DUE_FOR_CALIBRATION / OUT_OF_SERVICE for Equipment; RUNNING / DEGRADED / OFFLINE for System."@en .


# --- Scope — intent ---
# BFO note: Scope is mixed-membership, so the category carries no BFO
# peer; the edge is declared per leaf instead. Portfolio / Program /
# Project are all generically dependent continuants in BFO terms.

top:Scope a owl:Class ;
    rdfs:label "Scope"@en ;
    rdfs:subClassOf top:CommonEntity, prov:Plan ;
    rdfs:comment "The logical boundary, strategic intent, or organizational container for work. Studies, programs, batch records, projects, campaigns, regulatory submissions — anything that groups Activities under a shared 'why'."@en .

top:governedBy a owl:ObjectProperty ;
    rdfs:label "governed by"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Scope ;
    rdfs:range top:Constraint ;
    rdfs:comment "Links the Scope to specific Constraints — regulatory, contractual, safety. The legal frame the Scope operates within."@en .

top:containsActivity a owl:ObjectProperty ;
    rdfs:label "contains activity"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Scope ;
    rdfs:range top:Temporal ;
    rdfs:comment "Links the Scope to the Temporal entities (planned or executed activities) happening within it. Backbone for 'what's in flight under this Scope right now'."@en .

top:objectiveStatement a owl:DatatypeProperty ;
    rdfs:label "objective statement"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Scope ;
    rdfs:range xsd:string ;
    rdfs:comment "High-level description of the strategic 'why'. Operator-grounded — what an investigator, sponsor, or regulator would say this Scope is for."@en .


# --- Temporal — rhythm ---

top:Temporal a owl:Class ;
    rdfs:label "Temporal"@en ;
    rdfs:subClassOf top:CommonEntity, prov:Activity, bfo:Process ;
    rdfs:comment "The time-based dimension of operations. Both plans (schedules, milestones, campaigns) and execution (visits, procedures, batches, shipments)."@en .

top:startTime a owl:DatatypeProperty ;
    rdfs:label "start time"@en ;
    top:flavor "Invariant" ;
    rdfs:domain top:Temporal ;
    rdfs:range xsd:dateTime ;
    rdfs:subPropertyOf prov:startedAtTime ;
    rdfs:comment "Actual or planned start. PROV-aligned to prov:startedAtTime; for plans this is intended start, for executions this is observed start."@en .

top:endTime a owl:DatatypeProperty ;
    rdfs:label "end time"@en ;
    top:flavor "Invariant" ;
    rdfs:domain top:Temporal ;
    rdfs:range xsd:dateTime ;
    rdfs:subPropertyOf prov:endedAtTime ;
    rdfs:comment "Actual or planned end. May be open (null) for ongoing activities."@en .

top:precededBy a owl:ObjectProperty ;
    rdfs:label "preceded by"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Temporal ;
    rdfs:range top:Temporal ;
    rdfs:subPropertyOf prov:wasInformedBy ;
    rdfs:comment "Sequence logic — the Temporal that immediately precedes this one. PROV-aligned: this Temporal was informed by its predecessor."@en .

top:occursAt a owl:ObjectProperty ;
    rdfs:label "occurs at"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Temporal ;
    rdfs:range top:Location ;
    rdfs:subPropertyOf prov:atLocation ;
    rdfs:comment "Where the Temporal happens. PROV-aligned to prov:atLocation."@en .


# --- Evidence — proof ---

top:Evidence a owl:Class ;
    rdfs:label "Evidence"@en ;
    rdfs:subClassOf top:CommonEntity, prov:Entity, bfo:GenericallyDependentContinuant ;
    rdfs:comment "Artifacts that provide verifiable proof of an event, state, or action. Lab reports, signed forms, audit logs, calibration certificates, batch records, MedWatch submissions."@en .

top:verifiesOutcome a owl:ObjectProperty ;
    rdfs:label "verifies outcome"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Evidence ;
    rdfs:range top:Outcome ;
    rdfs:comment "Direct link to the Outcome this Evidence supports. The signed lab report verifies the lab-value Outcome; the calibration certificate verifies the equipment-readiness Outcome."@en .

top:integrityHash a owl:DatatypeProperty ;
    rdfs:label "integrity hash"@en ;
    top:flavor "Invariant" ;
    rdfs:domain top:Evidence ;
    rdfs:range xsd:string ;
    rdfs:comment "Digital fingerprint (SHA-256 or stronger) ensuring non-repudiation. Anchors GxP / 21 CFR Part 11 audit-trail discipline at the Core layer."@en .

top:signedBy a owl:ObjectProperty ;
    rdfs:label "signed by"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Evidence ;
    rdfs:range top:Agent ;
    rdfs:subPropertyOf prov:wasAttributedTo ;
    rdfs:comment "Links the Evidence to the Agent who attested to its truth. E-signature semantics (21 CFR Part 11) and PROV attribution."@en .


# --- Outcome — results ---
# BFO note: Outcome is mixed-membership, so the category carries no BFO
# peer; the edge is declared per leaf instead. Observation is a GDC;
# StatusChange is a ProcessBoundary; Artifact is a MaterialEntity;
# Conclusion is a GDC.

top:Outcome a owl:Class ;
    rdfs:label "Outcome"@en ;
    rdfs:subClassOf top:CommonEntity, prov:Entity ;
    rdfs:comment "Data, state changes, or artifacts produced by a process. Lab values, observations, decisions, batch yields, throughput counts, derived metrics."@en .

top:measuredBy a owl:ObjectProperty ;
    rdfs:label "measured by"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Outcome ;
    rdfs:range top:Resource ;
    rdfs:subPropertyOf prov:wasGeneratedBy ;
    rdfs:comment "Links the Outcome to the Resource (Equipment, System) that captured or produced it. Audit-trail anchor — every measured Outcome traces to its measuring Resource."@en .

top:satisfiesConstraint a owl:ObjectProperty ;
    rdfs:label "satisfies constraint"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Outcome ;
    rdfs:range top:Constraint ;
    rdfs:comment "Links the Outcome to the Constraint(s) it has been validated against. Out-of-range Outcomes surface as the absence of this link to a relevant Constraint."@en .

top:variance a owl:DatatypeProperty ;
    rdfs:label "variance"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Outcome ;
    rdfs:range xsd:string ;
    rdfs:comment "Delta between expected and actual. Format depends on leaf specialization — numeric for measured values, structured for multi-dimensional. Universal at this layer for cross-leaf trend queries."@en .


# --- Constraint — validity ---
# BFO note: Constraint is mixed-membership, so the category carries no
# BFO peer; the edge is declared per leaf instead. PhysicalLimit is a
# Quality; RegulatoryLaw is a GDC; SafetyGuardrail is a GDC.

top:Constraint a owl:Class ;
    rdfs:label "Constraint"@en ;
    rdfs:subClassOf top:CommonEntity, prov:Entity ;
    rdfs:comment "Non-negotiable boundaries — physical, legal, regulatory, contractual, safety. Inclusion criteria, dose limits, regulatory deadlines, blinding rules, biosafety floors, SLAs."@en .

top:enforcedBy a owl:ObjectProperty ;
    rdfs:label "enforced by"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Constraint ;
    rdfs:range top:Agent ;
    rdfs:subPropertyOf prov:wasAssociatedWith ;
    rdfs:comment "Links the Constraint to the Agent responsible for oversight. The IRB enforces the inclusion criterion; the QA Lead enforces the calibration window; the Pharmacist enforces the dose limit."@en .

top:severityLevel a owl:DatatypeProperty ;
    rdfs:label "severity level"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Constraint ;
    rdfs:range xsd:string ;
    rdfs:comment "Operational impact of violation. Universal enum — INFORMATIONAL / MINOR / MAJOR / CRITICAL. Workflow extensions can refine."@en .

top:appliesTo a owl:ObjectProperty ;
    rdfs:label "applies to"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:Constraint ;
    rdfs:range top:CommonEntity ;
    rdfs:comment "Targets of the Constraint. Constraints can scope to Agents, Resources, Scopes, or Temporals; range is top:CommonEntity so the targeting is uniform across Categories. Leaf layer narrows by domain."@en .


# ====================================================================
# Cross-category role bindings (per ADR-0022)
# ====================================================================
# Two role bindings that cut across the eight functional categories.
# Neither mints a type; each attaches a role by relation (per ADR-0002).
# Domain and range are top:CommonEntity because the role is borne by
# different kinds in different contexts — the same Person is an Agent
# when they consent and a subject when they are observed.

top:hasSubject a owl:ObjectProperty ;
    rdfs:label "has subject"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:CommonEntity ;   # typically a Scope (a study) or a Temporal (a procedure)
    rdfs:range top:CommonEntity ;    # the entity the work is about (a Person, or a domain living/molecular kind)
    rdfs:comment "Binds an operation (a Scope such as a study, or a Temporal such as a procedure) to the entity it is performed upon, cares for, or studies: its subject. A role binding, not a type. The same Person is an Agent when they consent and a subject when they are observed; the same virion is a subject in the sequencing lab and a causal participant in an infection. No PROV-O peer (prov:used denotes a tool or consumed entity, not the subject-of-care)."@en .

top:denotes a owl:ObjectProperty ;
    rdfs:label "denotes"@en ;
    top:flavor "Tightenable" ;
    rdfs:domain top:CommonEntity ;   # an information artifact: a Document / Observation
    rdfs:range top:CommonEntity ;    # the entity it stands for
    rdfs:comment "Links a representation (a sequence record, a SMILES string, an identifier) to the entity it stands for. A SMILES string (a top:Document) denotes a molecular entity; the string is data, the molecule is the referent. Semiotic relation, no PROV-O peer (declared absence)."@en .


# ====================================================================
# L3 — Leaf classes (28)
# ====================================================================
# Each rdfs:subClassOf its L2 category (transitively pulling in
# top:CommonEntity + Universal DNA + the category's PROV-O alignment)
# plus its own PROV-O leaf alignment from taxonomy/taxonomy.ttl.
# Leaves under the four mixed-membership categories (Resource, Scope,
# Outcome, Constraint) also carry a light-edge BFO peer here, since
# their category declares none; see the BFO ALIGNMENT note in the
# header for the full leaf → bfo:* map.

# --- Agent leaves (4) ---

top:Person a owl:Class ;
    rdfs:label "Person"@en ;
    rdfs:subClassOf top:Agent, prov:Person ;
    rdfs:comment "An individual human acting in any role across any workflow."@en .

top:Organization a owl:Class ;
    rdfs:label "Organization"@en ;
    rdfs:subClassOf top:Agent, prov:Organization ;
    rdfs:comment "A legal or business entity — corporate parent, operating company, hospital, academic institution, regulator, vendor, sponsor."@en .

top:Group a owl:Class ;
    rdfs:label "Group"@en ;
    rdfs:subClassOf top:Agent, prov:Agent ;
    rdfs:comment "A bounded collective acting with shared purpose and accountability — committee, team, working group, oversight body, panel."@en .

top:AutonomousAgent a owl:Class ;
    rdfs:label "Autonomous Agent"@en ;
    rdfs:subClassOf top:Agent, prov:SoftwareAgent ;
    rdfs:comment "A software entity acting on delegated authority — robotic process, AI agent, automated decision system, scheduler, monitor."@en .

# NOTE (per ADR-0022): top:Organism was removed from Core. Agency is a
# role, not a kind: a living non-human (lab animal, microbe, plant) acts
# causally but bears no accountability, so it cannot inherit the Agent
# authority wiring (signedBy / ownedBy / enforcedBy / hasCredential).
# Biological kinds now live in the domains as rdfs:subClassOf
# top:CommonEntity (e.g. topcr:StudyAnimal); the "who or what the work is
# performed upon" role attaches via top:hasSubject (below). The shared
# "Organism" vocabulary anchor is retained in taxonomy/taxonomy.ttl.


# --- Location leaves (3) ---

top:Physical a owl:Class ;
    rdfs:label "Physical Location"@en ;
    rdfs:subClassOf top:Location, prov:Location ;
    rdfs:comment "A real-world place with geospatial coordinates — building, room, floor, campus, depot, manufacturing line, ward."@en .

top:Virtual a owl:Class ;
    rdfs:label "Virtual Location"@en ;
    rdfs:subClassOf top:Location, prov:Location ;
    rdfs:comment "A logical place addressable via URI / path / network identifier — data warehouse, system zone, application namespace, regulatory jurisdiction (logical, not the physical address of the regulator)."@en .

top:Storage a owl:Class ;
    rdfs:label "Storage Location"@en ;
    rdfs:subClassOf top:Location, prov:Location ;
    rdfs:comment "A place where Resources reside under controlled conditions — biorepository freezer, IP storage, sample archive, document repository, data vault."@en .


# --- Resource leaves (3) ---

top:System a owl:Class ;
    rdfs:label "System"@en ;
    rdfs:subClassOf top:Resource, prov:Entity, bfo:GenericallyDependentContinuant ;
    rdfs:comment "A software or operational system used to execute work — EDC, CTMS, IRT, LIMS, MES, ERP."@en .

top:Equipment a owl:Class ;
    rdfs:label "Equipment"@en ;
    rdfs:subClassOf top:Resource, prov:Entity, bfo:MaterialEntity ;
    rdfs:comment "A physical device used in operations — analyzer, scale, freezer, infusion pump, imaging modality, sequencer, sensor."@en .

top:Material a owl:Class ;
    rdfs:label "Material"@en ;
    rdfs:subClassOf top:Resource, prov:Entity, bfo:MaterialEntity ;
    rdfs:comment "A consumable or substance used or transformed — sample, kit, reagent, raw material, drug substance, dosage unit."@en .


# --- Scope leaves (3) ---

top:Portfolio a owl:Class ;
    rdfs:label "Portfolio"@en ;
    rdfs:subClassOf top:Scope, prov:Plan, bfo:GenericallyDependentContinuant ;
    rdfs:comment "The widest organizational container — a collection of Programs sharing strategic direction, oversight, or funding."@en .

top:Program a owl:Class ;
    rdfs:label "Program"@en ;
    rdfs:subClassOf top:Scope, prov:Plan, bfo:GenericallyDependentContinuant ;
    rdfs:comment "An intermediate container — a coordinated set of Projects sharing therapeutic area, product family, or regulatory pathway."@en .

top:Project a owl:Class ;
    rdfs:label "Project"@en ;
    rdfs:subClassOf top:Scope, prov:Plan, bfo:GenericallyDependentContinuant ;
    rdfs:comment "A bounded body of work with a defined start, end, and objective — a study, a campaign, a batch, a submission, a commissioning effort."@en .


# --- Temporal leaves (4) ---

top:Schedule a owl:Class ;
    rdfs:label "Schedule"@en ;
    rdfs:subClassOf top:Temporal, prov:Activity ;
    rdfs:comment "A planned sequence of activities with intended timing — Schedule of Assessments, manufacturing campaign plan, audit calendar, dosing schedule."@en .

top:Window a owl:Class ;
    rdfs:label "Window"@en ;
    rdfs:subClassOf top:Temporal, prov:Activity ;
    rdfs:comment "A bounded interval within which an activity must occur — visit window, dose window, regulatory submission window, calibration window."@en .

top:Activity a owl:Class ;
    rdfs:label "Activity"@en ;
    rdfs:subClassOf top:Temporal, prov:Activity ;
    rdfs:comment "An executed unit of operational work — a procedure performed, a batch run, a shipment received, a review completed."@en .

top:Milestone a owl:Class ;
    rdfs:label "Milestone"@en ;
    rdfs:subClassOf top:Temporal, prov:Activity ;
    rdfs:comment "A point-in-time marker of significant progress — first-patient-in, last-patient-last-visit, batch release, regulatory approval."@en .


# --- Evidence leaves (4) ---

top:Document a owl:Class ;
    rdfs:label "Document"@en ;
    rdfs:subClassOf top:Evidence, prov:Entity ;
    rdfs:comment "A formal artifact carrying recorded content — protocol, SOP, IB, ICF, CAPA report, batch record, regulatory submission."@en .

top:Log a owl:Class ;
    rdfs:label "Log"@en ;
    rdfs:subClassOf top:Evidence, prov:Collection ;
    rdfs:comment "A time-ordered collection of recorded events — audit log, communication log, calibration log, equipment log, system event log."@en .

top:Attestation a owl:Class ;
    rdfs:label "Attestation"@en ;
    rdfs:subClassOf top:Evidence, prov:Entity ;
    rdfs:comment "A formal declaration by an Agent affirming a fact — signed consent, regulatory attestation, compliance declaration, e-signature on a record."@en .

top:Credential a owl:Class ;
    rdfs:label "Credential"@en ;
    rdfs:subClassOf top:Evidence, prov:Entity ;
    rdfs:comment "Proof of qualification or identity for an Agent — license, certification, training record, role assignment, e-credential."@en .


# --- Outcome leaves (4) ---

top:Observation a owl:Class ;
    rdfs:label "Observation"@en ;
    rdfs:subClassOf top:Outcome, prov:Entity, bfo:GenericallyDependentContinuant ;
    rdfs:comment "A captured data point — vital sign, lab value, sensor reading, qualitative assessment, computed metric."@en .

top:StatusChange a owl:Class ;
    rdfs:label "Status Change"@en ;
    rdfs:subClassOf top:Outcome, prov:Entity, bfo:ProcessBoundary ;
    rdfs:comment "A discrete transition in lifecycle state — enrollment, withdrawal, batch release, IRB approval, record finalization."@en .

top:Artifact a owl:Class ;
    rdfs:label "Artifact"@en ;
    rdfs:subClassOf top:Outcome, prov:Entity, bfo:MaterialEntity ;
    rdfs:comment "A produced object — a manufactured batch unit, a generated dataset, a derived report, a synthesized substance."@en .

top:Conclusion a owl:Class ;
    rdfs:label "Conclusion"@en ;
    rdfs:subClassOf top:Outcome, prov:Entity, bfo:GenericallyDependentContinuant ;
    rdfs:comment "A reasoned determination — adjudication outcome, root-cause finding, regulatory decision, eligibility determination."@en .


# --- Constraint leaves (3) ---

top:PhysicalLimit a owl:Class ;
    rdfs:label "Physical Limit"@en ;
    rdfs:subClassOf top:Constraint, prov:Entity, bfo:Quality ;
    rdfs:comment "A bound rooted in physical reality — temperature range, dose ceiling, pressure limit, mass tolerance, biological viability window."@en .

top:RegulatoryLaw a owl:Class ;
    rdfs:label "Regulatory Law"@en ;
    rdfs:subClassOf top:Constraint, prov:Entity, bfo:GenericallyDependentContinuant ;
    rdfs:comment "A rule rooted in legal or regulatory authority — 21 CFR clause, ICH guideline, EU CTR provision, contractual SLA, jurisdictional reporting requirement."@en .

top:SafetyGuardrail a owl:Class ;
    rdfs:label "Safety Guardrail"@en ;
    rdfs:subClassOf top:Constraint, prov:Entity, bfo:GenericallyDependentContinuant ;
    rdfs:comment "A boundary rooted in safety discipline — biosafety floor, blinding rule, contamination boundary, escalation threshold, stop-rule."@en .


# ====================================================================
# Bitemporal model (per ADR-0021)
# ====================================================================
# Core carries two clocks. TRANSACTION TIME — top:observedAt (above),
# Universal DNA, always required — is when the system recorded an
# entity-version. VALID TIME — top:validFrom / top:validUntil (here) —
# is when that recorded state was true in the world. The two are
# independently queryable ("as we knew it at T1" vs. "as it was true at
# T2").
#
# Valid time is OPT-IN: it attaches to versioned nodes (top:Versioned)
# via top:BitemporalShape and is NOT folded into the always-on
# UniversalDNAShape, so mono-temporal entities stay valid and the
# minimum contract does not move.
#
# Versioning is append-only and PROV-native: a correction mints a new
# immutable top:Versioned node, prov:wasRevisionOf the prior, both
# prov:specializationOf a stable identity, the prior closed with
# prov:invalidatedAtTime. The grain is the attribute-value-at-a-time;
# the composed entity is a prov:Collection assembled at query time.
#
# WHICH values get versioned (ADR-0021 triggering):
#   Tier 1 (here, always-on, enforced): a value carrying top:integrityHash
#     or top:signedBy, or a top:Attestation / top:StatusChange, MUST be a
#     version — you cannot hash or sign a value and then mutate it.
#   Tiers 2-3 (follow-on PRs): propagation along regulated edges, and
#     workflow opt-in per ADR-0019. Default-off otherwise.

top:Versioned a owl:Class ;
    rdfs:label "Versioned"@en ;
    rdfs:comment "Marker for an immutable, bitemporally-tracked value-version — an attribute-value-at-a-time (or whole-entity snapshot) carrying valid time and a stable identity via prov:specializationOf. Applied where Tier-1 entailment fires or where a workflow opts an attribute in. Not every TOP entity is Versioned; only those that need full bitemporal history."@en .

top:validFrom a owl:DatatypeProperty ;
    rdfs:label "valid from"@en ;
    top:flavor "Invariant" ;
    rdfs:domain top:Versioned ;
    rdfs:range xsd:dateTime ;
    rdfs:comment "Start of the valid-time interval — when this version's state became true in the world. Distinct from top:observedAt (transaction time). Invariant per ADR-0019, like top:startTime/top:endTime. No PROV-O peer: PROV models system time, not valid-time-of-a-fact (declared absence, per ADR-0021)."@en .

top:validUntil a owl:DatatypeProperty ;
    rdfs:label "valid until"@en ;
    top:flavor "Invariant" ;
    rdfs:domain top:Versioned ;
    rdfs:range xsd:dateTime ;
    rdfs:comment "End of the valid-time interval; open (absent) for the currently-valid version. Invariant per ADR-0019."@en .


# --- The opt-in bitemporal contract ---
# Requires a valid-time start and a stable identity on a versioned node.
# Invoked directly on top:Versioned instances, and via sh:node from the
# Tier-1 enforcement shapes below.

top:BitemporalShape a sh:NodeShape ;
    rdfs:label "Bitemporal Shape"@en ;
    rdfs:comment "The contract a versioned value satisfies: a valid-time start, an optional (open) valid-time end, and a stable identity via prov:specializationOf. Opt-in — NOT targeted at top:CommonEntity, so it never burdens mono-temporal entities."@en ;
    sh:targetClass top:Versioned ;
    sh:property [
        sh:path top:validFrom ;
        sh:datatype xsd:dateTime ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "A versioned value must state when its state became valid (top:validFrom, exactly one)." ;
    ] ;
    sh:property [
        sh:path top:validUntil ;
        sh:datatype xsd:dateTime ;
        sh:maxCount 1 ;
        sh:message "top:validUntil is open (absent) for the current version, or exactly one xsd:dateTime when closed." ;
    ] ;
    sh:property [
        sh:path prov:specializationOf ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message "A versioned value must point at its stable identity (prov:specializationOf, exactly one)." ;
    ] .


# --- Tier-1 entailment: committed markers force versioning (hard) ---
# Always-on in Core, at sh:Violation. Mechanism is sh:targetSubjectsOf /
# sh:targetClass -> sh:node top:BitemporalShape; SHACL Core, no SPARQL.

top:HashedMustVersionShape a sh:NodeShape ;
    rdfs:label "Hashed values must be versioned"@en ;
    sh:targetSubjectsOf top:integrityHash ;
    sh:severity sh:Violation ;
    sh:node top:BitemporalShape ;
    sh:message "A value carrying top:integrityHash must be an immutable version (top:Versioned: top:validFrom + prov:specializationOf). You cannot hash a value and leave it mutable." .

top:SignedMustVersionShape a sh:NodeShape ;
    rdfs:label "Signed values must be versioned"@en ;
    sh:targetSubjectsOf top:signedBy ;
    sh:severity sh:Violation ;
    sh:node top:BitemporalShape ;
    sh:message "A value carrying top:signedBy must be an immutable version. You cannot sign a value and leave it mutable." .

top:AttestationMustVersionShape a sh:NodeShape ;
    rdfs:label "Attestations must be versioned"@en ;
    sh:targetClass top:Attestation ;
    sh:severity sh:Violation ;
    sh:node top:BitemporalShape ;
    sh:message "A top:Attestation is a committed, signed declaration and must be an immutable version." .

top:StatusChangeMustVersionShape a sh:NodeShape ;
    rdfs:label "Status changes must be versioned"@en ;
    sh:targetClass top:StatusChange ;
    sh:severity sh:Violation ;
    sh:node top:BitemporalShape ;
    sh:message "A top:StatusChange is the audit event of a transition and must be an immutable version." .


# --- Tier-1 lifecycle calibration: in-progress evidence warns (soft) ---
# A draft Document/Log/Credential is legitimately mutable until it is
# committed; warn (not fail) until it carries a valid-time start. Once
# hashed or signed, the hard shapes above take over at sh:Violation.
# Direct property check (not sh:node) so the result stays at Warning.

top:EvidenceShouldVersionShape a sh:NodeShape ;
    rdfs:label "Evidence should be versioned once committed"@en ;
    sh:targetClass top:Document, top:Log, top:Credential ;
    sh:property [
        sh:path top:validFrom ;
        sh:minCount 1 ;
        sh:severity sh:Warning ;
        sh:message "This evidentiary value is not yet a version. Drafts may stay mutable; once finalized (and certainly once hashed or signed) it must be versioned (top:Versioned with top:validFrom)." ;
    ] .


# === End of TOP Core OWL/SHACL ===
