- Introduced the ImageTilingServiceEndpoint class for tiled high-resolution image delivery, including deep-zoom and transformation capabilities, with multilingual descriptions and structured aliases. - Archived the ID class as a backwards-compatible alias for Identifier, marking it as deprecated to enforce the use of the canonical Identifier model.
174 lines
6.3 KiB
Markdown
174 lines
6.3 KiB
Markdown
# Rule 49: Slot Usage Minimization - No Redundant Overrides
|
|
|
|
## Summary
|
|
|
|
LinkML `slot_usage` entries MUST provide meaningful modifications to the generic slot definition. Redundant `slot_usage` entries that merely re-declare the same values as the generic slot MUST be removed.
|
|
|
|
## Background
|
|
|
|
### What is slot_usage?
|
|
|
|
In LinkML, [`slot_usage`](https://linkml.io/linkml-model/latest/docs/slot_usage/) allows a class to customize how an inherited slot behaves within that specific class context. It enables:
|
|
|
|
- Narrowing the `range` to a more specific type
|
|
- Adding class-specific `required`, `multivalued`, or `identifier` constraints
|
|
- Providing class-specific `description`, `examples`, or `pattern` overrides
|
|
- Adding class-specific semantic mappings (`exact_mappings`, `close_mappings`, etc.)
|
|
|
|
### The Problem
|
|
|
|
A code generation process created **874 redundant `slot_usage` entries** across **374 class files** that simply re-declare the same `range` and `inlined` values already defined in the generic slot:
|
|
|
|
```yaml
|
|
# In modules/slots/template_specificity.yaml (GENERIC DEFINITION)
|
|
slots:
|
|
template_specificity:
|
|
slot_uri: hc:templateSpecificity
|
|
range: TemplateSpecificityScores
|
|
inlined: true
|
|
|
|
# In modules/classes/AdministrativeOffice.yaml (REDUNDANT OVERRIDE)
|
|
slot_usage:
|
|
template_specificity:
|
|
range: TemplateSpecificityScores # Same as generic!
|
|
inlined: true # Same as generic!
|
|
```
|
|
|
|
This creates:
|
|
1. **Visual noise** in the schema viewer (slot_usage badge displayed when nothing is actually customized)
|
|
2. **Maintenance burden** (changes to generic slot must be mirrored in 374 files)
|
|
3. **Semantic confusion** (suggests customization where none exists)
|
|
|
|
## The Rule
|
|
|
|
### MUST Remove: Truly Redundant Overrides
|
|
|
|
A `slot_usage` entry is **truly redundant** and MUST be removed if:
|
|
|
|
1. **All properties match the generic slot definition exactly**
|
|
2. **No additional properties are added** (no extra `examples`, `description`, `required`, etc.)
|
|
|
|
```yaml
|
|
# REDUNDANT - Remove this entire slot_usage entry
|
|
slot_usage:
|
|
template_specificity:
|
|
range: TemplateSpecificityScores
|
|
inlined: true
|
|
```
|
|
|
|
### MAY Keep: Description-Only Modifications
|
|
|
|
A `slot_usage` entry that ONLY modifies the `description` by adding articles or context MAY be kept if it provides **semantic value** by referring to a specific entity rather than a general concept.
|
|
|
|
**Tolerated Example** (adds definiteness):
|
|
```yaml
|
|
# Generic slot
|
|
slots:
|
|
has_or_had_record_set:
|
|
description: Record sets associated with a custodian.
|
|
range: RecordSet
|
|
|
|
# Class-specific slot_usage - TOLERABLE
|
|
slot_usage:
|
|
has_or_had_record_set:
|
|
description: The record sets held by this archive. # "The" makes it definite
|
|
```
|
|
|
|
**Rationale**: "The record sets" (definite) vs "record sets" (indefinite) conveys that this class specifically requires/expects record sets, rather than merely allowing them. This is a **semantic distinction** in linguistic terms (definiteness marking).
|
|
|
|
### MUST Keep: Meaningful Modifications
|
|
|
|
A `slot_usage` entry MUST be kept if it provides ANY of the following:
|
|
|
|
| Modification Type | Example |
|
|
|-------------------|---------|
|
|
| **Range narrowing** | `range: MuseumCollection` (from generic `Collection`) |
|
|
| **Required constraint** | `required: true` (when generic is optional) |
|
|
| **Pattern override** | `pattern: "^NL-.*"` (Dutch ISIL codes only) |
|
|
| **Examples addition** | Class-specific examples not in generic |
|
|
| **Inlined change** | `inlined: true` when generic is `false` |
|
|
| **Identifier designation** | `identifier: true` for primary key |
|
|
|
|
## Decision Matrix
|
|
|
|
| Scenario | Action |
|
|
|----------|--------|
|
|
| All properties match generic exactly | **REMOVE** |
|
|
| Only `range` and/or `inlined` match generic | **REMOVE** |
|
|
| Only `description` differs by adding articles | **TOLERATE** (but consider removing) |
|
|
| `description` provides substantive new information | **KEEP** |
|
|
| Any other property modified | **KEEP** |
|
|
|
|
## Implementation
|
|
|
|
### Cleanup Script
|
|
|
|
Use the following to identify and remove redundant overrides:
|
|
|
|
```python
|
|
# scripts/cleanup_redundant_slot_usage.py
|
|
import yaml
|
|
import glob
|
|
|
|
SLOTS_TO_CHECK = ['template_specificity', 'specificity_annotation']
|
|
|
|
for class_file in glob.glob('schemas/20251121/linkml/modules/classes/*.yaml'):
|
|
with open(class_file) as f:
|
|
content = yaml.safe_load(f)
|
|
|
|
modified = False
|
|
for cls_name, cls_def in content.get('classes', {}).items():
|
|
slot_usage = cls_def.get('slot_usage', {})
|
|
for slot_name in SLOTS_TO_CHECK:
|
|
if slot_name in slot_usage:
|
|
override = slot_usage[slot_name]
|
|
# Check if redundant (only range/inlined matching generic)
|
|
if is_redundant(override, slot_name):
|
|
del slot_usage[slot_name]
|
|
modified = True
|
|
|
|
# Remove empty slot_usage
|
|
if not slot_usage:
|
|
del cls_def['slot_usage']
|
|
|
|
if modified:
|
|
with open(class_file, 'w') as f:
|
|
yaml.dump(content, f, allow_unicode=True, sort_keys=False)
|
|
```
|
|
|
|
### Validation
|
|
|
|
After cleanup, validate that:
|
|
1. `linkml-validate` passes for all schemas
|
|
2. Generated RDF/OWL output is unchanged (redundant overrides have no semantic effect)
|
|
3. Frontend slot viewer shows fewer `slot_usage` badges
|
|
|
|
## Frontend UX Implications
|
|
|
|
The frontend LinkML viewer should:
|
|
|
|
1. **Display "Slot Usage"** (with space, no underscore) instead of `slot_usage`
|
|
2. **Add tooltip** explaining what slot_usage means, linking to [LinkML documentation](https://linkml.io/linkml-model/latest/docs/slot_usage/)
|
|
3. **Only show badge** when `slot_usage` contains meaningful modifications
|
|
4. **Comparison view** should highlight actual differences, not redundant re-declarations
|
|
|
|
## Affected Slots
|
|
|
|
Current analysis found redundant overrides for:
|
|
|
|
| Slot | Redundant Overrides | Files Affected |
|
|
|------|---------------------|----------------|
|
|
| `template_specificity` | 873 | 374 |
|
|
| `specificity_annotation` | 874 | 374 |
|
|
|
|
## References
|
|
|
|
- [LinkML slot_usage documentation](https://linkml.io/linkml-model/latest/docs/slot_usage/)
|
|
- Rule 38: Slot Centralization and Semantic URI Requirements
|
|
- Rule 48: Class Files Must Not Define Inline Slots
|
|
|
|
## Version History
|
|
|
|
| Date | Change |
|
|
|------|--------|
|
|
| 2026-01-12 | Initial rule created after identifying 874 redundant slot_usage entries |
|