# Slot Naming Conventions for Hyper-Modular Schema **Version**: 0.1.0 **Date**: 2025-11-21 **Schema**: Heritage Custodian Observation and Reconstruction Pattern --- ## Overview In a hyper-modular schema where each slot is defined in its own file, we need clear conventions for handling **semantically identical slots with different ranges** (typing constraints). **Problem**: The same ontological property (e.g., `prov:wasRevisionOf`) may need to be applied to multiple classes with different range constraints: - `was_revision_of` for `CustodianReconstruction` → previous `CustodianReconstruction` - `was_revision_of` for `Record` → previous `Record` - `was_revision_of` for `Collection` → previous `Collection` **Solution**: Co-locate range-specialized variants in the **same file**, using hyphenated suffixes to distinguish slot names. --- ## Naming Convention ### Rule 1: Base Slot Name = Primary/First Use Case The **first defined slot** uses the base name without suffix: ```yaml # File: modules/slots/was_revision_of.yaml slots: was_revision_of: slot_uri: prov:wasRevisionOf range: CustodianReconstruction # Primary use case description: "Previous version of this reconstruction (if updated)" ``` **File location**: `/modules/slots/was_revision_of.yaml` **Slot name**: `was_revision_of` (no suffix) --- ### Rule 2: Range-Specialized Variants = Hyphenated Suffix Subsequent slots with **different ranges** but the **same `slot_uri`** are added to the **same file** with hyphenated suffixes: ```yaml # File: modules/slots/was_revision_of.yaml (SAME FILE) slots: was_revision_of: slot_uri: prov:wasRevisionOf range: CustodianReconstruction description: "Previous version of this reconstruction (if updated)" was_revision_of-record: slot_uri: prov:wasRevisionOf # SAME ontological property range: Record # DIFFERENT range description: "Previous version of this record (if updated)" was_revision_of-collection: slot_uri: prov:wasRevisionOf range: Collection description: "Previous version of this collection (if updated)" ``` **Hyphen placement**: `{base_slot_name}-{range_type_lowercase}` **Examples**: - `was_revision_of` → `CustodianReconstruction` (base) - `was_revision_of-record` → `Record` (specialized) - `was_revision_of-collection` → `Collection` (specialized) - `was_revision_of-observation` → `CustodianObservation` (specialized) --- ### Rule 3: File Organization **Single file per ontological property**, containing all range variants: ``` modules/slots/ ├── was_revision_of.yaml # Contains: was_revision_of, was_revision_of-record, was_revision_of-collection ├── was_derived_from.yaml # Contains: was_derived_from, was_derived_from-entity ├── identifier_scheme.yaml # Contains: identifier_scheme (single variant - no specialization needed) └── ... ``` **Benefits**: - ✅ Easy to find all variants of a property (one file) - ✅ Centralized documentation of ontological alignment - ✅ Clear relationship between semantically identical slots - ✅ Reduces file count (59 files vs. potentially 100+ with separate files per variant) --- ## Why Hyphens? ### ✅ Hyphens ARE allowed in LinkML slot names LinkML permits hyphens (`-`) in slot identifiers: ```python from linkml_runtime.linkml_model import SlotDefinition # All valid: SlotDefinition(name="was_revision_of") # Underscores SlotDefinition(name="was-revision-of") # Hyphens SlotDefinition(name="was_revision_of-record") # Mixed ``` ### Advantages of Hyphen Suffix Convention 1. **Visual Separation**: `was_revision_of-record` clearly shows: - `was_revision_of` = base semantic concept - `-record` = range specialization suffix 2. **Avoids Double Underscores**: Using underscores would create: - ❌ `was_revision_of_record` (ambiguous: is it "was_revision" of "of_record"?) - ✅ `was_revision_of-record` (clear: "was_revision_of" specialized for "record") 3. **Consistency with LinkML Module Names**: LinkML uses hyphens in module IDs: - `was-revision-of-slot` (module name) - `was_revision_of-record` (slot name) --- ## Exceptions and Edge Cases ### Exception 1: Single-Range Slots If a slot is **only used with one range**, no suffix is needed: ```yaml # File: modules/slots/legal_name.yaml slots: legal_name: slot_uri: cpov:legalName range: string # Single, unchanging range description: "Official legal name as registered" ``` **No variants**: `legal_name-string` is NOT needed (strings are the universal default). --- ### Exception 2: Slots with Multiple Acceptable Ranges (Union Types) If a slot accepts **multiple ranges simultaneously** (union type), use `any_of`: ```yaml # File: modules/slots/subject.yaml slots: subject: slot_uri: dcterms:subject any_of: - range: string - range: Concept - range: uriorcurie description: "Subject or topic (string, SKOS Concept, or URI)" ``` **No hyphenated variants needed**: This is a single polymorphic slot, not multiple specialized slots. --- ### Exception 3: Ontologically Distinct Properties If two slots have **different `slot_uri` values**, they belong in **separate files**: ```yaml # File: modules/slots/was_revision_of.yaml slots: was_revision_of: slot_uri: prov:wasRevisionOf # PROV-O revision # File: modules/slots/replaces.yaml (SEPARATE FILE) slots: replaces: slot_uri: dcterms:replaces # DIFFERENT ontological property ``` Even if both represent "replaces previous version" semantically, different ontology properties = different files. --- ## Implementation Guidelines ### When Adding a New Range Variant 1. **Check if slot file exists**: Look for `modules/slots/{base_slot_name}.yaml` 2. **Check ontological alignment**: Does the new slot use the **same `slot_uri`**? 3. **If YES**: Add to existing file with hyphenated suffix 4. **If NO**: Create new file with appropriate base name ### Example: Adding `was_revision_of-observation` ```bash # 1. Check existing file cat modules/slots/was_revision_of.yaml # 2. Verify slot_uri matches (prov:wasRevisionOf) # 3. Add new variant to SAME file ``` ```yaml # File: modules/slots/was_revision_of.yaml id: https://nde.nl/ontology/hc/slot/was_revision_of name: was-revision-of-slot imports: - ../classes/CustodianReconstruction - ../classes/CustodianObservation # NEW import slots: was_revision_of: slot_uri: prov:wasRevisionOf range: CustodianReconstruction description: "Previous version of this reconstruction (if updated)" was_revision_of-observation: # NEW variant slot_uri: prov:wasRevisionOf range: CustodianObservation description: "Previous version of this observation (if updated)" ``` **Update aggregator** (`modules/slots_all.yaml`): ```yaml imports: - slots/was_revision_of # Already imports file (contains both variants now) ``` **No change needed**: Aggregator imports the file, which now contains both slots. --- ## Documentation Requirements Each slot file containing multiple variants MUST include: 1. **File-level comment** explaining the ontological property 2. **Import statements** for ALL range classes 3. **Slot-level descriptions** distinguishing each variant **Example**: ```yaml # CustodianReconstruction Slot: was_revision_of # PROV-O wasRevisionOf property with multiple range specializations id: https://nde.nl/ontology/hc/slot/was_revision_of name: was-revision-of-slot imports: - ../classes/CustodianReconstruction - ../classes/CustodianObservation - ../classes/Record - ../classes/Collection slots: was_revision_of: slot_uri: prov:wasRevisionOf range: CustodianReconstruction description: >- Previous version of this reconstruction (if updated). PROV-O: wasRevisionOf for CustodianReconstruction versioning. was_revision_of-observation: slot_uri: prov:wasRevisionOf range: CustodianObservation description: >- Previous version of this observation (if updated). PROV-O: wasRevisionOf for CustodianObservation versioning. was_revision_of-record: slot_uri: prov:wasRevisionOf range: Record description: >- Previous version of this record (if updated). PROV-O: wasRevisionOf for Record versioning. comments: - "All variants map to PROV-O prov:wasRevisionOf" - "Range specialization enables type-safe versioning" - "Hyphenated suffix pattern: {base_name}-{range_lowercase}" ``` --- ## Rationale: Why Co-location? ### Alternative 1: Separate Files Per Variant ❌ ``` modules/slots/ ├── was_revision_of.yaml ├── was_revision_of_record.yaml ├── was_revision_of_collection.yaml ├── was_revision_of_observation.yaml ``` **Problems**: - ❌ File explosion (59 slots → 150+ files with variants) - ❌ Difficult to see all variants of a property - ❌ Duplicated ontology documentation across files - ❌ Import bloat in aggregator ### Alternative 2: Co-location with Hyphenated Suffixes ✅ ``` modules/slots/ ├── was_revision_of.yaml # Contains all 4 variants ``` **Benefits**: - ✅ Manageable file count - ✅ Single source of truth for ontological property - ✅ Easy maintenance (one file to update) - ✅ Clear relationship between variants --- ## Summary | Convention | Rule | Example | |------------|------|---------| | **Base slot** | No suffix | `was_revision_of` | | **Range variant** | Hyphenated suffix | `was_revision_of-record` | | **File location** | Single file per ontological property | `/slots/was_revision_of.yaml` | | **File contains** | All range variants | `was_revision_of`, `was_revision_of-record`, ... | | **Suffix format** | `-{range_lowercase}` | `-record`, `-observation`, `-collection` | | **When to create variant** | Same `slot_uri`, different `range` | `slot_uri: prov:wasRevisionOf` | | **When to create new file** | Different `slot_uri` | `prov:wasRevisionOf` vs `dcterms:replaces` | --- ## References - LinkML Slot Definition: https://linkml.io/linkml/schemas/slots.html - PROV-O wasRevisionOf: https://www.w3.org/TR/prov-o/#wasRevisionOf - Heritage Custodian Schema: `/schemas/20251121/linkml/01_custodian_name_modular.yaml` --- **Last Updated**: 2025-11-21 **Maintainer**: GLAM Data Extraction Project