3a4fde9b0c
Align context tier defaults with the specification and ensure invalid values are rejected via positive-integer validation. Behave coverage locks in the defaults and validation behavior. ISSUES CLOSED: #5230 #4907
212 lines
7.7 KiB
Gherkin
212 lines
7.7 KiB
Gherkin
Feature: ACMS Context Tiers
|
|
As a developer
|
|
I want hot/warm/cold context tiers with actor views and project scoping
|
|
So that the context management system can efficiently manage fragment lifecycle
|
|
|
|
# ---- ContextTier enum ----
|
|
|
|
Scenario: ContextTier has three values
|
|
Then ContextTier should have values "hot", "warm", "cold"
|
|
|
|
# ---- ActorRole enum ----
|
|
|
|
Scenario: ActorRole has four values
|
|
Then ActorRole should have values "strategist", "executor", "reviewer", "estimator"
|
|
|
|
# ---- TieredFragment ----
|
|
|
|
Scenario: Create a valid TieredFragment
|
|
Given a TieredFragment with id "frag-001" and content "hello world"
|
|
Then the fragment tier should be "hot"
|
|
And the fragment token_count should be 0
|
|
And the fragment access_count should be 0
|
|
|
|
Scenario: TieredFragment rejects empty fragment_id
|
|
Then creating a TieredFragment with empty fragment_id should raise ValidationError
|
|
|
|
Scenario: TieredFragment rejects negative token_count
|
|
Then creating a TieredFragment with negative token_count should raise ValidationError
|
|
|
|
# ---- TierBudget ----
|
|
|
|
Scenario: TierBudget has sensible defaults
|
|
Given a default TierBudget
|
|
Then max_tokens_hot should be 16000
|
|
And max_decisions_warm should be 100
|
|
And max_decisions_cold should be 500
|
|
|
|
Scenario Outline: TierBudget rejects non-positive <field>
|
|
Then creating a TierBudget with hot <hot>, warm <warm>, cold <cold> should fail for "<field>"
|
|
|
|
Examples:
|
|
| hot | warm | cold | field |
|
|
| 0 | 100 | 500 | max_tokens_hot |
|
|
| 16000 | 0 | 500 | max_decisions_warm |
|
|
| 16000 | 100 | 0 | max_decisions_cold |
|
|
| -50 | 100 | 500 | max_tokens_hot |
|
|
|
|
# ---- ActorContextView ----
|
|
|
|
Scenario: Strategist sees all tiers by default
|
|
Given an ActorContextView for "strategist"
|
|
Then effective tiers should be "hot", "warm", "cold"
|
|
|
|
Scenario: Executor sees hot and warm by default
|
|
Given an ActorContextView for "executor"
|
|
Then effective tiers should be "hot", "warm"
|
|
|
|
Scenario: Reviewer sees only hot by default
|
|
Given an ActorContextView for "reviewer"
|
|
Then effective tiers should be "hot"
|
|
|
|
# ---- TierMetrics ----
|
|
|
|
Scenario: TierMetrics defaults to zero
|
|
Given a default TierMetrics
|
|
Then total_fragments should be 0
|
|
And hot_hit_rate should be 0.0
|
|
|
|
# ---- ScopedBackendView ----
|
|
|
|
Scenario: ScopedBackendView filters by project
|
|
Given a ScopedBackendView for project "proj-a"
|
|
And a TieredFragment with id "frag-a" in project "proj-a"
|
|
And a TieredFragment with id "frag-b" in project "proj-b"
|
|
Then fragment "frag-a" should be visible
|
|
And fragment "frag-b" should not be visible
|
|
|
|
Scenario: ScopedBackendView excludes empty project_name
|
|
Given a ScopedBackendView for project "proj-a"
|
|
And a TieredFragment with id "frag-x" and no project
|
|
Then fragment "frag-x" should not be visible
|
|
|
|
# ---- ContextTierService: store/get ----
|
|
|
|
Scenario: Store and retrieve a fragment
|
|
Given a ContextTierService
|
|
When I store a fragment with id "f1" content "data" in tier "hot"
|
|
Then tier getting "f1" should return content "data"
|
|
|
|
Scenario: Get returns None for unknown fragment
|
|
Given a ContextTierService
|
|
Then tier getting "nonexistent" should return None
|
|
|
|
# ---- ContextTierService: promotion ----
|
|
|
|
Scenario: Promote from cold to warm
|
|
Given a ContextTierService
|
|
When I store a fragment with id "f2" content "cold-data" in tier "cold"
|
|
And I promote "f2"
|
|
Then "f2" should be in tier "warm"
|
|
|
|
Scenario: Promote from warm to hot
|
|
Given a ContextTierService
|
|
When I store a fragment with id "f3" content "warm-data" in tier "warm"
|
|
And I promote "f3"
|
|
Then "f3" should be in tier "hot"
|
|
|
|
Scenario: Promote unknown fragment returns None
|
|
Given a ContextTierService
|
|
Then promoting "unknown" should return None
|
|
|
|
# ---- ContextTierService: demotion ----
|
|
|
|
Scenario: Demote from hot to warm
|
|
Given a ContextTierService
|
|
When I store a fragment with id "f4" content "hot-data" in tier "hot"
|
|
And I demote "f4"
|
|
Then "f4" should be in tier "warm"
|
|
|
|
Scenario: Demote from warm to cold with summarization
|
|
Given a ContextTierService
|
|
When I store a long fragment "f5" in tier "warm"
|
|
And I demote "f5"
|
|
Then "f5" should be in tier "cold"
|
|
And "f5" content should be summarized
|
|
|
|
Scenario: Demote unknown fragment returns None
|
|
Given a ContextTierService
|
|
Then demoting "unknown" should return None
|
|
|
|
# ---- ContextTierService: LRU eviction ----
|
|
|
|
Scenario: Evict LRU fragments from hot tier
|
|
Given a ContextTierService
|
|
When I store a fragment with id "e1" content "first" in tier "hot"
|
|
And I store a fragment with id "e2" content "second" in tier "hot"
|
|
And I store a fragment with id "e3" content "third" in tier "hot"
|
|
And I evict 2 LRU fragments from "hot"
|
|
Then "hot" tier should have 1 fragment
|
|
|
|
Scenario: Evict with invalid count raises ValueError
|
|
Given a ContextTierService
|
|
Then evicting 0 from "hot" should raise ValueError
|
|
|
|
# ---- ContextTierService: actor views ----
|
|
|
|
Scenario: Strategist sees fragments from all tiers
|
|
Given a ContextTierService
|
|
When I store fragment "a1" with content "hot" tier "hot" project "p1"
|
|
And I store fragment "a2" with content "warm" tier "warm" project "p1"
|
|
And I store fragment "a3" with content "cold" tier "cold" project "p1"
|
|
Then strategist for project "p1" should see 3 fragments
|
|
|
|
Scenario: Executor sees only hot and warm
|
|
Given a ContextTierService
|
|
When I store fragment "b1" with content "hot" tier "hot" project "p1"
|
|
And I store fragment "b2" with content "warm" tier "warm" project "p1"
|
|
And I store fragment "b3" with content "cold" tier "cold" project "p1"
|
|
Then executor for project "p1" should see 2 fragments
|
|
|
|
Scenario: Reviewer sees only hot
|
|
Given a ContextTierService
|
|
When I store fragment "c1" with content "hot" tier "hot" project "p1"
|
|
And I store fragment "c2" with content "warm" tier "warm" project "p1"
|
|
Then reviewer for project "p1" should see 1 fragment
|
|
|
|
# ---- ContextTierService: project scoping ----
|
|
|
|
Scenario: Scoped view filters by project
|
|
Given a ContextTierService
|
|
When I store fragment "s1" with content "yes" tier "hot" project "alpha"
|
|
And I store fragment "s2" with content "no" tier "hot" project "beta"
|
|
Then scoped view for "alpha" should have 1 fragment
|
|
|
|
# ---- ContextTierService: metrics ----
|
|
|
|
Scenario: Metrics track hits and misses
|
|
Given a ContextTierService
|
|
When I store a fragment with id "m1" content "data" in tier "hot"
|
|
And I get fragment "m1"
|
|
And I get fragment "nonexistent"
|
|
Then hot_hit_count should be 1
|
|
And hot_miss_count should be 1
|
|
|
|
# ---- DI Container ----
|
|
|
|
Scenario: DI container provides context_tier_service
|
|
Given the DI container is reset
|
|
Then the container should provide a context_tier_service
|
|
And the context_tier_service should be a ContextTierService
|
|
|
|
Scenario: DI container context_tier_service is singleton
|
|
Given the DI container is reset
|
|
Then resolving context_tier_service twice should return the same instance
|
|
|
|
# ---- Settings ----
|
|
|
|
Scenario: Settings expose spec-aligned context tier defaults
|
|
Then settings should have context_max_tokens_hot
|
|
And settings should have context_max_decisions_warm
|
|
And settings should have context_max_decisions_cold
|
|
|
|
Scenario Outline: Context tier settings reject non-positive <field>
|
|
When I create settings with context tier values <hot>, <warm>, <cold>
|
|
Then settings validation should fail for "<field>"
|
|
|
|
Examples:
|
|
| hot | warm | cold | field |
|
|
| 0 | 100 | 500 | context_max_tokens_hot |
|
|
| 16000 | 0 | 500 | context_max_decisions_warm |
|
|
| 16000 | 100 | 0 | context_max_decisions_cold |
|