# Context Strategy Registry The Context Strategy Registry manages pluggable retrieval strategies for the ACMS Context Assembly Pipeline. Strategies implement the `ContextStrategy` protocol and are registered via TOML configuration or programmatic API. ## Architecture ``` ContextRequest ┌─── StrategySelector ────┐ │ can_handle() polling │ └──────────┬──────────────┘ v ┌─── BudgetAllocator ─────┐ │ proportional alloc │ └──────────┬──────────────┘ v ┌─── StrategyExecutor ────┐ │ parallel w/ timeout │ │ circuit breaker │ └──────────┬──────────────┘ v ContextFragment[] ``` ## ContextStrategy Protocol Every strategy implements: | Member | Type | Description | |--------|------|-------------| | `name` | `property -> str` | Unique strategy name | | `capabilities` | `property -> StrategyCapabilities` | Backend requirements and quality score | | `can_handle(request, backends)` | `-> float` | 0.0-1.0 confidence for this request | | `assemble(request, backends, budget, plan_context)` | `-> list[ContextFragment]` | Execute and return fragments; must respect budget | | `explain()` | `-> str` | Human-readable description | ## StrategyCapabilities | Field | Type | Default | Description | |-------|------|---------|-------------| | `uses_text` | `bool` | `False` | Requires TextBackend | | `uses_vector` | `bool` | `False` | Requires VectorBackend | | `uses_graph` | `bool` | `False` | Requires GraphBackend | | `uses_temporal` | `bool` | `False` | Requires temporal/cold-tier data | | `resource_types` | `tuple[str, ...]` | `()` | Supported resource types (empty = all) | | `quality_score` | `float` | `0.5` | Intrinsic quality score (0.0-1.0) | | `supports_depth_breadth` | `bool` | `False` | Supports depth/breadth projection | | `supports_plan_hierarchy` | `bool` | `False` | Supports plan hierarchy traversal | | `supports_temporal` | `bool` | `False` | Supports temporal archaeology queries | ## Built-in Strategies All six built-in strategies now implement real backend-driven retrieval logic (v3.8.0+, issue #3500). Previously they were no-op stubs that returned empty fragment lists. The `SpecStrategyAdapter` bridges each strategy into the `ACMSPipeline` at construction time. | Strategy | Quality | Backends | Retrieval Logic | |----------|---------|----------|-----------------| | `simple-keyword` | 0.3 | Text | `TextBackend.search()` using keywords extracted from the `ContextRequest`; results packed greedily into token budget | | `semantic-embedding` | 0.6 | Vector | `VectorBackend.similarity_search()` using a character-frequency embedding as a v1 approximation; budget-aware packing | | `breadth-depth-navigator` | 0.85 | Graph | `GraphBackend` traversal from focus nodes declared in the `ContextRequest`, expanding outward by `request.breadth` hops | | `arce` | 0.95 | All | Multi-modal pipeline: text search (40% budget) + vector similarity (40%) + graph traversal (20%); results merged and deduplicated | | `temporal-archaeology` | 0.5 | Graph + Cold | Two-phase: `TemporalBackend.query_by_tier()` for cold-tier historical nodes, then `GraphBackend` traversal from those nodes | | `plan-decision-context` | 0.7 | Warm/Cold | `TemporalBackend`-driven lookup walking parent and ancestor plan hierarchy, retrieving decision records from warm/cold tiers | Default enabled (spec `context.strategies.enabled`): `["simple-keyword", "semantic-embedding", "breadth-depth-navigator"]` > **Note:** The `SemanticEmbeddingStrategy` uses a character-frequency > embedding as a v1 approximation of semantic similarity. A real embedding > model integration is planned for a future milestone. ## Configuration ### Global (config.toml) ```toml [context.strategies] enabled = ["simple-keyword", "semantic-embedding", "breadth-depth-navigator"] [context.strategies.custom] "my-strategy" = "my_package.strategies:MyStrategy" ``` ### Per-strategy settings | Key | Type | Default | Description | |-----|------|---------|-------------| | `timeout_seconds` | int | 30 | Per-strategy assembly timeout | | `max_fragments` | int | 100 | Maximum fragments per call | | `max_workers` | int | 4 | Parallel workers for executor | | `circuit_breaker_threshold` | int | 3 | Failures before circuit opens | | `enabled` | bool | `true` | Whether the strategy is active | ### Per-project overrides Projects can override the global enabled list using: ``` agents project context set --strategy simple-keyword --strategy semantic-embedding ``` This replaces the global `context.strategies.enabled` list for that project. ## ContextStrategyResult Output of a single strategy execution: | Field | Type | Description | |-------|------|-------------| | `strategy_name` | `str` | Name of the producing strategy | | `fragments` | `tuple[ContextFragment, ...]` | Deterministically ordered fragments | | `total_fragments` | `int` | Total fragments before limits | | `tokens_used` | `int` | Total tokens across fragments | | `execution_time_ms` | `float` | Execution wall-clock time (ms) | | `errors` | `tuple[str, ...]` | Error messages | | `stats` | `dict[str, Any]` | Strategy-specific statistics | Fragment ordering: `(relevance_score DESC, uko_node ASC)`. ## Registry Validation The registry validates that: 1. Every enabled strategy is actually registered. 2. Every strategy declares at least one backend capability. 3. Every strategy declares supported resource types. ## Fallback Degradation Path When backends are unavailable, the system degrades gracefully: 1. `arce` (requires all) → 2. `breadth-depth-navigator` (graph) → 3. `semantic-embedding` (vector) → 4. `simple-keyword` (text only) This ensures context is always produced.