# Rule 53: Full Slot Migration - No Deprecation Notes 🚨 **CRITICAL**: When migrating slots from `slot_fixes.yaml`: 1. **Follow the `revision` section EXACTLY** - The `slot_fixes.yaml` file specifies the exact replacement slots and classes to use 2. **Perform FULL MIGRATION** - Completely remove the deprecated slot from the entity class 3. **Do NOT add deprecation notes** - Never keep both old and new slots with deprecation markers --- ## 🚨 slot_fixes.yaml is AUTHORITATIVE AND CURATED 🚨 **File Location**: `schemas/20251121/linkml/modules/slots/slot_fixes.yaml` **THIS FILE IS THE SINGLE SOURCE OF TRUTH FOR ALL SLOT MIGRATIONS.** The `slot_fixes.yaml` file has been **manually curated** to specify the exact replacement slots and classes for each deprecated slot. The revisions are based on: 1. **Ontology analysis** - Each replacement was chosen based on alignment with base ontologies (CIDOC-CRM, RiC-O, PROV-O, Schema.org, etc.) 2. **Semantic correctness** - Revisions reflect the intended meaning of the original slot 3. **Pattern consistency** - Follows established naming conventions (Rule 39: RiC-O style, Rule 43: singular nouns) 4. **Class hierarchy design** - Type/Types pattern (Rule 0b) applied where appropriate **YOU MUST NOT**: - ❌ Substitute different slots than those specified in `revision` - ❌ Use your own judgment to pick "similar" slots - ❌ Skip the revision and invent new mappings - ❌ Partially apply the revision (e.g., use the slot but not the class) **YOU MUST**: - ✅ Follow the `revision` section TO THE LETTER - ✅ Use EXACTLY the slots and classes specified - ✅ Apply ALL components of the revision (both slots AND classes) - ✅ Interpret `link_branch` fields correctly (see below) - ✅ Update `processed.status: true` after completing migration --- ## Understanding `link_branch` in Revision Plans 🚨 **CRITICAL**: The `link_branch` field in revision plans indicates **nested class attributes**. Items with `link_branch: N` are slots/classes that belong TO the primary class, not standalone replacements. ### How to Interpret `link_branch` | Revision Item | Meaning | |---------------|---------| | Items **WITHOUT** `link_branch` | **PRIMARY** slot and class to create | | Items **WITH** `link_branch: 1` | First attribute branch that the primary class needs | | Items **WITH** `link_branch: 2` | Second attribute branch that the primary class needs | | Items **WITH** `link_branch: N` | Nth attribute branch for the primary class | ### Example: `visitor_count` Revision ```yaml - original_slot_id: https://nde.nl/ontology/hc/slot/visitor_count revision: - label: has_or_had_quantity # PRIMARY SLOT (no link_branch) type: slot - label: Quantity # PRIMARY CLASS (no link_branch) type: class - label: has_or_had_measurement_unit # Quantity needs this slot type: slot link_branch: 1 # ← Branch 1: unit attribute - label: MeasureUnit # Range of has_or_had_measurement_unit type: class value: - visitors link_branch: 1 - label: temporal_extent # Quantity needs this slot too type: slot link_branch: 2 # ← Branch 2: time attribute - label: TimeSpan # Range of temporal_extent type: class link_branch: 2 ``` **Interpretation**: This creates: 1. **Primary**: `has_or_had_quantity` slot → `Quantity` class 2. **Branch 1**: `Quantity.has_or_had_measurement_unit` → `MeasureUnit` (with value "visitors") 3. **Branch 2**: `Quantity.temporal_extent` → `TimeSpan` ### Resulting Class Structure ```yaml # The Quantity class should have these slots: Quantity: slots: - has_or_had_measurement_unit # From link_branch: 1 - temporal_extent # From link_branch: 2 ``` ### Complex Example: `visitor_conversion_rate` ```yaml - original_slot_id: https://nde.nl/ontology/hc/slot/visitor_conversion_rate revision: - label: has_or_had_conversion_rate # PRIMARY SLOT type: slot - label: ConversionRate # PRIMARY CLASS type: class - label: has_or_had_type # ConversionRate.has_or_had_type type: slot link_branch: 1 - label: ConversionRateType # Abstract type class type: class link_branch: 1 - label: includes_or_included # ConversionRateType hierarchy slot type: slot link_branch: 1 - label: ConversionRateTypes # Concrete subclasses file type: class link_branch: 1 - label: temporal_extent # ConversionRate.temporal_extent type: slot link_branch: 2 - label: TimeSpan # Range of temporal_extent type: class link_branch: 2 ``` **Interpretation**: 1. **Primary**: `has_or_had_conversion_rate` → `ConversionRate` 2. **Branch 1**: Type hierarchy with `ConversionRateType` (abstract) + `ConversionRateTypes` (concrete subclasses) 3. **Branch 2**: Temporal tracking via `temporal_extent` → `TimeSpan` ### Migration Checklist for `link_branch` Revisions - [ ] Create/verify PRIMARY slot exists - [ ] Create/verify PRIMARY class exists - [ ] For EACH `link_branch: N`: - [ ] Add the branch slot to PRIMARY class's `slots:` list - [ ] Import the branch slot file - [ ] Import the branch class file (if creating new class) - [ ] Verify range of branch slot points to branch class - [ ] Update consuming class to use PRIMARY slot (not deprecated slot) - [ ] Update examples to show nested structure --- ## Mandatory: Follow slot_fixes.yaml Revisions Exactly **The `revision` section in `slot_fixes.yaml` is AUTHORITATIVE.** Do not substitute different slots based on your own judgment. **Example from slot_fixes.yaml**: ```yaml - original_slot_id: https://nde.nl/ontology/hc/slot/actual_start revision: - label: begin_of_the_begin # ← USE THIS SLOT type: slot - label: TimeSpan # ← USE THIS CLASS type: class ``` **CORRECT**: Use `begin_of_the_begin` slot (as specified) **WRONG**: Substitute `has_actual_start_date` (not in revision) ## The Problem Adding deprecation notes while keeping both old and new slots: - Creates schema bloat with redundant properties - Confuses data consumers about which slot to use - Violates single-source-of-truth principle - Complicates future data validation ## Anti-Pattern (WRONG) ```yaml # WRONG - Keeping deprecated slot with deprecation note classes: TemporaryLocation: slots: - actual_start # OLD - kept with deprecation note - actual_end # OLD - kept with deprecation note - has_actual_start_date # NEW - has_actual_end_date # NEW slot_usage: actual_start: deprecated: | DEPRECATED: Use has_actual_start_date instead. # ... more deprecation documentation ``` ## Correct Pattern ```yaml # CORRECT - Only new slots, old slots completely removed classes: TemporaryLocation: slots: - has_actual_start_date # NEW - only new slots present - has_actual_end_date # NEW # NO slot_usage for deprecated slots - they don't exist in this class ``` ## Migration Steps When processing a slot from `slot_fixes.yaml`: 1. **Identify affected entity class(es)** 2. **Remove old slot from imports** (if dedicated import file exists) 3. **Remove old slot from slots list** 4. **Remove any slot_usage for old slot** 5. **Add new slot import** (if not already present) 6. **Add new slot to slots list** 7. **Add slot_usage for new slot** (if range override or customization needed) 8. **Update examples** to use new slot 9. **Validate with gen-owl** ## What Happens to Old Slot Files The old slot files in `modules/slots/` (e.g., `actual_start.yaml`, `activities_societies.yaml`) are **NOT deleted** because: - Other entity classes might still use them - They serve as documentation of the old schema - They can be archived when all usages are migrated However, the old slots are **removed from the entity class** being migrated. ## Example: TemporaryLocation Migration **Before** (with old slots): ```yaml imports: - ../slots/actual_end - ../slots/actual_start - ../slots/has_actual_start_date - ../slots/has_actual_end_date slots: - actual_end - actual_start - has_actual_start_date - has_actual_end_date ``` **After** (fully migrated): ```yaml imports: # actual_end and actual_start imports REMOVED - ../slots/has_actual_start_date - ../slots/has_actual_end_date slots: # actual_end and actual_start REMOVED from list - has_actual_start_date - has_actual_end_date ``` ## Slot Usage for New Slots Only add `slot_usage` for the new slot if you need to: - Override the range for this specific class - Add class-specific examples - Add class-specific constraints Do NOT add `slot_usage` just to document that it replaces an old slot. ## Recording in slot_fixes.yaml When marking a slot as processed: ```yaml - original_slot_id: https://nde.nl/ontology/hc/slot/actual_start processed: status: true timestamp: '2026-01-14T16:00:00Z' session: "session-2026-01-14-type-migration" notes: "FULLY MIGRATED: TemporaryLocation - actual_start REMOVED, using temporal_extent with TimeSpan.begin_of_the_begin (Rule 53)" ``` Note the "FULLY MIGRATED" prefix in notes to confirm this was a complete removal, not a deprecation-in-place. --- ## ⚠️ Common Mistakes to Avoid ⚠️ ### Mistake 1: Substituting Different Slots **slot_fixes.yaml specifies**: ```yaml - original_slot_id: https://nde.nl/ontology/hc/slot/actual_start revision: - label: begin_of_the_begin # ← MUST USE THIS type: slot - label: TimeSpan # ← WITH THIS CLASS type: class ``` | Action | Status | |--------|--------| | Using `begin_of_the_begin` with `TimeSpan` | ✅ CORRECT | | Using `has_actual_start_date` (invented) | ❌ WRONG | | Using `start_date` (different slot) | ❌ WRONG | | Using `begin_of_the_begin` WITHOUT `TimeSpan` | ❌ WRONG (incomplete) | ### Mistake 2: Partial Application The revision often specifies MULTIPLE components that work together: ```yaml revision: - label: has_or_had_type # ← Slot for linking type: slot - label: BackupType # ← Abstract base class type: class - label: includes_or_included # ← Slot for hierarchy type: slot - label: BackupTypes # ← Concrete subclasses type: class ``` **All four components** are part of the migration. Don't just use `has_or_had_type` and ignore the class structure. ### Mistake 3: Using `temporal_extent` Slot Correctly When `slot_fixes.yaml` specifies TimeSpan-based revision: ```yaml revision: - label: begin_of_the_begin type: slot - label: TimeSpan type: class ``` This means: **Use the `temporal_extent` slot** (which has `range: TimeSpan`) and access the temporal bounds via TimeSpan's slots: ```yaml # CORRECT: Use temporal_extent with TimeSpan structure temporal_extent: begin_of_the_begin: '2020-06-15' end_of_the_end: '2022-03-15' # WRONG: Create new has_actual_start_date slot has_actual_start_date: '2020-06-15' # ❌ Not in revision! ``` ### Mistake 4: Not Updating Examples When migrating slots, **update ALL examples** in the class file: - Description examples (in class description) - slot_usage examples - Class-level examples (at bottom of file) --- ## Verification Checklist Before marking a slot as processed: - [ ] Read the `revision` section completely - [ ] Identified ALL slots and classes in revision - [ ] Removed old slot from imports - [ ] Removed old slot from slots list - [ ] Removed old slot from slot_usage - [ ] Added new slot(s) per revision - [ ] Added new class import(s) per revision - [ ] Updated ALL examples to use new slots - [ ] Validated with `linkml-lint` or `gen-owl` - [ ] Updated `slot_fixes.yaml` with: - `status: true` - `timestamp` (ISO 8601) - `session` identifier - `notes` with "FULLY MIGRATED:" prefix --- ## See Also - Rule 9: Enum-to-Class Promotion (single source of truth principle) - Rule 0b: Type/Types File Naming Convention - Rule: Slot Naming Convention (Current Style) - `.opencode/ENUM_TO_CLASS_PRINCIPLE.md` - `schemas/20251121/linkml/modules/slots/slot_fixes.yaml` - **AUTHORITATIVE** master list of migrations