SponsorShape
type: NodeShape
target class: Sponsor
name: Sponsor
description: A Sponsor is an entity responsible for some aspect of a clinical trial: initiation, regulatory accountability, financing, or operational conduct. A study has at least one sponsor of record, who carries regulatory responsibility, and may have additional Sponsor entities for operational delegation (a CRO acting as proxy), financial backing (an academic medical center on an investigator-initiated trial), or co-sponsorship. The Sponsor entity is what the site, the study team, and the regulator interact with day to day. Corporate identity and parent/child structure live on the linked Organization.
property:
  path: sponsorId
  datatype: anyURI
  min count: 1
  max count: 1
  description: Globally unique NGSI-LD identifier.
  name: sponsorId
property:
  path: sponsorName
  datatype: string
  min count: 1
  max count: 1
  description: Display name.
  name: sponsorName
property:
  path: legalName
  datatype: string
  min count: 1
  max count: 1
  description: Registered legal name.
  name: legalName
property:
  path: sponsorType
  datatype: string
  min count: 1
  max count: 1
  in: PHARMACEUTICAL
  in: BIOTECH
  in: ACADEMIC
  in: GOVERNMENT
  in: INVESTIGATOR_SPONSOR
  in: CRO_AS_SPONSOR
  in: OTHER
  description: Sponsor type taxonomy. CRO_AS_SPONSOR covers CROs acting as legal sponsor. INVESTIGATOR_SPONSOR covers academic single-PI sponsorship.
  name: sponsorType
property:
  path: duns
  datatype: string
  min count: 0
  max count: 1
  description: Dun & Bradstreet DUNS number.
  name: duns
property:
  path: orcid
  datatype: string
  min count: 0
  max count: 1
  description: ORCID identifier when sponsor is an individual investigator-sponsor.
  name: orcid
property:
  path: address
  min count: 1
  max count: 1
  description: Headquarters address (line1, line2, city, region, postalCode).
  name: address
property:
  path: country
  datatype: string
  min count: 1
  max count: 1
  description: ISO 3166-1 alpha-3 country code of registration.
  name: country
property:
  path: phone
  datatype: string
  min count: 1
  max count: 1
  description: Primary phone.
  name: phone
property:
  path: email
  datatype: string
  min count: 1
  max count: 1
  description: Primary email.
  name: email
property:
  path: website
  datatype: anyURI
  min count: 1
  max count: 1
  description: Sponsor website.
  name: website
property:
  path: status
  datatype: string
  min count: 1
  max count: 1
  in: ACTIVE
  in: INACTIVE
  in: MERGED
  in: ACQUIRED
  description: Lifecycle state.
  name: status
property:
  path: isSponsorOfRecord
  datatype: boolean
  min count: 1
  max count: 1
  description: True if this Sponsor entity holds regulatory accountability per 21 CFR 312 (or equivalent in other jurisdictions). Exactly one Sponsor entity per (Study × RegulatoryAuthorityScope) carries this flag set true; SHACL constraint enforces the rule per jurisdiction.
  name: isSponsorOfRecord
property:
  path: hasRegulatoryResponsibility
  datatype: boolean
  min count: 1
  max count: 1
  description: True if this Sponsor entity carries regulatory accountability for the Study. Often the same as isSponsorOfRecord but separated for the rare case where regulatory submission is delegated without transfer of legal sponsor-of-record status.
  name: hasRegulatoryResponsibility
property:
  path: hasFinancialResponsibility
  datatype: boolean
  min count: 1
  max count: 1
  description: True if this Sponsor entity provides funding for the Study. Distinct from sponsor-of-record: an academic medical center may be the financial sponsor while a PI is the legal sponsor of an IIT.
  name: hasFinancialResponsibility
property:
  path: hasOperationalResponsibility
  datatype: boolean
  min count: 1
  max count: 1
  description: True if this Sponsor entity manages day-to-day operational conduct of the Study. Most common case where a CRO acts as proxy for the sponsor of record.
  name: hasOperationalResponsibility
property:
  path: isInitiator
  datatype: boolean
  min count: 1
  max count: 1
  description: True if this Sponsor entity initiated the Study (the entity that triggered the trial). Often the same as the financial sponsor for IITs; often the same as sponsor of record for industry-sponsored trials.
  name: isInitiator
property:
  path: validFrom
  datatype: dateTime
  min count: 0
  max count: 1
  description: Datetime from which this Sponsor relationship is operationally valid. Empty for the initial Sponsor record on a Study. Populated when sponsor transfers occur (M&A, divestiture, asset sale). Uses NGSI-LD's validFrom temporal property semantics.
  name: validFrom
property:
  path: validUntil
  datatype: dateTime
  min count: 0
  max count: 1
  description: Datetime through which this Sponsor relationship was operationally valid. Empty for currently-active Sponsor records. Populated when this Sponsor record is superseded by a new one (M&A transfer, sponsor handoff). Acquiring entities in M&A often do not move all studies at once; the temporal bounds are how this gets modeled honestly.
  name: validUntil
property:
  path: primaryTherapeuticArea
  datatype: string
  min count: 0
  max count: 1
  description: The therapeutic area this Sponsor entity's role on this Study is focused on (oncology, cardiology, infectious disease, rare disease, etc.). Per-Study lens: the Sponsor entity's TA focus for this specific Study, which may be a single area even when the parent Organization's portfolio spans many. The corporate TA spread lives on Organization.primaryTherapeuticAreas. Optional because not every Study has a single dominant TA (basket trials, platform trials).
  name: primaryTherapeuticArea
property:
  path: belongsToOrganization
  class: Organization
  min count: 1
  max count: 1
  node kind: IRI
  description: The Organization (corporate / legal entity) this Sponsor entity is backed by. USDM models Sponsor as a type on Organization; TOP keeps Sponsor as an operator-grade top-level and uses this relationship to anchor it to the corporate truth. J&J Innovative Medicine (Sponsor) → belongsToOrganization → Organization{name: 'J&J Innovative Medicine', parentOrganization: J&J}.
  name: belongsToOrganization
property:
  path: actsOnBehalfOf
  class: Sponsor
  min count: 0
  max count: 1
  node kind: IRI
  description: Self-ref: this Sponsor entity acts as proxy for another Sponsor entity (typically a CRO operational sponsor pointing to the sponsor of record). Empty when this Sponsor is itself the principal. The IQVIA-Sponsor entity that operationally runs Pfizer's Study X has actsOnBehalfOf → Pfizer-Sponsor entity. Distinct from parentSponsor: actsOnBehalfOf is operational delegation, parentSponsor is structural lineage.
  name: actsOnBehalfOf
property:
  path: parentSponsor
  class: Sponsor
  min count: 0
  max count: 1
  node kind: IRI
  description: Self-ref: this Sponsor entity has a structural parent Sponsor entity. Use only when the per-Org-per-Study lineage is meaningfully different from what Organization.parentOrganization expresses. Three operational cases: (1) M&A successor lineage, where Sponsor B supersedes Sponsor A on the same Study after corporate transfer, B.parentSponsor → A captures the lineage handoff alongside validFrom/validUntil. (2) Lead/co-sponsor in co-development, where the co-sponsor entity points at the lead-sponsor entity. (3) EU CTR Article 74 legal representatives, where a non-EU principal Sponsor designates an EU Sponsor entity as their legal rep, with the EU rep's parentSponsor → principal. Distinct from belongsToOrganization (corporate identity) and actsOnBehalfOf (operational proxy).
  name: parentSponsor
