Files
cleveragents-core/features/skeleton_compressor.feature
freemo fae438a7a7 refactor(acms): unify ContextFragment model hierarchies by extending CRP base types
Core domain types (FragmentProvenance, ContextFragment, ContextBudget,
ContextPayload) now extend their CRP counterparts via Pydantic v2
inheritance, ensuring isinstance compatibility across the model
hierarchy.

Key changes:
- CRP base types made frozen=True (no consumer mutates them)
- CRP AssembledContext fields changed from list to tuple (frozen consistency)
- Core types extend CRP bases: FragmentProvenance(CRPFragmentProvenance),
  ContextFragment(CRPContextFragment), ContextBudget(CRPContextBudget),
  ContextPayload(CRPAssembledContext)
- Removed duplicate ContextFragment dataclass from skeleton_compressor
- Updated project_context.py to pass tuples to frozen AssembledContext
- Added Behave tests (10 scenarios), Robot integration tests (3 cases),
  and ASV benchmarks for the unified hierarchy
- Updated Known Limitations table in docs/reference/acms.md

ISSUES CLOSED: #569
2026-03-05 21:38:55 +00:00

152 lines
6.1 KiB
Gherkin

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.3
# --- 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"