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