property:
  path: regulatoryAuthorityScope
  min count: 0
  node kind: IRI
  description: Regulatory authorities this Sponsor entity is the sponsor of record under. Used for multi-jurisdictional studies where different legal entities act as sponsor of record in different jurisdictions (Pfizer Inc under FDA, Pfizer Ireland under EMA, on the same trial). Empty for single-jurisdiction studies; the SHACL 'exactly one sponsor of record per Study' constraint relaxes to per-jurisdiction.
  comment: TARGET-MISSING: RegulatoryAuthority is a flagged-missing object in OOUX v0.2 (#60).
  name: regulatoryAuthorityScope
property:
  path: runs
  class: Study
  min count: 1
  max count: 1
  node kind: IRI
  description: The Study this Sponsor entity is scoped to. Each Sponsor entity is per-Organization-per-Study. A company that sponsors many studies has many Sponsor entities, one per study, all linked through belongsToOrganization to the same Organization. The enterprise-level 'all studies Pfizer sponsors' view is served from Organization.playsSponsorRole, not from a single Sponsor entity.
  name: runs
property:
  path: employs
  class: Person
  min count: 0
  node kind: IRI
  description: Employees and contractors. 0..N at the per-Study Sponsor scope: a Sponsor record may be created before staffing assignments are linked. Enterprise-level employee counts roll up via Organization.
  name: employs

StudyShape
type: NodeShape
target class: Study
name: Study
description: A Study is a research project intended to evaluate the effects of an intervention (interventional), to characterize a population or natural history (observational), or to provide expanded access to an investigational product. The Study entity is the central organizing concept of the clinical-trials reference graph: every other top-level relates to Study somehow. Study is reached upstream from Sponsor (via Sponsor.runs, 1..1) and from StudySite (via StudySite.forStudy, 1..1). Study itself owns the definition-side chain (Protocol, Arms, Schedule of Assessments, Endpoints, Inclusion/Exclusion Criteria) as sub-objects. Operational facts (per-Site participation, per-Participant data, per-Visit-occurrence events) are reached through StudySite, Participant, and Visit-occurrence — not as direct edges on Study, per the direct-vs-traversed discipline established in the Site spec.
property:
  path: studyId
  datatype: anyURI
  min count: 1
  max count: 1
  description: Globally unique NGSI-LD identifier.
  name: studyId
property:
  path: sponsorProtocolId
  datatype: string
  min count: 1
  max count: 1
  description: Sponsor's internal protocol identifier (e.g., 'ONCO-423-001'). Distinct from registry IDs (NCT, EudraCT).
  name: sponsorProtocolId
property:
  path: studyTitle
  datatype: string
  min count: 0
  max count: 1
  description: Official long title of the study (e.g., 'A Phase 3 Randomized Double-Blind Placebo-Controlled Study of Drug X in Patients with Advanced Non-Small Cell Lung Cancer'). Optional at strawman; required when Study is registered with ClinicalTrials.gov / EU CTIS.
  name: studyTitle
property:
  path: studyShortTitle
  datatype: string
  min count: 0
  max count: 1
  description: Operator-friendly short title used in dashboards and conversation.
  name: studyShortTitle
property:
  path: studyAcronym
  datatype: string
  min count: 0
  max count: 1
  description: Single-token acronym (e.g., 'ONCO-423').
  name: studyAcronym
property:
  path: studyDescription
  datatype: string
  min count: 0
  max count: 1
  description: Narrative description of the study's purpose and design.
  name: studyDescription
property:
  path: studyType
  datatype: string
  min count: 0
  max count: 1
  in: INTERVENTIONAL
  in: OBSERVATIONAL
  in: EXPANDED_ACCESS
  in: PATIENT_REGISTRY
  description: Study category. Optional at strawman to accommodate PLANNED-state Studies. Aligned with ClinicalTrials.gov StudyType and USDM StudyDesign.studyType.
  name: studyType
property:
  path: studyPhase
  datatype: string
  min count: 0
  max count: 1
  in: PHASE_0
  in: PHASE_1
  in: PHASE_1_2
  in: PHASE_2
  in: PHASE_2_3
  in: PHASE_3
  in: PHASE_4
  in: NOT_APPLICABLE
  description: Trial phase per ICH E8 / ClinicalTrials.gov / USDM. NOT_APPLICABLE for observational and registry studies.
  name: studyPhase
property:
  path: interventionModel
  datatype: string
  min count: 0
  max count: 1
  in: SINGLE_GROUP
  in: PARALLEL
  in: CROSSOVER
  in: FACTORIAL
  in: SEQUENTIAL
  description: ClinicalTrials.gov interventional model assignment.
  name: interventionModel
property:
  path: allocation
  datatype: string
  min count: 0
  max count: 1
  in: RANDOMIZED
  in: NON_RANDOMIZED
  in: NOT_APPLICABLE
  description: Allocation model per ClinicalTrials.gov / ICH E8.
  name: allocation
property:
  path: masking
  datatype: string
  min count: 0
  max count: 1
  in: OPEN_LABEL
  in: SINGLE_BLIND
  in: DOUBLE_BLIND
  in: TRIPLE_BLIND
  in: QUADRUPLE_BLIND
  description: Blinding/masking level. Aligned with ClinicalTrials.gov Masking and USDM.
  name: masking
property:
  path: primaryPurpose
  datatype: string
  min count: 0
  max count: 1
  in: TREATMENT
  in: PREVENTION
  in: DIAGNOSTIC
  in: SUPPORTIVE_CARE
  in: SCREENING
  in: HEALTH_SERVICES_RESEARCH
  in: BASIC_SCIENCE
  in: DEVICE_FEASIBILITY
  in: OTHER
  description: ClinicalTrials.gov primary purpose classification.
  name: primaryPurpose
property:
  path: studyStatus
  datatype: string
  min count: 1
  max count: 1
  in: PLANNED
  in: RECRUITING
  in: ENROLLING_BY_INVITATION
  in: ACTIVE_NOT_RECRUITING
  in: COMPLETED
  in: SUSPENDED
  in: TERMINATED
  in: WITHDRAWN
  in: UNKNOWN_STATUS
  description: Lifecycle state. Aligned with ClinicalTrials.gov OverallStatus and FHIR ResearchStudy.status. Distinct from per-StudySite status (which lives on StudySite.studySiteStatus).
  name: studyStatus
property:
  path: conditionStudied
  datatype: string
  min count: 0
  max count: 1
  description: Primary condition or disease being studied (e.g., 'Advanced Non-Small Cell Lung Cancer'). Free text or SNOMED-coded; comma-separated for multiple conditions.
  name: conditionStudied
property:
  path: therapeuticArea
  datatype: string
  min count: 0
  max count: 1
  description: Therapeutic area classification (e.g., ONCOLOGY, CARDIOLOGY, NEUROLOGY, IMMUNOLOGY). Per-Study TA; corporate-portfolio TA spread lives on the linked Sponsor's Organization.
  name: therapeuticArea
property:
  path: targetEnrollment
  datatype: integer
  min count: 0
  max count: 1
  description: Target enrollment across all sites for the entire study. Aggregate; per-StudySite enrollment targets live on StudySite.enrollmentTarget.
  name: targetEnrollment
property:
  path: actualEnrollment
  datatype: integer
  min count: 0
  max count: 1
  description: Current actual enrollment across all sites. Aggregate; computable as SUM over StudySite.actualEnrollment but stored for view-speed.
  name: actualEnrollment
property:
  path: enrollmentType
  datatype: string
  min count: 0
  max count: 1
  in: ANTICIPATED
  in: ACTUAL
  description: Whether targetEnrollment is anticipated or actual. Aligned with ClinicalTrials.gov EnrollmentType.
  name: enrollmentType
property:
  path: minAge
  datatype: string
  min count: 0
  max count: 1
  description: Minimum age for participant eligibility (e.g., '18 Years', '6 Months'). String to preserve unit.
  name: minAge
property:
  path: maxAge
  datatype: string
  min count: 0
  max count: 1
  description: Maximum age for participant eligibility.
  name: maxAge
property:
  path: sexEligibility
  datatype: string
  min count: 0
  max count: 1
  in: ALL
  in: MALE
  in: FEMALE
  description: Sex eligibility per ClinicalTrials.gov.
  name: sexEligibility
property:
  path: acceptsHealthyVolunteers
  datatype: boolean
  min count: 0
  max count: 1
  description: Whether the study accepts healthy volunteers.
  name: acceptsHealthyVolunteers

ProtocolShape
type: NodeShape
target class: Protocol
name: Protocol
description: The Protocol is the formal document defining the study's design, methodology, statistical plan, and conduct procedures. Sub-object of Study. Protocol amendments are tracked via Study.hasAmendment; this Protocol points at the current effective version.
property:
  path: protocolId
  datatype: anyURI
  min count: 1
  max count: 1
  name: protocolId
property:
  path: protocolNumber
  datatype: string
  min count: 0
  max count: 1
  description: Sponsor's protocol identifier (often duplicates Study.sponsorProtocolId; kept distinct because the protocol-as-document has its own identity separate from the Study-as-trial).
  name: protocolNumber
property:
  path: protocolTitle
  datatype: string
  min count: 0
  max count: 1
  description: Protocol document title (often duplicates Study.studyTitle for consistency, but kept as separate field for cases where the document title differs).
  name: protocolTitle
property:
  path: protocolVersion
  datatype: string
  min count: 1
  max count: 1
  description: Semver-style version (e.g., '3.0.0', '3.2.1'). Each amendment increments.
  name: protocolVersion
property:
  path: protocolStatus
  datatype: string
  min count: 1
  max count: 1
  in: DRAFT
  in: IN_REVIEW
  in: APPROVED
  in: EFFECTIVE
  in: AMENDED
  in: SUPERSEDED
  in: RETIRED
  description: Lifecycle state. EFFECTIVE means currently in force; AMENDED means a successor version exists; SUPERSEDED means replaced; RETIRED means Study closed and Protocol archived.
  name: protocolStatus
property:
  path: approvalDate
  datatype: date
  min count: 0
  max count: 1
  description: Date of regulatory or IRB approval of this Protocol version.
  name: approvalDate
property:
  path: effectiveDate
  datatype: date
  min count: 0
  max count: 1
  description: Date this Protocol version became effective at sites.
  name: effectiveDate
property:
  path: protocolDocumentRef
  datatype: anyURI
  min count: 0
  max count: 1
  description: URI of the actual Protocol PDF (typically in eTMF). Distinct from the JSON-LD/RDF representation.
  name: protocolDocumentRef
property:
  path: ddfDocumentRef
  datatype: anyURI
  min count: 0
  max count: 1
  description: URI of the USDM Digital Definition Format JSON document (machine-readable protocol). Aligned with USDM v3 DDF deliverable.
  name: ddfDocumentRef
property:
  path: studyDesignRationale
  datatype: string
  min count: 0
  max count: 1
  description: Narrative rationale for the chosen study design. Aligned with USDM StudyDesign.rationale.
  name: studyDesignRationale

ArmShape
type: NodeShape
target class: Arm
name: Arm
description: An Arm is a group of Participants who receive a specific intervention (or no intervention) per the protocol. Sub-object of Study. Single-arm studies have one Arm; multi-arm studies (parallel, crossover, factorial) have multiple. Each Participant is assigned to exactly one Arm at randomization (or is unassigned in pre-randomization phases).
property:
  path: armId
  datatype: anyURI
  min count: 1
  max count: 1
  name: armId
property:
  path: armName
  datatype: string
  min count: 1
  max count: 1
  description: Display name (e.g., 'Drug X 200mg', 'Standard of Care', 'Placebo').
  name: armName
property:
  path: armShortName
  datatype: string
  min count: 0
  max count: 1
  description: Abbreviated label for charts and dashboards.
  name: armShortName
property:
  path: armType
  datatype: string
  min count: 1
  max count: 1
  in: EXPERIMENTAL
  in: ACTIVE_COMPARATOR
  in: PLACEBO_COMPARATOR
  in: NO_INTERVENTION
  in: SHAM_COMPARATOR
  in: OTHER
  description: Arm type per ClinicalTrials.gov ArmType.
  name: armType
property:
  path: armDescription
  datatype: string
  min count: 0
  max count: 1
  description: Narrative description of what participants in this arm receive.
  name: armDescription
property:
  path: armSize
  datatype: integer
  min count: 0
  max count: 1
  description: Planned number of Participants for this arm.
  name: armSize
property:
  path: interventionDescription
  datatype: string
  min count: 0
  max count: 1
  description: One-line summary of the intervention (e.g., 'Drug X 200mg PO QD for 12 weeks').
  name: interventionDescription
property:
  path: isPlaceboArm
  datatype: boolean
  min count: 0
  max count: 1
  name: isPlaceboArm
property:
  path: isControlArm
  datatype: boolean
  min count: 0
  max count: 1
  description: True if this arm serves as the control (placebo, active comparator, or no-intervention).
  name: isControlArm

ScheduleOfAssessmentsShape
type: NodeShape
target class: ScheduleOfAssessments
name: ScheduleOfAssessments
description: The Schedule of Assessments (SOA) defines the visit-by-procedure matrix for the study: which procedures, assessments, samples, and data collections happen at which protocol-defined visit. Sub-object of Study. The SOA anchors the Visit-template chain: each row is a procedure or assessment; each column is a Visit-template. The cell at (procedure, visit) tells the operator whether that procedure is performed at that visit.
property:
  path: soaId
  datatype: anyURI
  min count: 1
  max count: 1
  name: soaId
property:
  path: soaName
  datatype: string
  min count: 1
  max count: 1
  description: Display name (e.g., 'ONCO-423 Schedule of Assessments v3.0').
  name: soaName
property:
  path: soaVersion
  datatype: string
  min count: 1
  max count: 1
  description: Version identifier; tracks alongside Protocol version through amendments.
  name: soaVersion
property:
  path: soaStatus
  datatype: string
  min count: 1
  max count: 1
  in: DRAFT
  in: APPROVED
  in: EFFECTIVE
  in: SUPERSEDED
  description: Lifecycle state. EFFECTIVE means currently in force at activated sites.
  name: soaStatus
property:
  path: approvalDate
  datatype: date
  min count: 0
  max count: 1
  name: approvalDate
property:
  path: effectiveDate
  datatype: date
  min count: 0
  max count: 1
  name: effectiveDate
property:
  path: soaDocumentRef
  datatype: anyURI
  min count: 0
  max count: 1
  description: URI of the SOA artifact (typically a table embedded in the Protocol PDF or a separate Excel/PDF file).
  name: soaDocumentRef
property:
  path: description
  datatype: string
  min count: 0
  max count: 1
  description: Narrative description; useful when the SOA covers complex multi-arm or crossover designs.
  name: description

EndpointShape
type: NodeShape
target class: Endpoint
name: Endpoint
description: An Endpoint is a measurable outcome used to evaluate the study's intervention or natural history. Sub-object of Study. Endpoints are categorized as PRIMARY (the main outcome the study is powered to detect), SECONDARY (additional pre-specified outcomes), EXPLORATORY (hypothesis-generating), or SAFETY (adverse event-driven). Each endpoint has a measurement type, a time frame, and an associated statistical approach.
property:
  path: endpointId
  datatype: anyURI
  min count: 1
  max count: 1
  name: endpointId
property:
  path: endpointName
  datatype: string
  min count: 1
  max count: 1
  description: Short name for dashboards (e.g., 'Overall Survival', 'PFS at 12 months', 'C-max').
  name: endpointName
property:
  path: endpointDescription
  datatype: string
  min count: 1
  max count: 1
  description: Full text definition of the endpoint, including how it is measured and at what time points.
  name: endpointDescription
property:
  path: endpointType
  datatype: string
  min count: 1
  max count: 1
  in: PRIMARY
  in: SECONDARY
  in: EXPLORATORY
  in: SAFETY
  description: Endpoint category.
  name: endpointType
property:
  path: endpointMeasurementType
  datatype: string
  min count: 0
  max count: 1
  in: BINARY
  in: CONTINUOUS
  in: ORDINAL
  in: TIME_TO_EVENT
  in: COUNT
  in: RATE
  in: OTHER
  description: Statistical type of the measurement.
  name: endpointMeasurementType
property:
  path: measurementUnit
  datatype: string
  min count: 0
  max count: 1
  description: Unit of measurement (e.g., 'months', 'mg/dL', '%').
  name: measurementUnit
property:
  path: timeFrame
  datatype: string
  min count: 0
  max count: 1
  description: Time window over which the endpoint is assessed (e.g., 'Up to 24 weeks', 'From randomization to death from any cause').
  name: timeFrame
property:
  path: statisticalApproach
  datatype: string
  min count: 0
  max count: 1
  description: Statistical method used to analyze this endpoint (e.g., 'Cox proportional hazards model', 'Kaplan-Meier survival analysis', 'Mixed-effects model for repeated measures').
  name: statisticalApproach

InclusionCriterionShape
type: NodeShape
target class: InclusionCriterion
name: InclusionCriterion
description: An InclusionCriterion is a specific characteristic that potential Participants must have to be eligible for the Study. Sub-object of Study. Eligibility is determined per-Participant during screening; failed inclusion criteria result in screen failure.
property:
  path: criterionId
  datatype: anyURI
  min count: 1
  max count: 1
  name: criterionId
property:
  path: criterionNumber
  datatype: string
  min count: 1
  max count: 1
  description: Display number/code (e.g., 'I1', 'I2', '1.a'). Operator-readable identifier within the protocol.
  name: criterionNumber
property:
  path: criterionText
  datatype: string
  min count: 1
  max count: 1
  description: Full text of the criterion as written in the Protocol.
  name: criterionText
property:
  path: criterionCategory
  datatype: string
  min count: 0
  max count: 1
  in: AGE
  in: SEX
  in: DIAGNOSIS
  in: DISEASE_STAGE
  in: LAB_VALUES
  in: MEDICAL_HISTORY
  in: PRIOR_TREATMENT
  in: MEDICATIONS
  in: PERFORMANCE_STATUS
  in: GENETIC
  in: OTHER
  description: Categorization for SFQ-style filtering and feasibility analysis.
  name: criterionCategory
property:
  path: waiverAllowed
  datatype: boolean
  min count: 0
  max count: 1
  description: Whether deviations from this criterion are allowed via medical monitor approval (most criteria do NOT allow waivers).
  name: waiverAllowed
property:
  path: waiverConditions
  datatype: string
  min count: 0
  max count: 1
  description: Conditions under which a waiver may be granted (if waiverAllowed=true).
  name: waiverConditions

ExclusionCriterionShape
type: NodeShape
target class: ExclusionCriterion
name: ExclusionCriterion
description: An ExclusionCriterion is a specific characteristic that disqualifies potential Participants from the Study. Sub-object of Study. A Participant who meets ANY exclusion criterion is ineligible.
property:
  path: criterionId
  datatype: anyURI
  min count: 1
  max count: 1
  name: criterionId
property:
  path: criterionNumber
  datatype: string
  min count: 1
  max count: 1
  description: Display number/code (e.g., 'E1', 'E2', '2.b').
  name: criterionNumber
property:
  path: criterionText
  datatype: string
  min count: 1
  max count: 1
  description: Full text of the criterion.
  name: criterionText
property:
  path: criterionCategory
  datatype: string
  min count: 0
  max count: 1
  in: AGE
  in: SEX
  in: DIAGNOSIS
  in: DISEASE_STAGE
  in: LAB_VALUES
  in: MEDICAL_HISTORY
  in: PRIOR_TREATMENT
  in: MEDICATIONS
  in: PERFORMANCE_STATUS
  in: GENETIC
  in: PREGNANCY
  in: OTHER
  description: Categorization. PREGNANCY appears in exclusion category list because pregnancy/lactation is a near-universal exclusion in interventional studies but rarely an inclusion criterion.
  name: criterionCategory
property:
  path: waiverAllowed
  datatype: boolean
  min count: 0
  max count: 1
  description: Whether deviations from this criterion are allowed via medical monitor approval.
  name: waiverAllowed
property:
  path: waiverConditions
  datatype: string
  min count: 0
  max count: 1
  name: waiverConditions

VisitDefinitionShape
type: NodeShape
target class: VisitDefinition
name: VisitDefinition
description: VisitDefinition captures what the protocol says happens at a given visit (template-side). It carries the visit window, expected duration, day-relative-to-anchor scheduling, and references to ActivityTemplates that should be performed. Distinct from Visit (the operational occurrence). USDM-ingest-derivable from StudyDesign.encounters[]; the operational-side Visit is created by EDC/scheduling/eVisit systems at runtime.
property:
  path: visitDefinitionId
  datatype: anyURI
  min count: 1
  max count: 1
  description: Globally unique NGSI-LD identifier. Mints from USDM Encounter.id under the urn:top:study:{usdm_study_id}/visit-definition:{usdm_encounter_id} URI policy.
  name: visitDefinitionId
property:
  path: visitNumber
  datatype: string
  min count: 1
  max count: 1
  description: Display number/code (e.g., 'V1', 'Visit 4', 'Day 28'). Operator-readable identifier within the protocol.
  name: visitNumber
property:
  path: visitName
  datatype: string
  min count: 1
  max count: 1
  description: Operator-friendly name (e.g., 'Screening Visit', 'Baseline / Day 1', 'End of Treatment').
  name: visitName
property:
  path: visitDay
  datatype: integer
  min count: 0
  max count: 1
  description: Days from study anchor (typically randomization or first dose). Negative for screening (Day -7), 0 for baseline, positive for follow-up. Maps to SDTM VISITDY.
  name: visitDay
property:
  path: visitWindowMinDays
  datatype: integer
  min count: 0
  max count: 1
  description: Minimum days from visitDay the visit can occur and still be in-window. Negative offset (e.g., -3 means 'up to 3 days early').
  name: visitWindowMinDays
property:
  path: visitWindowMaxDays
  datatype: integer
  min count: 0
  max count: 1
  description: Maximum days from visitDay the visit can occur and still be in-window. Positive offset (e.g., +3 means 'up to 3 days late').
  name: visitWindowMaxDays
property:
  path: expectedDurationMinutes
  datatype: integer
  min count: 0
  max count: 1
  description: Expected duration of the visit in minutes (operational scheduling input).
  name: expectedDurationMinutes
property:
  path: description
  datatype: string
  min count: 0
  max count: 1
  description: Narrative description. Useful when the visit's purpose isn't obvious from name + day.
  name: description
property:
  path: visitDefinitionStatus
  datatype: string
  min count: 1
  max count: 1
  in: DRAFT
  in: EFFECTIVE
  in: SUPERSEDED
  description: Lifecycle of the template. EFFECTIVE means currently in force; SUPERSEDED if a protocol amendment introduced a new VisitDefinition. NGSI-LD temporal property.
  name: visitDefinitionStatus
property:
  path: tags
  datatype: string
  min count: 0
  max count: 1
  description: Comma-separated user-defined tags.
  name: tags
property:
  path: appearsInSchedule
  class: ScheduleOfAssessments
  min count: 0
  node kind: IRI
  description: The Schedule(s) of Assessments this VisitDefinition appears in. 0..N because protocol amendments can reference the same VisitDefinition across multiple SOA versions.
  name: appearsInSchedule
property:
  path: hasExpectedActivityTemplate
  min count: 0
  node kind: IRI
  description: ActivityTemplates expected at this visit per the SOA. Flagged-missing for now: ActivityTemplate as a separate entity defers to v0.6+; v0.5 carries this as a forward reference for future lift.
  comment: TARGET-MISSING: ActivityTemplate is a v0.6+ entity; for v0.5 the SOA grid is referenced indirectly via this relationship. Visit-occurrences carry runtime Activity sub-objects directly.
  name: hasExpectedActivityTemplate

SiteShape
type: NodeShape
target class: Site
name: Site
description: A Site is the location or set of locations where trial-related activities are conducted and/or coordinated under the investigator's/institution's oversight (ICH E6(R3) Annex 1 Section 2). Site captures the operational reality and stable feasibility profile of a research site. Per-Study facts (siteNumber, enrollmentTarget, IRB approval status, oversight tier, per-Study staff delegation, per-Study Systems and Contracts) live on the StudySite horizontal, which captures Site's role on a specific Study. Site itself is study-independent: a Site exists with its staff, equipment, IRB-of-record default, qualifications, and infrastructure regardless of which Studies are active.
property:
  path: siteId
  datatype: anyURI
  min count: 1
  max count: 1
  description: Globally unique NGSI-LD identifier.
  name: siteId
property:
  path: siteName
  datatype: string
  min count: 1
  max count: 1
  description: Display name.
  name: siteName
property:
  path: siteAlias
  datatype: string
  min count: 0
  max count: 1
  description: Operating name when distinct from legal Site name.
  name: siteAlias
property:
  path: siteType
  datatype: string
  min count: 1
  max count: 1
  in: HOSPITAL
  in: CLINIC
  in: ACADEMIC_MEDICAL_CENTER
  in: RESEARCH_CENTER
  in: COMMUNITY_PRACTICE
  in: DECENTRALIZED_HUB
  in: VIRTUAL
  description: Site type taxonomy. DECENTRALIZED_HUB and VIRTUAL cover R3 Annex 2 non-traditional modalities.
  name: siteType
property:
  path: address
  min count: 0
  max count: 1
  description: Primary address. For DECENTRALIZED_HUB sites this may be 0..N when the hub serves multiple geographic locations; the strawman emits as a single object and the broker layer normalizes to multi-valued when needed.
  name: address
property:
  path: city
  datatype: string
  min count: 0
  max count: 1
  name: city
property:
  path: state
  datatype: string
  min count: 0
  max count: 1
  name: state
property:
  path: country
  datatype: string
  min count: 1
  max count: 1
  description: ISO 3166-1 alpha-3 country code.
  name: country
property:
  path: postalCode
  datatype: string
  min count: 0
  max count: 1
  name: postalCode
property:
  path: phone
  datatype: string
  min count: 0
  max count: 1
  name: phone
property:
  path: email
  datatype: string
  min count: 0
  max count: 1
  name: email
property:
  path: website
  datatype: anyURI
  min count: 0
  max count: 1
  name: website
property:
  path: gcpQualified
  datatype: boolean
  min count: 0
  max count: 1
  description: Site holds a current GCP qualification at the institution level (R3 Section 2.1). Per-Study GCP currency for individual staff lives on Person.gcpTrainingStatus.
  name: gcpQualified
property:
  path: facilitiesAdequate
  datatype: boolean
  min count: 0
  max count: 1
  description: General facilities adequacy for clinical research (R3 Section 2.2). Per-Study/per-protocol facilities adequacy lives on StudySite.staffingAdequate and is protocol-dependent.
  name: facilitiesAdequate
property:
  path: therapeuticAreasExperienced
  datatype: string
  min count: 0
  max count: 1
  description: Comma-separated array of therapeutic areas the Site has experience in (oncology, cardiology, neurology, immunology, infectious disease, rare disease, etc.). Drives feasibility-questionnaire matching.
  name: therapeuticAreasExperienced
property:
  path: indicationExperience
  min count: 0
  max count: 1
  description: Array of structured records: {indication, totalTrials, totalPatientsEnrolled}. Captures past indication-specific experience for SFQ matching.
  name: indicationExperience
property:
  path: patientPopulationAccess
  min count: 0
  max count: 1
  description: Array of {populationDescription, estimatedReach, sourceType}. SFQ feasibility input.
  name: patientPopulationAccess
property:
  path: patientReferralSources
  datatype: string
  min count: 0
  max count: 1
  description: Comma-separated array of recruitment sources the Site uses (HOSPITAL_OWN, EMR_DATABASE, ADVERTISING, REFERRAL_NETWORK, REGISTRY, PATIENT_ADVOCACY, OTHER). Stored as comma-separated string for the strawman; native NGSI-LD multi-value once the broker layer is in place.
  name: patientReferralSources
property:
  path: totalTrialsConducted
  datatype: integer
  min count: 0
  max count: 1
  description: Lifetime count of trials conducted at this Site.
  name: totalTrialsConducted
property:
  path: trialsByPhase
  min count: 0
  max count: 1
  description: Array of {phase, count} for past trial experience by phase.
  name: trialsByPhase
property:
  path: averageEnrollmentRate
  datatype: decimal
  min count: 0
  max count: 1
  description: Average patients enrolled per month across past trials. SFQ benchmark.
  name: averageEnrollmentRate
property:
  path: firstPatientInToActivationDays
  datatype: integer
  min count: 0
  max count: 1
  description: Average days from contract execution to first patient enrolled.
  name: firstPatientInToActivationDays
property:
  path: queryResponseTimeHours
  datatype: decimal
  min count: 0
  max count: 1
  description: Average hours to respond to data queries; data-quality SFQ signal.
  name: queryResponseTimeHours
property:
  path: sponsorRetentionRate
  datatype: decimal
  min count: 0
  max count: 1
  description: Percentage of past sponsors that have run multiple trials at this Site (0.0-1.0).
  name: sponsorRetentionRate
property:
  path: freezerCapacity
  min count: 0
  max count: 1
  description: Array of {tempRange (e.g. '-80C', '-20C', '4C'), volume, units}. Storage feasibility for biological samples.
  name: freezerCapacity
property:
  path: imagingCapabilities
  datatype: string
  min count: 0
  max count: 1
  description: Comma-separated array of on-site imaging modalities (XRAY, CT, MRI, ULTRASOUND, PET, SPECT, ECHO, NUCLEAR_MEDICINE, MAMMOGRAPHY). Stored as comma-separated string for the strawman; native NGSI-LD multi-value once the broker layer is in place.
  name: imagingCapabilities
property:
  path: labCapabilities
  datatype: string
  min count: 0
  max count: 1
  description: Comma-separated array of lab certifications/types available (CLIA, CAP, CENTRAL, POINT_OF_CARE, SPECIALTY). Stored as comma-separated string for the strawman; native NGSI-LD multi-value once the broker layer is in place.
  name: labCapabilities
property:
  path: pharmacyOnSite
  datatype: boolean
  min count: 0
  max count: 1
  description: Site has a pharmacy on-site capable of IP handling.
  name: pharmacyOnSite
property:
  path: dctCapable
  datatype: boolean
  min count: 0
  max count: 1
  description: Site supports decentralized trial activities (remote visits, home health, telehealth).
  name: dctCapable

ParticipantShape
type: NodeShape
target class: Participant
name: Participant
description: A Participant is a real human enrolled in a Study at a StudySite. Per FIRST-PRINCIPLES (operator-grounded foundation, ephemeral projections), Participant is the trial-conduct-realm role-entity for the underlying human; the same human is a Patient in their care realm, a Claimant in their claims realm, an RWE-Patient in research-warehouse projections — those are projection targets, not TOP entities. The operational hierarchy: Site -> StudySite -> Study -> Protocol -> SOA -> Visit -> Activity, with Participant anchored at StudySite (1..1; multi-Study participation is modeled as separate Participant entities). Lifecycle events (Consent, Screening, Enrollment, Withdrawal) are sub-objects under Participant — the SDTM DS-record pattern; operators see workflow events, the projection adapters emit DS rows. participantStatus is a NGSI-LD temporal property (validFrom/validUntil) so trajectory is queryable for downstream digital-twin synthesis (key enabler for twin-for-enrollment in v0.5+).
property:
  path: participantId
  datatype: anyURI
  min count: 1
  max count: 1
  description: Globally unique NGSI-LD identifier. Operators type the parts (screeningNumber + randomizationNumber); USUBJID = STUDYID-SITEID-SUBJID concatenation is a SDTM-projection-time derivation, not a TOP attribute.
  name: participantId
property:
  path: screeningNumber
  datatype: string
  min count: 1
  max count: 1
  description: Site-assigned screening identifier (operator-facing). Maps to SDTM SUBJID. CDASH SUBJID. Operator types this when registering a new Participant after consent.
  name: screeningNumber
property:
  path: randomizationNumber
  datatype: string
  min count: 0
  max count: 1
  description: Sponsor-assigned identifier issued at randomization. Often used for IP kit assignment. Empty until randomization. SDTM has no canonical column; carried in SUPPDM or kit-level records.
  name: randomizationNumber
property:
  path: randomizationDate
  datatype: date
  min count: 0
  max count: 1
  description: Date of randomization. Empty until randomization. Required when participantStatus=RANDOMIZED (SHACL hard violation).
  name: randomizationDate
property:
  path: firstName
  datatype: string
  min count: 0
  max count: 1
  description: Operator-grounded; populated with real value for site-coordinator UX or empty/de-identified for research-warehouse projections per deployment-side identification policy.
  name: firstName
property:
  path: middleName
  datatype: string
  min count: 0
  max count: 1
  name: middleName
property:
  path: lastName
  datatype: string
  min count: 0
  max count: 1
  description: Operator-grounded; same de-identification posture as firstName.
  name: lastName
property:
  path: dateOfBirth
  datatype: date
  min count: 0
  max count: 1
  description: Real DOB, or year-only approximation, or shifted date depending on deployment. Maps to SDTM BRTHDTC (ISO 8601). FHIR Patient.birthDate.
  name: dateOfBirth
property:
  path: sex
  datatype: string
  min count: 0
  max count: 1
  in: MALE
  in: FEMALE
  in: INTERSEX
  in: UNKNOWN
  in: NOT_REPORTED
  description: Biological sex per ICH E5 / FDA guidance. Operator-meaningful enum; SDTM projection emits the terser M/F/U/UNDIFFERENTIATED codes (INTERSEX -> UNDIFFERENTIATED per CDISC controlled term). Gender identity is a separate concern when needed.
  name: sex
property:
  path: race
  datatype: string
  min count: 0
  max count: 1
  description: Comma-separated for multiracial. Maps to SDTM RACE (CDISC controlled term); SDTM uses MULTIPLE + SUPPDM RACEMUL for multiracial.
  name: race
property:
  path: ethnicity
  datatype: string
  min count: 0
  max count: 1
  in: HISPANIC_OR_LATINO
  in: NOT_HISPANIC_OR_LATINO
  in: NOT_REPORTED
  in: UNKNOWN
  description: CDISC controlled term.
  name: ethnicity
property:
  path: primaryLanguage
  datatype: string
  min count: 0
  max count: 1
  description: ISO 639-1 code (en, es, fr, zh, etc.). Operator-grounded for site-coordinator UX (preferred language for visit interactions). Not in SDTM DM core.
  name: primaryLanguage
property:
  path: country
  datatype: string
  min count: 0
  max count: 1
  description: ISO 3166-1 alpha-3 country code. For multi-region trials.
  name: country
property:
  path: participantStatus
  datatype: string
  min count: 1
  max count: 1
  in: SCREENING
  in: SCREEN_FAILED
  in: CONSENTED
  in: ENROLLED
  in: RANDOMIZED
  in: ON_TREATMENT
  in: IN_FOLLOW_UP
  in: COMPLETED
  in: WITHDRAWN
  in: DISCONTINUED
  in: LOST_TO_FOLLOW_UP
  description: Operationally-distinct lifecycle states (11). Operator-meaningful; standards projections live below the line. NGSI-LD temporal property (validFrom/validUntil bracketing each value) so trajectory is queryable downstream (Decision 10 twin-queryability discipline).
  name: participantStatus
property:
  path: enrollmentDate
  datatype: date
  min count: 0
  max count: 1
  description: Date of enrollment (single canonical Sponsor-assigned moment). Distinct from randomizationDate (later) and consent date (on InformedConsent sub-object). Maps to SDTM RFSTDTC.
  name: enrollmentDate
property:
  path: completionDate
  datatype: date
  min count: 0
  max count: 1
  description: Date the Participant completed protocol participation (LPLV-equivalent for this Participant). SOFT SHACL: should be populated when participantStatus=COMPLETED.
  name: completionDate
property:
  path: withdrawalDate
  datatype: date
  min count: 0
  max count: 1
  description: Most recent withdrawal event date (canonical query convenience; full history lives on WithdrawalRecord sub-objects).
  name: withdrawalDate
property:
  path: tags
  datatype: string
  min count: 0
  max count: 1
  description: Comma-separated user-defined tags (per OOUX Tag pattern).
  name: tags
property:
  path: validFrom
  datatype: dateTime
  min count: 0
  max count: 1
  description: NGSI-LD-native temporal property: datetime from which this Participant record is operationally valid. Pattern parallels Sponsor and StudySite.
  name: validFrom
property:
  path: validUntil
  datatype: dateTime
  min count: 0
  max count: 1
  description: NGSI-LD-native temporal property: datetime through which this Participant record was operationally valid. Empty for currently-active Participants.
  name: validUntil
property:
  path: forStudySite
  class: StudySite
  min count: 1
  max count: 1
  node kind: IRI
  description: The StudySite where this Participant is enrolled. Per the operational hierarchy correction (Site -> StudySite -> Study), Participant anchors at StudySite, not Site directly. The OOUX Participant->1 Site direct edge is a correction surfaced during the Site spec lift; tracked.
  name: forStudySite
property:
  path: forStudy
  class: Study
  min count: 1
  max count: 1
  node kind: IRI
  description: The Study this Participant is enrolled in. Reachable via forStudySite.forStudy traversal but kept as a direct edge for query convenience and SHACL invariant simplicity (Participant.assignedToArm.forStudy == Participant.forStudy).
  name: forStudy
property:
  path: assignedToArm
  class: Arm
  min count: 0
  max count: 1
  node kind: IRI
  description: The Study Arm the Participant is assigned to. 0 in pre-randomization phases; 1..1 once randomized. Hard SHACL: when participantStatus=RANDOMIZED, assignedToArm must be populated AND the Arm must belong to the same Study as Participant.forStudy (cross-entity consistency).
  name: assignedToArm
property:
  path: hasInformedConsent
  class: InformedConsent
  min count: 0
  node kind: IRI
  description: Informed consent event records. 0..N to support re-consent (after protocol amendment, ICF version change, lapse-and-re-establish). Each InformedConsent sub-object is one consent event with its own date, consenter, witness, document reference, lifecycle status.
  name: hasInformedConsent
property:
  path: hasScreeningRecord
  class: ScreeningRecord
  min count: 0
  node kind: IRI
  description: Screening event records. 0..N to support re-screening attempts. Hard SHACL: when participantStatus=SCREEN_FAILED, at least one ScreeningRecord with screeningOutcome=SCREEN_FAILED must exist.
  name: hasScreeningRecord

InformedConsentShape
type: NodeShape
target class: InformedConsent
name: InformedConsent
description: An InformedConsent sub-object captures one consent event for a Participant: the moment the participant (or LAR) signed an ICF acknowledging the study's purpose, procedures, risks, and benefits. ICH E6(R3) Section 2.4 GCP-required. Re-consent (after amendment, ICF version change, or lapse) creates additional InformedConsent records under the same Participant — full event history. Maps to FHIR Consent resource (one per record) and SDTM DS records with DSDECOD=INFORMED CONSENT OBTAINED / WITHDRAWAL OF CONSENT.
property:
  path: consentId
  datatype: anyURI
  min count: 1
  max count: 1
  name: consentId
property:
  path: consentVersion
  datatype: string
  min count: 1
  max count: 1
  description: ICF document version (e.g., 'v3.2'). Tracks which Protocol/ICF revision the consent was given against.
  name: consentVersion
property:
  path: consentDate
  datatype: date
  min count: 1
  max count: 1
  description: Date consent was obtained. Maps to SDTM DSSTDTC for the corresponding DS record.
  name: consentDate
property:
  path: consentTime
  datatype: time
  min count: 0
  max count: 1
  description: Time of day consent was obtained, if recorded (eConsent typically captures this; paper consent often does not).
  name: consentTime
property:
  path: consentMethod
  datatype: string
  min count: 1
  max count: 1
  in: PAPER
  in: ELECTRONIC
  in: ELECTRONIC_REMOTE
  description: Method of consent capture. ELECTRONIC_REMOTE supports DCT/decentralized-trial workflows (telehealth consent).
  name: consentMethod
property:
  path: consenterRelationship
  datatype: string
  min count: 1
  max count: 1
  in: SELF
  in: LEGALLY_AUTHORIZED_REPRESENTATIVE
  in: PARENT_GUARDIAN
  in: OTHER
  description: Who is consenting on the Participant's behalf. SELF for adult competent participants; LAR for incapacitated adults; PARENT_GUARDIAN for pediatric.
  name: consenterRelationship
property:
  path: language
  datatype: string
  min count: 0
  max count: 1
  description: ISO 639-1 code of the language the ICF was presented in. Maps to FHIR Consent.language.
  name: language
property:
  path: translatorUsed
  datatype: boolean
  min count: 0
  max count: 1
  description: Whether a translator/interpreter was used. FHIR represents this as Consent.actor with role=interpreter.
  name: translatorUsed
property:
  path: consentStatus
  datatype: string
  min count: 1
  max count: 1
  in: OBTAINED
  in: WITHDRAWN
  in: EXPIRED
  in: RECONSENTED
  description: Lifecycle of this specific consent record. OBTAINED on creation; WITHDRAWN if subject withdraws; EXPIRED if ICF expires; RECONSENTED if a new InformedConsent supersedes this one (the new record points back via reconsentReason).
  name: consentStatus
property:
  path: reconsentRequired
  datatype: boolean
  min count: 0
  max count: 1
  description: True if this consent record was created because a reconsent was required (e.g., after a protocol amendment changed risk profile).
  name: reconsentRequired
property:
  path: reconsentReason
  datatype: string
  min count: 0
  max count: 1
  description: Reason for reconsent (e.g., 'Protocol Amendment v3.2 added a new procedure'). Free text or coded.
  name: reconsentReason
property:
  path: withdrawalDate
  datatype: date
  min count: 0
  max count: 1
  description: Date this specific consent was withdrawn (if applicable). Distinct from Participant.withdrawalDate (which is the most-recent across all WithdrawalRecords).
  name: withdrawalDate
property:
  path: consentingPerson
  class: Person
  min count: 0
  max count: 1
  node kind: IRI
  description: The Person who consented (often the Participant themselves; or the LAR / parent / guardian). 0..1 because the Participant entity itself is the most common case and TOP doesn't always model the human-as-Person entity.
  name: consentingPerson
property:
  path: personObtainingConsent
  class: Person
  min count: 1
  max count: 1
  node kind: IRI
  description: The site staff member (Person, drawn from forStudySite.delegatesAuthorityTo) who obtained the consent. ICH E6(R3) Section 2.4 GCP-required attribution.
  name: personObtainingConsent
property:
  path: consentWitness
  class: Person
  min count: 0
  max count: 1
  node kind: IRI
  description: Witness to the consent process, where required by jurisdictional regulation or sponsor SOP.
  name: consentWitness
property:
  path: consentDocument
  min count: 0
  max count: 1
  node kind: IRI
  description: The signed ICF document in the eTMF/ISF.
  comment: TARGET-MISSING: Document is a horizontal in TOP source; relationship valid.
  name: consentDocument

ScreeningRecordShape
type: NodeShape
target class: ScreeningRecord
name: ScreeningRecord
description: A ScreeningRecord captures one screening attempt for a Participant against the Study's inclusion/exclusion criteria. ICH E6(R3) Section 2.5 GCP-anchored. Re-screening (after a screen failure, per protocol re-screening rules) creates additional ScreeningRecords. Maps to FHIR ResearchSubject.progress entries with subjectState=screening / off-study and SDTM DS records with DSDECOD=SCREEN FAILURE (when failed) plus SDTM IE records (Inclusion/Exclusion Not Met) for failed criteria.
property:
  path: screeningRecordId
  datatype: anyURI
  min count: 1
  max count: 1
  name: screeningRecordId
property:
  path: screeningStartDate
  datatype: date
  min count: 1
  max count: 1
  description: Date screening began (often consent date or shortly after).
  name: screeningStartDate
property:
  path: screeningEndDate
  datatype: date
  min count: 0
  max count: 1
  description: Date screening concluded (with outcome). Empty for in-progress screening.
  name: screeningEndDate
property:
  path: screeningOutcome
  datatype: string
  min count: 1
  max count: 1
  in: IN_PROGRESS
  in: ENROLLED
  in: SCREEN_FAILED
  in: RE_SCREENING_PENDING
  in: WITHDREW_BEFORE_DECISION
  description: Final outcome of this screening attempt. IN_PROGRESS while open; one of the terminal states once concluded.
  name: screeningOutcome
property:
  path: screenFailReason
  datatype: string
  min count: 0
  max count: 1
  description: Verbatim reason for screen failure (free text or coded). Maps to SDTM DSTERM (verbatim) and DSDECOD.
  name: screenFailReason
property:
  path: failedInclusionCriteria
  datatype: string
  min count: 0
  max count: 1
  description: Comma-separated list of inclusion criterion numbers (e.g., 'I1, I3') the Participant failed. SDTM IE domain is the canonical projection (one IE record per failed criterion).
  name: failedInclusionCriteria
property:
  path: failedExclusionCriteria
  datatype: string
  min count: 0
  max count: 1
  description: Comma-separated list of exclusion criterion numbers (e.g., 'E2, E5') the Participant met. SDTM IE domain is the canonical projection.
  name: failedExclusionCriteria
property:
  path: reScreeningEligibility
  datatype: boolean
  min count: 0
  max count: 1
  description: Whether the Participant is eligible to be re-screened (per protocol re-screening rules; some screen failures are permanent disqualifications).
  name: reScreeningEligibility
property:
  path: screenedBy
  class: Person
  min count: 0
  max count: 1
  node kind: IRI
  description: The site staff member (PI or sub-investigator, drawn from forStudySite.delegatesAuthorityTo) who conducted/signed-off-on the screening.
  name: screenedBy

EnrollmentRecordShape
type: NodeShape
target class: EnrollmentRecord
name: EnrollmentRecord
description: An EnrollmentRecord captures the moment a Participant was enrolled into the Study (eligibility confirmed; assigned to the trial). Distinct from RANDOMIZED (which may follow). Typically 1 per Participant; multi-enrollment supported for re-enrollment scenarios where a previously withdrawn Participant rejoins (rare; some long-running registries). Maps to FHIR ResearchSubject.progress (milestone=Enrolled) and SDTM DS DSDECOD=ENROLLED.
property:
  path: enrollmentRecordId
  datatype: anyURI
  min count: 1
  max count: 1
  name: enrollmentRecordId
property:
  path: enrollmentDate
  datatype: date
  min count: 1
  max count: 1
  description: Date of enrollment. Maps to SDTM RFSTDTC and DS DSSTDTC for DSDECOD=ENROLLED.
  name: enrollmentDate
property:
  path: enrollmentMethod
  datatype: string
  min count: 0
  max count: 1
  in: ON_SITE
  in: REMOTE
  in: HYBRID
  description: Method of enrollment. ON_SITE is traditional; REMOTE supports DCT (decentralized trial) workflows; HYBRID for partial-DCT designs.
  name: enrollmentMethod
property:
  path: enrollmentNumber
  datatype: string
  min count: 0
  max count: 1
  description: Sponsor-assigned enrollment number (often sequential, distinct from screeningNumber and randomizationNumber).
  name: enrollmentNumber
property:
  path: protocolVersionAtEnrollment
  datatype: string
  min count: 0
  max count: 1
  description: Protocol version in force at time of enrollment. References the USDM StudyVersion identifier in force; useful for audit when amendments cascade.
  name: protocolVersionAtEnrollment
property:
  path: eligibilityConfirmedBy
  class: Person
  min count: 1
  max count: 1
  node kind: IRI
  description: The Principal Investigator (Person, drawn from forStudySite.hasPrincipalInvestigator typically) who confirmed eligibility per ICH E6(R3) Section 2.4 GCP-required attribution.
  name: eligibilityConfirmedBy

WithdrawalRecordShape
type: NodeShape
target class: WithdrawalRecord
name: WithdrawalRecord
description: A WithdrawalRecord captures the moment a Participant left the Study (subject-initiated withdrawal of consent, investigator-initiated discontinuation, lost-to-follow-up, etc.). Each event is a separate record so the full lifecycle is auditable. Maps to FHIR ResearchSubject.progress (milestone=Withdrawn) and SDTM DS records with DSDECOD per CDISC controlled term.
property:
  path: withdrawalRecordId
  datatype: anyURI
  min count: 1
  max count: 1
  name: withdrawalRecordId
property:
  path: withdrawalDate
  datatype: date
  min count: 1
  max count: 1
  description: Date of withdrawal/discontinuation. Maps to SDTM DSSTDTC.
  name: withdrawalDate
property:
  path: withdrawalCategory
  datatype: string
  min count: 1
  max count: 1
  in: CONSENT_WITHDRAWN
  in: INVESTIGATOR_DECISION
  in: ADVERSE_EVENT
  in: LOST_TO_FOLLOW_UP
  in: PROTOCOL_DEVIATION
  in: NON_COMPLIANCE
  in: DEATH
  in: OTHER
  description: Category of the withdrawal event. Maps to SDTM DSDECOD: CONSENT_WITHDRAWN -> WITHDRAWAL OF CONSENT; INVESTIGATOR_DECISION -> DISCONTINUED; etc.
  name: withdrawalCategory
property:
  path: withdrawalReason
  datatype: string
  min count: 0
  max count: 1
  description: Verbatim reason for withdrawal (free text or coded). Maps to SDTM DSTERM.
  name: withdrawalReason
property:
  path: continueDataCollection
  datatype: boolean
  min count: 0
  max count: 1
  description: True if the Participant withdrew from active treatment but data collection (follow-up visits) continues per protocol. FHIR represents as continued ResearchSubject without period.end despite withdrawn status.
  name: continueDataCollection
property:
  path: withdrawnFromAllProcedures
  datatype: boolean
  min count: 0
  max count: 1
  description: True if the Participant withdrew consent for all study procedures including data use (full withdrawal). When true, deployment-side data-handling policies apply (data deletion, retention exception, etc.).
  name: withdrawnFromAllProcedures
property:
  path: notes
  datatype: string
  min count: 0
  max count: 1
  description: Free-text notes (often used by site coordinators for context that doesn't fit the controlled fields).
  name: notes
property:
  path: documentedBy
  class: Person
  min count: 0
  max count: 1
  node kind: IRI
  description: The site staff member (Person) who documented the withdrawal event. Required by GCP audit; relationship optional in TOP source because some legacy data may lack the attribution.
  name: documentedBy

RecruitShape
type: NodeShape
target class: Recruit
name: Recruit
description: A Recruit is a person who has responded to or been identified by a recruitment funnel for a Study but has NOT yet given informed consent. The recruitment realm has its own operator (recruitment coordinator / outreach lead) and its own workflow (advertising response, pre-screening calls, eligibility pre-check, scheduling, contact attempts). Per FIRST-PRINCIPLES, Recruit is a separate top-level entity rather than a pre-consent state on Participant: the recruiter's workflow is operationally distinct from the coordinator's, the data shape is lighter (no consent, often just contact info + light eligibility pre-check), and PHI handling differs (recruiter does not need full demographics or medical history). When a Recruit consents, they convert to a Participant via Participant.convertedFromRecruit. Recruit data persists as recruitment-funnel analytics (conversion rates per source) regardless of whether conversion occurred.
property:
  path: recruitId
  datatype: anyURI
  min count: 1
  max count: 1
  description: Globally unique NGSI-LD identifier.
  name: recruitId
property:
  path: firstName
  datatype: string
  min count: 0
  max count: 1
  description: Operator-grounded; populated when recruitment coordinator has captured contact info. Identification-status-agnostic posture (same as Participant).
  name: firstName
property:
  path: lastName
  datatype: string
  min count: 0
  max count: 1
  name: lastName
property:
  path: phone
  datatype: string
  min count: 0
  max count: 1
  description: Phone number for recruiter contact. Often the only identifier captured at first response (radio ad call-in, web-form submission).
  name: phone
property:
  path: email
  datatype: string
  min count: 0
  max count: 1
  name: email
property:
  path: preferredContactMethod
  datatype: string
  min count: 0
  max count: 1
  in: PHONE
  in: EMAIL
  in: TEXT
  in: PORTAL
  in: OTHER
  description: Recruit's stated preferred contact method.
  name: preferredContactMethod
property:
  path: recruitStatus
  datatype: string
  min count: 1
  max count: 1
  in: RESPONDED
  in: CONTACTED
  in: PRE_SCREENING_SCHEDULED
  in: PRE_SCREENED
  in: QUALIFIED_PENDING_CONSENT
  in: CONVERTED_TO_PARTICIPANT
  in: DECLINED
  in: NO_SHOW
  in: NOT_QUALIFIED
  in: DROPPED
  description: Recruitment-funnel state. CONVERTED_TO_PARTICIPANT terminates the Recruit lifecycle (Participant record now exists). DECLINED / NO_SHOW / NOT_QUALIFIED / DROPPED are terminal failure states. NGSI-LD temporal property (validFrom/validUntil) for trajectory queryability (parallel to Participant.participantStatus).
  name: recruitStatus
property:
  path: recruitmentSource
  datatype: string
  min count: 0
  max count: 1
  in: SITE_DATABASE
  in: EMR_OUTREACH
  in: ADVERTISING_DIGITAL
  in: ADVERTISING_PRINT
  in: ADVERTISING_RADIO
  in: REFERRAL_PROVIDER
  in: REFERRAL_PARTICIPANT
  in: REGISTRY
  in: PATIENT_ADVOCACY
  in: WALK_IN
  in: OTHER
  description: How the Recruit entered the funnel. Drives recruitment-channel ROI analysis.
  name: recruitmentSource
property:
  path: recruitmentSourceDetails
  datatype: string
  min count: 0
  max count: 1
  description: Free-text detail (e.g., specific ad campaign ID, specific registry name, referring physician).
  name: recruitmentSourceDetails
property:
  path: responseDate
  datatype: date
  min count: 1
  max count: 1
  description: Date the Recruit first entered the funnel (responded to ad / referred / identified by EMR mining).
  name: responseDate
property:
  path: preScreeningOutcome
  datatype: string
  min count: 0
  max count: 1
  in: QUALIFIED
  in: NOT_QUALIFIED
  in: DEFERRED
  in: PENDING
  description: Outcome of the recruiter's pre-screening assessment (NOT formal protocol screening; that happens post-consent on the Participant via ScreeningRecord). PENDING while in progress; QUALIFIED proceeds to consent scheduling.
  name: preScreeningOutcome
property:
  path: preScreeningNotes
  datatype: string
  min count: 0
  max count: 1
  description: Free-text notes from pre-screening conversation (high-level eligibility flags, concerns, motivations). Limited PHI by design — full medical history not captured here.
  name: preScreeningNotes
property:
  path: contactAttempts
  datatype: integer
  min count: 0
  max count: 1
  description: Count of contact attempts made by the recruiter (calls, emails, texts). Operational metric; drives recruiter follow-up cadence.
  name: contactAttempts
property:
  path: lastContactDate
  datatype: date
  min count: 0
  max count: 1
  description: Most recent contact attempt date (successful or not).
  name: lastContactDate
property:
  path: consentScheduled
  datatype: boolean
  min count: 0
  max count: 1
  description: True if a consent appointment is scheduled. Bridges to Participant creation.
  name: consentScheduled
property:
  path: consentAppointmentDate
  datatype: date
  min count: 0
  max count: 1
  name: consentAppointmentDate
property:
  path: country
  datatype: string
  min count: 0
  max count: 1
  description: ISO 3166-1 alpha-3. Useful for multi-country recruitment funnel analytics.
  name: country
property:
  path: primaryLanguage
  datatype: string
  min count: 0
  max count: 1
  description: ISO 639-1. Drives recruiter language-matching.
  name: primaryLanguage
property:
  path: tags
  datatype: string
  min count: 0
  max count: 1
  description: Comma-separated user-defined tags.
  name: tags
property:
  path: validFrom
  datatype: dateTime
  min count: 0
  max count: 1
  description: NGSI-LD temporal property for recruit-record validity.
  name: validFrom
property:
  path: validUntil
  datatype: dateTime
  min count: 0
  max count: 1
  name: validUntil
property:
  path: forStudy
  class: Study
  min count: 1
  max count: 1
  node kind: IRI
  description: The Study this Recruit was identified for. Recruits are scoped per-Study (a person responding to two trial ads is two Recruits, even if same human; cross-Study identity resolution is federation, not foundation).
  name: forStudy
property:
  path: forStudySite
  class: StudySite
  min count: 0
  max count: 1
  node kind: IRI
  description: The StudySite the Recruit was funneled to (often known by recruitment-source channel). 0..1 because some Recruits enter the funnel before site assignment is finalized (multi-site studies with central-recruitment-then-site-routing).
  name: forStudySite
property:
  path: recruitedBy
  class: Person
  min count: 0
  max count: 1
  node kind: IRI
  description: The recruitment coordinator (Person) handling this Recruit. From forStudySite.delegatesAuthorityTo with role=recruitment-coordinator (when delegation is per-Study) or from a sponsor-side recruitment team.
  name: recruitedBy

VisitShape
type: NodeShape
target class: Visit
name: Visit
description: A Visit is an actual visit-occurrence: a Participant attended at a StudySite on a specific date. Distinct from VisitDefinition (the protocol-template). Visits carry actual datetimes, status, mode (in-person / telehealth / remote / async), Activities performed, Tasks captured, and any Observations the operator noted. Per FIRST-PRINCIPLES universal-foundation posture, the Visit > Activity > Task hierarchy handles ANY assessment without modeling specifics — a DICOM imaging Activity and a blood-draw Activity are the same TOP shape. The OOUX Visit->Site direct edge is corrected: Visit.forStudySite -> StudySite (1..1).
property:
  path: visitId
  datatype: anyURI
  min count: 1
  max count: 1
  description: Globally unique NGSI-LD identifier.
  name: visitId
property:
  path: visitNumber
  datatype: string
  min count: 0
  max count: 1
  description: Numeric ordering per protocol (matches VisitDefinition.visitNumber when definedBy is populated). Maps to SDTM VISITNUM.
  name: visitNumber
property:
  path: visitName
  datatype: string
  min count: 0
  max count: 1
  description: Operator-friendly name. For UNSCHEDULED visits, free text describing the reason. Maps to SDTM VISIT.
  name: visitName
property:
  path: visitMode
  datatype: string
  min count: 1
  max count: 1
  in: IN_PERSON_CLINIC
  in: IN_PERSON_HOME
  in: REMOTE_VIDEO
  in: REMOTE_PHONE
  in: REMOTE_ASYNC
  in: HYBRID
  description: Visit modality per ICH E6(R3) Annex 2 DCT framing. IN_PERSON_CLINIC for traditional clinic visits; IN_PERSON_HOME for home health; REMOTE_VIDEO for telehealth; REMOTE_PHONE for phone visits; REMOTE_ASYNC for ePRO/eDiary capture without live interaction; HYBRID for mixed-modality visits. FHIR Encounter.virtualService + Encounter.location are the projection targets.
  name: visitMode
property:
  path: visitStatus
  datatype: string
  min count: 1
  max count: 1
  in: SCHEDULED
  in: IN_PROGRESS
  in: COMPLETED
  in: PARTIALLY_COMPLETED
  in: MISSED
  in: RESCHEDULED
  in: CANCELLED
  in: OUT_OF_WINDOW
  in: UNSCHEDULED
  description: Visit lifecycle state. NGSI-LD temporal property (validFrom/validUntil per value) for trajectory queryability. SCHEDULED for booked-but-not-started; IN_PROGRESS during active visit; COMPLETED for per-protocol completion; PARTIALLY_COMPLETED when some Activities not performed (rescheduled separately); MISSED for didn't-happen-no-makeup; OUT_OF_WINDOW when actual datetime falls outside visitDefinition.visitWindow; UNSCHEDULED for ad-hoc (urgent care, AE workup, sponsor-requested). FHIR Encounter.status is the projection target.
  name: visitStatus
property:
  path: plannedStartDate
  datatype: date
  min count: 0
  max count: 1
  description: Planned visit date per SOA / scheduling system. What the operator/coordinator booked.
  name: plannedStartDate
property:
  path: plannedEndDate
  datatype: date
  min count: 0
  max count: 1
  description: Planned end date (typically same day; multi-day visits possible for inpatient procedures or PK time-courses).
  name: plannedEndDate
property:
  path: actualStartDate
  datatype: date
  min count: 0
  max count: 1
  description: Actual visit start date. Empty for SCHEDULED visits not yet started. Maps to SDTM SVSTDTC.
  name: actualStartDate
property:
  path: actualStartTime
  datatype: time
  min count: 0
  max count: 1
  description: Actual start time-of-day where captured. Operational completeness.
  name: actualStartTime
property:
  path: actualEndDate
  datatype: date
  min count: 0
  max count: 1
  description: Actual visit end date. Maps to SDTM SVENDTC.
  name: actualEndDate
property:
  path: actualEndTime
  datatype: time
  min count: 0
  max count: 1
  description: Actual end time-of-day where captured.
  name: actualEndTime
property:
  path: visitDay
  datatype: integer
  min count: 0
  max count: 1
  description: Days from study anchor (typically randomization or first dose). Computed from actualStartDate when definedBy is populated. Maps to SDTM VISITDY.
  name: visitDay
property:
  path: protocolDeviationCode
  datatype: string
  min count: 0
  max count: 1
  description: Sponsor-defined deviation code when visitStatus=OUT_OF_WINDOW or other deviation. Free text or coded; aligns with sponsor deviation taxonomy.
  name: protocolDeviationCode
property:
  path: unscheduledReason
  datatype: string
  min count: 0
  max count: 1
  description: Reason for an unscheduled visit (urgent care, AE workup, sponsor-requested follow-up). Required when visitStatus=UNSCHEDULED. Maps to SDTM SVUPDES.
  name: unscheduledReason
property:
  path: tags
  datatype: string
  min count: 0
  max count: 1
  description: Comma-separated user-defined tags.
  name: tags
property:
  path: validFrom
  datatype: dateTime
  min count: 0
  max count: 1
  description: NGSI-LD temporal property: when this Visit record became operationally valid.
  name: validFrom
property:
  path: validUntil
  datatype: dateTime
  min count: 0
  max count: 1
  description: NGSI-LD temporal property: when this Visit record was superseded or closed.
  name: validUntil
property:
  path: forParticipant
  class: Participant
  min count: 1
  max count: 1
  node kind: IRI
  description: The Participant whose visit this is. PROV: this Visit Activity is wasAttributedTo this Participant. Maps to FHIR Encounter.subject (via ResearchSubject.subject linkage).
  name: forParticipant
property:
  path: forStudySite
  class: StudySite
  min count: 1
  max count: 1
  node kind: IRI
  description: The StudySite hosting this visit (operational owner regardless of physical location — telehealth visits still have a StudySite of record). OOUX Visit->Site corrected to Visit->StudySite per the operational hierarchy. Maps to FHIR Encounter.serviceProvider + Encounter.location.
  name: forStudySite
property:
  path: definedBy
  class: VisitDefinition
  min count: 0
  max count: 1
  node kind: IRI
  description: The VisitDefinition (protocol template) this Visit instantiates. 0..1 because UNSCHEDULED visits don't have a corresponding template. PROV: wasInformedBy semantics — the template informed the actual visit's expected scope.
  name: definedBy
property:
  path: hasActivity
  class: Activity
  min count: 0
  node kind: IRI
  description: Activities performed at this Visit (universal sub-objects: vitals, MRI, ePRO, biopsy, IP-admin, etc.). Per FIRST-PRINCIPLES universal-foundation posture, Activity is the same TOP shape regardless of activity type.
  name: hasActivity
property:
  path: hasTask
  class: Task
  min count: 0
  node kind: IRI
  description: Tasks (leaf data-capture units) performed at this Visit. Each Task has belongsToActivity referencing its parent Activity within the same Visit. Polymorphic taskValue handles all data shapes (numeric, text, coded, URI references, structured).
  name: hasTask
property:
  path: hasVisitObservation
  class: VisitObservation
  min count: 0
  node kind: IRI
  description: Operator-narrative observations captured during the visit that don't fit a structured Activity slot (per OOUX Path C reportability handoff). May escalate to Event when relevant.
  name: hasVisitObservation
property:
  path: partOf
  class: Visit
  min count: 0
  max count: 1
  node kind: IRI
  description: Parent Visit this Visit is part of (multi-part visits, follow-up linkage). Maps to FHIR Encounter.partOf and OMOP preceding_visit_occurrence_id (linked-list).
  name: partOf
property:
  path: hasAdverseEvent
  class: Event
  min count: 0
  node kind: IRI
  description: Adverse events identified at or attributed to this Visit. Inverse of Event.duringVisit. As with Participant.hasAdverseEvent, the relationship label is operator-vocabulary; Event with category in {DEVIATION, DISCREPANCY, OTHER_CLINICAL_EVENT} arising during a Visit reach back through Event.duringVisit.
  name: hasAdverseEvent
property:
  path: hasTag
  min count: 0
  node kind: IRI
  description: User-defined tags.
  comment: TARGET-MISSING: Tag flagged-missing as before.
  name: hasTag

ActivityShape
type: NodeShape
target class: Activity
name: Activity
description: Activity is the universal work unit at a Visit — Vitals, Blood Draw, MRI, ePRO session, IP administration, ECG, biopsy, sequencing draw, ADAS-Cog session, anything. Per FIRST-PRINCIPLES universal-foundation posture, the SAME entity shape handles all activity types; specialization is content (biomedicalConceptCode + activityType for filter/sort + linked Equipment + governing Document), never entity shape. activityStatus is a NGSI-LD temporal property. PROV: each Activity is a prov:Activity with wasAssociatedWith Person agents, used Equipment, governed-by Documents.
property:
  path: activityId
  datatype: anyURI
  min count: 1
  max count: 1
  name: activityId
property:
  path: activityName
  datatype: string
  min count: 1
  max count: 1
  description: Operator-friendly name (e.g., 'Vital Signs', 'MRI Brain', 'ECOG Performance Status', 'Drug X Administration', 'EQ-5D-5L').
  name: activityName
property:
  path: activityType
  datatype: string
  min count: 1
  max count: 1
  in: PROCEDURE
  in: ASSESSMENT
  in: IP_ADMINISTRATION
  in: SAMPLE_COLLECTION
  in: QUESTIONNAIRE
  in: IMAGING
  in: OTHER
  description: Coarse categorization for operator sort/filter, NOT for specialization. Per FIRST-PRINCIPLES universal-foundation posture, the entity shape is the same for all types — activityType is a hint, not a discriminator that changes structure.
  name: activityType
property:
  path: activityStatus
  datatype: string
  min count: 1
  max count: 1
  in: PERFORMED
  in: NOT_PERFORMED
  in: PARTIALLY_PERFORMED
  in: RESCHEDULED
  description: Lifecycle of this Activity. NGSI-LD temporal property.
  name: activityStatus
property:
  path: notPerformedReason
  datatype: string
  min count: 0
  max count: 1
  description: When activityStatus=NOT_PERFORMED, the reason (subject refused, equipment failure, scheduling conflict, etc.). Required by SHACL when status indicates non-performance.
  name: notPerformedReason
property:
  path: biomedicalConceptCode
  datatype: string
  min count: 0
  max count: 1
  description: NCIt C-code (or LOINC where applicable) identifying what the Activity IS. References COSMoS BC catalog. The discriminator that operators (and downstream systems) use to know 'this is a Vital Signs activity' vs 'this is an MRI Brain activity' — content, not shape.
  name: biomedicalConceptCode
property:
  path: validFrom
  datatype: dateTime
  min count: 0
  max count: 1
  description: NGSI-LD temporal property: operational start time of the Activity within the Visit.
  name: validFrom
property:
  path: validUntil
  datatype: dateTime
  min count: 0
  max count: 1
  description: NGSI-LD temporal property: operational end time.
  name: validUntil
property:
  path: performedBy
  class: Person
  min count: 1
  node kind: IRI
  description: Person(s) who performed the Activity. PROV: prov:wasAssociatedWith. Drawn from forStudySite.delegatesAuthorityTo for delegated tasks.
  name: performedBy
property:
  path: usedEquipment
  class: Equipment
  min count: 0
  node kind: IRI
  description: Equipment used to perform the Activity (centrifuge, MRI scanner, infusion pump, ECG machine, etc.). PROV: prov:used. The Equipment's calibration/credential chain is queryable from here.
  name: usedEquipment
property:
  path: governedBy
  class: Document
  min count: 0
  node kind: IRI
  description: Document(s) that govern how this Activity should be performed (protocol section, SOP, lab manual). Document carries the section anchor. Per the chain-of-custody mock-up: 'Per shipping SOP-2026-CL-019' is a governedBy reference.
  name: governedBy

TaskShape
type: NodeShape
target class: Task
name: Task
description: Task is the universal leaf data-capture unit at a Visit (one Task per measurement / response / dose / observation). Per FIRST-PRINCIPLES universal-foundation posture, Task handles ANY captured data via polymorphic taskValue (NUMERIC / TEXT / CODED / URI_REFERENCE / STRUCTURED / DATE / IMAGE_REFERENCE). A BP measurement, an MRI Study Instance UID reference, a PHQ-9 item response, a drug dose record, a tumor lesion measurement — all the same TOP entity shape. The specialization lives in content. Each Task carries observedAt as Property metadata on taskValue (NOT a separate flat performedDateTime attribute) per NGSI-LD temporal conventions. Maps to FHIR Observation (one Observation per Task) and per-domain SDTM rows (VS/LB/EX/etc.).
property:
  path: taskId
  datatype: anyURI
  min count: 1
  max count: 1
  name: taskId
property:
  path: taskName
  datatype: string
  min count: 1
  max count: 1
  description: Operator-friendly name (e.g., 'Systolic BP', 'MRI Study Instance UID', 'PHQ-9 Item 1', 'Drug X dose').
  name: taskName
property:
  path: taskValueType
  datatype: string
  min count: 1
  max count: 1
  in: NUMERIC
  in: TEXT
  in: CODED
  in: URI_REFERENCE
  in: STRUCTURED
  in: DATE
  in: IMAGE_REFERENCE
  description: Discriminates the shape of taskValue. NUMERIC for numeric measurements; TEXT for free text; CODED for enum/concept-code values; URI_REFERENCE for URIs to external artifacts (DICOM PACS, S3, lab LIS); STRUCTURED for nested object values (lesion measurements with components, BP with sys/dia/MAP); DATE for captured dates; IMAGE_REFERENCE for radiology/pathology image URIs.
  name: taskValueType
property:
  path: taskValue
  datatype: string
  min count: 1
  max count: 1
  description: The captured value, polymorphic per taskValueType. NUMERIC values held as string for SHACL flexibility; deployment-side typing applies at projection time. NGSI-LD observedAt Property metadata captures when the value was measured/observed (NOT a separate performedDateTime attribute).
  name: taskValue
property:
  path: taskUnit
  datatype: string
  min count: 0
  max count: 1
  description: UCUM unit where applicable (e.g., '[mmHg]', 'cm', 'mg', 'beats/min'). Empty for taskValueType=TEXT/CODED/URI_REFERENCE/etc. where unit doesn't apply.
  name: taskUnit
property:
  path: biomedicalConceptCode
  datatype: string
  min count: 0
  max count: 1
  description: NCIt or LOINC C-code identifying what the Task IS (the BC catalog lookup). e.g., NCIt:C25298 for Systolic BP, LOINC:44261-6 for PHQ-9 Q1, NCIt:C16809 for MRI Brain.
  name: biomedicalConceptCode
property:
  path: taskStatus
  datatype: string
  min count: 1
  max count: 1
  in: COMPLETED
  in: NOT_PERFORMED
  in: PARTIALLY_COMPLETED
  description: Lifecycle of the Task. NGSI-LD temporal property.
  name: taskStatus
property:
  path: notPerformedReason
  datatype: string
  min count: 0
  max count: 1
  description: When taskStatus=NOT_PERFORMED. Required by SHACL.
  name: notPerformedReason
property:
  path: observedAt
  datatype: dateTime
  min count: 0
  max count: 1
  description: When the value was observed/measured. Canonical NGSI-LD Property metadata for measurement timestamps. Maps to FHIR Observation.effectiveDateTime and SDTM per-domain DTC fields.
  name: observedAt
property:
  path: belongsToActivity
  class: Activity
  min count: 1
  max count: 1
  node kind: IRI
  description: The parent Activity within the same Visit. Tasks group under Activities for operator sort/filter and projection-adapter routing (e.g., all VS-domain Tasks in one Vitals Activity).
  name: belongsToActivity
property:
  path: performedBy
  class: Person
  min count: 1
  max count: 1
  node kind: IRI
  description: The Person who captured this Task. PROV: prov:wasAssociatedWith.
  name: performedBy

VisitObservationShape
type: NodeShape
target class: VisitObservation
name: VisitObservation
description: VisitObservation captures something the operator notices during a visit that doesn't fit a structured Activity / Task slot — observational notes, unexpected events, patient-reported context. Per OOUX Path C, may escalate to a categorized Event (when Event lifts) via escalatedTo. Distinct from Task (which is structured data capture). PROV: each VisitObservation is a prov:Activity that wasInformedBy by the parent Visit; if escalated, the resulting Event was wasInformedBy this VisitObservation.
property:
  path: observationId
  datatype: anyURI
  min count: 1
  max count: 1
  name: observationId
property:
  path: observationText
  datatype: string
  min count: 1
  max count: 1
  description: The operator's narrative observation.
  name: observationText
property:
  path: observationCategory
  datatype: string
  min count: 1
  max count: 1
  in: PROTOCOL_DEVIATION
  in: SAFETY_SIGNAL
  in: DATA_DISCREPANCY
  in: OPERATIONAL_NOTE
  in: OTHER
  description: Coarse categorization. SAFETY_SIGNAL escalates to AE workflow; PROTOCOL_DEVIATION goes to deviation tracking; DATA_DISCREPANCY into query workflow; OPERATIONAL_NOTE for routine notes; OTHER for catch-all.
  name: observationCategory
property:
  path: observationDate
  datatype: date
  min count: 1
  max count: 1
  description: When the observation was recorded.
  name: observationDate
property:
  path: observationTime
  datatype: time
  min count: 0
  max count: 1
  description: Time-of-day the observation was recorded.
  name: observationTime
property:
  path: escalated
  datatype: boolean
  min count: 0
  max count: 1
  description: True if this observation has been escalated to a categorized Event. SHACL soft warning: escalated=true should have escalatedTo populated.
  name: escalated
property:
  path: escalationDate
  datatype: date
  min count: 0
  max count: 1
  description: Date the escalation occurred.
  name: escalationDate
property:
  path: recordedBy
  class: Person
  min count: 1
  max count: 1
  node kind: IRI
  description: The Person who recorded the observation (typically a CRA, coordinator, or PI). PROV: prov:wasAssociatedWith.
  name: recordedBy
property:
  path: escalatedTo
  class: Event
  min count: 0
  max count: 1
  node kind: IRI
  description: When escalated, the categorized Event that resulted from this observation. PROV: the Event was wasInformedBy this observation. Inverse of Event.derivedFrom (operator-meaningful escalation chain).
  name: escalatedTo

OversightBodyShape
type: NodeShape
target class: OversightBody
name: OversightBody
description: An OversightBody is a committee that holds review authority over a Study or StudySite — IRB (Institutional Review Board) for site-level ethics review, EC (Ethics Committee) for the EU equivalent, DSMB / IDMC (Data Safety Monitoring Board / Independent Data Monitoring Committee) for sponsor-level interim safety review, Steering Committee for cross-site governance, CEC (Clinical Events Committee) for endpoint adjudication. Per FIRST-PRINCIPLES universal-foundation posture, OversightBody is a foundation primitive (every regulated trial has oversight bodies regardless of therapeutic area). The oversight body holds authority; the review activities happen through ReviewDecision sub-objects.
property:
  path: oversightBodyId
  datatype: anyURI
  min count: 1
  max count: 1
  description: Globally unique NGSI-LD identifier.
  name: oversightBodyId
property:
  path: oversightBodyName
  datatype: string
  min count: 1
  max count: 1
  description: Display name (e.g., 'Memorial Sloan Kettering Cancer Center IRB', 'ONCO-423 Independent Data Monitoring Committee').
  name: oversightBodyName
property:
  path: oversightBodyType
  datatype: string
  min count: 1
  max count: 1
  in: IRB
  in: EC
  in: DSMB
  in: IDMC
  in: STEERING_COMMITTEE
  in: CEC
  in: OTHER
  description: Type of oversight body. IRB for US institutional review boards; EC for European ethics committees; DSMB / IDMC are interchangeable terms for sponsor-level interim safety review boards; STEERING_COMMITTEE for cross-site governance; CEC for clinical events committees doing endpoint adjudication; OTHER for catch-all.
  name: oversightBodyType
property:
  path: scope
  datatype: string
  min count: 1
  max count: 1
  in: LOCAL
  in: CENTRAL
  in: SPONSOR
  in: REGULATORY
  in: OTHER
  description: Scope of authority. LOCAL for site-specific (typical IRB at a single institution); CENTRAL for multi-site coverage (a single IRB serving multiple sites); SPONSOR for sponsor-level (DSMB/IDMC); REGULATORY for regulator-affiliated; OTHER for catch-all.
  name: scope
property:
  path: registrationNumber
  datatype: string
  min count: 0
  max count: 1
  description: Registration identifier (e.g., FDA OHRP IRB registration number IRB00000123, FWA00001234, EU EC reference).
  name: registrationNumber
property:
  path: registrationAuthority
  datatype: string
  min count: 0
  max count: 1
  description: The authority that issued the registration (e.g., 'FDA OHRP', 'EU CTIS', 'NHS HRA').
  name: registrationAuthority
property:
  path: registrationCountry
  datatype: string
  min count: 0
  max count: 1
  description: ISO 3166-1 alpha-3 country code where the body is registered.
  name: registrationCountry
property:
  path: address
  min count: 0
  max count: 1
  description: Mailing address (line1, city, region, postalCode, country).
  name: address
property:
  path: phone
  datatype: string
  min count: 0
  max count: 1
  name: phone
property:
  path: email
  datatype: string
  min count: 0
  max count: 1
  name: email
property:
  path: website
  datatype: anyURI
  min count: 0
  max count: 1
  name: website
property:
  path: operatingProcedure
  datatype: anyURI
  min count: 0
  max count: 1
  description: URI to the body's published operating procedure / charter / SOP. References a Document horizontal entity for full lineage when uploaded.
  name: operatingProcedure
property:
  path: establishedDate
  datatype: date
  min count: 0
  max count: 1
  description: Date the body was established.
  name: establishedDate
property:
  path: status
  datatype: string
  min count: 1
  max count: 1
  in: ACTIVE
  in: SUSPENDED
  in: DISBANDED
  description: Lifecycle state. NGSI-LD temporal property — bodies can be suspended (regulatory hold) or disbanded after study completion.
  name: status
property:
  path: validFrom
  datatype: dateTime
  min count: 0
  max count: 1
  description: NGSI-LD temporal property: when this OversightBody record became operationally valid for the trial.
  name: validFrom
property:
  path: validUntil
  datatype: dateTime
  min count: 0
  max count: 1
  description: NGSI-LD temporal property: when this OversightBody record was superseded or closed.
  name: validUntil
property:
  path: belongsToOrganization
  class: Organization
  min count: 0
  max count: 1
  node kind: IRI
  description: The Organization that hosts / sponsors / convened the oversight body. 0..1 because some bodies (especially DSMBs) are convened ad-hoc without a hosting Organization. PROV: the Organization is a higher-order Agent.
  name: belongsToOrganization
property:
  path: hasMember
  class: Person
  min count: 0
  node kind: IRI
  description: Committee members. Each Person has expertise relevant to the body's mandate (clinical, statistical, ethical, patient advocacy). PROV: each member is a prov:Agent acting on behalf of the OversightBody.
  name: hasMember
property:
  path: chair
  class: Person
  min count: 0
  max count: 1
  node kind: IRI
  description: The committee chair. 0..1 because some bodies operate with co-chairs or rotating chairs.
  name: chair
property:
  path: reviewsStudy
  class: Study
  min count: 0
  node kind: IRI
  description: Studies this body has review authority over. 0..N: an IRB reviews many studies; a DSMB typically reviews one.
  name: reviewsStudy
property:
  path: reviewsStudySite
  min count: 0
  node kind: IRI
  description: StudySites this body has review authority over. Site-level IRBs typically review per-StudySite; central IRBs review multiple StudySites under one Study.
  comment: TARGET-MISSING: StudySite is a horizontal but the relationship target resolves correctly; no flag needed in v0.5.1.
  name: reviewsStudySite

InvestigationalProductShape
type: NodeShape
target class: InvestigationalProduct
name: InvestigationalProduct
description: An InvestigationalProduct (IP) is the substance, biologic, medical device, or combination being studied in a Study. Per FIRST-PRINCIPLES universal-foundation posture, IP is a single entity covering all product types — drugs, biologics, devices, diagnostics, combination products — discriminated by investigationalProductType enum. Specialization is content (productCode, dosageForm, mechanismOfAction, regulatorySource); not entity shape. Per ICH E6(R3) Section 2.7 and 21 CFR 312.6, IPs require lot tracking, blinded kit packaging (when applicable), and dispensation accountability. TOP models these via two sub-objects: Lot (per-batch manufacturing identity) and Kit (per-blinded-packaging-unit). Dispensation events live as Visit Activities (activityType=IP_ADMINISTRATION) per the universal Visit > Activity > Task foundation; no separate Dispensation entity needed.
property:
  path: investigationalProductId
  datatype: anyURI
  min count: 1
  max count: 1
  description: Globally unique NGSI-LD identifier.
  name: investigationalProductId
property:
  path: investigationalProductName
  datatype: string
  min count: 1
  max count: 1
  description: Operator-friendly name (e.g., 'Drug X', 'BioCar-T-001', 'NeuroMonitor v2').
  name: investigationalProductName
property:
  path: genericName
  datatype: string
  min count: 0
  max count: 1
  description: Generic / non-proprietary name (when applicable).
  name: genericName
property:
  path: brandName
  datatype: string
  min count: 0
  max count: 1
  description: Brand / proprietary name (when commercially available, e.g., for active comparators or reformulations).
  name: brandName
property:
  path: investigationalProductType
  datatype: string
  min count: 1
  max count: 1
  in: DRUG
  in: BIOLOGIC
  in: DEVICE
  in: DIAGNOSTIC
  in: COMBINATION_PRODUCT
  in: OTHER
  description: Coarse type discriminator. DRUG for small-molecule pharmaceuticals; BIOLOGIC for biologics including monoclonal antibodies, vaccines, cell/gene therapies; DEVICE for medical devices; DIAGNOSTIC for in vitro diagnostics; COMBINATION_PRODUCT for drug-device or biologic-device combinations; OTHER for catch-all. Per FIRST-PRINCIPLES universal-foundation posture, this is a category discriminator for sort/filter, NOT a shape discriminator — the entity is the same shape regardless of type.
  name: investigationalProductType
property:
  path: mechanismOfAction
  datatype: string
  min count: 0
  max count: 1
  description: Brief description of how the product works (e.g., 'PD-1 checkpoint inhibitor', 'CAR-T cell therapy targeting CD19').
  name: mechanismOfAction
property:
  path: dosageForm
  datatype: string
  min count: 0
  max count: 1
  description: Dosage form (TABLET / CAPSULE / SOLUTION / SUSPENSION / INJECTION / INFUSION / TOPICAL / IMPLANT / DEVICE — free text accepts NCIt or FHIR Medication.form codes).
  name: dosageForm
property:
  path: routeOfAdministration
  datatype: string
  min count: 0
  max count: 1
  description: Primary route of administration (ORAL / IV / IM / SC / TOPICAL / INTRATHECAL / etc.).
  name: routeOfAdministration
property:
  path: strength
  datatype: string
  min count: 0
  max count: 1
  description: Strength / concentration (e.g., '200 mg', '50 mg/mL', '10^7 cells/dose').
  name: strength
property:
  path: isBlinded
  datatype: boolean
  min count: 1
  max count: 1
  description: Whether this IP is dispensed under blinding (true requires Kit sub-objects with treatmentAssignment for IRT-managed kit assignment; false means open-label).
  name: isBlinded
property:
  path: regulatoryStatus
  datatype: string
  min count: 0
  max count: 1
  in: INVESTIGATIONAL
  in: APPROVED_OFF_LABEL
  in: EXPANDED_ACCESS
  in: MARKETED_COMPARATOR
  in: OTHER
  description: Regulatory status of the product. INVESTIGATIONAL for true IND/IDE products; APPROVED_OFF_LABEL when an approved drug is investigated for a new indication; EXPANDED_ACCESS for compassionate-use frameworks; MARKETED_COMPARATOR for active comparator arms using approved drugs; OTHER for catch-all.
  name: regulatoryStatus
property:
  path: regulatorySource
  datatype: string
  min count: 0
  max count: 1
  description: Regulatory authority and identifier (e.g., 'FDA IND #123456', 'EMA EudraCT 2024-001234-56', 'PMDA Notification #...').
  name: regulatorySource
property:
  path: biomedicalConceptCode
  datatype: string
  min count: 0
  max count: 1
  description: NCIt C-code for the substance / device. References COSMoS BC catalog or external substance registries (UNII, RxNorm).
  name: biomedicalConceptCode
property:
  path: investigationalProductStatus
  datatype: string
  min count: 1
  max count: 1
  in: PLANNED
  in: IN_DEVELOPMENT
  in: IN_USE
  in: DISCONTINUED
  in: WITHDRAWN
  description: Lifecycle of the IP across all studies that use it. PLANNED for pre-IND; IN_DEVELOPMENT for pre-first-in-human; IN_USE for actively-administered; DISCONTINUED for development paused; WITHDRAWN for safety-driven removal. NGSI-LD temporal property.
  name: investigationalProductStatus
property:
  path: validFrom
  datatype: dateTime
  min count: 0
  max count: 1
  description: NGSI-LD temporal property: when this IP record became operationally valid.
  name: validFrom
property:
  path: validUntil
  datatype: dateTime
  min count: 0
  max count: 1
  name: validUntil
property:
  path: suppliedBySponsor
  class: Sponsor
  min count: 1
  max count: 1
  node kind: IRI
  description: The Sponsor that supplies / manufactures / imports this IP. Per 21 CFR 312.6 the IP supplier is regulatorily accountable for product labeling, lot tracking, and dispensation oversight.
  name: suppliedBySponsor
property:
  path: forStudy
  class: Study
  min count: 0
  node kind: IRI
  description: The Studies that use this IP. 0..N because some IPs are used across multiple studies (platform trials, basket trials, expanded-access programs).
  name: forStudy
property:
  path: hasLot
  class: Lot
  min count: 0
  node kind: IRI
  description: Manufacturing lots / batches of this IP. Each Lot has its own manufacturing date, expiration, release status, and accountability chain.
  name: hasLot
property:
  path: hasKit
  class: Kit
  min count: 0
  node kind: IRI
  description: Blinded packaging units (kits) prepared from this IP. Required when isBlinded=true (SHACL invariant). Each Kit ties to a Lot and is assigned to a Participant via IRT.
  name: hasKit
property:
  path: governedByDocument
  class: Document
  min count: 0
  node kind: IRI
  description: Documents governing this IP — Investigator's Brochure, IP handling instructions, product label, Certificate of Analysis (lot-specific), IP destruction record. Per ICH E6(R3) Section 2.7.
  name: governedByDocument

LotShape
type: NodeShape
target class: Lot
name: Lot
description: A Lot represents a single manufacturing batch of an InvestigationalProduct. Per ICH E6(R3) Section 2.7, IP must be tracked at lot level for accountability, expiry management, and recall response. The Lot carries manufacturing date, release date, expiration date, retest date (when applicable), manufacturer / facility identifiers, and lot status. Dispensation events at Visits reference the Lot used (via Visit's STRUCTURED taskValue or via Kit assignment for blinded studies).
property:
  path: lotId
  datatype: anyURI
  min count: 1
  max count: 1
  name: lotId
property:
  path: lotNumber
  datatype: string
  min count: 1
  max count: 1
  description: Sponsor-assigned lot identifier (e.g., 'DRX-2026-0117'). Operator-grounded — what gets printed on the IP label and tracked in pharmacy.
  name: lotNumber
property:
  path: manufacturedDate
  datatype: date
  min count: 0
  max count: 1
  description: Date the lot was manufactured.
  name: manufacturedDate
property:
  path: releaseDate
  datatype: date
  min count: 0
  max count: 1
  description: Date the lot was released for clinical use (post-QC / post-Certificate-of-Analysis).
  name: releaseDate
property:
  path: expirationDate
  datatype: date
  min count: 1
  max count: 1
  description: Expiration date. Hard SHACL: lots cannot be administered after expiration; lotStatus=EXPIRED requires this date <= today.
  name: expirationDate
property:
  path: retestDate
  datatype: date
  min count: 0
  max count: 1
  description: Date by which the lot must be re-tested (for stability-extension lots). Optional — only applies when stability data supports retest extension.
  name: retestDate
property:
  path: manufacturer
  datatype: string
  min count: 0
  max count: 1
  description: Name of the manufacturer (when distinct from suppliedBySponsor — e.g., contract manufacturer).
  name: manufacturer
property:
  path: manufacturingFacility
  datatype: string
  min count: 0
  max count: 1
  description: Manufacturing facility identifier or address.
  name: manufacturingFacility
property:
  path: quantityProduced
  datatype: integer
  min count: 0
  max count: 1
  description: Number of units produced in this lot (kits, vials, tablets — unit depends on dosageForm).
  name: quantityProduced
property:
  path: lotStatus
  datatype: string
  min count: 1
  max count: 1
  in: MANUFACTURING
  in: RELEASED
  in: IN_DISTRIBUTION
  in: DISTRIBUTED
  in: EXPIRED
  in: RECALLED
  in: DESTROYED
  description: Lot lifecycle. NGSI-LD temporal property. MANUFACTURING during production; RELEASED after QC sign-off; IN_DISTRIBUTION during shipment; DISTRIBUTED when arrived at sites; EXPIRED past expiration date; RECALLED for safety / quality recall; DESTROYED post-reconciliation.
  name: lotStatus
property:
  path: governedByDocument
  class: Document
  min count: 0
  node kind: IRI
  description: Documents governing this lot — Certificate of Analysis (lot-specific), lot release record, lot destruction record.
  name: governedByDocument

KitShape
type: NodeShape
target class: Kit
name: Kit
description: A Kit is a single blinded packaging unit prepared from a Lot, assigned to a Participant via IRT (Interactive Response Technology). Required for blinded studies where treatment assignment is masked at the dispensation level. Each Kit carries the kit number (printed on the label), its source Lot, the treatment assignment code (the IRT-issued randomization code; the unblinding key is held separately by the IRT vendor), and lifecycle status (PACKAGED → IN_INVENTORY → DISPENSED → RETURNED → RECONCILED).
property:
  path: kitId
  datatype: anyURI
  min count: 1
  max count: 1
  name: kitId
property:
  path: kitNumber
  datatype: string
  min count: 1
  max count: 1
  description: Sponsor / IRT-assigned kit identifier (e.g., 'KIT-00042'). Operator-grounded — what gets scanned at dispensation.
  name: kitNumber
property:
  path: packagedDate
  datatype: date
  min count: 0
  max count: 1
  description: Date the kit was packaged from its Lot.
  name: packagedDate
property:
  path: treatmentAssignment
  datatype: string
  min count: 0
  max count: 1
  description: IRT-issued treatment-assignment code. For blinded studies, this is a coded label (e.g., 'A', 'B', 'PLACEBO_GROUP_2') whose unblinding key is held separately by the IRT vendor; the foundation carries the code without the unblinding map.
  name: treatmentAssignment
property:
  path: assignmentDate
  datatype: date
  min count: 0
  max count: 1
  description: Date the kit was assigned to a Participant (typically the randomization or dispensation date).
  name: assignmentDate
property:
  path: kitStatus
  datatype: string
  min count: 1
  max count: 1
  in: PACKAGED
  in: IN_INVENTORY
  in: ASSIGNED
  in: DISPENSED
  in: RETURNED
  in: RECONCILED
  in: DESTROYED
  description: Kit lifecycle. NGSI-LD temporal property. PACKAGED at packaging facility; IN_INVENTORY at site pharmacy; ASSIGNED when IRT issues to Participant (pre-dispensation); DISPENSED when handed to Participant; RETURNED when unused returned to pharmacy; RECONCILED at end-of-trial reconciliation; DESTROYED per IP destruction record.
  name: kitStatus
property:
  path: belongsToLot
  class: Lot
  min count: 1
  max count: 1
  node kind: IRI
  description: The Lot this Kit was packaged from. Each Kit traces back to exactly one Lot for accountability.
  name: belongsToLot
property:
  path: assignedToParticipant
  class: Participant
  min count: 0
  max count: 1
  node kind: IRI
  description: The Participant the Kit is assigned to (post-IRT-assignment). 0..1 because Kits in IN_INVENTORY haven't been assigned yet. SHACL: kitStatus=ASSIGNED or DISPENSED requires this to be populated.
  name: assignedToParticipant

EventShape
type: NodeShape
target class: Event
name: Event
description: An Event is a single container holding occurrences related to a Study lifecycle: Adverse Event (AE), Serious Adverse Event (SAE), Protocol Deviation, Data Discrepancy, Safety Signal, Safety Report, Other Clinical Event. Per FIRST-PRINCIPLES universal-foundation posture, Event is one entity for all categories — discriminated by eventCategory enum rather than split into specialized classes. Per ICH E2A / E2B(R3) and 21 CFR 312.32, regulatory reportability is a first-class attribute with submission timeline tracking. Per ICH E6(R3) Section 6, protocol deviations carry category and impact. Other Clinical Event carries derivedFrom back to a VisitObservation when a routine observation escalates to a tracked Event.
property:
  path: eventId
  datatype: anyURI
  min count: 1
  max count: 1
  description: Globally unique NGSI-LD identifier.
  name: eventId
property:
  path: eventCategory
  datatype: string
  min count: 1
  max count: 1
  in: ADVERSE_EVENT
  in: SERIOUS_ADVERSE_EVENT
  in: DEVIATION
  in: DISCREPANCY
  in: SAFETY_SIGNAL
  in: SAFETY_REPORT
  in: OTHER_CLINICAL_EVENT
  description: Discriminator across the Event categories. ADVERSE_EVENT for any untoward medical occurrence; SERIOUS_ADVERSE_EVENT for SAEs (death, life-threatening, hospitalization, persistent disability, congenital anomaly, medically important — ICH E2A definition); DEVIATION for protocol deviations (ICH E6 Section 6); DISCREPANCY for data discrepancies surfaced during cleaning; SAFETY_SIGNAL for aggregate safety signals (cross-participant trends); SAFETY_REPORT for E2B(R3) Individual Case Safety Reports submitted to regulators; OTHER_CLINICAL_EVENT for catch-all escalations (e.g., an unusual VisitObservation that doesn't fit AE but warrants tracking).
  name: eventCategory
property:
  path: eventType
  datatype: string
  min count: 0
  max count: 1
  description: Free-form workflow-domain term for the specific occurrence (e.g., 'Grade 3 nausea', 'Missed visit window', 'Lab discrepancy: alkaline phosphatase'). Not a controlled vocabulary at this layer; controlled vocabulary lives in meddraPreferredTerm (for AE/SAE) or protocolDeviationCategory (for DEVIATION).
  name: eventType
property:
  path: eventDate
  datatype: dateTime
  min count: 1
  max count: 1
  description: When the event occurred (or, for ongoing events, when it began). NGSI-LD temporal property — events have a real-world timeline distinct from when they were reported. PROV: this is the prov:atTime of the prov:Activity.
  name: eventDate
property:
  path: detectedDate
  datatype: dateTime
  min count: 0
  max count: 1
  description: When the event was detected (which may be later than when it occurred — e.g., a Grade 1 AE noticed retroactively at the next visit, or a discrepancy surfaced during data cleaning weeks after data entry).
  name: detectedDate
property:
  path: reportedDate
  datatype: dateTime
  min count: 0
  max count: 1
  description: When the event was formally reported into the trial system. For SAEs, this anchors the 24-hour / 7-day / 15-day reporting clocks.
  name: reportedDate
property:
  path: description
  datatype: string
  min count: 1
  max count: 1
  description: Operator-grounded narrative description. For AE/SAE this is the verbatim term; for DEVIATION the deviation narrative; for DISCREPANCY the specific data quality issue.
  name: description
property:
  path: severity
  datatype: string
  min count: 0
  max count: 1
  in: MILD
  in: MODERATE
  in: SEVERE
  in: LIFE_THREATENING
  in: FATAL
  in: LOW
  in: MEDIUM
  in: HIGH
  in: CRITICAL
  description: Severity grading. MILD/MODERATE/SEVERE/LIFE_THREATENING/FATAL for AE/SAE per CTCAE/ICH E2A; LOW/MEDIUM/HIGH/CRITICAL for non-clinical event categories (DEVIATION, DISCREPANCY). Mutually-exclusive scales kept in one enum for foundation simplicity; controlled-vocabulary projection at the adapter layer enforces the right scale per category.
  name: severity
property:
  path: status
  datatype: string
  min count: 1
  max count: 1
  in: REPORTED
  in: UNDER_REVIEW
  in: ASSESSED
  in: RESOLVED
  in: ONGOING
  in: CLOSED
  description: Lifecycle state. NGSI-LD temporal property — Events transition REPORTED → UNDER_REVIEW → ASSESSED → (RESOLVED|ONGOING) → CLOSED with full audit trail.
  name: status
property:
  path: detectionSource
  datatype: string
  min count: 0
  max count: 1
  in: VISIT_OBSERVATION
  in: SELF_REPORT
  in: EXTERNAL_REPORT
  in: MONITORING
  in: ROUTINE_LAB
  in: DATA_CLEANING
  in: AGGREGATE_REVIEW
  in: OTHER
  description: How the Event was detected. VISIT_OBSERVATION pairs with derivedFrom (the routine observation that escalated); SELF_REPORT is participant-initiated; EXTERNAL_REPORT covers ER visits, hospitalizations reported by family/caregiver; MONITORING surfaces during CRA review; ROUTINE_LAB for lab-flagged values; DATA_CLEANING for query-driven discrepancies; AGGREGATE_REVIEW for cross-participant safety signals.
  name: detectionSource
property:
  path: identifier
  datatype: string
  min count: 0
  max count: 1
  description: Workflow-issued identifier (e.g., 'AE-2026-0014', 'DEV-MSKCC-008'). Distinct from eventId (URI); identifier is the human-meaningful reference operators use in narratives and CAPAs.
  name: identifier
property:
  path: causality
  datatype: string
  min count: 0
  max count: 1
  in: UNRELATED
  in: UNLIKELY
  in: POSSIBLY
  in: PROBABLY
  in: DEFINITELY
  in: NOT_ASSESSABLE
  description: Investigator's causality assessment relative to the InvestigationalProduct. Required field for AE/SAE per ICH E2A; not applicable to DEVIATION or DISCREPANCY. The action taken with IP (actionTakenWithIp) often correlates with causality but is recorded separately.
  name: causality
property:
  path: expectedness
  datatype: string
  min count: 0
  max count: 1
  in: EXPECTED
  in: UNEXPECTED
  description: Whether the event is expected per the Investigator's Brochure (IB). UNEXPECTED + SERIOUS + IP-related = SUSAR (Suspected Unexpected Serious Adverse Reaction) — the highest-priority regulatory reporting category per ICH E2A.
  name: expectedness
property:
  path: regulatoryReportable
  datatype: boolean
  min count: 1
  max count: 1
  description: Whether this event triggers a regulatory submission (e.g., to FDA via E2B, to EMA via EudraVigilance). SHACL invariant: SERIOUS_ADVERSE_EVENT must have regulatoryReportable=true.
  name: regulatoryReportable
property:
  path: regulatoryReportDeadline
  datatype: dateTime
  min count: 0
  max count: 1
  description: Deadline for regulatory submission. SUSARs: 7 days for fatal/life-threatening, 15 days for other; non-SUSAR SAEs: 15 days; periodic safety reports vary. SHACL soft warning when this is in the past and regulatoryReportSubmitted is still false (overdue).
  name: regulatoryReportDeadline
property:
  path: regulatoryReportSubmitted
  datatype: boolean
  min count: 1
  max count: 1
  description: Whether the regulatory report has been submitted. NGSI-LD temporal property — flips from false to true once submission lands. SHACL invariant: when true, regulatoryReportSubmittedDate must be populated.
  name: regulatoryReportSubmitted
property:
  path: regulatoryReportSubmittedDate
  datatype: dateTime
  min count: 0
  max count: 1
  description: Date/time the regulatory report was submitted. Anchors compliance audit trails — comparing this to eventDate validates timeline compliance.
  name: regulatoryReportSubmittedDate
property:
  path: meddraPreferredTerm
  datatype: string
  min count: 0
  max count: 1
  description: MedDRA Preferred Term (PT) for AE/SAE coding. Controlled vocabulary; CDISC-pipeline manifest carries the active MedDRA version. Required for AE/SAE that submit to E2B.
  name: meddraPreferredTerm
property:
  path: meddraSystemOrganClass
  datatype: string
  min count: 0
  max count: 1
  description: MedDRA System Organ Class (SOC). Highest level in the MedDRA hierarchy; derived from PT but stored separately for query convenience and aggregate reporting.
  name: meddraSystemOrganClass
property:
  path: ctcaeGrade
  datatype: string
  min count: 0
  max count: 1
  in: GRADE_1
  in: GRADE_2
  in: GRADE_3
  in: GRADE_4
  in: GRADE_5
  description: CTCAE grading per CTCAE 5.0 (NCI Common Terminology Criteria for Adverse Events). 1=Mild, 2=Moderate, 3=Severe, 4=Life-threatening, 5=Death. SHACL invariant: ctcaeGrade only valid when eventCategory IN {ADVERSE_EVENT, SERIOUS_ADVERSE_EVENT}.
  name: ctcaeGrade
property:
  path: actionTakenWithIp
  datatype: string
  min count: 0
  max count: 1
  in: NONE
  in: DOSE_REDUCED
  in: DOSE_INTERRUPTED
  in: DOSE_DISCONTINUED
  in: NEW_TREATMENT_INITIATED
  in: NOT_APPLICABLE
  in: UNKNOWN
  description: Action taken with the InvestigationalProduct in response to the event. Per ICH E2A required AE field. NOT_APPLICABLE for DEVIATION / DISCREPANCY events.
  name: actionTakenWithIp

OrganizationShape
type: NodeShape
target class: Organization
name: Organization
description: The legal/business entity. Sponsor and Site (TOP top-levels) reference Organization for their corporate identity and roll-up structure. Modeled after USDM v3 Organization, with the addition of parentOrganization for explicit corporate hierarchy. Cross-industry: Organizations also represent operating companies in energy (refiners, EPCs), manufacturing (parent corp, plants, contract manufacturers), and other domains.
property:
  path: organizationId
  datatype: anyURI
  min count: 1
  max count: 1
  description: Globally unique NGSI-LD identifier.
  name: organizationId
property:
  path: organizationName
  datatype: string
  min count: 1
  max count: 1
  description: Display name.
  name: organizationName
property:
  path: legalName
  datatype: string
  min count: 1
  max count: 1
  description: Registered legal name.
  name: legalName
property:
  path: organizationType
  datatype: string
  min count: 1
  max count: 1
  in: PARENT_CORPORATION
  in: OPERATING_COMPANY
  in: SPONSOR
  in: CRO
  in: SITE
  in: SITE_NETWORK
  in: SMO
  in: REGULATORY_AUTHORITY
  in: OVERSIGHT_BODY
  in: VENDOR
  in: LABORATORY
  in: CONTRACT_MANUFACTURER
  in: ACADEMIC_INSTITUTION
  in: GOVERNMENT
  in: OTHER
  description: Role classification (multi-valued in practice via separate role assignments). Aligns with USDM Organization.type Code.
  name: organizationType
property:
  path: identifierScheme
  datatype: string
  min count: 1
  max count: 1
  in: DUNS
  in: ORCID
  in: GLN
  in: GS1
  in: FDA_FEI
  in: EMA_EUD
  in: OTHER
  description: Scheme for the identifier value. USDM-aligned.
  name: identifierScheme
property:
  path: identifier
  datatype: string
  min count: 1
  max count: 1
  description: Identifier value scoped by identifierScheme.
  name: identifier
property:
  path: legalAddress
  min count: 0
  max count: 1
  description: Headquarters/registered address (line1, line2, city, region, postalCode).
  name: legalAddress
property:
  path: country
  datatype: string
  min count: 1
  max count: 1
  description: ISO 3166-1 alpha-3 country code of registration.
  name: country
property:
  path: website
  datatype: anyURI
  min count: 0
  max count: 1
  description: Organization website.
  name: website
property:
  path: status
  datatype: string
  min count: 1
  max count: 1
  in: ACTIVE
  in: INACTIVE
  in: MERGED
  in: ACQUIRED
  in: DISSOLVED
  description: Lifecycle state.
  name: status
property:
  path: employeeSizeBand
  datatype: string
  min count: 0
  max count: 1
  in: 1-10
  in: 11-50
  in: 51-200
  in: 201-500
  in: 501-1000
  in: 1001-5000
  in: 5001-10000
  in: 10001-50000
  in: 50001-100000
  in: 100001+
  description: Banded employee count for the Organization. Corporate-scope fact; does not vary per Study, so lives here rather than on the per-Study Sponsor entity. Bands rather than exact counts because exact headcount is volatile and rarely needed for Sponsor portfolio analysis.
  name: employeeSizeBand
property:
  path: fiscalYearEnd
  datatype: string
  min count: 0
  max count: 1
  description: Fiscal year end as MM-DD (e.g., '12-31' for calendar year, '03-31' for many UK/Asian companies, '09-30' for US federal). Corporate-scope fact; useful for budget alignment, contract renewal cycles, and forecasting.
  name: fiscalYearEnd
property:
  path: primaryTherapeuticAreas
  datatype: string
  min count: 0
  max count: 1
  description: Comma-separated or JSON array of the Organization's portfolio therapeutic areas (oncology, cardiology, infectious disease, rare disease, etc.). Corporate-scope: Pfizer's TA spread is many; J&J Innovative Medicine's TA spread is a subset. The per-Study TA focus lives on Sponsor.primaryTherapeuticArea. Multi-value semantics: native NGSI-LD multi-value once the broker layer is in place; for the strawman emission, comma-separated string is the lowest-risk encoding.
  name: primaryTherapeuticAreas
property:
  path: parentOrganization
  class: Organization
  min count: 0
  max count: 1
  node kind: IRI
  description: Self-reference for corporate hierarchy. J&J Innovative Medicine.parentOrganization = J&J. Empty for root-level entities.
  name: parentOrganization
property:
  path: hasChildOrganization
  class: Organization
  min count: 0
  node kind: IRI
  description: Inverse of parentOrganization. Convenience relationship for downward traversal.
  name: hasChildOrganization
property:
  path: managesSite
  class: Site
  min count: 0
  node kind: IRI
  description: Sites operationally managed by this Organization. USDM Organization.managedSites.
  name: managesSite
property:
  path: playsSponsorRole
  class: Sponsor
  min count: 0
  node kind: IRI
  description: Sponsor entities backed by this Organization in specific Studies.
  name: playsSponsorRole
property:
  path: isLocatedIn
  min count: 0
  max count: 1
  node kind: IRI
  description: Country of registration; flagged-missing object in OOUX v0.2.
  comment: TARGET-MISSING: Country is a flagged-missing object in OOUX v0.2 (#57). minCount relaxed from 1 to 0 until target class is defined.
  name: isLocatedIn

DocumentShape
type: NodeShape
target class: Document
name: Document
description: Document represents any file or formal record associated with the trial. ICH E6(R3) Appendix C is the canonical record taxonomy: records are categorized by purpose (what they contribute to under GCP) and by responsible party. The TMF Reference Model and the ISF section taxonomy are the legacy operational views that map onto R3 purposes. TOP carries both axes: essentialRecordPurpose (R3 primary) and isfSection (legacy operational view).
property:
  path: documentId
  datatype: anyURI
  min count: 1
  max count: 1
  name: documentId
property:
  path: documentTitle
  datatype: string
  min count: 1
  max count: 1
  name: documentTitle
property:
  path: documentType
  datatype: string
  min count: 1
  max count: 1
  in: PROTOCOL
  in: INVESTIGATOR_BROCHURE
  in: ICF
  in: FORM_1572
  in: IRB_APPROVAL_LETTER
  in: REGULATORY_SUBMISSION
  in: CTA
  in: CDA
  in: MTA
  in: DTA
  in: INSURANCE_CERTIFICATE
  in: SOURCE_DOCUMENT
  in: IP_HANDLING_INSTRUCTIONS
  in: IP_DESTRUCTION_RECORD
  in: BLINDING_PROCEDURES
  in: LAB_NORMAL_RANGES
  in: LAB_CERTIFICATION
  in: SAMPLE_HANDLING_MANUAL
  in: RECRUITMENT_AD
  in: TRANSLATION_CERTIFICATE
  in: DELEGATION_LOG
  in: SIGNATURE_SHEET
  in: CV
  in: TRAINING_RECORD
  in: MONITORING_REPORT
  in: AUDIT_REPORT
  in: VALIDATION_RECORD
  in: SECURITY_ASSESSMENT
  in: PROCEDURES_MANUAL
  in: SOP
  in: ESSENTIAL_RECORD_OTHER
  in: OTHER
  description: Document subtype taxonomy aligned to ISF section identifiers and TMF Reference Model zones. Operational/UX label.
  name: documentType
property:
  path: documentVersion
  datatype: string
  min count: 0
  max count: 1
  name: documentVersion
property:
  path: documentStatus
  datatype: string
  min count: 0
  max count: 1
  in: DRAFT
  in: IN_REVIEW
  in: APPROVED
  in: EFFECTIVE
  in: SUPERSEDED
  in: WITHDRAWN
  in: ARCHIVED
  description: Lifecycle state.
  name: documentStatus
property:
  path: essentialRecordPurpose
  datatype: string
  min count: 0
  max count: 1
  in: QUALIFICATION
  in: DELEGATION
  in: TRAINING
  in: IP_MANAGEMENT
  in: MONITORING
  in: DATA_HANDLING
  in: SYSTEMS_VALIDATION
  in: OTHER
  description: R3 Appendix C purpose: what this record contributes to under GCP.
  name: essentialRecordPurpose
property:
  path: responsibleParty
  datatype: string
  min count: 0
  max count: 1
  in: INVESTIGATOR_INSTITUTION
  in: SPONSOR
  in: IRB_IEC
  in: REGULATORY_AUTHORITY
  in: VENDOR
  in: OTHER
  description: R3 Appendix C: party responsible for creating and maintaining this record.
  name: responsibleParty
property:
  path: isfSection
  datatype: string
  min count: 0
  max count: 1
  description: Legacy operational view: ISF section identifier (e.g., '11.1' for Signature Sheet, '14.3' for IP Accountability Log, '22.1' for Sponsor correspondences). Free-text rather than enum because ISF flavors vary (Singapore HSA, FDA, EMA all have variations).
  name: isfSection
property:
  path: etmfLocation
  datatype: anyURI
  min count: 0
  max count: 1
  description: URI of the document in its eTMF/ISF system.
  name: etmfLocation
property:
  path: creationDate
  datatype: date
  min count: 0
  max count: 1
  name: creationDate
property:
  path: effectiveDate
  datatype: date
  min count: 0
  max count: 1
  name: effectiveDate
property:
  path: expirationDate
  datatype: date
  min count: 0
  max count: 1
  name: expirationDate
property:
  path: retentionUntil
  datatype: date
  min count: 0
  max count: 1
  description: Retention end date per regulatory/contractual requirements.
  name: retentionUntil
property:
  path: language
  datatype: string
  min count: 0
  max count: 1
  description: ISO 639-1 code.
  name: language

StudySiteShape
type: NodeShape
target class: StudySite
name: StudySite
description: StudySite captures a Site's role on a specific Study. Every per-Site-per-Study fact (siteNumber, enrollmentTarget, IRB approval status, oversight tier, activation/deactivation dates, per-Study staff delegation, per-Study Systems, per-Study contracts) lives here. StudySite is the entry point for Participants enrolled at this Site for this Study and Visit-occurrences happening at this Site for this Study. The operational hierarchy runs Site -> StudySite -> Study -> Protocol -> SOA -> Visit -> Activity. StudySite is reached by the operator clicking 'this Site on this Study' and is where most of the day-to-day workflow lives.
property:
  path: studySiteId
  datatype: anyURI
  min count: 1
  max count: 1
  description: Globally unique NGSI-LD identifier for this Site-Study pair.
  name: studySiteId
property:
  path: siteNumber
  datatype: string
  min count: 1
  max count: 1
  description: Site number assigned by the sponsor for this Study. Distinct from Site.siteId (which is global).
  name: siteNumber
property:
  path: studySiteStatus
  datatype: string
  min count: 1
  max count: 1
  in: PLANNED
  in: IN_QUALIFICATION
  in: ACTIVE
  in: ON_HOLD
  in: CLOSED
  description: Per-Study lifecycle state. R3 Section 2.6 grounds the termination/suspension framing.
  name: studySiteStatus
property:
  path: activationDate
  datatype: date
  min count: 0
  max count: 1
  description: Date the Site was activated for this Study (Site Initiation Visit completed; first patient can be enrolled).
  name: activationDate
property:
  path: deactivationDate
  datatype: date
  min count: 0
  max count: 1
  description: Date the Site was deactivated for this Study (close-out completed). Empty for currently-active StudySite records.
  name: deactivationDate
property:
  path: enrollmentTarget
  datatype: integer
  min count: 0
  max count: 1
  description: Target number of Participants for this Site for this Study.
  name: enrollmentTarget
property:
  path: actualEnrollment
  datatype: integer
  min count: 0
  max count: 1
  description: Current count of Participants enrolled at this Site for this Study. Could be a derived attribute via SPARQL aggregation; surfaced as a stored attribute for operational view speed.
  name: actualEnrollment
property:
  path: lastMonitoringVisitDate
  datatype: date
  min count: 0
  max count: 1
  name: lastMonitoringVisitDate
property:
  path: oversightTier
  datatype: string
  min count: 0
  max count: 1
  in: LOW
  in: MEDIUM
  in: HIGH
  description: R3 Section 3.10 risk-based monitoring tier for this Site on this Study. Drives Sponsor monitoring frequency and Audit prioritization. The same Site can be HIGH on a complex oncology trial and LOW on a simple registry — hence per-StudySite, not per-Site.
  name: oversightTier
property:
  path: recruitmentPotential
  datatype: integer
  min count: 0
  max count: 1
  description: Per-protocol estimate of recruitable Participants. Distinct from Site.totalTrialsConducted (lifetime) and Site.averageEnrollmentRate (cross-trial). R3 Section 2.2 grounds the requirement.
  name: recruitmentPotential
property:
  path: staffingAdequate
  datatype: boolean
  min count: 0
  max count: 1
  description: Per-protocol staffing adequacy. R3 Section 2.2 — adequacy depends on protocol complexity, so per-StudySite.
  name: staffingAdequate
property:
  path: essentialRecordsRetentionUntil
  datatype: date
  min count: 0
  max count: 1
  description: Date until which essential records for this StudySite must be retained. Per-Study because retention requirements vary by jurisdiction x Study type.
  name: essentialRecordsRetentionUntil
property:
  path: irbApprovalStatus
  datatype: string
  min count: 0
  max count: 1
  in: PENDING
  in: APPROVED
  in: WITH_CONDITIONS
  in: EXPIRED
  in: WITHDRAWN
  in: DENIED
  description: Current IRB approval status for this StudySite.
  name: irbApprovalStatus
property:
  path: irbApprovalDate
  datatype: date
  min count: 0
  max count: 1
  name: irbApprovalDate
property:
  path: regulatoryAuthorizationStatus
  datatype: string
  min count: 0
  max count: 1
  in: NOT_REQUIRED
  in: PENDING
  in: APPROVED
  in: EXPIRED
  in: WITHDRAWN
  in: DENIED
  description: Per-Study regulatory authorization status (FDA, EMA, etc., per jurisdiction).
  name: regulatoryAuthorizationStatus
property:
  path: validFrom
  datatype: dateTime
  min count: 0
  max count: 1
  description: Datetime from which this StudySite participation is operationally valid. Mirrors Sponsor's NGSI-LD-native temporal property for relationship handoffs (e.g., when a Site changes Principal Investigator mid-study).
  name: validFrom
property:
  path: validUntil
  datatype: dateTime
  min count: 0
  max count: 1
  name: validUntil
property:
  path: forSite
  class: Site
  min count: 1
  max count: 1
  node kind: IRI
  description: The Site this StudySite participation belongs to.
  name: forSite
property:
  path: forStudy
  class: Study
  min count: 1
  max count: 1
  node kind: IRI
  description: The Study this Site is participating in.
  name: forStudy
property:
  path: hasPrincipalInvestigator
  class: Person
  min count: 1
  max count: 1
  node kind: IRI
  description: The per-Study Principal Investigator at this Site. R3 Section 2.1 GCP-required. The Person must be drawn from forSite.hasStaff (SHACL invariant). Temporal handoffs use validFrom/validUntil on the relationship.
  name: hasPrincipalInvestigator
property:
  path: delegatesAuthorityTo
  class: Person
  min count: 1
  node kind: IRI
  description: Per-Study Delegation of Authority Log roster. R3 Section 2.3.3 GCP-required. Each delegation carries role (sub-investigator, study coordinator, regulatory coordinator, pharmacist, etc.), scope, validFrom, validUntil. Each Person must be drawn from forSite.hasStaff.
  name: delegatesAuthorityTo
property:
  path: hasIRB
  class: OversightBody
  min count: 1
  node kind: IRI
  description: Per-Study IRB(s)/IEC(s) of record for this StudySite. 1..N for multi-IRB cases.
  name: hasIRB
property:
  path: submitsTo
  min count: 0
  node kind: IRI
  description: Per-jurisdiction regulatory authorities this StudySite files with. R3 Section 2.3.5 inspection right anchored here.
  comment: TARGET-MISSING: RegulatoryAuthority is a flagged-missing horizontal in OOUX v0.2.
  name: submitsTo
property:
  path: hasContract
  min count: 0
  node kind: IRI
  description: Site-level contracts for this StudySite participation: CTA, CDA, MTA, DTA, etc.
  comment: TARGET-MISSING: Contract is a flagged-missing horizontal in OOUX v0.2.
  name: hasContract
property:
  path: hasStudyStartupPackage
  min count: 0
  max count: 1
  node kind: IRI
  description: The Study Startup Package distributed to this Site for this Study.
  comment: TARGET-MISSING: StudyStartupPackage is in OOUX v0.2 catalog but not yet in TOP source.
  name: hasStudyStartupPackage

PersonShape
type: NodeShape
target class: Person
name: Person
description: Person represents any individual involved in trial conduct: principal investigators, sub-investigators, study coordinators, regulatory coordinators, pharmacists, study nurses, lab techs, monitors, sponsor staff, regulators, IRB members. Persons exist independently of any specific Site or Study; their roles in specific contexts are captured via relationship targets and PersonRole assignments. USDM models AssignedPerson as nested inside StudyRole — TOP makes Person a horizontal so it can be referenced consistently across the operational chain (Site.hasStaff, StudySite.hasPrincipalInvestigator, StudySite.delegatesAuthorityTo, Sponsor.employs, OversightBody.members, Audit.auditors).
property:
  path: personId
  datatype: anyURI
  min count: 1
  max count: 1
  description: Globally unique NGSI-LD identifier.
  name: personId
property:
  path: firstName
  datatype: string
  min count: 1
  max count: 1
  name: firstName
property:
  path: middleName
  datatype: string
  min count: 0
  max count: 1
  name: middleName
property:
  path: lastName
  datatype: string
  min count: 1
  max count: 1
  name: lastName
property:
  path: title
  datatype: string
  min count: 0
  max count: 1
  description: Professional title (Dr., Prof., MD, RN, PharmD, etc.).
  name: title
property:
  path: jobTitle
  datatype: string
  min count: 0
  max count: 1
  description: USDM AssignedPerson.jobTitle. The functional role at the employing Organization (e.g., Director of Clinical Research, Senior CRA, Study Coordinator).
  name: jobTitle
property:
  path: email
  datatype: string
  min count: 0
  max count: 1
  name: email
property:
  path: phone
  datatype: string
  min count: 0
  max count: 1
  name: phone
property:
  path: orcid
  datatype: string
  min count: 0
  max count: 1
  description: ORCID identifier.
  name: orcid
property:
  path: npi
  datatype: string
  min count: 0
  max count: 1
  description: US National Provider Identifier (where applicable).
  name: npi
property:
  path: preferredLanguages
  datatype: string
  min count: 0
  max count: 1
  description: Comma-separated ISO 639-1 codes.
  name: preferredLanguages
property:
  path: gcpTrainingStatus
  datatype: string
  min count: 0
  max count: 1
  in: CURRENT
  in: EXPIRED
  in: NOT_REQUIRED
  description: GCP training currency. Per-Person fact independent of any Site or Study.
  name: gcpTrainingStatus
property:
  path: gcpTrainingExpiry
  datatype: date
  min count: 0
  max count: 1
  name: gcpTrainingExpiry
property:
  path: status
  datatype: string
  min count: 1
  max count: 1
  in: ACTIVE
  in: INACTIVE
  in: RETIRED
  in: DECEASED
  description: Lifecycle state.
  name: status
property:
  path: employedBy
  class: Organization
  min count: 0
  max count: 1
  node kind: IRI
  description: Primary employing Organization. USDM AssignedPerson.organizationId. A Person can have multiple StudySite/Sponsor relationships independent of where they're employed.
  name: employedBy
property:
  path: hasCredential
  class: Credential
  min count: 0
  node kind: IRI
  description: Credentials this Person holds (medical license, specialty board certifications, GCP certificate, etc.).
  name: hasCredential
property:
  path: hasTrainingRecord
  min count: 0
  node kind: IRI
  description: Training records for this Person (study-specific GCP, study-specific protocol training, etc.).
  comment: TARGET-MISSING: TrainingRecord is in OOUX v0.2 (#77) but not yet in TOP source.
  name: hasTrainingRecord

SystemShape
type: NodeShape
target class: System
name: System
description: System represents a computerised system used in trial conduct: EDC, CTMS, eTMF/ISF, IRT/RTSM, safety database, EMR, ELN, eCOA/ePRO platform, eConsent platform, sample management system, etc. Systems carry their R3 Section 4.3 governance attributes (validation, security, access controls, release status, contingency plans, support) and a three-axis role pattern (operatedBy / usedBy / oversightHeldBy) that captures GCP responsibility allocation.
property:
  path: systemId
  datatype: anyURI
  min count: 1
  max count: 1
  name: systemId
property:
  path: vendor
  datatype: string
  min count: 1
  max count: 1
  description: Vendor name (e.g., 'Veeva', 'Medidata', 'Oracle', 'Castor').
  name: vendor
property:
  path: productName
  datatype: string
  min count: 1
  max count: 1
  description: Product name (e.g., 'Vault eTMF', 'Rave EDC', 'Siebel CTMS', 'CDMS').
  name: productName
property:
  path: instanceId
  datatype: string
  min count: 0
  max count: 1
  description: Tenant or instance identifier (e.g., 'mskcc-prod', 'pfizer-tenant-7').
  name: instanceId
property:
  path: baseUrl
  datatype: anyURI
  min count: 0
  max count: 1
  description: Base URL for the System instance. May be unpopulated when the consumer of the System record does not have access to the instance details (R3 Section 3.9 oversight-as-relationship framing).
  name: baseUrl
property:
  path: systemType
  datatype: string
  min count: 1
  max count: 1
  in: EDC
  in: CTMS
  in: ETMF
  in: ISF
  in: IRT
  in: RTSM
  in: SAFETY_DB
  in: EMR
  in: ELN
  in: ECOA
  in: EPRO
  in: ECONSENT
  in: SAMPLE_TRACKING
  in: LABORATORY_INFORMATION
  in: PHARMACY_MANAGEMENT
  in: OTHER
  description: Functional system type.
  name: systemType
property:
  path: version
  datatype: string
  min count: 0
  max count: 1
  name: version
property:
  path: validatedFor21CfrPart11
  datatype: boolean
  min count: 0
  max count: 1
  description: FDA 21 CFR Part 11 validation status.
  name: validatedFor21CfrPart11
property:
  path: validatedForEuAnnex11
  datatype: boolean
  min count: 0
  max count: 1
  description: EU EudraLex Annex 11 validation status.
  name: validatedForEuAnnex11
property:
  path: validationStatus
  datatype: string
  min count: 0
  max count: 1
  in: NOT_VALIDATED
  in: IN_VALIDATION
  in: VALIDATED
  in: REVALIDATING
  in: RETIRED
  description: R3 Section 4.3.4 validation lifecycle state.
  name: validationStatus
property:
  path: validationApproach
  datatype: string
  min count: 0
  max count: 1
  in: RISK_BASED
  in: FULL_VALIDATION
  in: VENDOR_QUALIFICATION_ONLY
  description: R3 Section 4.3.4 risk-based validation approach.
  name: validationApproach
property:
  path: lastValidationDate
  datatype: date
  min count: 0
  max count: 1
  name: lastValidationDate
property:
  path: releaseStatus
  datatype: string
  min count: 0
  max count: 1
  in: DEVELOPMENT
  in: UAT
  in: PRODUCTION
  in: REVALIDATING
  in: RETIRED
  description: R3 Section 4.3.5 release lifecycle.
  name: releaseStatus
property:
  path: auditTrailEnabled
  datatype: boolean
  min count: 0
  max count: 1
  description: R3 Section 4.2.2 audit-trail capability.
  name: auditTrailEnabled
property:
  path: operatedBy
  class: Organization
  min count: 1
  max count: 1
  node kind: IRI
  description: The Organization that operates this System and is responsible for its R3 Section 4.3 obligations (validation, security, access controls, release, contingency, support). A Sponsor's EDC has operatedBy -> Pfizer (or Pfizer's CRO under documented agreement); a Site's local source-document repository has operatedBy -> MSKCC.
  name: operatedBy
property:
  path: usedBy
  class: Organization
  min count: 0
  node kind: IRI
  description: Organizations that use this System for trial activities. A Sponsor-operated EDC is used by both Sponsor staff and authorized Site staff; the same System has multiple usedBy triples.
  name: usedBy
property:
  path: oversightHeldBy
  class: Organization
  min count: 1
  max count: 1
  node kind: IRI
  description: The Organization holding GCP-mandated oversight responsibility for this System's use in trial conduct. R3 Section 3.9 (Sponsor for trial-critical Sponsor-delegated Systems) or Section 2.12 (Site for Site-internal records). For sponsor-critical Systems (EDC, CTMS, IRT, SAFETY_DB), oversightHeldBy must be a Sponsor (SHACL invariant); the IIT case where Site=Sponsor exempts via the Site.belongsToOrganization == Sponsor.belongsToOrganization equality test.
  name: oversightHeldBy
property:
  path: proceduresDocumentRef
  class: Document
  min count: 0
  max count: 1
  node kind: IRI
  description: R3 Section 4.3.1 procedures document.
  name: proceduresDocumentRef
property:
  path: securityAssessmentRef
  class: Document
  min count: 0
  max count: 1
  node kind: IRI
  description: R3 Section 4.3.3 security assessment.
  name: securityAssessmentRef
property:
  path: accessControlPolicyRef
  class: Document
  min count: 0
  max count: 1
  node kind: IRI
  description: R3 Section 4.3.8 access control policy.
  name: accessControlPolicyRef
property:
  path: contingencyPlanRef
  class: Document
  min count: 0
  max count: 1
  node kind: IRI
  description: R3 Section 4.3.6 contingency / disaster-recovery plan.
  name: contingencyPlanRef
property:
  path: supportContact
  class: Person
  min count: 0
  max count: 1
  node kind: IRI
  description: R3 Section 4.3.7 technical support point of contact.
  name: supportContact

LogShape
type: NodeShape
target class: Log
name: Log
description: Log represents records of events, actions, or observations that occur during trial conduct. Logs are append-only by GCP discipline (R3 Section 4.2.2) — entries cannot be retroactively edited. Logs are distinct from Documents in that they have lifecycle behavior (entry, review, sign-off) and are inherently temporal sequences. Covers Subject Logs (ISF section 13), IP Accountability Logs (14.3), IP Storage Temperature Logs (14.5), Site Visit Logs (16.1), Sample Handling Logs (18.1), SAE Tracking Logs (19.1), Communication Logs (22), and others.
property:
  path: logId
  datatype: anyURI
  min count: 1
  max count: 1
  name: logId
property:
  path: logType
  datatype: string
  min count: 1
  max count: 1
  in: SUBJECT_SCREENING
  in: SUBJECT_ENROLLMENT
  in: SUBJECT_IDENTIFICATION
  in: SUBJECT_VISIT_TRACKING
  in: IP_DISPENSING
  in: IP_ACCOUNTABILITY
  in: IP_TEMPERATURE
  in: IP_STORAGE_TEMPERATURE
  in: SITE_VISIT
  in: MONITORING_VISIT
  in: SAMPLE_HANDLING
  in: SAMPLE_SHIPPING
  in: SAE_TRACKING
  in: COMMUNICATION
  in: TRAINING
  in: AUDIT_TRAIL
  in: DELEGATION
  in: TEMPERATURE_DEVIATION
  in: OTHER
  description: The log's discriminator. CommunicationLog folds in as COMMUNICATION; AuditTrail folds in as AUDIT_TRAIL.
  name: logType
property:
  path: logTitle
  datatype: string
  min count: 1
  max count: 1
  description: Human-readable title of the log (e.g., 'IP Storage Temperature — Freezer F-12 — 2026 Q1').
  name: logTitle
property:
  path: openedDate
  datatype: date
  min count: 1
  max count: 1
  name: openedDate
property:
  path: closedDate
  datatype: date
  min count: 0
  max count: 1
  description: Empty for currently-active logs.
  name: closedDate
property:
  path: status
  datatype: string
  min count: 1
  max count: 1
  in: ACTIVE
  in: CLOSED
  in: ARCHIVED
  description: Lifecycle state.
  name: status
property:
  path: entryCount
  datatype: integer
  min count: 0
  max count: 1
  description: Count of entries in this log; aggregate signal.
  name: entryCount
property:
  path: retentionUntil
  datatype: date
  min count: 0
  max count: 1
  description: Date until which this log must be retained per regulatory/contractual requirements.
  name: retentionUntil
property:
  path: forStudySite
  class: StudySite
  min count: 0
  max count: 1
  node kind: IRI
  description: The StudySite this log belongs to. Most operational logs are per-StudySite. Empty for Site-wide logs (e.g., institutional audit trail) which use forSite instead.
  name: forStudySite
property:
  path: forSite
  class: Site
  min count: 0
  max count: 1
  node kind: IRI
  description: The Site this log belongs to, when the log is study-independent (e.g., institutional GCP training log).
  name: forSite
property:
  path: forStudy
  class: Study
  min count: 0
  max count: 1
  node kind: IRI
  description: The Study this log belongs to, when the log is Sponsor-side and not Site-scoped.
  name: forStudy
property:
  path: forSystem
  class: System
  min count: 0
  max count: 1
  node kind: IRI
  description: The System this log records (e.g., audit-trail logs are System-scoped under R3 Section 4.2.2).
  name: forSystem
property:
  path: owner
  class: Person
  min count: 0
  max count: 1
  node kind: IRI
  description: The Person responsible for maintaining this log.
  name: owner
property:
  path: correspondent
  class: Organization
  min count: 0
  node kind: IRI
  description: For logType=COMMUNICATION: the parties this correspondence log captures exchanges with (Sponsor, IRB, RegulatoryAuthority, central lab, vendor). 0..N because some correspondence logs aggregate across multiple parties.
  name: correspondent
property:
  path: forEquipment
  class: Equipment
  min count: 0
  max count: 1
  node kind: IRI
  description: The Equipment this log is about (e.g., a temperature log for freezer F-12). Distinct from forSystem which captures the monitoring System; logs about Equipment with IoT monitoring will populate both forEquipment and forSystem.
  name: forEquipment

EquipmentShape
type: NodeShape
target class: Equipment
name: Equipment
description: Equipment represents physical devices used in clinical-trial conduct: refrigerators, freezers, centrifuges, scales, ECG machines, ultrasound, blood pressure devices, glucometers, pulse oximeters, etc. Equipment is distinct from System (computerised systems): a freezer with IoT temperature monitoring is Equipment + a System (the monitoring platform), linked via Equipment.monitoredBySystem. Under R3, Equipment carries qualification, calibration, maintenance, and training discipline; computerised-systems aspects (validation, audit trails, access controls per R3 Section 4.3) live on the linked System.
property:
  path: equipmentId
  datatype: anyURI
  min count: 1
  max count: 1
  name: equipmentId
property:
  path: equipmentName
  datatype: string
  min count: 1
  max count: 1
  description: Display name (e.g., 'Freezer F-12 Pharmacy', 'Eppendorf 5810R Centrifuge').
  name: equipmentName
property:
  path: equipmentClass
  datatype: string
  min count: 1
  max count: 1
  in: FREEZER
  in: REFRIGERATOR
  in: CENTRIFUGE
  in: SCALE
  in: ECG_MACHINE
  in: ULTRASOUND
  in: BP_DEVICE
  in: THERMOMETER
  in: INCUBATOR
  in: AUTOCLAVE
  in: MICROSCOPE
  in: PIPETTE
  in: PH_METER
  in: SPIROMETER
  in: GLUCOMETER
  in: PULSE_OXIMETER
  in: WEARABLE
  in: INFUSION_PUMP
  in: COMPUTER
  in: PRINTER
  in: OTHER
  description: Equipment class taxonomy. Covers most clinical-trial Equipment classes including participant-loaned wearables.
  name: equipmentClass
property:
  path: equipmentBinding
  datatype: string
  min count: 1
  max count: 1
  in: SITE_BOUND
  in: VENDOR_OWNED
  in: PARTICIPANT_LOANED
  description: OOUX-locked binding pattern: SITE_BOUND for institution-owned equipment at a Site; VENDOR_OWNED for sponsor- or vendor-supplied equipment used at a Site; PARTICIPANT_LOANED for equipment loaned to a participant (wearables, BP cuff, glucometer).
  name: equipmentBinding
property:
  path: manufacturer
  datatype: string
  min count: 0
  max count: 1
  name: manufacturer
property:
  path: model
  datatype: string
  min count: 0
  max count: 1
  name: model
property:
  path: serialNumber
  datatype: string
  min count: 0
  max count: 1
  name: serialNumber
property:
  path: purchaseDate
  datatype: date
  min count: 0
  max count: 1
  name: purchaseDate
property:
  path: installationDate
  datatype: date
  min count: 0
  max count: 1
  name: installationDate
property:
  path: lastCalibrationDate
  datatype: date
  min count: 0
  max count: 1
  name: lastCalibrationDate
property:
  path: nextCalibrationDueDate
  datatype: date
  min count: 0
  max count: 1
  name: nextCalibrationDueDate
property:
  path: calibrationFrequency
  datatype: string
  min count: 0
  max count: 1
  in: DAILY
  in: WEEKLY
  in: MONTHLY
  in: QUARTERLY
  in: SEMIANNUAL
  in: ANNUAL
  in: BIANNUAL
  in: ON_USE
  in: NOT_REQUIRED
  name: calibrationFrequency
property:
  path: lastMaintenanceDate
  datatype: date
  min count: 0
  max count: 1
  name: lastMaintenanceDate
property:
  path: maintenanceSchedule
  datatype: string
  min count: 0
  max count: 1
  in: DAILY
  in: WEEKLY
  in: MONTHLY
  in: QUARTERLY
  in: SEMIANNUAL
  in: ANNUAL
  in: ON_DEMAND
  in: NOT_REQUIRED
  name: maintenanceSchedule
property:
  path: status
  datatype: string
  min count: 1
  max count: 1
  in: OPERATIONAL
  in: UNDER_MAINTENANCE
  in: OUT_OF_SERVICE
  in: RETIRED
  in: QUARANTINED
  description: Lifecycle state.
  name: status
property:
  path: locationDescription
  datatype: string
  min count: 0
  max count: 1
  description: Free-text location (e.g., 'Pharmacy Room 3, second shelf'). For structured location, use atStorageLocation relationship via the StorageLocation horizontal.
  name: locationDescription
property:
  path: temperatureRange
  min count: 0
  max count: 1
  description: For temperature-controlled Equipment: {minTempC, maxTempC, units}. Distinct from monitored temperature readings, which live in Log entries.
  name: temperatureRange
property:
  path: atSite
  class: Site
  min count: 0
  max count: 1
  node kind: IRI
  description: The Site where this Equipment is located. Inverse of Site.hostsEquipment. 0..1 because VENDOR_OWNED equipment may move between sites; PARTICIPANT_LOANED equipment is at a Participant.
  name: atSite
property:
  path: atStudySite
  class: StudySite
  min count: 0
  node kind: IRI
  description: The StudySites this Equipment is dedicated to. Empty for Site-shared Equipment (a general-purpose centrifuge); populated for per-Study dedicated Equipment (a study-specific freezer).
  name: atStudySite
property:
  path: vendor
  class: Organization
  min count: 0
  max count: 1
  node kind: IRI
  description: The Organization that manufactured or supplies this Equipment. Organization with organizationType=VENDOR.
  name: vendor
property:
  path: monitoredBySystem
  class: System
  min count: 0
  node kind: IRI
  description: Computerised System(s) that monitor or control this Equipment. A pharmacy-grade freezer with cloud-based temperature logging has monitoredBySystem pointing to the IoT temperature monitor System. The Equipment-System split keeps R3 Section 4.3 obligations on the System and Equipment-qualification obligations on the Equipment.
  name: monitoredBySystem
property:
  path: responsiblePerson
  class: Person
  min count: 0
  max count: 1
  node kind: IRI
  description: The Person responsible for maintaining/operating this Equipment.
  name: responsiblePerson
property:
  path: hasCredential
  class: Credential
  min count: 0
  node kind: IRI
  description: Equipment-level credentials: calibration certificates, validation certificates, vendor certifications.
  name: hasCredential

StorageLocationShape
type: NodeShape
target class: StorageLocation
name: StorageLocation
description: StorageLocation represents an addressable storage point: a slot in a freezer rack, a shelf in a refrigerator, a position in a sample matrix, a drawer in a secure cabinet, an offsite vault location. StorageLocation is distinct from Equipment: an Equipment freezer provides multiple StorageLocations (its slots/shelves/racks); a secure cabinet (Equipment) provides drawer StorageLocations. Some StorageLocations are not inside Equipment (an ambient-temperature shelf in a controlled-access pharmacy room).
property:
  path: storageLocationId
  datatype: anyURI
  min count: 1
  max count: 1
  name: storageLocationId
property:
  path: locationName
  datatype: string
  min count: 1
  max count: 1
  description: Display name (e.g., 'Freezer F-12, Rack 3, Slot A4').
  name: locationName
property:
  path: storageType
  datatype: string
  min count: 1
  max count: 1
  in: FREEZER_SLOT
  in: REFRIGERATOR_SHELF
  in: AMBIENT_SHELF
  in: SECURE_CABINET_DRAWER
  in: OFFSITE_VAULT
  in: PHARMACY_SHELF
  in: BIOREPOSITORY_RACK
  in: OTHER
  name: storageType
property:
  path: temperatureRangeC
  datatype: string
  min count: 0
  max count: 1
  in: MINUS_80
  in: MINUS_20
  in: FOUR
  in: FIFTEEN
  in: ROOM_TEMP
  in: AMBIENT
  in: OTHER
  description: Standard temperature ranges in Celsius. For non-standard ranges document via the linked Equipment.temperatureRange.
  name: temperatureRangeC
property:
  path: capacity
  datatype: integer
  min count: 0
  max count: 1
  description: Total capacity (count or volume).
  name: capacity
property:
  path: capacityUnit
  datatype: string
  min count: 0
  max count: 1
  description: Unit of capacity (slots, mL, etc.).
  name: capacityUnit
property:
  path: currentOccupancy
  datatype: integer
  min count: 0
  max count: 1
  description: Current count of items stored.
  name: currentOccupancy
property:
  path: accessRestriction
  datatype: string
  min count: 0
  max count: 1
  in: UNRESTRICTED
  in: AUTHORIZED_ONLY
  in: PI_ONLY
  in: PHARMACY_ONLY
  in: OTHER
  name: accessRestriction
property:
  path: securityLevel
  datatype: string
  min count: 0
  max count: 1
  in: LOW
  in: MEDIUM
  in: HIGH
  name: securityLevel
property:
  path: gpsCoordinates
  datatype: string
  min count: 0
  max count: 1
  description: Lat/long for offsite vaults (e.g., '40.7128,-74.0060').
  name: gpsCoordinates
property:
  path: status
  datatype: string
  min count: 1
  max count: 1
  in: ACTIVE
  in: DECOMMISSIONED
  in: QUARANTINED
  description: Lifecycle state.
  name: status
property:
  path: atSite
  class: Site
  min count: 1
  max count: 1
  node kind: IRI
  description: The Site this StorageLocation belongs to. Inverse of Site.hasStorageLocation.
  name: atSite
property:
  path: inEquipment
  class: Equipment
  min count: 0
  max count: 1
  node kind: IRI
  description: The Equipment this StorageLocation is housed in (when applicable). A slot in freezer F-12 has inEquipment pointing to Freezer F-12; an ambient pharmacy shelf has no inEquipment.
  name: inEquipment
property:
  path: monitoredBySystem
  class: System
  min count: 0
  node kind: IRI
  description: Computerised systems that monitor this StorageLocation (inventory tracking, slot-level temperature monitoring).
  name: monitoredBySystem

CredentialShape
type: NodeShape
target class: Credential
name: Credential
description: Credential represents a qualification, certification, license, or accreditation. Credentials apply polymorphically to Persons (medical licenses, GCP certificates, board certifications), Sites (CLIA certification, JCAHO accreditation, ISO 9001), and Equipment (calibration certificates, validation certificates). Each Credential carries an issuing authority, an issue/expiry window, and a verification status, plus an optional reference to the certificate Document.
property:
  path: credentialId
  datatype: anyURI
  min count: 1
  max count: 1
  name: credentialId
property:
  path: credentialType
  datatype: string
  min count: 1
  max count: 1
  in: MEDICAL_LICENSE
  in: BOARD_CERTIFICATION
  in: GCP_CERTIFICATE
  in: CITI_CERTIFICATE
  in: ACLS
  in: BLS
  in: CV
  in: CLIA_CERTIFICATION
  in: CAP_CERTIFICATION
  in: JCAHO_ACCREDITATION
  in: ISO_9001
  in: ISO_15189
  in: CALIBRATION_CERTIFICATE
  in: VALIDATION_CERTIFICATE
  in: VENDOR_CERTIFICATION
  in: INSTITUTIONAL_LICENSE
  in: OTHER
  name: credentialType
property:
  path: credentialNumber
  datatype: string
  min count: 0
  max count: 1
  description: Identifier issued by the issuing authority.
  name: credentialNumber
property:
  path: issuingAuthorityName
  datatype: string
  min count: 1
  max count: 1
  description: Free-text name when the issuing authority is not modeled as an Organization (e.g., 'Texas Medical Board'); use issuingAuthorityOrg relationship for modeled authorities.
  name: issuingAuthorityName
property:
  path: issueDate
  datatype: date
  min count: 0
  max count: 1
  name: issueDate
property:
  path: expirationDate
  datatype: date
  min count: 0
  max count: 1
  name: expirationDate
property:
  path: status
  datatype: string
  min count: 1
  max count: 1
  in: ACTIVE
  in: PENDING_VERIFICATION
  in: EXPIRED
  in: REVOKED
  in: SUSPENDED
  description: Lifecycle state.
  name: status
property:
  path: verificationStatus
  datatype: string
  min count: 0
  max count: 1
  in: NOT_VERIFIED
  in: IN_PROGRESS
  in: VERIFIED
  in: FAILED_VERIFICATION
  name: verificationStatus
property:
  path: verificationDate
  datatype: date
  min count: 0
  max count: 1
  name: verificationDate
property:
  path: lastReviewDate
  datatype: date
  min count: 0
  max count: 1
  name: lastReviewDate
property:
  path: nextReviewDate
  datatype: date
  min count: 0
  max count: 1
  name: nextReviewDate
property:
  path: forPerson
  class: Person
  min count: 0
  max count: 1
  node kind: IRI
  description: Person this Credential is held by (medical license, GCP certificate, etc.). Mutually exclusive with forSite and forEquipment in operational practice; SHACL invariant enforces exactly-one-target.
  name: forPerson
property:
  path: forSite
  class: Site
  min count: 0
  max count: 1
  node kind: IRI
  description: Site this Credential is held by (CLIA, JCAHO, etc.).
  name: forSite
property:
  path: forEquipment
  class: Equipment
  min count: 0
  max count: 1
  node kind: IRI
  description: Equipment this Credential is held by (calibration certificate, validation certificate).
  name: forEquipment
property:
  path: issuingAuthorityOrg
  class: Organization
  min count: 0
  max count: 1
  node kind: IRI
  description: The Organization issuing this Credential, when modeled (e.g., American Board of Internal Medicine). Use when the issuing authority is also referenced elsewhere; otherwise use issuingAuthorityName free-text.
  name: issuingAuthorityOrg
property:
  path: verifiedBy
  class: Person
  min count: 0
  max count: 1
  node kind: IRI
  description: Person who verified this Credential.
  name: verifiedBy
property:
  path: referenceDocument
  class: Document
  min count: 0
  max count: 1
  node kind: IRI
  description: The certificate / license / attestation document file.
  name: referenceDocument

SponsorSoRImpliesRegRespShape
type: NodeShape
target class: Sponsor
sparql: SPARQLConstraint
  message: Sponsor flagged isSponsorOfRecord=true but hasRegulatoryResponsibility=false. Permitted under FDA 21 CFR 312.52 (transfer of obligations) but unusual; verify intent.
  severity: Warning
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this top:isSponsorOfRecord true . $this top:hasRegulatoryResponsibility false . }

StudyMustHaveSoRShape
type: NodeShape
target class: Study
sparql: SPARQLConstraint
  message: Study has no Sponsor flagged isSponsorOfRecord=true. At least one sponsor of record is required to carry regulatory accountability.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Study . FILTER NOT EXISTS { ?sponsor top:runs $this . ?sponsor top:isSponsorOfRecord true . } }

OneSoRPerStudyPerJurisdictionShape
type: NodeShape
target class: Study
sparql: SPARQLConstraint
  message: Study has more than one Sponsor flagged isSponsorOfRecord=true under the same RegulatoryAuthority (or with no explicit scope). Exactly one SoR per (Study x jurisdiction) is required; Sponsors lacking regulatoryAuthorityScope are treated as the implicit single-jurisdiction bucket.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this ?ra WHERE { { SELECT $this ?ra (COUNT(?sponsor) AS ?cnt) WHERE { ?sponsor top:runs $this . ?sponsor top:isSponsorOfRecord true . OPTIONAL { ?sponsor top:regulatoryAuthorityScope ?ra } } GROUP BY $this ?ra } FILTER (?cnt > 1) }

StudyMustHaveOperationalSponsorShape
type: NodeShape
target class: Study
sparql: SPARQLConstraint
  message: Study has no Sponsor with hasOperationalResponsibility=true. Day-to-day operational ownership must be assigned to at least one Sponsor entity.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Study . FILTER NOT EXISTS { ?sponsor top:runs $this . ?sponsor top:hasOperationalResponsibility true . } }

SiteDecentralizedHubNeedsOrgShape
type: NodeShape
target class: Site
sparql: SPARQLConstraint
  message: Site has siteType=DECENTRALIZED_HUB but no belongsToOrganization. A decentralized hub still requires a legal/operational Organization to anchor regulatory and contractual responsibility.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Site . $this top:siteType "DECENTRALIZED_HUB" . FILTER NOT EXISTS { $this top:belongsToOrganization ?org } }

SiteNetworkOrgTypeShape
type: NodeShape
target class: Site
sparql: SPARQLConstraint
  message: Site.partOfSiteNetwork points at an Organization whose organizationType is not SITE_NETWORK or SMO. The relationship is intended for site-network or SMO Organizations only; pointing at other types is a modeling error.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> PREFIX topc: <https://top.scientix.ai/onto/commons/v1#> SELECT $this ?org ?orgType WHERE { $this top:partOfSiteNetwork ?org . ?org topc:organizationType ?orgType . FILTER (?orgType != "SITE_NETWORK" && ?orgType != "SMO") }

StudySiteActiveNeedsPIShape
type: NodeShape
target class: StudySite
sparql: SPARQLConstraint
  message: StudySite has studySiteStatus=ACTIVE but no hasPrincipalInvestigator. ICH E6(R3) Section 2.1 requires a qualified Principal Investigator for any active Site participation.
  severity: Violation
  select: PREFIX topc: <https://top.scientix.ai/onto/commons/v1#> SELECT $this WHERE { $this a topc:StudySite . $this topc:studySiteStatus "ACTIVE" . FILTER NOT EXISTS { $this topc:hasPrincipalInvestigator ?pi } }

StudySiteActiveNeedsDelegationShape
type: NodeShape
target class: StudySite
sparql: SPARQLConstraint
  message: StudySite has studySiteStatus=ACTIVE but no delegatesAuthorityTo entries. ICH E6(R3) Section 2.3.3 GCP-requires a Delegation of Authority Log for any active Site participation.
  severity: Violation
  select: PREFIX topc: <https://top.scientix.ai/onto/commons/v1#> SELECT $this WHERE { $this a topc:StudySite . $this topc:studySiteStatus "ACTIVE" . FILTER NOT EXISTS { $this topc:delegatesAuthorityTo ?p } }

SystemSponsorCriticalOversightShape
type: NodeShape
target class: System
sparql: SPARQLConstraint
  message: System has systemType in {EDC, CTMS, IRT, SAFETY_DB} (sponsor-critical) but oversightHeldBy points at an Organization with organizationType=SITE. ICH E6(R3) Section 3.9 places oversight on the Sponsor for sponsor-critical systems. IIT exception applies when the same Organization also plays a Sponsor role on a Study using this System (checked via playsSponsorRole).
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> PREFIX topc: <https://top.scientix.ai/onto/commons/v1#> SELECT $this ?org WHERE { $this a topc:System . $this topc:systemType ?type . FILTER (?type IN ("EDC", "CTMS", "IRT", "SAFETY_DB")) $this topc:oversightHeldBy ?org . ?org topc:organizationType "SITE" . FILTER NOT EXISTS { ?org topc:playsSponsorRole ?sponsor . ?studySite topc:usesSystem $this . ?studySite topc:forStudy ?study . ?sponsor top:runs ?study . } }

CredentialExactlyOneTargetShape
type: NodeShape
target class: Credential
sparql: SPARQLConstraint
  message: Credential must have exactly one of forPerson, forSite, forEquipment populated. Polymorphic-target discipline requires single-target binding; a Credential cannot apply to multiple subject types.
  severity: Violation
  select: PREFIX topc: <https://top.scientix.ai/onto/commons/v1#> SELECT $this WHERE { $this a topc:Credential . { SELECT $this (COUNT(?t) AS ?cnt) WHERE { $this a topc:Credential . OPTIONAL { $this topc:forPerson ?p . BIND(?p AS ?t) } OPTIONAL { $this topc:forSite ?s . BIND(?s AS ?t) } OPTIONAL { $this topc:forEquipment ?e . BIND(?e AS ?t) } } GROUP BY $this } FILTER (?cnt != 1) }

StudyActiveNeedsEndpointShape
type: NodeShape
target class: Study
sparql: SPARQLConstraint
  message: Study has studyStatus in {RECRUITING, ENROLLING_BY_INVITATION, ACTIVE_NOT_RECRUITING, COMPLETED} but no hasEndpoint. A study at or past activation must have at least one defined endpoint to measure.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Study . $this top:studyStatus ?status . FILTER (?status IN ("RECRUITING", "ENROLLING_BY_INVITATION", "ACTIVE_NOT_RECRUITING", "COMPLETED")) FILTER NOT EXISTS { $this top:hasEndpoint ?ep } }

