Feature: Skeleton compressor
  As an ACMS subsystem
  I want to compress context fragments for subplan inheritance
  So that child plans receive relevant context within a token budget

  Background:
    Given a skeleton compressor service

  # --- ratio validation -------------------------------------------------

  Scenario: Reject ratio below 0.0
    Given context fragments with total tokens 1000
    When I compress with skeleton_ratio -0.1
    Then the compressor should raise a ValueError for invalid ratio

  Scenario: Reject ratio above 1.0
    Given context fragments with total tokens 1000
    When I compress with skeleton_ratio 1.5
    Then the compressor should raise a ValueError for invalid ratio

  Scenario: Accept ratio 0.0
    Given context fragments with total tokens 1000
    When I compress with skeleton_ratio 0.0
    Then all fragments should be returned unchanged

  Scenario: Accept ratio 1.0
    Given context fragments with total tokens 1000
    When I compress with skeleton_ratio 1.0
    Then only the highest-relevance fragment should be returned

  Scenario: Accept ratio at boundary 0.5
    Given context fragments with total tokens 1000
    When I compress with skeleton_ratio 0.5
    Then compressed tokens should be at most 500

  # --- default handling -------------------------------------------------

  Scenario: Default ratio applied when None
    Given context fragments with total tokens 1000
    When I compress with skeleton_ratio not specified
    Then the metadata ratio should equal the default 0.15

  # --- stable ordering --------------------------------------------------

  Scenario: Fragments with equal relevance are ordered by id
    Given three fragments with equal relevance 0.5
    When I compress with skeleton_ratio 0.0
    Then fragments should be ordered by fragment_id ascending

  Scenario: Fragments are ordered by relevance descending
    Given fragments with relevances 0.9, 0.3, and 0.7
    When I compress with skeleton_ratio 0.0
    Then the first fragment should have relevance 0.9
    And the last fragment should have relevance 0.3

  # --- metadata ----------------------------------------------------------

  Scenario: Metadata records correct token counts
    Given context fragments with total tokens 1000
    When I compress with skeleton_ratio 0.5
    Then metadata original_tokens should be 1000
    And metadata compressed_tokens should be at most 500

  Scenario: Metadata records source decision IDs
    Given fragments with known decision IDs
    When I compress with skeleton_ratio 0.0
    Then metadata should contain all source decision IDs

  Scenario: Metadata ratio matches input
    Given context fragments with total tokens 1000
    When I compress with skeleton_ratio 0.7
    Then metadata ratio should be 0.7

  # --- edge cases -------------------------------------------------------

  Scenario: Empty fragment list compresses to empty
    Given an empty fragment list
    When I compress with skeleton_ratio 0.5
    Then the result should contain zero fragments
    And metadata original_tokens should be 0
    And metadata compressed_tokens should equal 0

  Scenario: Single fragment at ratio 0.5
    Given a single fragment with 100 tokens
    When I compress with skeleton_ratio 0.5
    Then the result should contain one fragment

  # --- argument validation ----------------------------------------------

  Scenario: Reject non-list fragments argument
    When I compress with a non-list fragments argument
    Then the compressor should raise a TypeError

  Scenario: Reject fragment with negative token count
    Given a fragment with negative token count
    When I compress with skeleton_ratio 0.5
    Then the compressor should raise a ValueError for invalid fragment

  Scenario: Reject fragment with empty id
    Given a fragment with empty fragment_id
    When I compress with skeleton_ratio 0.5
    Then the compressor should raise a ValueError for invalid fragment

  Scenario: Reject fragment with relevance out of range
    Given a fragment with relevance 1.5
    When I compress with skeleton_ratio 0.5
    Then the compressor should raise a ValueError for invalid fragment

  Scenario: Reject non-ContextFragment item in list
    When I compress with a list containing a non-fragment item
    Then the compressor should raise a TypeError for invalid item

  Scenario: Reject non-numeric skeleton_ratio
    Given context fragments with total tokens 1000
    When I compress with a non-numeric skeleton_ratio
    Then the compressor should raise a TypeError for invalid ratio type

  Scenario: Reject skeleton metadata with compressed exceeding original
    When I create skeleton metadata with compressed exceeding original
    Then a validation error should be raised for compressed exceeding original

  # --- compression summary (original vs compressed) ----------------------

  Scenario: Compression summary stored in plan metadata
    Given context fragments with total tokens 1000
    When I compress with skeleton_ratio 0.6
    Then compressed_tokens should be less than original_tokens

  # --- skeleton_ratio integration with plan model ------------------------

  Scenario: Plan model accepts skeleton_metadata
    Given a skeleton metadata with ratio 0.5 and 1000 original tokens and 500 compressed
    When I attach skeleton_metadata to a plan
    Then the plan should expose skeleton metadata in cli dict

  # --- _validate_fragments edge-cases (lines 153-163) --------------------

  Scenario: Reject fragment with negative token_count
    Given a context fragment constructed with negative token_count
    When I validate the invalid fragments
    Then the compressor should raise a ValueError mentioning "token_count must be >= 0"

  Scenario: Reject fragment with out-of-range relevance_score
    Given a context fragment constructed with relevance_score 1.5
    When I validate the invalid fragments
    Then the compressor should raise a ValueError mentioning "relevance_score must be in"

  Scenario: Reject fragment with empty fragment_id
    Given a context fragment constructed with empty fragment_id
    When I validate the invalid fragments
    Then the compressor should raise a ValueError mentioning "fragment_id must be non-empty"
