# ACMS Backend Abstraction Layer The Backend Abstraction Layer (BAL) provides a uniform interface to heterogeneous data stores used by the Advanced Context Management System. Context strategies query text, vector, and graph backends through protocol-defined APIs, enabling backend implementations to be swapped without changing strategy code. ## Architecture ``` Strategy ──► ScopedView ──► Backend Protocol ──► Physical Store │ └── resource_filter (scope) ``` Each backend type has a `Protocol` (structural subtyping) and a corresponding frozen result `dataclass`. Strategies never instantiate backends directly — they receive scoped views from the Context Assembly Pipeline via dependency injection. ## Protocol Contracts ### TextBackend Full-text search over indexed resource content. | Method | Signature | Returns | |--------|-----------|---------| | `search` | `(query: str, *, scope: frozenset[str], max_results: int = 20)` | `list[TextResult]` | **Preconditions:** - `query` must be a non-empty string. - `max_results` must be a positive integer. **Postconditions:** - Returns results ordered by descending `score`. - Results are restricted to resources whose ULIDs appear in `scope`. ### VectorBackend Embedding similarity search over chunked resource content. | Method | Signature | Returns | |--------|-----------|---------| | `similarity_search` | `(embedding: list[float], *, scope: frozenset[str], top_k: int = 20)` | `list[VectorResult]` | **Preconditions:** - `embedding` must be a non-empty list of floats. - `top_k` must be a positive integer. **Postconditions:** - Returns results ordered by descending `score` (cosine similarity). - Results are restricted to resources whose ULIDs appear in `scope`. ### GraphBackend Knowledge-graph queries and traversals over UKO triples. | Method | Signature | Returns | |--------|-----------|---------| | `sparql_query` | `(query: str, *, scope: frozenset[str])` | `GraphResult` | | `get_triples` | `(subject: str)` | `GraphResult` | | `traverse` | `(start: str, *, depth: int = 2)` | `GraphResult` | **Preconditions:** - `query` and `subject` and `start` must be non-empty strings. - `depth` must be a non-negative integer. **Postconditions:** - `sparql_query` restricts results to resources in `scope`. - `traverse` returns triples discovered within `depth` hops of `start`. ## Result Types All result types are frozen (immutable) dataclasses. ### TextResult | Field | Type | Description | |-------|------|-------------| | `uko_uri` | `str` | UKO URI of the matching information unit (non-empty) | | `content` | `str` | Matched text content | | `score` | `float` | Relevance score, 0.0 -- 1.0 | | `metadata` | `dict[str, str]` | Backend-specific metadata (default: empty) | ### VectorResult | Field | Type | Description | |-------|------|-------------| | `uko_uri` | `str` | UKO URI of the matching information unit (non-empty) | | `content` | `str` | Text content of matched chunk | | `score` | `float` | Cosine similarity, 0.0 -- 1.0 | | `metadata` | `dict[str, str]` | Backend-specific metadata (default: empty) | ### GraphResult | Field | Type | Description | |-------|------|-------------| | `triples` | `list[tuple[str, str, str]]` | (subject, predicate, object) triples | | `metadata` | `dict[str, str]` | Backend-specific metadata (default: empty) | ## Extension Points ### Implementing a Custom Backend To add a new backend (e.g., Tantivy for text search): 1. Create a class that satisfies the corresponding `Protocol` (e.g., `TextBackend`). 2. Implement all protocol methods with proper argument validation. 3. Register the backend in the DI container by overriding the provider: ```python from cleveragents.application.container import override_providers override_providers(text_backend=TantivyTextBackend(index_path="/data/tantivy")) ``` ### In-Memory Stubs The following stubs are provided for development and testing: | Stub | Protocol | Behaviour | |------|----------|-----------| | `InMemoryTextBackend` | `TextBackend` | Returns empty list; validates args | | `InMemoryVectorBackend` | `VectorBackend` | Returns empty list; validates args | | `InMemoryGraphBackend` | `GraphBackend` | Returns empty `GraphResult`; validates args | Stubs are registered as the default providers in the DI container. They can be overridden at runtime for production or per-test via `override_providers()`. ### DI Container Registration Backends are registered as singletons in the DI container (`cleveragents.application.container.Container`): ```python text_backend = providers.Singleton(InMemoryTextBackend) vector_backend = providers.Singleton(InMemoryVectorBackend) graph_backend = providers.Singleton(InMemoryGraphBackend) ``` To swap to a production backend, override the provider before first use: ```python container = get_container() container.text_backend.override(providers.Singleton(TantivyTextBackend)) ``` ## Module Locations | Module | Purpose | |--------|---------| | `cleveragents.domain.models.acms.backends` | Protocol definitions and result dataclasses | | `cleveragents.domain.models.acms.stubs` | In-memory stub implementations | | `cleveragents.application.container` | DI container backend registration | ## Related - [CRP Reference](crp.md) — Context Request Protocol types - [Specification: ACMS > Backend Abstraction Layer](../specification.md) — Authoritative design - [ADR-014: Context Management](../adr/ADR-014-context-management-acms.md) — Architecture decision record