StudyActiveNeedsInclusionCriterionShape
type: NodeShape
target class: Study
sparql: SPARQLConstraint
  message: Study has studyStatus in {RECRUITING, ENROLLING_BY_INVITATION, ACTIVE_NOT_RECRUITING, COMPLETED} but no hasInclusionCriterion. A study at or past recruitment must have at least one inclusion criterion to define eligibility.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Study . $this top:studyStatus ?status . FILTER (?status IN ("RECRUITING", "ENROLLING_BY_INVITATION", "ACTIVE_NOT_RECRUITING", "COMPLETED")) FILTER NOT EXISTS { $this top:hasInclusionCriterion ?ic } }

StudyActiveNeedsScheduleShape
type: NodeShape
target class: Study
sparql: SPARQLConstraint
  message: Study has studyStatus in {RECRUITING, ENROLLING_BY_INVITATION, ACTIVE_NOT_RECRUITING, COMPLETED} but no hasSchedule (Schedule of Assessments). A study at or past recruitment must have a defined SOA to guide site operations.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Study . $this top:studyStatus ?status . FILTER (?status IN ("RECRUITING", "ENROLLING_BY_INVITATION", "ACTIVE_NOT_RECRUITING", "COMPLETED")) FILTER NOT EXISTS { $this top:hasSchedule ?soa } }

