@phase2 @acms @uko_layer2
Feature: UKO Layer 2 Paradigm Vocabularies
  As a CleverAgents developer
  I want paradigm-specific UKO vocabulary specializations
  So that OO, functional, and procedural code concepts have precise ontology types

  # ---------------------------------------------------------------------------
  # VocabularyClass — Construction and Validation
  # ---------------------------------------------------------------------------

  @vocab_class
  Scenario: Create a VocabularyClass for uko_l2
    Given a simple vocabulary class with uri "https://cleveragents.ai/ontology/uko/oo#Class" and label "Class" for uko_l2
    Then the vocabulary class uri should be "https://cleveragents.ai/ontology/uko/oo#Class" for uko_l2
    And the vocabulary class label should be "Class" for uko_l2
    And the vocabulary class comment should be empty for uko_l2
    And the vocabulary class parent_uris should be empty for uko_l2

  @vocab_class
  Scenario: Create a VocabularyClass with parents for uko_l2
    Given a vocabulary class with uri "https://cleveragents.ai/ontology/uko/oo#Class" and label "Class" and parents "https://cleveragents.ai/ontology/uko/code#TypeDefinition,https://cleveragents.ai/ontology/uko#Container" for uko_l2
    Then the vocabulary class should have 2 parent URIs for uko_l2
    And the vocabulary class parent 0 should be "https://cleveragents.ai/ontology/uko/code#TypeDefinition" for uko_l2

  @vocab_class @validation
  Scenario: Reject VocabularyClass with empty URI for uko_l2
    When I create a vocabulary class with empty uri for uko_l2
    Then a validation error should be raised for uko_l2

  @vocab_class @validation
  Scenario: Reject VocabularyClass with whitespace-only URI for uko_l2
    When I create a vocabulary class with whitespace uri for uko_l2
    Then a validation error should be raised for uko_l2

  @vocab_class @validation
  Scenario: Reject VocabularyClass with empty label for uko_l2
    When I create a vocabulary class with empty label for uko_l2
    Then a validation error should be raised for uko_l2

  @vocab_class @vocab_frozen
  Scenario: VocabularyClass is immutable for uko_l2
    Given a simple vocabulary class with uri "https://cleveragents.ai/ontology/uko/oo#Class" and label "Class" for uko_l2
    When I try to mutate the vocabulary class uri for uko_l2
    Then a frozen mutation error should be raised for uko_l2

  # ---------------------------------------------------------------------------
  # VocabularyProperty — Construction and Validation
  # ---------------------------------------------------------------------------

  @vocab_property
  Scenario: Create a VocabularyProperty for uko_l2
    Given a basic vocabulary property with uri "https://cleveragents.ai/ontology/uko/oo#inheritsFrom" and label "inheritsFrom" and domain "https://cleveragents.ai/ontology/uko/oo#Class" and range "https://cleveragents.ai/ontology/uko/oo#Class" for uko_l2
    Then the vocabulary property uri should be "https://cleveragents.ai/ontology/uko/oo#inheritsFrom" for uko_l2
    And the vocabulary property label should be "inheritsFrom" for uko_l2
    And the vocabulary property sub_property_of should be empty for uko_l2

  @vocab_property
  Scenario: Create a VocabularyProperty with subPropertyOf for uko_l2
    Given a vocabulary property with uri "https://cleveragents.ai/ontology/uko/oo#inheritsFrom" and label "inheritsFrom" and domain "https://cleveragents.ai/ontology/uko/oo#Class" and range "https://cleveragents.ai/ontology/uko/oo#Class" and sub_property_of "https://cleveragents.ai/ontology/uko#dependsOn" for uko_l2
    Then the vocabulary property sub_property_of should be "https://cleveragents.ai/ontology/uko#dependsOn" for uko_l2

  @vocab_property @validation
  Scenario: Reject VocabularyProperty with empty URI for uko_l2
    When I create a vocabulary property with empty uri for uko_l2
    Then a validation error should be raised for uko_l2

  @vocab_property @vocab_frozen
  Scenario: VocabularyProperty is immutable for uko_l2
    Given a basic vocabulary property with uri "https://cleveragents.ai/ontology/uko/oo#inheritsFrom" and label "inheritsFrom" and domain "https://cleveragents.ai/ontology/uko/oo#Class" and range "https://cleveragents.ai/ontology/uko/oo#Class" for uko_l2
    When I try to mutate the vocabulary property uri for uko_l2
    Then a frozen mutation error should be raised for uko_l2

  # ---------------------------------------------------------------------------
  # Object-Oriented Vocabulary (uko-oo:)
  # ---------------------------------------------------------------------------

  @uko_oo
  Scenario: uko-oo vocabulary has all required classes for uko_l2
    Given the uko-oo vocabulary for uko_l2
    Then the vocabulary should have prefix "uko-oo:" for uko_l2
    And the vocabulary should have IRI "https://cleveragents.ai/ontology/uko/oo#" for uko_l2
    And the vocabulary should have layer 2 for uko_l2
    And the vocabulary should have 4 classes for uko_l2
    And the vocabulary should contain class "Class" for uko_l2
    And the vocabulary should contain class "Interface" for uko_l2
    And the vocabulary should contain class "Method" for uko_l2
    And the vocabulary should contain class "Attribute" for uko_l2

  @uko_oo
  Scenario: uko-oo vocabulary has all required properties for uko_l2
    Given the uko-oo vocabulary for uko_l2
    Then the vocabulary should have 2 properties for uko_l2
    And the vocabulary should contain property "inheritsFrom" for uko_l2
    And the vocabulary should contain property "implements" for uko_l2

  @uko_oo
  Scenario: uko-oo Class has correct parent URIs for uko_l2
    Given the uko-oo vocabulary for uko_l2
    When I look up class "Class" for uko_l2
    Then the class should have parent "https://cleveragents.ai/ontology/uko/code#TypeDefinition" for uko_l2
    And the class should have parent "https://cleveragents.ai/ontology/uko#Container" for uko_l2

  @uko_oo
  Scenario: uko-oo Interface has correct parent URIs for uko_l2
    Given the uko-oo vocabulary for uko_l2
    When I look up class "Interface" for uko_l2
    Then the class should have parent "https://cleveragents.ai/ontology/uko/code#TypeDefinition" for uko_l2
    And the class should have parent "https://cleveragents.ai/ontology/uko#Boundary" for uko_l2

  @uko_oo
  Scenario: uko-oo Method has correct parent URI for uko_l2
    Given the uko-oo vocabulary for uko_l2
    When I look up class "Method" for uko_l2
    Then the class should have parent "https://cleveragents.ai/ontology/uko/code#Callable" for uko_l2

  @uko_oo
  Scenario: uko-oo Attribute has correct parent URI for uko_l2
    Given the uko-oo vocabulary for uko_l2
    When I look up class "Attribute" for uko_l2
    Then the class should have parent "https://cleveragents.ai/ontology/uko#Atom" for uko_l2

  @uko_oo
  Scenario: uko-oo inheritsFrom property has correct domain and range for uko_l2
    Given the uko-oo vocabulary for uko_l2
    When I look up property "inheritsFrom" for uko_l2
    Then the property domain should be "https://cleveragents.ai/ontology/uko/oo#Class" for uko_l2
    And the property range should be "https://cleveragents.ai/ontology/uko/oo#Class" for uko_l2
    And the property sub_property_of should be "https://cleveragents.ai/ontology/uko#dependsOn" for uko_l2

  @uko_oo
  Scenario: uko-oo implements property has correct domain and range for uko_l2
    Given the uko-oo vocabulary for uko_l2
    When I look up property "implements" for uko_l2
    Then the property domain should be "https://cleveragents.ai/ontology/uko/oo#Class" for uko_l2
    And the property range should be "https://cleveragents.ai/ontology/uko/oo#Interface" for uko_l2

  # ---------------------------------------------------------------------------
  # Functional Vocabulary (uko-func:)
  # ---------------------------------------------------------------------------

  @uko_func
  Scenario: uko-func vocabulary has all required classes for uko_l2
    Given the uko-func vocabulary for uko_l2
    Then the vocabulary should have prefix "uko-func:" for uko_l2
    And the vocabulary should have IRI "https://cleveragents.ai/ontology/uko/func#" for uko_l2
    And the vocabulary should have layer 2 for uko_l2
    And the vocabulary should have 3 classes for uko_l2
    And the vocabulary should contain class "PureFunction" for uko_l2
    And the vocabulary should contain class "TypeClass" for uko_l2
    And the vocabulary should contain class "Monad" for uko_l2

  @uko_func
  Scenario: uko-func vocabulary has no properties for uko_l2
    Given the uko-func vocabulary for uko_l2
    Then the vocabulary should have 0 properties for uko_l2

  @uko_func
  Scenario: uko-func PureFunction has correct parent URI for uko_l2
    Given the uko-func vocabulary for uko_l2
    When I look up class "PureFunction" for uko_l2
    Then the class should have parent "https://cleveragents.ai/ontology/uko/code#Callable" for uko_l2

  @uko_func
  Scenario: uko-func TypeClass has correct parent URIs for uko_l2
    Given the uko-func vocabulary for uko_l2
    When I look up class "TypeClass" for uko_l2
    Then the class should have parent "https://cleveragents.ai/ontology/uko/code#TypeDefinition" for uko_l2
    And the class should have parent "https://cleveragents.ai/ontology/uko#Boundary" for uko_l2

  @uko_func
  Scenario: uko-func Monad has correct parent URI for uko_l2
    Given the uko-func vocabulary for uko_l2
    When I look up class "Monad" for uko_l2
    Then the class should have parent "https://cleveragents.ai/ontology/uko/code#TypeDefinition" for uko_l2

  # ---------------------------------------------------------------------------
  # Procedural Vocabulary (uko-proc:)
  # ---------------------------------------------------------------------------

  @uko_proc
  Scenario: uko-proc vocabulary has all required classes for uko_l2
    Given the uko-proc vocabulary for uko_l2
    Then the vocabulary should have prefix "uko-proc:" for uko_l2
    And the vocabulary should have IRI "https://cleveragents.ai/ontology/uko/proc#" for uko_l2
    And the vocabulary should have layer 2 for uko_l2
    And the vocabulary should have 5 classes for uko_l2
    And the vocabulary should contain class "ProceduralFunction" for uko_l2
    And the vocabulary should contain class "GlobalVariable" for uko_l2
    And the vocabulary should contain class "HeaderFile" for uko_l2
    And the vocabulary should contain class "StructDefinition" for uko_l2
    And the vocabulary should contain class "Macro" for uko_l2

  @uko_proc
  Scenario: uko-proc vocabulary has no properties for uko_l2
    Given the uko-proc vocabulary for uko_l2
    Then the vocabulary should have 0 properties for uko_l2

  @uko_proc
  Scenario: uko-proc ProceduralFunction has correct parent URI for uko_l2
    Given the uko-proc vocabulary for uko_l2
    When I look up class "ProceduralFunction" for uko_l2
    Then the class should have parent "https://cleveragents.ai/ontology/uko/code#Callable" for uko_l2

  @uko_proc
  Scenario: uko-proc GlobalVariable has correct parent URI for uko_l2
    Given the uko-proc vocabulary for uko_l2
    When I look up class "GlobalVariable" for uko_l2
    Then the class should have parent "https://cleveragents.ai/ontology/uko#Atom" for uko_l2

  @uko_proc
  Scenario: uko-proc HeaderFile has correct parent URI for uko_l2
    Given the uko-proc vocabulary for uko_l2
    When I look up class "HeaderFile" for uko_l2
    Then the class should have parent "https://cleveragents.ai/ontology/uko#Container" for uko_l2

  @uko_proc
  Scenario: uko-proc StructDefinition has correct parent URI for uko_l2
    Given the uko-proc vocabulary for uko_l2
    When I look up class "StructDefinition" for uko_l2
    Then the class should have parent "https://cleveragents.ai/ontology/uko/code#TypeDefinition" for uko_l2

  @uko_proc
  Scenario: uko-proc Macro has correct parent URI for uko_l2
    Given the uko-proc vocabulary for uko_l2
    When I look up class "Macro" for uko_l2
    Then the class should have parent "https://cleveragents.ai/ontology/uko#Atom" for uko_l2

  # ---------------------------------------------------------------------------
  # ParadigmVocabulary — Lookup helpers
  # ---------------------------------------------------------------------------

  @vocab_lookup
  Scenario: Look up class by label for uko_l2
    Given the uko-oo vocabulary for uko_l2
    When I look up class "Class" for uko_l2
    Then the looked up class should not be None for uko_l2
    And the looked up class uri should be "https://cleveragents.ai/ontology/uko/oo#Class" for uko_l2

  @vocab_lookup
  Scenario: Look up missing class returns None for uko_l2
    Given the uko-oo vocabulary for uko_l2
    When I look up class "NonExistent" for uko_l2
    Then the looked up class should be None for uko_l2

  @vocab_lookup
  Scenario: Look up property by label for uko_l2
    Given the uko-oo vocabulary for uko_l2
    When I look up property "inheritsFrom" for uko_l2
    Then the looked up property should not be None for uko_l2

  @vocab_lookup
  Scenario: Look up missing property returns None for uko_l2
    Given the uko-oo vocabulary for uko_l2
    When I look up property "nonExistent" for uko_l2
    Then the looked up property should be None for uko_l2

  @vocab_lookup
  Scenario: class_uris returns all class URIs for uko_l2
    Given the uko-oo vocabulary for uko_l2
    Then class_uris should have 4 entries for uko_l2

  @vocab_lookup
  Scenario: property_uris returns all property URIs for uko_l2
    Given the uko-oo vocabulary for uko_l2
    Then property_uris should have 2 entries for uko_l2

  # ---------------------------------------------------------------------------
  # VocabularyRegistry
  # ---------------------------------------------------------------------------

  @vocab_registry
  Scenario: Register and look up vocabularies for uko_l2
    Given a vocabulary registry with all paradigm vocabularies for uko_l2
    Then the registry should have 3 vocabularies for uko_l2
    And the registry should contain prefix "uko-oo:" for uko_l2
    And the registry should contain prefix "uko-func:" for uko_l2
    And the registry should contain prefix "uko-proc:" for uko_l2

  @vocab_registry
  Scenario: Look up vocabulary by prefix for uko_l2
    Given a vocabulary registry with all paradigm vocabularies for uko_l2
    When I look up vocabulary by prefix "uko-oo:" for uko_l2
    Then the looked up vocabulary should not be None for uko_l2
    And the looked up vocabulary prefix should be "uko-oo:" for uko_l2

  @vocab_registry
  Scenario: Look up vocabulary by IRI for uko_l2
    Given a vocabulary registry with all paradigm vocabularies for uko_l2
    When I look up vocabulary by IRI "https://cleveragents.ai/ontology/uko/func#" for uko_l2
    Then the looked up vocabulary should not be None for uko_l2
    And the looked up vocabulary prefix should be "uko-func:" for uko_l2

  @vocab_registry
  Scenario: Look up missing prefix returns None for uko_l2
    Given a vocabulary registry with all paradigm vocabularies for uko_l2
    When I look up vocabulary by prefix "uko-unknown:" for uko_l2
    Then the looked up vocabulary should be None for uko_l2

  @vocab_registry @validation
  Scenario: Reject duplicate vocabulary registration for uko_l2
    Given a vocabulary registry with all paradigm vocabularies for uko_l2
    When I try to register a duplicate vocabulary for uko_l2
    Then a duplicate registration error should be raised for uko_l2

  @vocab_registry
  Scenario: list_prefixes returns sorted prefixes for uko_l2
    Given a vocabulary registry with all paradigm vocabularies for uko_l2
    Then list_prefixes should return "uko-func:,uko-oo:,uko-proc:" for uko_l2

  @vocab_registry
  Scenario: list_all returns all vocabularies for uko_l2
    Given a vocabulary registry with all paradigm vocabularies for uko_l2
    Then list_all should return 3 vocabularies for uko_l2

  @vocab_registry
  Scenario: Registry contains check for uko_l2
    Given a vocabulary registry with all paradigm vocabularies for uko_l2
    Then "uko-oo:" should be in the registry for uko_l2
    And "uko-missing:" should not be in the registry for uko_l2

  @vocab_registry
  Scenario: Registry contains check supports IRI for uko_l2
    Given a vocabulary registry with all paradigm vocabularies for uko_l2
    Then "https://cleveragents.ai/ontology/uko/oo#" should be in the registry for uko_l2

  @vocab_registry
  Scenario: Unregister vocabulary from registry for uko_l2
    Given a vocabulary registry with all paradigm vocabularies for uko_l2
    When I unregister prefix "uko-oo:" from the registry for uko_l2
    Then the registry should have 2 vocabularies for uko_l2
    And "uko-oo:" should not be in the registry for uko_l2

  @vocab_registry
  Scenario: Unregister missing prefix returns False for uko_l2
    Given a vocabulary registry with all paradigm vocabularies for uko_l2
    When I unregister prefix "uko-missing:" from the registry for uko_l2
    Then the unregister result should be False for uko_l2

  # ---------------------------------------------------------------------------
  # DetailLevelMap — Layer 1 base map (uko-code:)
  # ---------------------------------------------------------------------------

  @detail_level_map
  Scenario: uko-code base map has correct levels for uko_l2
    Given the uko-code detail level map for uko_l2
    Then the map should have domain "uko-code:" for uko_l2
    And the map should have max_depth 9 for uko_l2
    And the map should resolve "MODULE_LISTING" to 0 for uko_l2
    And the map should resolve "FULL_SOURCE" to 9 for uko_l2
    And the map should resolve "SIGNATURES" to 4 for uko_l2

  @detail_level_map
  Scenario: uko-code base map has 10 named levels for uko_l2
    Given the uko-code detail level map for uko_l2
    Then the map should have 10 levels for uko_l2

  # ---------------------------------------------------------------------------
  # DetailLevelMap — uko-oo: with insertions
  # ---------------------------------------------------------------------------

  @detail_level_map @uko_oo
  Scenario: uko-oo map inserts CLASS_HIERARCHY at depth 3 for uko_l2
    Given the uko-oo detail level map for uko_l2
    Then the map should have domain "uko-oo:" for uko_l2
    And the map should resolve "CLASS_HIERARCHY" to 3 for uko_l2

  @detail_level_map @uko_oo
  Scenario: uko-oo map inserts VISIBILITY_ANNOTATED at depth 7 for uko_l2
    Given the uko-oo detail level map for uko_l2
    Then the map should resolve "VISIBILITY_ANNOTATED" to 7 for uko_l2

  @detail_level_map @uko_oo
  Scenario: uko-oo map shifts subsequent depths for uko_l2
    Given the uko-oo detail level map for uko_l2
    Then the map should resolve "MEMBER_SUMMARY" to 4 for uko_l2
    And the map should resolve "SIGNATURES" to 5 for uko_l2
    And the map should resolve "SIGNATURES_WITH_DOCS" to 6 for uko_l2
    And the map should resolve "STRUCTURAL_OUTLINE" to 8 for uko_l2
    And the map should resolve "FULL_SOURCE" to 11 for uko_l2

  @detail_level_map @uko_oo
  Scenario: uko-oo map has 12 total levels for uko_l2
    Given the uko-oo detail level map for uko_l2
    Then the map should have 12 levels for uko_l2
    And the map should have max_depth 11 for uko_l2

  @detail_level_map @uko_oo
  Scenario: uko-oo map resolves integer depths for uko_l2
    Given the uko-oo detail level map for uko_l2
    Then the map should resolve integer 0 to 0 for uko_l2
    And the map should resolve integer 5 to 5 for uko_l2
    And the map should resolve integer 100 to 11 for uko_l2

  @detail_level_map @uko_oo
  Scenario: uko-oo map inherits from uko-code parent for uko_l2
    Given the uko-oo detail level map for uko_l2
    Then the map parent domain should be "uko-code:" for uko_l2

  # ---------------------------------------------------------------------------
  # DetailLevelMap — uko-func:
  # ---------------------------------------------------------------------------

  @detail_level_map @uko_func
  Scenario: uko-func map has same levels as uko-code for uko_l2
    Given the uko-func detail level map for uko_l2
    Then the map should have domain "uko-func:" for uko_l2
    And the map should have 10 levels for uko_l2
    And the map should have max_depth 9 for uko_l2
    And the map should resolve "SIGNATURES" to 4 for uko_l2

  # ---------------------------------------------------------------------------
  # DetailLevelMap — uko-proc:
  # ---------------------------------------------------------------------------

  @detail_level_map @uko_proc
  Scenario: uko-proc map has same levels as uko-code for uko_l2
    Given the uko-proc detail level map for uko_l2
    Then the map should have domain "uko-proc:" for uko_l2
    And the map should have 10 levels for uko_l2
    And the map should have max_depth 9 for uko_l2
    And the map should resolve "SIGNATURES_WITH_DOCS" to 5 for uko_l2

  # ---------------------------------------------------------------------------
  # DetailLevelMapBuilder — Construction and edge cases
  # ---------------------------------------------------------------------------

  @detail_level_map_builder
  Scenario: Build a child map with single insertion for uko_l2
    Given a detail level map builder with parent "uko-code:" and domain "test:" for uko_l2
    When I insert "TEST_LEVEL" after "MEMBER_LISTING" for uko_l2
    And I build the map for uko_l2
    Then the built map should have domain "test:" for uko_l2
    And the built map should resolve "TEST_LEVEL" to 3 for uko_l2
    And the built map should resolve "MEMBER_SUMMARY" to 4 for uko_l2
    And the built map should have 11 levels for uko_l2

  @detail_level_map_builder @validation
  Scenario: Reject insertion after non-existent level for uko_l2
    Given a detail level map builder with parent "uko-code:" and domain "test:" for uko_l2
    When I try to insert after non-existent level "BOGUS" for uko_l2
    Then a value error should be raised for uko_l2

  @detail_level_map_builder @validation
  Scenario: Reject builder with empty domain for uko_l2
    When I try to create a builder with empty domain for uko_l2
    Then a value error should be raised for uko_l2

  @detail_level_map_builder @validation
  Scenario: Reject insertion with empty new_level name for uko_l2
    Given a detail level map builder with parent "uko-code:" and domain "test:" for uko_l2
    When I try to insert empty level name after "MEMBER_LISTING" for uko_l2
    Then a value error should be raised for uko_l2

  @detail_level_map_builder @validation
  Scenario: Reject insertion with empty after_level name for uko_l2
    Given a detail level map builder with parent "uko-code:" and domain "test:" for uko_l2
    When I try to insert "TEST" after empty level name for uko_l2
    Then a value error should be raised for uko_l2

  @detail_level_map_builder
  Scenario: Build with multiple insertions for uko_l2
    Given a detail level map builder with parent "uko-code:" and domain "test:" for uko_l2
    When I insert "FIRST" after "MODULE_LISTING" for uko_l2
    And I insert "SECOND" after "FIRST" for uko_l2
    And I build the map for uko_l2
    Then the built map should resolve "FIRST" to 1 for uko_l2
    And the built map should resolve "SECOND" to 2 for uko_l2
    And the built map should resolve "MODULE_GRAPH" to 3 for uko_l2

  @detail_level_map_builder
  Scenario: Builder exposes parent and domain properties for uko_l2
    Given a detail level map builder with parent "uko-code:" and domain "test:" for uko_l2
    Then the builder parent domain should be "uko-code:" for uko_l2
    And the builder domain should be "test:" for uko_l2

  # ---------------------------------------------------------------------------
  # build_effective_map function
  # ---------------------------------------------------------------------------

  @effective_map
  Scenario: Build effective map with no insertions for uko_l2
    Given the uko-code detail level map for uko_l2
    When I build an effective map with no insertions for uko_l2
    Then the effective map should have 10 entries for uko_l2
    And the effective map entry 0 should be "MODULE_LISTING" at depth 0 for uko_l2

  @effective_map
  Scenario: Build effective map with insertions for uko_l2
    Given the uko-code detail level map for uko_l2
    When I build an effective map with insertion "CLASS_HIERARCHY" after "MEMBER_LISTING" for uko_l2
    Then the effective map should have 11 entries for uko_l2
    And the effective map entry 3 should be "CLASS_HIERARCHY" at depth 3 for uko_l2
    And the effective map entry 4 should be "MEMBER_SUMMARY" at depth 4 for uko_l2

  @effective_map @validation
  Scenario: build_effective_map rejects invalid after_level for uko_l2
    Given the uko-code detail level map for uko_l2
    When I try to build an effective map with insertion after "BOGUS" for uko_l2
    Then a value error should be raised for uko_l2

  # ---------------------------------------------------------------------------
  # DetailLevelMap unknown level resolution
  # ---------------------------------------------------------------------------

  @detail_level_map @error
  Scenario: Reject unknown named level for uko_l2
    Given the uko-code detail level map for uko_l2
    When I try to resolve unknown level "NONEXISTENT" for uko_l2
    Then a value error should be raised for uko_l2

  # ---------------------------------------------------------------------------
  # Turtle validation — TTL file loads successfully
  # ---------------------------------------------------------------------------

  @turtle @validation
  Scenario: TTL file loads and validates for uko_l2
    When I load the UKO TTL file for uko_l2
    Then the ontology should load without errors for uko_l2
    And the ontology should contain uko-func prefix for uko_l2
    And the ontology should contain uko-proc prefix for uko_l2

  @turtle @validation
  Scenario: TTL file contains uko-func classes for uko_l2
    When I load the UKO TTL file for uko_l2
    Then the ontology should contain node "PureFunction" for uko_l2
    And the ontology should contain node "TypeClass" for uko_l2
    And the ontology should contain node "Monad" for uko_l2

  @turtle @validation
  Scenario: TTL file contains uko-proc classes for uko_l2
    When I load the UKO TTL file for uko_l2
    Then the ontology should contain node "ProceduralFunction" for uko_l2
    And the ontology should contain node "GlobalVariable" for uko_l2
    And the ontology should contain node "HeaderFile" for uko_l2
    And the ontology should contain node "StructDefinition" for uko_l2
    And the ontology should contain node "Macro" for uko_l2

  @turtle @validation
  Scenario: TTL file contains existing uko-oo classes for uko_l2
    When I load the UKO TTL file for uko_l2
    Then the ontology should contain node "Class" for uko_l2
    And the ontology should contain node "Interface" for uko_l2
    And the ontology should contain node "Method" for uko_l2
    And the ontology should contain node "Attribute" for uko_l2

  @turtle @validation
  Scenario: TTL file has layer 2 nodes for uko_l2
    When I load the UKO TTL file for uko_l2
    Then the ontology should have at least 12 layer 2 nodes for uko_l2

  # ---------------------------------------------------------------------------
  # ParadigmVocabulary — frozen immutability
  # ---------------------------------------------------------------------------

  @vocab_frozen
  Scenario: ParadigmVocabulary is immutable for uko_l2
    Given the uko-oo vocabulary for uko_l2
    When I try to mutate the vocabulary prefix for uko_l2
    Then a frozen mutation error should be raised for uko_l2

  # ---------------------------------------------------------------------------
  # Additional coverage: validation edge cases
  # ---------------------------------------------------------------------------

  @vocab_class @validation
  Scenario: Reject ParadigmVocabulary with empty prefix for uko_l2
    When I create a paradigm vocabulary with empty prefix for uko_l2
    Then a validation error should be raised for uko_l2

  @vocab_class @validation
  Scenario: Reject ParadigmVocabulary with whitespace prefix for uko_l2
    When I create a paradigm vocabulary with whitespace prefix for uko_l2
    Then a validation error should be raised for uko_l2

  @vocab_class @validation
  Scenario: Reject ParadigmVocabulary with prefix missing colon for uko_l2
    When I create a paradigm vocabulary with prefix missing colon for uko_l2
    Then a validation error should be raised for uko_l2

  @vocab_property @validation
  Scenario: Reject VocabularyProperty with whitespace-only URI for uko_l2
    When I create a vocabulary property with whitespace uri for uko_l2
    Then a validation error should be raised for uko_l2

  @vocab_registry
  Scenario: Registry __contains__ returns False for non-string for uko_l2
    Given a vocabulary registry with all paradigm vocabularies for uko_l2
    Then the registry should return False for non-string contains for uko_l2

  @vocab_registry @validation
  Scenario: Reject duplicate IRI registration for uko_l2
    Given a vocabulary registry with all paradigm vocabularies for uko_l2
    When I try to register a vocabulary with duplicate IRI for uko_l2
    Then a duplicate registration error should be raised for uko_l2

  @vocab_registry
  Scenario: Look up missing IRI returns None for uko_l2
    Given a vocabulary registry with all paradigm vocabularies for uko_l2
    When I look up vocabulary by IRI "https://nonexistent.example.org/" for uko_l2
    Then the looked up vocabulary should be None for uko_l2

  @detail_level_map
  Scenario: DetailLevelMap register adds new level for uko_l2
    Given a fresh detail level map for uko_l2
    When I register level "CUSTOM" with value 5 for uko_l2
    Then the fresh map should resolve "CUSTOM" to 5 for uko_l2

  @detail_level_map @validation
  Scenario: DetailLevelMap register rejects negative depth for uko_l2
    Given a fresh detail level map for uko_l2
    When I try to register level "BAD" with value -1 for uko_l2
    Then a value error should be raised for uko_l2

  @detail_level_map
  Scenario: DetailLevelMap levels are immutable MappingProxy for uko_l2
    Given the uko-code detail level map for uko_l2
    When I try to mutate the levels dict for uko_l2
    Then a type error should be raised for uko_l2

  @detail_level_map_builder @validation
  Scenario: Reject insertion of duplicate level name for uko_l2
    Given a detail level map builder with parent "uko-code:" and domain "test:" for uko_l2
    When I try to insert duplicate level "MODULE_LISTING" after "MEMBER_LISTING" for uko_l2
    Then a value error should be raised for uko_l2

  @effective_map @validation
  Scenario: build_effective_map rejects duplicate level name for uko_l2
    Given the uko-code detail level map for uko_l2
    When I try to build an effective map with duplicate level for uko_l2
    Then a value error should be raised for uko_l2

  @detail_level_map
  Scenario: effective_levels returns immutable mapping for uko_l2
    Given the uko-code detail level map for uko_l2
    When I try to mutate effective_levels for uko_l2
    Then a type error should be raised for uko_l2

  @detail_level_map @uko_func
  Scenario: uko-func map resolves levels via parent inheritance for uko_l2
    Given the uko-func detail level map for uko_l2
    Then the map should resolve "MODULE_LISTING" to 0 for uko_l2
    And the map should resolve "FULL_SOURCE" to 9 for uko_l2

  # ---------------------------------------------------------------------------
  # Review findings: M8 — empty label/domain/range rejection
  # ---------------------------------------------------------------------------

  @vocab_property @validation
  Scenario: Reject VocabularyProperty with empty label for uko_l2
    When I create a vocabulary property with empty label for uko_l2
    Then a validation error should be raised for uko_l2

  @vocab_property @validation
  Scenario: Reject VocabularyProperty with empty domain for uko_l2
    When I create a vocabulary property with empty domain for uko_l2
    Then a validation error should be raised for uko_l2

  @vocab_property @validation
  Scenario: Reject VocabularyProperty with empty range for uko_l2
    When I create a vocabulary property with empty range for uko_l2
    Then a validation error should be raised for uko_l2

  # ---------------------------------------------------------------------------
  # Review findings: M9 — invalid URI scheme rejection
  # ---------------------------------------------------------------------------

  @vocab_class @validation
  Scenario: Reject VocabularyClass with non-HTTP URI for uko_l2
    When I create a vocabulary class with non-http uri for uko_l2
    Then a validation error should be raised for uko_l2

  @vocab_property @validation
  Scenario: Reject VocabularyProperty with non-HTTP URI for uko_l2
    When I create a vocabulary property with non-http uri for uko_l2
    Then a validation error should be raised for uko_l2

  @vocab_class @validation
  Scenario: Reject VocabularyClass with non-HTTP parent URI for uko_l2
    When I create a vocabulary class with non-http parent uri for uko_l2
    Then a validation error should be raised for uko_l2

  @vocab_property @validation
  Scenario: Reject VocabularyProperty with non-HTTP domain URI for uko_l2
    When I create a vocabulary property with non-http domain uri for uko_l2
    Then a validation error should be raised for uko_l2

  @vocab_property @validation
  Scenario: Reject VocabularyProperty with non-HTTP range URI for uko_l2
    When I create a vocabulary property with non-http range uri for uko_l2
    Then a validation error should be raised for uko_l2

  @vocab_property @validation
  Scenario: Reject VocabularyProperty with non-HTTP sub_property_of for uko_l2
    When I create a vocabulary property with non-http sub_property_of for uko_l2
    Then a validation error should be raised for uko_l2

  # ---------------------------------------------------------------------------
  # Review findings: M10 — insert_after at tail of level list
  # ---------------------------------------------------------------------------

  @detail_level_map_builder
  Scenario: Insert after last level FULL_SOURCE for uko_l2
    Given a detail level map builder with parent "uko-code:" and domain "test:" for uko_l2
    When I insert "BEYOND_SOURCE" after "FULL_SOURCE" for uko_l2
    And I build the map for uko_l2
    Then the built map should resolve "BEYOND_SOURCE" to 10 for uko_l2
    And the built map should resolve "FULL_SOURCE" to 9 for uko_l2
    And the built map should have 11 levels for uko_l2

  # ---------------------------------------------------------------------------
  # Review findings: H3 — MappingProxyType serialization
  # ---------------------------------------------------------------------------

  @detail_level_map
  Scenario: DetailLevelMap model_dump_json succeeds with MappingProxy for uko_l2
    Given the uko-code detail level map for uko_l2
    When I serialize the detail level map to JSON for uko_l2
    Then the serialized JSON should contain "MODULE_LISTING" for uko_l2

  @detail_level_map
  Scenario: DetailLevelMap model_dump succeeds with MappingProxy for uko_l2
    Given the uko-code detail level map for uko_l2
    When I dump the detail level map to dict for uko_l2
    Then the dumped dict levels should contain "MODULE_LISTING" for uko_l2

  # ---------------------------------------------------------------------------
  # Review findings: M5 — cycle guard in resolve()
  # ---------------------------------------------------------------------------

  @detail_level_map @error
  Scenario: Detect cycle in parent chain during resolve for uko_l2
    Given a detail level map with circular parent for uko_l2
    When I try to resolve level "ANYTHING" on the circular map for uko_l2
    Then a cycle error should be raised for uko_l2

  # ---------------------------------------------------------------------------
  # Review findings: H2 — levels field re-frozen on assignment
  # ---------------------------------------------------------------------------

  @detail_level_map
  Scenario: Assigning dict to levels re-freezes as MappingProxy for uko_l2
    Given a fresh detail level map for uko_l2
    When I assign a dict to the levels field for uko_l2
    Then the levels should still be an immutable MappingProxy for uko_l2

  # ---------------------------------------------------------------------------
  # Review findings: F7 — cycle guard in effective_levels()
  # ---------------------------------------------------------------------------

  @detail_level_map @error
  Scenario: Detect cycle in parent chain during effective_levels for uko_l2
    Given a detail level map with circular parent for uko_l2
    When I try to get effective levels on the circular map for uko_l2
    Then a cycle error should be raised for uko_l2

  # ---------------------------------------------------------------------------
  # Review findings: F13 — deepcopy support
  # ---------------------------------------------------------------------------

  @detail_level_map
  Scenario: Deep copy of DetailLevelMap preserves data for uko_l2
    Given the uko-oo detail level map for uko_l2
    When I deep copy the detail level map for uko_l2
    Then the copied map should have domain "uko-oo:" for uko_l2
    And the copied map should resolve "CLASS_HIERARCHY" to 3 for uko_l2
    And the copied map should not be the same object for uko_l2
