# LinkML YAML Best Practices Rule ## Rule: Follow LinkML Conventions for Valid, Interoperable Schema Files ### 1. equals_expression Anti-Pattern `equals_expression` is for dynamic formula evaluation (e.g., `"{age_in_years} * 12"`). Never use it for static value constraints. **WRONG:** ```yaml slot_usage: has_type: equals_expression: '["hc:ArchiveOrganizationType"]' hold_record_set: equals_expression: '["hc:Fonds", "hc:Series"]' ``` **CORRECT** (single value): ```yaml slot_usage: has_type: equals_string: "hc:ArchiveOrganizationType" ``` **CORRECT** (multiple allowed values - if classes): ```yaml slot_usage: hold_record_set: any_of: - range: UniversityAdministrativeFonds - range: StudentRecordSeries - range: FacultyPaperCollection ``` **CORRECT** (multiple allowed values - if literals): ```yaml slot_usage: status: equals_string_in: - "active" - "inactive" - "pending" ``` ### 2. Declare All Used Prefixes Every CURIE prefix used in the file must be declared in the `prefixes:` block. **WRONG:** ```yaml prefixes: linkml: https://w3id.org/linkml/ skos: http://www.w3.org/2004/02/skos/core# slot_usage: has_type: equals_string: "hc:ArchiveOrganizationType" # hc: not declared! ``` **CORRECT:** ```yaml prefixes: linkml: https://w3id.org/linkml/ hc: https://nde.nl/ontology/hc/ skos: http://www.w3.org/2004/02/skos/core# default_prefix: hc slot_usage: has_type: equals_string: "hc:ArchiveOrganizationType" ``` ### 3. Import Referenced Classes When using external classes in `is_a`, `range`, or other references, import them. **WRONG:** ```yaml imports: - linkml:types classes: AcademicArchive: is_a: ArchiveOrganizationType # Not imported! slot_usage: related_to: range: WikidataAlignment # Not imported! ``` **CORRECT:** ```yaml imports: - linkml:types - ../classes/ArchiveOrganizationType - ../classes/WikidataAlignment classes: AcademicArchive: is_a: ArchiveOrganizationType slot_usage: related_to: range: WikidataAlignment ``` ### 4. Quote Regex Patterns and Annotation Values **Regex patterns:** ```yaml # WRONG pattern: ^Q[0-9]+$ # CORRECT pattern: "^Q[0-9]+$" ``` **Annotation values (must be strings):** ```yaml # WRONG annotations: specificity_score: 0.1 # CORRECT annotations: specificity_score: "0.1" ``` ### 5. Remove Unused Imports Only import slots and classes that are actually used in the file. **WRONG:** ```yaml imports: - ../slots/has_scope # Never used in slots: or slot_usage: - ../slots/has_score - ../slots/has_type ``` **CORRECT:** ```yaml imports: - ../slots/has_score - ../slots/has_type ``` ### 6. Slot Usage Requires Slot Presence A slot referenced in `slot_usage:` must either be: - Listed in the `slots:` array, OR - Inherited from a parent class via `is_a` **WRONG:** ```yaml classes: MyClass: slots: - has_type slot_usage: has_type: {...} identified_by: {...} # Not in slots: and not inherited! ``` **CORRECT:** ```yaml classes: MyClass: slots: - has_type - identified_by slot_usage: has_type: {...} identified_by: {...} ``` ## Checklist for Class Files - [ ] All prefixes used in CURIEs are declared - [ ] `default_prefix` set if module belongs to that namespace - [ ] All referenced classes are imported - [ ] All used slots are imported - [ ] No `equals_expression` with static JSON arrays - [ ] Regex patterns are quoted - [ ] Annotation values are quoted strings - [ ] No unused imports - [ ] `slot_usage` only references slots that exist (via slots: or inheritance)