InterventionalStudyNeedsPhaseShape
type: NodeShape
target class: Study
sparql: SPARQLConstraint
  message: Study has studyType=INTERVENTIONAL but no studyPhase populated. Interventional studies must declare their phase per ICH E8 / ClinicalTrials.gov. Observational, expanded-access, and registry studies are exempt.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Study . $this top:studyType "INTERVENTIONAL" . FILTER NOT EXISTS { $this top:studyPhase ?phase } }

StudyCompletedNeedsCompletionDateShape
type: NodeShape
target class: Study
sparql: SPARQLConstraint
  message: Study has studyStatus=COMPLETED but no actualCompletionDate. Verify the completion date is recorded; this is typically last-patient-last-visit (LPLV).
  severity: Warning
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Study . $this top:studyStatus "COMPLETED" . FILTER NOT EXISTS { $this top:actualCompletionDate ?d } }

MultiArmModelNeedsMultipleArmsShape
type: NodeShape
target class: Study
sparql: SPARQLConstraint
  message: Study has interventionModel in {PARALLEL, CROSSOVER, FACTORIAL, SEQUENTIAL} but only one hasArm. Multi-arm intervention models require multiple Arm sub-objects.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Study . $this top:interventionModel ?model . FILTER (?model IN ("PARALLEL", "CROSSOVER", "FACTORIAL", "SEQUENTIAL")) { SELECT $this (COUNT(?arm) AS ?armCount) WHERE { $this top:hasArm ?arm . } GROUP BY $this } FILTER (?armCount = 1) }

