glam/.opencode/SLOT_NAMING_CONVENTIONS.md
2025-11-21 22:12:33 +01:00

10 KiB

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:

# 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:

# 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_ofCustodianReconstruction (base)
  • was_revision_of-recordRecord (specialized)
  • was_revision_of-collectionCollection (specialized)
  • was_revision_of-observationCustodianObservation (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:

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:

# 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:

# 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:

# 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

# 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
# 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):

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:

# 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


Last Updated: 2025-11-21
Maintainer: GLAM Data Extraction Project