- Updated ranges for multiple slots from `string` to `uriorcurie` to address OWL "Ambiguous type" warnings and allow for URI/CURIE references. - Removed specialized slots for subtitle and transcript formats, consolidating them under broader predicates. - Introduced new slots for structured descriptions, observation source documents, and entity statuses to improve data modeling. - Implemented Rule 54 to broaden generic predicate ranges instead of creating bespoke predicates, promoting schema reuse and reducing complexity. - Added a script for generating OWL ontology with type-object handling to ensure consistent ObjectProperty treatment for polymorphic slots.
5.4 KiB
Rule 54: Broaden Generic Predicate Ranges Instead of Creating Bespoke Predicates
🚨 CRITICAL: When fixing gen-owl "Ambiguous type" warnings, broaden the range of generic predicates rather than creating specialized bespoke predicates.
The Problem
gen-owl "Ambiguous type" warnings occur when a slot is used as both:
- DatatypeProperty (base range:
string,integer,uri, etc.) - ObjectProperty (slot_usage override range: a class like
Description,SubtitleFormatEnum)
This creates OWL ambiguity because OWL requires properties to be either DatatypeProperty OR ObjectProperty, not both.
❌ WRONG Approach: Create Bespoke Predicates
# DON'T DO THIS - creates proliferation of rare-use predicates
slots:
has_or_had_subtitle_format: # Only used by VideoSubtitle
range: SubtitleFormatEnum
has_or_had_transcript_format: # Only used by VideoTranscript
range: TranscriptFormat
Why This Is Wrong:
- Creates predicate proliferation (schema bloat)
- Bespoke predicates are rarely reused across classes
- Increases cognitive load for schema users
- Fragments the ontology unnecessarily
- Violates the principle of schema parsimony
✅ CORRECT Approach: Broaden Generic Predicate Ranges
# DO THIS - make the generic predicate flexible enough
slots:
has_or_had_format:
range: uriorcurie # Broadened from string
description: |
The format of a resource. Classes narrow this to specific
enum types (SubtitleFormatEnum, TranscriptFormatEnum) via slot_usage.
Then in class files, use slot_usage to narrow the range:
classes:
VideoSubtitle:
slots:
- has_or_had_format
slot_usage:
has_or_had_format:
range: SubtitleFormatEnum # Narrowed for this class
required: true
Range Broadening Options
| Original Range | Broadened Range | When to Use |
|---|---|---|
string |
uriorcurie |
When class overrides use URI-identified types or enums |
string |
Any |
When truly polymorphic (strings AND class instances) |
| Specific class | Common base class | When multiple subclasses are used |
Decision Tree
gen-owl warning: "Ambiguous type for: SLOTNAME"
↓
Is base slot range a primitive (string, integer, uri)?
├─ YES → Broaden to uriorcurie or Any
│ - Edit modules/slots/SLOTNAME.yaml
│ - Change range: string → range: uriorcurie
│ - Document change with Rule 54 reference
│ - Keep class-level slot_usage overrides (they narrow the range)
│
└─ NO → Consider if base slot needs common ancestor class
- Create abstract base class if needed
- Or broaden to uriorcurie
Implementation Workflow
-
Identify warning:
gen-owl ... 2>&1 | grep "Ambiguous type for:" -
Check base slot range:
cat modules/slots/SLOTNAME.yaml | grep -A5 "^slots:" | grep "range:" -
Find class overrides:
for f in modules/classes/*.yaml; do grep -l "SLOTNAME" "$f" && grep -A3 "SLOTNAME:" "$f" | grep "range:" done -
Broaden base range:
- Edit
modules/slots/SLOTNAME.yaml - Change
range: string→range: uriorcurie - Add annotation documenting the change
- Edit
-
Verify fix: Run gen-owl and confirm warning is gone
-
Keep slot_usage overrides: Class-level range narrowing is fine and expected
Examples
Example 1: has_or_had_format
Before (caused warning):
# Base slot
slots:
has_or_had_format:
range: string # DatatypeProperty
# Class override
classes:
VideoSubtitle:
slot_usage:
has_or_had_format:
range: SubtitleFormatEnum # ObjectProperty → CONFLICT!
After (fixed):
# Base slot - broadened
slots:
has_or_had_format:
range: uriorcurie # Now ObjectProperty-compatible
# Class override - unchanged, still narrows
classes:
VideoSubtitle:
slot_usage:
has_or_had_format:
range: SubtitleFormatEnum # Valid narrowing
Example 2: has_or_had_hypernym
Before: range: string (DatatypeProperty)
After: range: uriorcurie (ObjectProperty-compatible)
Classes that override to class ranges now work without ambiguity.
Validation
After broadening, run:
gen-owl 01_custodian_name_modular.yaml 2>&1 | grep "Ambiguous type for: SLOTNAME"
The warning should disappear without creating new predicates.
Anti-Patterns to Avoid
| ❌ Anti-Pattern | ✅ Correct Pattern |
|---|---|
Create has_or_had_subtitle_format |
Broaden has_or_had_format to uriorcurie |
Create has_or_had_entity_type |
Broaden has_or_had_type to uriorcurie |
Create has_or_had_X_label |
Broaden has_or_had_label to uriorcurie |
Create has_or_had_X_status |
Broaden has_or_had_status to uriorcurie |
Rationale
This approach:
- Reduces schema complexity - Fewer predicates to understand
- Promotes reuse - Generic predicates work across domains
- Maintains OWL consistency - Single property type per predicate
- Preserves type safety - slot_usage still enforces class-specific ranges
- Follows semantic web best practices - Broad predicates, narrow contexts
See Also
- Rule 38: Slot Centralization and Semantic URI Requirements
- Rule 39: Slot Naming Convention (RiC-O Style)
- Rule 49: Slot Usage Minimization
- LinkML Documentation: slot_usage