ParticipantOnTrialNeedsConsentShape
type: NodeShape
target class: Participant
sparql: SPARQLConstraint
  message: Participant has participantStatus in {ENROLLED, RANDOMIZED, ON_TREATMENT, IN_FOLLOW_UP, COMPLETED, WITHDRAWN, DISCONTINUED, LOST_TO_FOLLOW_UP} but no InformedConsent sub-object with consentStatus=OBTAINED. ICH E6(R3) Section 2.4 GCP-required: cannot be on study without documented consent.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Participant . $this top:participantStatus ?status . FILTER (?status IN ("ENROLLED", "RANDOMIZED", "ON_TREATMENT", "IN_FOLLOW_UP", "COMPLETED", "WITHDRAWN", "DISCONTINUED", "LOST_TO_FOLLOW_UP")) FILTER NOT EXISTS { $this top:hasInformedConsent ?consent . ?consent top:consentStatus "OBTAINED" . } }

ParticipantScreenFailedNeedsRecordShape
type: NodeShape
target class: Participant
sparql: SPARQLConstraint
  message: Participant has participantStatus=SCREEN_FAILED but no ScreeningRecord with screeningOutcome=SCREEN_FAILED. The status implies a recorded screening event with documented failure.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Participant . $this top:participantStatus "SCREEN_FAILED" . FILTER NOT EXISTS { $this top:hasScreeningRecord ?sr . ?sr top:screeningOutcome "SCREEN_FAILED" . } }

