Feature: CRP (Context Request Protocol) Domain Models
  As a developer
  I want CRP domain models for the Advanced Context Management System
  So that actors can issue structured context requests during reasoning

  # ---- DetailLevelMap ----

  Scenario: Create a DetailLevelMap with valid levels
    Given a DetailLevelMap for domain "uko-code:" with max depth 9
    And the map has level "MODULE_LISTING" at depth 0
    And the map has level "FULL_SOURCE" at depth 9
    Then the map should resolve "MODULE_LISTING" to 0
    And the map should resolve "FULL_SOURCE" to 9

  Scenario: DetailLevelMap clamps integer depth to max_depth
    Given a DetailLevelMap for domain "uko-code:" with max depth 9
    Then the map should resolve integer 15 to 9
    And the map should resolve integer 0 to 0
    And the map should resolve integer 5 to 5

  Scenario: DetailLevelMap resolves from parent map
    Given a parent DetailLevelMap for domain "uko-code:" with max depth 9
    And the parent map has level "MODULE_LISTING" at depth 0
    And a child DetailLevelMap for domain "uko-oo:" with max depth 11
    And the child map has level "CLASS_HIERARCHY" at depth 3
    Then the child map should resolve "MODULE_LISTING" to 0
    And the child map should resolve "CLASS_HIERARCHY" to 3

  Scenario: DetailLevelMap raises on unknown named level
    Given a DetailLevelMap for domain "uko-code:" with max depth 9
    Then resolving "NONEXISTENT" should raise ValueError

  Scenario: DetailLevelMap register adds custom level
    Given a DetailLevelMap for domain "uko-code:" with max depth 9
    When I register level "CUSTOM_LEVEL" at depth 7
    Then the map should resolve "CUSTOM_LEVEL" to 7

  Scenario: DetailLevelMap rejects negative depth in levels
    Then creating a DetailLevelMap with level "BAD" at depth -1 should raise ValueError

  Scenario: DetailLevelMap register rejects negative depth
    Given a DetailLevelMap for domain "uko-code:" with max depth 9
    Then registering level "BAD" at depth -1 should raise ValueError

  Scenario: DetailLevelMap effective_levels merges parent and child
    Given a parent DetailLevelMap for domain "uko-code:" with max depth 9
    And the parent map has level "MODULE_LISTING" at depth 0
    And the parent map has level "FULL_SOURCE" at depth 9
    And a child DetailLevelMap for domain "uko-oo:" with max depth 11
    And the child map has level "CLASS_HIERARCHY" at depth 3
    Then the child effective_levels should contain "MODULE_LISTING" at 0
    And the child effective_levels should contain "FULL_SOURCE" at 9
    And the child effective_levels should contain "CLASS_HIERARCHY" at 3

  Scenario: DetailLevelMap created with pre-populated levels dict
    Given a DetailLevelMap for domain "uko-code:" with max depth 9 and levels "SIGNATURES" at 4
    Then the map should resolve "SIGNATURES" to 4

  # ---- FragmentProvenance ----

  Scenario: Create a valid FragmentProvenance
    Given a FragmentProvenance with resource URI "uko-py:module/auth"
    Then the provenance resource_uri should be "uko-py:module/auth"
    And the provenance location should be empty
    And the provenance strategy should be empty

  Scenario: FragmentProvenance rejects empty resource_uri
    Then creating a FragmentProvenance with empty resource_uri should raise ValueError

  # ---- ContextBudget ----

  Scenario: Create a valid ContextBudget
    Given a ContextBudget with max_tokens 8000 and reserved_tokens 1000
    Then the budget available_tokens should be 7000
    And the budget max_tokens should be 8000
    And the budget reserved_tokens should be 1000

  Scenario: ContextBudget with zero reservation
    Given a ContextBudget with max_tokens 4000 and reserved_tokens 0
    Then the budget available_tokens should be 4000

  Scenario: ContextBudget rejects negative max_tokens
    Then creating a ContextBudget with max_tokens -1 should raise ValueError

  Scenario: ContextBudget rejects negative reserved_tokens
    Then creating a ContextBudget with max_tokens 100 and reserved_tokens -5 should raise ValueError

  Scenario: ContextBudget rejects reserved exceeding max
    Then creating a ContextBudget with max_tokens 100 and reserved_tokens 200 should raise ValueError

  # ---- ContextFragment ----

  Scenario: Create a valid ContextFragment
    Given a ContextFragment with uko_node "uko-py:class/AuthManager" and content "class AuthManager: ..."
    And the fragment has detail_depth 9 and token_count 800
    And the fragment has relevance_score 0.95
    Then the fragment uko_node should be "uko-py:class/AuthManager"
    And the fragment token_count should be 800
    And the fragment relevance_score should be 0.95
    And the fragment detail_depth should be 9

  Scenario: ContextFragment rejects negative token_count
    Then creating a ContextFragment with token_count -1 should raise ValueError

  Scenario: ContextFragment rejects relevance_score above 1.0
    Then creating a ContextFragment with relevance_score 1.5 should raise ValueError

  Scenario: ContextFragment rejects relevance_score below 0.0
    Then creating a ContextFragment with relevance_score -0.1 should raise ValueError

  Scenario: ContextFragment rejects negative detail_depth
    Then creating a ContextFragment with detail_depth -1 should raise ValueError

  Scenario: ContextFragment rejects empty uko_node
    Then creating a ContextFragment with empty uko_node should raise ValueError

  # ---- ContextRequest ----

  Scenario: Create a ContextRequest with defaults
    Given a ContextRequest with purpose "Understand the auth module"
    Then the request purpose should be "Understand the auth module"
    And the request breadth should be 2
    And the request depth should be 3
    And the request depth_gradient should be true
    And the request priority should be 0.5
    And the request temporal should be "current"
    And the request query should be None
    And the request max_tokens should be None

  Scenario: Create a ContextRequest with all fields
    Given a full ContextRequest with query "auth flow" and focus "uko-py:class/AuthManager"
    And the request has breadth 3 and depth "SIGNATURES"
    And the request has priority 0.8 and purpose "Review auth"
    Then the request query should be "auth flow"
    And the request breadth should be 3
    And the request depth should be "SIGNATURES"
    And the request priority should be 0.8

  Scenario: ContextRequest rejects negative breadth
    Then creating a ContextRequest with breadth -1 should raise ValueError

  Scenario: ContextRequest rejects negative integer depth
    Then creating a ContextRequest with depth -1 should raise ValueError

  Scenario: ContextRequest rejects priority above 1.0
    Then creating a ContextRequest with priority 1.5 should raise ValueError

  Scenario: ContextRequest rejects priority below 0.0
    Then creating a ContextRequest with priority -0.1 should raise ValueError

  Scenario: ContextRequest accepts string depth
    Given a ContextRequest with depth "FULL_SOURCE"
    Then the request depth should be "FULL_SOURCE"

  Scenario: ContextRequest accepts zero breadth
    Given a ContextRequest with breadth 0
    Then the request breadth should be 0

  Scenario: ContextRequest accepts max_tokens
    Given a ContextRequest with max_tokens 4096
    Then the request max_tokens should be 4096

  Scenario: ContextRequest rejects negative max_tokens
    Then creating a ContextRequest with max_tokens -100 should raise ValueError

  # ---- AssembledContext ----

  Scenario: Create a valid AssembledContext
    Given an AssembledContext with total_tokens 1500 and budget_used 0.75
    And the assembled context has hash "abc123def"
    Then the assembled total_tokens should be 1500
    And the assembled budget_used should be 0.75
    And the assembled context_hash should be "abc123def"

  Scenario: AssembledContext rejects budget_used above 1.0
    Then creating an AssembledContext with budget_used 1.5 should raise ValueError

  Scenario: AssembledContext rejects negative total_tokens
    Then creating an AssembledContext with total_tokens -1 should raise ValueError

  # ---- Context Skill Tools (Wired to ACMS Pipeline) ----

  Scenario: request_context returns assembled context with fragments
    Given a context tier service with sample fragments
    When I call the request_context tool with purpose "test context"
    Then the request_context result should contain "fragments" key
    And the request_context result should contain "total_tokens" key

  Scenario: request_context returns empty result with no stored fragments
    Given an empty context tier service
    When I call the request_context tool with purpose "test context"
    Then the request_context result "fragments" should be an empty list
    And the request_context result "total_tokens" should be 0

  Scenario: request_context filters fragments by query
    Given a context tier service with sample fragments
    When I call the request_context tool filtering by query "auth"
    Then the request_context result "fragments" should only contain matching content

  Scenario: request_context filters fragments by focus targets
    Given a context tier service with sample fragments
    When I call the request_context tool with focus on "auth"
    Then the request_context result "fragments" should only contain matching content

  Scenario: query_history returns entries for stored fragments
    Given a context tier service with sample fragments
    When I call the query_history tool with query "auth"
    Then the query_history result should contain "entries" key
    And the query_history result "entries" should not be empty

  Scenario: query_history returns empty entries when no match
    Given a context tier service with sample fragments
    When I call the query_history tool with query "nonexistent_xyz_content"
    Then the query_history result "entries" should be an empty list

  Scenario: get_context_budget returns budget state
    Given an empty context tier service
    When I call the get_context_budget tool
    Then the budget result should contain "max_tokens" key
    And the budget result should contain "reserved_tokens" key
    And the budget result should contain "available_tokens" key
    And the budget result should contain "used_tokens" key
    And the budget result "used_tokens" should be 0

  Scenario: get_context_budget reports used tokens from hot tier
    Given a context tier service with sample fragments
    When I call the get_context_budget tool
    Then the budget result "used_tokens" should be greater than 0

  Scenario: builtin/context SkillDefinition can be built
    When I build the builtin/context SkillDefinition
    Then the skill definition name should be "builtin/context"
    And the skill definition should have 3 resolved tools
    And the skill definition should be read-only

  Scenario: Context skill tools are registered in the tool registry
    Given a CRP tool registry with context tools registered
    Then the CRP registry should contain tool "builtin/request-context"
    And the CRP registry should contain tool "builtin/query-history"
    And the CRP registry should contain tool "builtin/get-context-budget"

  Scenario: Context skill tools have read-only capability
    Given a CRP tool registry with context tools registered
    Then CRP tool "builtin/request-context" should have read_only capability
    And CRP tool "builtin/query-history" should have read_only capability
    And CRP tool "builtin/get-context-budget" should have read_only capability

  Scenario: request_context tool requires purpose in schema
    Given a CRP tool registry with context tools registered
    Then CRP tool "builtin/request-context" should require "purpose" in input schema

  Scenario: query_history tool requires query in schema
    Given a CRP tool registry with context tools registered
    Then CRP tool "builtin/query-history" should require "query" in input schema