ParticipantRandomizedNeedsArmAndDateShape
type: NodeShape
target class: Participant
sparql: SPARQLConstraint
  message: Participant has participantStatus=RANDOMIZED but is missing assignedToArm or randomizationDate (or both). Randomization is a discrete event requiring both an arm assignment and a date.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Participant . $this top:participantStatus "RANDOMIZED" . FILTER (NOT EXISTS { $this top:assignedToArm ?arm } || NOT EXISTS { $this top:randomizationDate ?d }) }

ParticipantWithdrawnNeedsConsentWithdrawalShape
type: NodeShape
target class: Participant
sparql: SPARQLConstraint
  message: Participant has participantStatus=WITHDRAWN but no WithdrawalRecord with withdrawalCategory=CONSENT_WITHDRAWN. The WITHDRAWN status is reserved for subject-initiated withdrawal of consent; investigator-initiated discontinuation should use participantStatus=DISCONTINUED instead.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Participant . $this top:participantStatus "WITHDRAWN" . FILTER NOT EXISTS { $this top:hasWithdrawalRecord ?wr . ?wr top:withdrawalCategory "CONSENT_WITHDRAWN" . } }

ParticipantCompletedNeedsCompletionDateShape
type: NodeShape
target class: Participant
sparql: SPARQLConstraint
  message: Participant has participantStatus=COMPLETED but no completionDate populated. Verify the completion date is recorded; this is the Participant-level last-visit date.
  severity: Warning
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Participant . $this top:participantStatus "COMPLETED" . FILTER NOT EXISTS { $this top:completionDate ?d } }

ParticipantArmStudyConsistencyShape
type: NodeShape
target class: Participant
sparql: SPARQLConstraint
  message: Participant.assignedToArm references an Arm that does not belong to Participant.forStudy. The Arm must come from this Study's design, not from another Study.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Participant . $this top:assignedToArm ?arm . $this top:forStudy ?participantStudy . FILTER NOT EXISTS { ?armStudy a top:Study . ?armStudy top:hasArm ?arm . FILTER (?armStudy = ?participantStudy) } }

ParticipantStudySiteStudyConsistencyShape
type: NodeShape
target class: Participant
sparql: SPARQLConstraint
  message: Participant.forStudySite references a StudySite whose forStudy does not match Participant.forStudy. The StudySite anchor and the Study anchor must agree.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Participant . $this top:forStudySite ?ss . $this top:forStudy ?participantStudy . ?ss topc:forStudy ?ssStudy . FILTER (?ssStudy != ?participantStudy) }

RecruitConvertedNeedsParticipantShape
type: NodeShape
target class: Recruit
sparql: SPARQLConstraint
  message: Recruit has recruitStatus=CONVERTED_TO_PARTICIPANT but convertedToParticipant relationship is not populated. The terminal-funnel-success status requires the operational link to the created Participant.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Recruit . $this top:recruitStatus "CONVERTED_TO_PARTICIPANT" . FILTER NOT EXISTS { $this top:convertedToParticipant ?p } }

RecruitStalledManyAttemptsShape
type: NodeShape
target class: Recruit
sparql: SPARQLConstraint
  message: Recruit has contactAttempts > 5 but is still in early-funnel state (RESPONDED or CONTACTED). Consider moving to DROPPED to keep the funnel clean and surface true conversion-rate metrics.
  severity: Warning
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Recruit . $this top:recruitStatus ?status . FILTER (?status IN ("RESPONDED", "CONTACTED")) $this top:contactAttempts ?n . FILTER (?n > 5) }

VisitCompletedNeedsActualStartShape
type: NodeShape
target class: Visit
sparql: SPARQLConstraint
  message: Visit has visitStatus in {COMPLETED, PARTIALLY_COMPLETED, OUT_OF_WINDOW} but no actualStartDate populated. A visit cannot be completed without recording when it actually happened.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Visit . $this top:visitStatus ?status . FILTER (?status IN ("COMPLETED", "PARTIALLY_COMPLETED", "OUT_OF_WINDOW")) FILTER NOT EXISTS { $this top:actualStartDate ?d } }

VisitCompletedNeedsActualEndShape
type: NodeShape
target class: Visit
sparql: SPARQLConstraint
  message: Visit has visitStatus=COMPLETED but no actualEndDate populated. A completed visit requires both start and end timestamps.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Visit . $this top:visitStatus "COMPLETED" . FILTER NOT EXISTS { $this top:actualEndDate ?d } }

VisitUnscheduledNeedsReasonShape
type: NodeShape
target class: Visit
sparql: SPARQLConstraint
  message: Visit has visitStatus=UNSCHEDULED but no unscheduledReason populated. Unscheduled visits require operator justification per protocol-deviation discipline.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Visit . $this top:visitStatus "UNSCHEDULED" . FILTER NOT EXISTS { $this top:unscheduledReason ?r } }

VisitOutOfWindowNeedsDeviationCodeShape
type: NodeShape
target class: Visit
sparql: SPARQLConstraint
  message: Visit has visitStatus=OUT_OF_WINDOW but no protocolDeviationCode populated. Out-of-window visits are protocol deviations and require a deviation code.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Visit . $this top:visitStatus "OUT_OF_WINDOW" . FILTER NOT EXISTS { $this top:protocolDeviationCode ?c } }

VisitParticipantStudySiteConsistencyShape
type: NodeShape
target class: Visit
sparql: SPARQLConstraint
  message: Visit's forParticipant.forStudySite does not match Visit.forStudySite. The participant's anchored StudySite and the visit's hosting StudySite must agree.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> PREFIX topc: <https://top.scientix.ai/onto/commons/v1#> SELECT $this WHERE { $this a top:Visit . $this top:forParticipant ?participant . $this top:forStudySite ?visitStudySite . ?participant top:forStudySite ?participantStudySite . FILTER (?participantStudySite != ?visitStudySite) }

ActivityNotPerformedNeedsReasonShape
type: NodeShape
target class: Activity
sparql: SPARQLConstraint
  message: Activity has activityStatus=NOT_PERFORMED but no notPerformedReason populated. Non-performance requires documented justification.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Activity . $this top:activityStatus "NOT_PERFORMED" . FILTER NOT EXISTS { $this top:notPerformedReason ?r } }

TaskNotPerformedNeedsReasonShape
type: NodeShape
target class: Task
sparql: SPARQLConstraint
  message: Task has taskStatus=NOT_PERFORMED but no notPerformedReason populated. Non-performance requires documented justification.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Task . $this top:taskStatus "NOT_PERFORMED" . FILTER NOT EXISTS { $this top:notPerformedReason ?r } }

TaskCompletedNeedsValueShape
type: NodeShape
target class: Task
sparql: SPARQLConstraint
  message: Task has taskStatus=COMPLETED but taskValue is missing. Completed Tasks must carry the captured value.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Task . $this top:taskStatus "COMPLETED" . FILTER NOT EXISTS { $this top:taskValue ?v } }

VisitObservationEscalatedNeedsLinkShape
type: NodeShape
target class: VisitObservation
sparql: SPARQLConstraint
  message: VisitObservation has escalated=true but no escalatedTo populated. Escalated observations should link to the resulting Event (when Event lifts in v0.7+).
  severity: Warning
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:VisitObservation . $this top:escalated true . FILTER NOT EXISTS { $this top:escalatedTo ?e } }

OversightBodyIRBScopeShape
type: NodeShape
target class: OversightBody
sparql: SPARQLConstraint
  message: OversightBody has oversightBodyType in {IRB, EC} but scope is not LOCAL or CENTRAL. IRBs and ECs are review boards with defined geographic / institutional scope; SPONSOR or REGULATORY scopes indicate a typing mismatch.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:OversightBody . $this top:oversightBodyType ?type . FILTER (?type IN ("IRB", "EC")) $this top:scope ?scope . FILTER (?scope NOT IN ("LOCAL", "CENTRAL")) }

OversightBodyDSMBScopeShape
type: NodeShape
target class: OversightBody
sparql: SPARQLConstraint
  message: OversightBody has oversightBodyType in {DSMB, IDMC} but scope is not SPONSOR. DSMB / IDMC are sponsor-convened safety review boards.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:OversightBody . $this top:oversightBodyType ?type . FILTER (?type IN ("DSMB", "IDMC")) $this top:scope ?scope . FILTER (?scope != "SPONSOR") }

IPBlindedNeedsKitShape
type: NodeShape
target class: InvestigationalProduct
sparql: SPARQLConstraint
  message: InvestigationalProduct has isBlinded=true but no hasKit. Blinded studies require Kit sub-objects for IRT-managed treatment-assignment masking.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:InvestigationalProduct . $this top:isBlinded true . FILTER NOT EXISTS { $this top:hasKit ?k } }

KitAssignedNeedsParticipantShape
type: NodeShape
target class: Kit
sparql: SPARQLConstraint
  message: Kit has kitStatus in {ASSIGNED, DISPENSED} but no assignedToParticipant. Assigned and dispensed kits must reference the Participant.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Kit . $this top:kitStatus ?status . FILTER (?status IN ("ASSIGNED", "DISPENSED")) FILTER NOT EXISTS { $this top:assignedToParticipant ?p } }

LotPastExpiryNeedsExpiredStatusShape
type: NodeShape
target class: Lot
sparql: SPARQLConstraint
  message: Lot has expirationDate in the past but lotStatus is not EXPIRED, RECALLED, or DESTROYED. Verify the lot has been retired from active distribution.
  severity: Warning
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> SELECT $this WHERE { $this a top:Lot . $this top:expirationDate ?exp . $this top:lotStatus ?status . BIND (xsd:dateTime(CONCAT(STR(?exp), "T23:59:59Z")) AS ?expDT) FILTER (?expDT < NOW()) FILTER (?status NOT IN ("EXPIRED", "RECALLED", "DESTROYED")) }

LotExpiredNeedsPastExpiryShape
type: NodeShape
target class: Lot
sparql: SPARQLConstraint
  message: Lot has lotStatus=EXPIRED but expirationDate is missing or in the future. EXPIRED status requires a past expiration date.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> SELECT $this WHERE { $this a top:Lot . $this top:lotStatus "EXPIRED" . FILTER (NOT EXISTS { $this top:expirationDate ?exp } || EXISTS { $this top:expirationDate ?exp . BIND (xsd:dateTime(CONCAT(STR(?exp), "T00:00:00Z")) AS ?expDT) FILTER (?expDT > NOW()) }) }

EventSAEMustBeReportableShape
type: NodeShape
target class: Event
sparql: SPARQLConstraint
  message: Event has eventCategory=SERIOUS_ADVERSE_EVENT but regulatoryReportable is not true. SAEs trigger regulatory submission by definition per ICH E2A and 21 CFR 312.32.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Event . $this top:eventCategory "SERIOUS_ADVERSE_EVENT" . FILTER NOT EXISTS { $this top:regulatoryReportable true } }

EventCtcaeOnlyForAEShape
type: NodeShape
target class: Event
sparql: SPARQLConstraint
  message: Event has ctcaeGrade populated but eventCategory is not ADVERSE_EVENT or SERIOUS_ADVERSE_EVENT. CTCAE grades only apply to clinical adverse events per CTCAE 5.0.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Event . $this top:ctcaeGrade ?grade . $this top:eventCategory ?cat . FILTER (?cat NOT IN ("ADVERSE_EVENT", "SERIOUS_ADVERSE_EVENT")) }

EventDeviationCategoryOnlyForDeviationShape
type: NodeShape
target class: Event
sparql: SPARQLConstraint
  message: Event has protocolDeviationCategory populated but eventCategory is not DEVIATION. Protocol deviation categorization only applies to DEVIATION events per ICH E6(R3) Section 6.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Event . $this top:protocolDeviationCategory ?dc . $this top:eventCategory ?cat . FILTER (?cat != "DEVIATION") }

EventSubmittedNeedsDateShape
type: NodeShape
target class: Event
sparql: SPARQLConstraint
  message: Event has regulatoryReportSubmitted=true but no regulatoryReportSubmittedDate. Audit-trail integrity requires the submission timestamp.
  severity: Violation
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> SELECT $this WHERE { $this a top:Event . $this top:regulatoryReportSubmitted true . FILTER NOT EXISTS { $this top:regulatoryReportSubmittedDate ?d } }

EventOverdueReportShape
type: NodeShape
target class: Event
sparql: SPARQLConstraint
  message: Event is regulatoryReportable=true with regulatoryReportDeadline in the past and regulatoryReportSubmitted still false. Submission is overdue; verify whether the report has been filed and update the record, or escalate per E2B SUSAR timelines.
  severity: Warning
  select: PREFIX top: <https://top.scientix.ai/onto/clinical/v1#> PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> SELECT $this WHERE { $this a top:Event . $this top:regulatoryReportable true . $this top:regulatoryReportDeadline ?dl . FILTER (?dl < NOW()) FILTER NOT EXISTS { $this top:regulatoryReportSubmitted true } }

path: engages
class: Site
min count: 0
node kind: IRI
description: Sites the sponsor has contracted on this Study. 0..N because Sponsor records exist before site selection completes.
name: engages

path: contractsWith
min count: 0
node kind: IRI
description: Contracted CROs.
comment: TARGET-MISSING: CRO is a flagged-missing object in OOUX v0.2; needs its own catalog entry.
name: contractsWith

path: holds
class: Contract
min count: 0
node kind: IRI
description: All sponsor-side contracts on this Study. 0..N because contracts get signed over time, not at Sponsor-record creation.
name: holds

path: authors
class: Budget
min count: 0
node kind: IRI
description: Budgets the sponsor maintains for this Study. 0..N because budgets may be authored downstream.
name: authors

path: publishesDocument
class: Document
min count: 0
node kind: IRI
description: Sponsor-controlled documents on this Study (TMF and beyond). 0..N because TMF accumulates over the Study lifecycle. Split from the polysemous 'publishes' verb in v0.1.2 so each predicate carries one target type, preserving clean projection to USDM and FHIR.
name: publishesDocument

path: publishesPublication
min count: 0
node kind: IRI
description: Resulting publications (peer-reviewed, conference, preprint). 0..N because most Studies have not produced publications yet at any given moment. Split from the polysemous 'publishes' verb in v0.1.2 so each predicate carries one target type, preserving clean projection to USDM and FHIR.
comment: TARGET-MISSING: Publication is not in OOUX v0.2 catalog; treat as Document subtype until specified.
name: publishesPublication

path: files
class: RegulatorySubmission
min count: 0
node kind: IRI
description: Submissions filed by the sponsor on this Study. 0..N because submissions accumulate; a brand-new Sponsor record has zero filings yet.
name: files

path: commissions
class: Audit
min count: 0
node kind: IRI
description: Sponsor-commissioned audits. 0..N: small IITs and academic-sponsored studies may never commission a sponsor-level audit.
name: commissions

path: operatesTrainingProgram
min count: 0
node kind: IRI
description: Sponsor training programs on this Study. 0..N at per-Study Sponsor scope. Split from the polysemous 'operates' verb in v0.1.2 so each predicate carries one target type, preserving clean projection to USDM and FHIR.
comment: TARGET-MISSING: TrainingProgram is not in OOUX v0.2 catalog; TrainingRecord (#77) covers individual completions; TrainingProgram needs its own entry.
name: operatesTrainingProgram

path: maintains
min count: 0
node kind: IRI
description: Standard operating procedures attached to this Study. 0..N: SOPs are typically maintained at the Organization level and inherited.
comment: TARGET-MISSING: SOP is not in OOUX v0.2 catalog; treat as Document subtype until specified.
name: maintains

path: operatesSystem
class: System
min count: 0
node kind: IRI
description: Sponsor-owned systems on this Study (EDC, CTMS, eTMF, IRT, safety database). 0..N because system attachment happens during Study startup, not at Sponsor creation. Split from the polysemous 'operates' verb in v0.1.2 so each predicate carries one target type, preserving clean projection to USDM and FHIR.
name: operatesSystem

path: produces
class: Report
min count: 0
node kind: IRI
description: Reports authored by the sponsor on this Study. 0..N because reports accumulate.
name: produces

path: plans
class: Milestone
min count: 0
node kind: IRI
description: Program-level milestones. 0..N because milestones get planned downstream of Sponsor record creation.
name: plans

path: conducts
class: RiskAssessment
min count: 0
node kind: IRI
description: Risk assessments owned by the sponsor on this Study. 0..N because risk assessment is a workflow that produces records over time.
name: conducts

path: executes
class: CAPA
min count: 0
node kind: IRI
description: Sponsor-driven CAPAs. 0..N: most Sponsor records have zero CAPAs at any given snapshot.
name: executes

path: interfacesWith
class: OversightBody
min count: 0
node kind: IRI
description: IRB, EC, DSMB, IDMC engagement. 0..N because oversight engagement gets established during startup, not at Sponsor creation.
name: interfacesWith

path: signs
min count: 0
node kind: IRI
description: Data transfer agreements. 0..N because DTAs are signed downstream of Sponsor record creation.
comment: TARGET-MISSING: DataTransferAgreement is a Contract subtype not separately enumerated in OOUX v0.2.
name: signs

path: supplies
class: InvestigationalProduct
min count: 0
node kind: IRI
description: IP the sponsor supplies on this Study. 0..N because IP supply chain attaches downstream, and observational studies may not involve IP at all.
name: supplies

path: organizes
class: Tag
min count: 0
node kind: IRI
description: User-defined organizational tags.
name: organizes

path: plannedStartDate
datatype: date
min count: 0
max count: 1
description: Planned date of first patient first visit.
name: plannedStartDate

path: actualStartDate
datatype: date
min count: 0
max count: 1
description: Actual date of first patient first visit (FPI). Empty until FPI is achieved.
name: actualStartDate

path: primaryCompletionDate
datatype: date
min count: 0
max count: 1
description: Date of last primary outcome measure assessment per ClinicalTrials.gov. Distinct from actualCompletionDate (last visit, all outcomes).
name: primaryCompletionDate

path: plannedCompletionDate
datatype: date
min count: 0
max count: 1
name: plannedCompletionDate

path: actualCompletionDate
datatype: date
min count: 0
max count: 1
description: Date of last patient last visit (LPLV). Empty until LPLV is achieved.
name: actualCompletionDate

path: responsibleParty
datatype: string
min count: 0
max count: 1
in: SPONSOR
in: INVESTIGATOR_SPONSOR
in: SPONSOR_INVESTIGATOR
in: OTHER
description: Who is responsible for the study per ClinicalTrials.gov ResponsibleParty.type. INVESTIGATOR_SPONSOR for IITs where the PI is the sponsor of record; SPONSOR_INVESTIGATOR for industry-sponsored with sub-investigator named.
name: responsibleParty

path: studyVersion
datatype: string
min count: 0
max count: 1
description: Current version identifier for the study definition (e.g., '3.2.1'). Mirrors USDM StudyVersion.versionIdentifier; richer multi-version semantics (separate StudyVersion sub-object) lifts in v0.4 if operationally needed. Amendments are tracked via the hasAmendment relationship.
name: studyVersion

path: clinicalTrialsGovId
datatype: string
min count: 0
max count: 1
description: ClinicalTrials.gov NCT identifier (e.g., 'NCT99999423'). Optional: IITs and early-phase trials may not have NCT IDs at time of Study creation; populated when ClinicalTrials.gov registration completes.
name: clinicalTrialsGovId

path: eudraCT
datatype: string
min count: 0
max count: 1
description: EudraCT (EU Clinical Trials Register) identifier (e.g., '2026-001234-56'). For studies submitted under the EU Clinical Trials Regulation; replaced by EU CTIS identifier for new submissions.
name: eudraCT

path: euCtisId
datatype: string
min count: 0
max count: 1
description: EU Clinical Trials Information System (CTIS) identifier; the EU CTR Article 80 register identifier replacing EudraCT for new submissions.
name: euCtisId

path: isrctn
datatype: string
min count: 0
max count: 1
description: ISRCTN registry identifier (UK).
name: isrctn

path: nciId
datatype: string
min count: 0
max count: 1
description: NCI Clinical Trials ID (oncology studies).
name: nciId

path: otherRegistryIds
datatype: string
min count: 0
max count: 1
description: Comma-separated additional registry identifiers (ANZCTR, ChiCTR, JPRN, etc.). Free-form for registries not enumerated above.
name: otherRegistryIds

path: tags
datatype: string
min count: 0
max count: 1
description: Comma-separated user-defined tags.
name: tags

path: hasProtocol
class: Protocol
min count: 1
max count: 1
node kind: IRI
description: The current effective Protocol for this Study. Sub-object. Protocol amendments are tracked via the hasAmendment relationship; the hasProtocol points at the current effective version.
name: hasProtocol

path: hasArm
class: Arm
min count: 1
node kind: IRI
description: Study arms (treatment groups). Sub-object. Single-arm studies have one Arm entity. Multi-arm studies (parallel, crossover, factorial) have multiple. Aligned with USDM StudyDesign.arms.
name: hasArm

path: hasSchedule
class: ScheduleOfAssessments
min count: 0
node kind: IRI
description: Schedule(s) of Assessments. Sub-object. 0..N because PLANNED-state Studies may not yet have an SOA; SHACL invariant enforces presence once Study is ACTIVE. 0..N also handles the case where SOA versions across protocol amendments are tracked separately. Aligned with USDM StudyDesign.scheduleTimelines.
name: hasSchedule

path: hasEndpoint
class: Endpoint
min count: 0
node kind: IRI
description: Study endpoints (primary, secondary, exploratory, safety). Sub-object. 0..N because PLANNED-state Studies may not yet have endpoints defined; SHACL invariant enforces presence once Study is ACTIVE. Aligned with USDM StudyDesign.objectives.endpoints.
name: hasEndpoint

path: hasInclusionCriterion
class: InclusionCriterion
min count: 0
node kind: IRI
description: Inclusion criteria for participant eligibility. Sub-object. 0..N because PLANNED-state Studies may not yet have criteria; SHACL invariant enforces presence once Study is RECRUITING. Aligned with USDM StudyDesign.eligibilityCriteria (subset of inclusion type).
name: hasInclusionCriterion

path: hasExclusionCriterion
class: ExclusionCriterion
min count: 0
node kind: IRI
description: Exclusion criteria for participant eligibility. Sub-object. 0..N because rare cases (some registries) may have no formal exclusion criteria. Aligned with USDM StudyDesign.eligibilityCriteria (subset of exclusion type).
name: hasExclusionCriterion

path: hasAmendment
min count: 0
node kind: IRI
description: Protocol amendments tracked over the Study lifecycle. Each Amendment captures the change history; the current effective Protocol is reached via hasProtocol.
comment: TARGET-MISSING: Amendment is in OOUX v0.2 catalog but not yet in TOP source.
name: hasAmendment

path: hasMilestone
min count: 0
node kind: IRI
description: Study-level milestones (FPI, LPI, DBL, CSR, IND submission, etc.). Site-level milestones live on StudySite.activationDate / deactivationDate.
comment: TARGET-MISSING: Milestone is in OOUX v0.2 catalog but not yet in TOP source.
name: hasMilestone

path: suppliesInvestigationalProduct
class: InvestigationalProduct
min count: 0
node kind: IRI
description: IPs supplied for this Study. 0..N because observational studies may have none. Mirrors Sponsor.supplies (the per-Sponsor IP list).
name: suppliesInvestigationalProduct

path: hasOversightBody
class: OversightBody
min count: 0
node kind: IRI
description: Study-level oversight bodies (DSMB, IDMC). Per-Site IRB/EC of record lives on StudySite.hasIRB.
name: hasOversightBody

path: hasStudyStartupPackage
min count: 0
max count: 1
node kind: IRI
description: The Study Startup Package containing essential documents and templates distributed to sites during initiation.
comment: TARGET-MISSING: StudyStartupPackage is in OOUX v0.2 catalog but not yet in TOP source.
name: hasStudyStartupPackage

path: usesSystem
class: System
min count: 0
node kind: IRI
description: Per-Study Systems (the EDC, CTMS, IRT, eTMF, safety database used for this Study). Sites and Sponsors using these Systems reach them via the System's three-axis relationships (operatedBy, usedBy, oversightHeldBy).
name: usesSystem

path: hasStatisticalAnalysisPlan
class: Document
min count: 0
max count: 1
node kind: IRI
description: The Statistical Analysis Plan (SAP) document. Document.documentType=SOP or a future SAP-specific subtype.
name: hasStatisticalAnalysisPlan

path: hasStudyTeam
class: Person
min count: 0
node kind: IRI
description: Study team members (Sponsor PM, Biostatistician, Medical Monitor, Pharmacovigilance Lead, etc.). Orthogonal to per-StudySite delegation (which is on StudySite.delegatesAuthorityTo). The same Person can be on multiple Studies' teams.
name: hasStudyTeam

path: hasTag
min count: 0
node kind: IRI
description: User-defined tags applied to this Study.
comment: TARGET-MISSING: Tag is in OOUX v0.2 catalog but not yet in TOP source.
name: hasTag

path: hasRiskAssessment
min count: 0
node kind: IRI
description: Risk assessments owned at the Study level (per ICH E8(R1) quality-by-design). Per-StudySite risk-tier is captured on StudySite.oversightTier.
comment: TARGET-MISSING: RiskAssessment is in OOUX v0.2 catalog but not yet in TOP source.
name: hasRiskAssessment

path: econsentCapable
datatype: boolean
min count: 0
max count: 1
description: Site supports electronic informed consent.
name: econsentCapable

path: eproCapable
datatype: boolean
min count: 0
max count: 1
description: Site supports electronic patient-reported outcomes.
name: eproCapable

path: edcVendorExperience
datatype: string
min count: 0
max count: 1
description: Comma-separated array of EDC vendors the Site has experience with (Medidata Rave, Veeva CDMS, Castor, REDCap, etc.). SFQ technology-readiness signal.
name: edcVendorExperience

path: irbType
datatype: string
min count: 0
max count: 1
in: CENTRAL
in: LOCAL
in: HYBRID
description: Default IRB type the Site uses; per-Study IRB-of-record assignment lives on StudySite.hasIRB.
name: irbType

path: typicalIrbApprovalDays
datatype: integer
min count: 0
max count: 1
description: Average days from IRB submission to approval. SFQ timeline signal.
name: typicalIrbApprovalDays

path: regulatoryAuthorityExperience
datatype: string
min count: 0
max count: 1
description: Comma-separated array of regulatory authorities the Site has filed under (FDA, EMA, PMDA, NMPA, MHRA, HSA, ANVISA, etc.).
name: regulatoryAuthorityExperience

path: sopsAvailable
datatype: boolean
min count: 0
max count: 1
description: Site maintains its own SOP library.
name: sopsAvailable

path: sopLibrarySize
datatype: integer
min count: 0
max count: 1
description: Count of distinct SOPs in the Site's library.
name: sopLibrarySize

path: insuranceCarrier
datatype: string
min count: 0
max count: 1
description: Name of the insurance carrier providing professional liability / clinical-trial insurance for the Site.
name: insuranceCarrier

path: insuranceCoverageAmount
datatype: decimal
min count: 0
max count: 1
name: insuranceCoverageAmount

path: insuranceCurrency
datatype: string
min count: 0
max count: 1
description: ISO 4217 currency code.
name: insuranceCurrency

path: insuranceExpiry
datatype: date
min count: 0
max count: 1
name: insuranceExpiry

path: subInvestigatorCount
datatype: integer
min count: 0
max count: 1
description: Aggregate count of available sub-investigators. The actual Person roster lives on hasStaff.
name: subInvestigatorCount

path: coordinatorCount
datatype: integer
min count: 0
max count: 1
description: Aggregate count of available study coordinators.
name: coordinatorCount

path: regulatoryCoordinatorCount
datatype: integer
min count: 0
max count: 1
name: regulatoryCoordinatorCount

path: studyNurseCount
datatype: integer
min count: 0
max count: 1
name: studyNurseCount

path: labTechCount
datatype: integer
min count: 0
max count: 1
name: labTechCount

path: languagesSupported
datatype: string
min count: 0
max count: 1
description: Comma-separated ISO 639-1 codes; languages staff can support for participant interactions.
name: languagesSupported

path: gcpTrainingCurrencyRate
datatype: decimal
min count: 0
max count: 1
description: Percentage of staff with current GCP training (0.0-1.0). SFQ signal; per-Person training currency lives on Person.
name: gcpTrainingCurrencyRate

path: tags
datatype: string
min count: 0
max count: 1
description: Comma-separated array of user-defined tags (per OOUX Tag pattern).
name: tags

path: belongsToOrganization
class: Organization
min count: 1
max count: 1
node kind: IRI
description: The legal Organization that owns or operates this Site (e.g., MSKCC's Organization for the MSKCC main-campus Site). USDM Organization.managedSites is the inverse.
name: belongsToOrganization

path: partOfSiteNetwork
class: Organization
min count: 0
max count: 1
node kind: IRI
description: An Organization with organizationType=SITE_NETWORK or SMO that this Site is part of. Elevate Research is an Organization; each of its locations is a Site with partOfSiteNetwork pointing to Elevate Research.
name: partOfSiteNetwork

path: parentSite
class: Site
min count: 0
max count: 1
node kind: IRI
description: Self-reference for satellite-of-main-site structure. A satellite clinic Site references the main hospital Site as its parent. Use when the relationship is operationally a parent-child pair, not just network membership.
name: parentSite

path: hasStaff
class: Person
min count: 0
node kind: IRI
description: Persons employed/affiliated at this Site, study-independent. The roster of people who CAN be delegated to per-Study; actual delegation per-Study lives on StudySite.delegatesAuthorityTo.
name: hasStaff

path: headOfClinicalResearch
class: Person
min count: 0
max count: 1
node kind: IRI
description: Administrative/institutional contact for the Site's clinical-research operations. NOT the per-Study Principal Investigator (which lives on StudySite.hasPrincipalInvestigator).
name: headOfClinicalResearch

path: hostsEquipment
class: Equipment
min count: 0
node kind: IRI
description: Site-bound equipment. Equipment.equipmentBinding=SITE_BOUND points back here.
name: hostsEquipment

path: hasStorageLocation
class: StorageLocation
min count: 0
node kind: IRI
description: Site-bound storage locations (freezer slots, refrigerator shelves, secure cabinet drawers, ambient pharmacy shelves, offsite vaults). The Equipment/StorageLocation split: a freezer is Equipment that provides multiple StorageLocations.
name: hasStorageLocation

path: hasInstitutionalDocument
class: Document
min count: 0
node kind: IRI
description: Site-level essential records that are study-independent: institutional licenses, CLIA certifications, lab accreditations, GCP training records (Site-level), institutional SOPs. Per-Study essential records live on StudySite.hasEssentialRecord.
name: hasInstitutionalDocument

path: hasInstitutionalCredential
class: Credential
min count: 0
node kind: IRI
description: Site-level credentials (CLIA, JCAHO, ISO 9001, lab accreditations, etc.).
name: hasInstitutionalCredential

path: usesSystem
class: System
min count: 0
node kind: IRI
description: Site-operational Systems (the Site's EMR, the Site's source-document repository, the Site's local pharmacy management system) that exist regardless of any specific Study. Per-Study System usage (Sponsor-provisioned EDC, per-Study IRT, etc.) lives on StudySite.usesSystem.
name: usesSystem

path: hasEnrollmentRecord
class: EnrollmentRecord
min count: 0
node kind: IRI
description: Enrollment event records. Typically 1 per Participant; multi-enrollment supported for re-enrollment scenarios.
name: hasEnrollmentRecord

path: hasWithdrawalRecord
class: WithdrawalRecord
min count: 0
node kind: IRI
description: Withdrawal event records. Hard SHACL: when participantStatus=WITHDRAWN, at least one WithdrawalRecord must exist with withdrawalCategory=CONSENT_WITHDRAWN.
name: hasWithdrawalRecord

path: convertedFromRecruit
class: Recruit
min count: 0
max count: 1
node kind: IRI
description: The Recruit entity that converted to this Participant when consent was obtained. Empty when Participant was registered without going through a tracked recruitment funnel (direct site walk-in). The InformedConsent sub-object's existence IS the conversion event; this relationship is the operational-funnel-side trace.
name: convertedFromRecruit

path: hasVisit
min count: 0
node kind: IRI
description: Visit-occurrences for this Participant. Inverse of Visit.atParticipant (when Visit lifts).
comment: TARGET-MISSING: Visit is a top-level in OOUX (one of the locked 8) but not yet in TOP source; lifts post-Participant per planning sequencing.
name: hasVisit

path: hasAdverseEvent
class: Event
min count: 0
node kind: IRI
description: Adverse-event records linked to this Participant. The relationship is named for AE/SAE category Events (the operator vocabulary); the broader Event entity also covers Deviations, Discrepancies, Safety Signals, etc., reachable via Event.forParticipant inverse.
name: hasAdverseEvent

path: hasTag
min count: 0
node kind: IRI
description: User-defined tags applied to this Participant.
comment: TARGET-MISSING: Tag is in OOUX v0.2 catalog but not yet in TOP source.
name: hasTag

path: convertedToParticipant
class: Participant
min count: 0
max count: 1
node kind: IRI
description: The Participant entity that was created when this Recruit consented. Empty until conversion. Inverse of Participant.convertedFromRecruit.
name: convertedToParticipant

path: outcome
datatype: string
min count: 0
max count: 1
in: RECOVERED
in: RECOVERING
in: NOT_RECOVERED
in: RECOVERED_WITH_SEQUELAE
in: FATAL
in: UNKNOWN
description: Clinical outcome of the event. Required for AE/SAE per E2A; not applicable to DEVIATION.
name: outcome

path: protocolDeviationCategory
datatype: string
min count: 0
max count: 1
in: INCLUSION_VIOLATION
in: EXCLUSION_VIOLATION
in: INFORMED_CONSENT
in: MISSED_VISIT
in: MISSED_PROCEDURE
in: OUT_OF_WINDOW_VISIT
in: IP_NONCOMPLIANCE
in: RANDOMIZATION_ERROR
in: BLINDING_BREAK
in: OTHER
description: Categorization of protocol deviations per ICH E6(R3) Section 6. SHACL invariant: protocolDeviationCategory only valid when eventCategory=DEVIATION.
name: protocolDeviationCategory

path: protocolDeviationImpact
datatype: string
min count: 0
max count: 1
in: NONE
in: MINOR
in: MAJOR
in: CRITICAL
description: Impact assessment for DEVIATION events per ICH E6(R3). MAJOR/CRITICAL deviations require root-cause analysis and CAPA.
name: protocolDeviationImpact

path: validFrom
datatype: dateTime
min count: 0
max count: 1
description: NGSI-LD temporal property: when this Event record became operationally valid.
name: validFrom

path: validUntil
datatype: dateTime
min count: 0
max count: 1
description: NGSI-LD temporal property: when this Event record was superseded or invalidated (e.g., reclassified after assessment).
name: validUntil

path: forStudy
class: Study
min count: 1
max count: 1
node kind: IRI
description: The Study this Event belongs to. Required — every Event ties to exactly one Study lifecycle.
name: forStudy

path: forParticipant
class: Participant
min count: 0
max count: 1
node kind: IRI
description: The Participant the Event concerns (when applicable). 0..1 because some DEVIATION events (e.g., procedural failures, system outages) don't map to a single Participant; aggregate SAFETY_SIGNAL events may span participants and are queried via causedBy.
name: forParticipant

path: forStudySite
class: StudySite
min count: 0
max count: 1
node kind: IRI
description: The StudySite where the Event occurred or was detected. Critical for site-level monitoring and CAPA scoping.
name: forStudySite

path: duringVisit
class: Visit
min count: 0
max count: 1
node kind: IRI
description: The Visit during which the Event was detected (when applicable). Pairs with derivedFrom when detection happened via VisitObservation escalation.
name: duringVisit

path: relatedToInvestigationalProduct
class: InvestigationalProduct
min count: 0
max count: 1
node kind: IRI
description: The IP suspected of causing or being relevant to the Event. Required for AE/SAE events where causality is being assessed; populated alongside causality and actionTakenWithIp.
name: relatedToInvestigationalProduct

path: relatedToLot
class: Lot
min count: 0
max count: 1
node kind: IRI
description: Specific Lot of IP relevant to the Event. Critical for safety signals tied to a manufacturing batch (e.g., a recall trigger).
name: relatedToLot

path: relatedToKit
class: Kit
min count: 0
max count: 1
node kind: IRI
description: Specific Kit involved in the Event (for blinded studies). Pairs with IP_NONCOMPLIANCE deviations and BLINDING_BREAK events.
name: relatedToKit

path: reportedBy
class: Person
min count: 1
max count: 1
node kind: IRI
description: The Person who reported the Event into the trial system. For AE/SAE typically the investigator or coordinator; for DEVIATION the monitor or coordinator. PROV: the event was wasAssociatedWith this Person.
name: reportedBy

path: assignedTo
class: Person
min count: 0
max count: 1
node kind: IRI
description: The Person responsible for assessing/closing the Event (e.g., investigator for AE causality assessment, sponsor safety lead for SAE workup). PROV: prov:wasAssociatedWith with prov:hadRole assessor.
name: assignedTo

path: derivedFrom
class: VisitObservation
min count: 0
max count: 1
node kind: IRI
description: The VisitObservation this Event was escalated from (when detectionSource=VISIT_OBSERVATION). PROV: this Event was wasInformedBy that observation. The escalation chain is operator-meaningful: a routine vital-sign observation escalates to a tracked AE Event with explicit lineage.
name: derivedFrom

path: partOf
class: Event
min count: 0
max count: 1
node kind: IRI
description: Parent Event when this Event is a sub-component (e.g., an SAE that aggregates multiple precursor AEs; a Safety Signal aggregating individual AEs). Self-reference for nesting.
name: partOf

path: causedBy
class: Event
min count: 0
node kind: IRI
description: Causal predecessor Events (e.g., a SAFETY_SIGNAL caused by a cluster of AEs; a SAFETY_REPORT caused by one or more SAEs). PROV: this Event was wasInformedBy these Events.
name: causedBy

path: reviewedBy
class: OversightBody
min count: 0
node kind: IRI
description: OversightBodies that reviewed this Event. DSMB/IDMC review SAEs and Safety Signals; IRB reviews aggregate safety reports per submitted updates; CEC adjudicates endpoint events.
name: reviewedBy

path: documentedIn
class: Document
min count: 0
node kind: IRI
description: Supporting documents — MedWatch 3500A forms, narrative documents, CIOMS forms, CAPA records, deviation reports.
name: documentedIn

path: hostsVisit
min count: 0
node kind: IRI
description: Visit-occurrences at this Site for this Study. Inverse of Visit.atStudySite (when Visit lifts).
comment: TARGET-MISSING: Visit is a top-level in OOUX (one of the locked 8) but not yet in TOP source.
name: hostsVisit

path: hasParticipant
min count: 0
node kind: IRI
description: Participants enrolled at this Site for this Study. The OOUX Participant->Site direct edge is a correction: should be Participant->StudySite when Participant lifts.
comment: TARGET-MISSING: Participant is a top-level in OOUX (one of the locked 8) but not yet in TOP source.
name: hasParticipant

path: hasMonitoringVisit
min count: 0
node kind: IRI
description: Per-Study monitoring visits at this Site.
comment: TARGET-MISSING: MonitoringVisit is in OOUX v0.2 catalog but not yet in TOP source.
name: hasMonitoringVisit

path: hasAudit
min count: 0
node kind: IRI
description: Per-Study audits at this Site.
comment: TARGET-MISSING: Audit is in OOUX v0.2 catalog but not yet in TOP source.
name: hasAudit

path: engagesVendor
class: Organization
min count: 0
node kind: IRI
description: Per-Study Site-engaged vendors (R3 Section 2.3.4 documented agreements). Sponsor-engaged vendors are different — those are the Sponsor's; this is the Site's per-Study direct engagement (after R3 Section 2.3 Investigator's right of acceptance/refusal).
name: engagesVendor

path: usesLaboratory
class: Organization
min count: 0
node kind: IRI
description: Per-Study Site-engaged laboratories (Organization with organizationType=LABORATORY). Distinct from Site.usesSystem for the Site's own internal lab system.
name: usesLaboratory

path: usesSystem
class: System
min count: 0
node kind: IRI
description: Per-Study Systems used at this Site participation: Sponsor-provisioned EDC, per-Study IRT, per-Study eTMF, etc. The System's three-axis pattern (operatedBy / usedBy / oversightHeldBy) on the System entity captures the GCP responsibility allocation.
name: usesSystem

path: reportsTo
class: Sponsor
min count: 0
node kind: IRI
description: Per-Study reporting target (R3 Sections 2.7, 2.13: safety, data, noncompliance reporting from Site to Sponsor).
name: reportsTo

path: hasEssentialRecord
class: Document
min count: 0
node kind: IRI
description: Per-Study essential records (with Document.essentialRecordPurpose set per R3 Appendix C and Document.responsibleParty=INVESTIGATOR_INSTITUTION). Distinct from Site.hasInstitutionalDocument (study-independent institutional records).
name: hasEssentialRecord

path: hasEnrollment
min count: 0
node kind: IRI
description: Enrollment records at this StudySite.
comment: TARGET-MISSING: Enrollment is in OOUX v0.2 catalog but not yet in TOP source.
name: hasEnrollment

path: hasUserManual
class: Document
min count: 0
max count: 1
node kind: IRI
description: User manual document.
name: hasUserManual