025d379946
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 14s
CI / quality (pull_request) Successful in 17s
CI / build (pull_request) Successful in 15s
CI / typecheck (pull_request) Successful in 33s
CI / security (pull_request) Successful in 42s
CI / unit_tests (pull_request) Successful in 2m36s
CI / docker (pull_request) Successful in 40s
CI / integration_tests (pull_request) Successful in 3m17s
CI / coverage (pull_request) Successful in 4m21s
CI / lint (push) Successful in 12s
CI / build (push) Successful in 15s
CI / quality (push) Successful in 16s
CI / security (push) Successful in 30s
CI / typecheck (push) Successful in 33s
CI / benchmark-regression (push) Has been skipped
CI / unit_tests (push) Successful in 2m36s
CI / docker (push) Successful in 40s
CI / integration_tests (push) Successful in 3m57s
CI / coverage (push) Successful in 5m22s
CI / benchmark-publish (push) Has been cancelled
CI / benchmark-regression (pull_request) Successful in 25m12s
Implemented the Backend Abstraction Layer (BAL) for the Advanced Context Management System, following the specification in docs/specification.md Section ACMS > Backend Abstraction Layer and ADR-014. Key additions: - TextBackend protocol with search(query, scope, max_results) returning list[TextResult], and TextResult frozen dataclass (uko_uri, content, score, metadata fields) - VectorBackend protocol with similarity_search(embedding, scope, top_k) returning list[VectorResult], and VectorResult frozen dataclass - GraphBackend protocol with sparql_query(query, scope), get_triples(subject), and traverse(start, depth) methods returning GraphResult frozen dataclass (triples, metadata fields) - In-memory stub backends (InMemoryTextBackend, InMemoryVectorBackend, InMemoryGraphBackend) that validate arguments and return empty results, serving as development placeholders and test doubles - DI container registration as configurable Singletons with provider selection via override_providers() - Behave BDD feature (35 scenarios / 83 steps) covering protocol compliance, argument validation, result immutability, and DI resolution - Robot Framework smoke tests (6 tests) for integration verification - ASV benchmarks for stub query overhead and instantiation time - Reference documentation at docs/reference/acms_backends.md Design decisions: - Used @runtime_checkable Protocol for structural subtyping, consistent with existing ResourceHandler pattern - Used frozen dataclasses (not Pydantic) for result types to minimize overhead in the hot path of context assembly - scope parameter typed as frozenset[str] for immutability and hashability - Stubs registered as default Singletons; production backends swap via DI ISSUES CLOSED: #498
172 lines
6.7 KiB
Gherkin
172 lines
6.7 KiB
Gherkin
Feature: ACMS Backend Abstraction Layer
|
|
As a developer
|
|
I want text, vector, and graph backend protocols with in-memory stubs
|
|
So that context strategies can query heterogeneous data stores uniformly
|
|
|
|
# ---- TextResult ----
|
|
|
|
Scenario: Create a valid TextResult
|
|
Given a TextResult with uko_uri "uko-py:class/Auth" and score 0.9
|
|
Then the text result uko_uri should be "uko-py:class/Auth"
|
|
And the text result content should be "class Auth: pass"
|
|
And the text result score should be 0.9
|
|
And the text result metadata should be empty
|
|
|
|
Scenario: TextResult rejects empty uko_uri
|
|
Then creating a TextResult with empty uko_uri should raise ValueError
|
|
|
|
Scenario: TextResult rejects score above 1.0
|
|
Then creating a TextResult with score 1.5 should raise ValueError
|
|
|
|
Scenario: TextResult rejects score below 0.0
|
|
Then creating a TextResult with score -0.1 should raise ValueError
|
|
|
|
Scenario: TextResult is immutable
|
|
Given a TextResult with uko_uri "uko-py:func/login" and score 0.5
|
|
Then modifying the text result score should raise an error
|
|
|
|
# ---- VectorResult ----
|
|
|
|
Scenario: Create a valid VectorResult
|
|
Given a VectorResult with uko_uri "uko-py:class/VecStore" and score 0.85
|
|
Then the vector result uko_uri should be "uko-py:class/VecStore"
|
|
And the vector result content should be "vector store content"
|
|
And the vector result score should be 0.85
|
|
And the vector result metadata should be empty
|
|
|
|
Scenario: VectorResult rejects empty uko_uri
|
|
Then creating a VectorResult with empty uko_uri should raise ValueError
|
|
|
|
Scenario: VectorResult rejects score above 1.0
|
|
Then creating a VectorResult with score 1.5 should raise ValueError
|
|
|
|
Scenario: VectorResult rejects score below 0.0
|
|
Then creating a VectorResult with score -0.1 should raise ValueError
|
|
|
|
Scenario: VectorResult is immutable
|
|
Given a VectorResult with uko_uri "uko-py:func/embed" and score 0.7
|
|
Then modifying the vector result score should raise an error
|
|
|
|
# ---- GraphResult ----
|
|
|
|
Scenario: Create a valid GraphResult with no triples
|
|
Given a GraphResult with no triples
|
|
Then the graph result triples should be empty
|
|
And the graph result metadata should be empty
|
|
|
|
Scenario: Create a GraphResult with triples
|
|
Given a GraphResult with triple "uko:A" "uko:contains" "uko:B"
|
|
Then the graph result should have 1 triple
|
|
|
|
Scenario: GraphResult is immutable
|
|
Given a GraphResult with no triples
|
|
Then modifying the graph result metadata should raise an error
|
|
|
|
# ---- InMemoryTextBackend ----
|
|
|
|
Scenario: InMemoryTextBackend satisfies TextBackend protocol
|
|
Given an InMemoryTextBackend instance
|
|
Then it should be a TextBackend
|
|
|
|
Scenario: InMemoryTextBackend search returns empty list
|
|
Given an InMemoryTextBackend instance
|
|
When I search for "auth flow" with scope "RES01"
|
|
Then the text search results should be empty
|
|
|
|
Scenario: InMemoryTextBackend search with max_results
|
|
Given an InMemoryTextBackend instance
|
|
When I search for "auth" with scope "RES01" and max_results 5
|
|
Then the text search results should be empty
|
|
|
|
Scenario: InMemoryTextBackend rejects empty query
|
|
Given an InMemoryTextBackend instance
|
|
Then searching with empty query should raise ValueError
|
|
|
|
Scenario: InMemoryTextBackend rejects non-positive max_results
|
|
Given an InMemoryTextBackend instance
|
|
Then searching with max_results 0 should raise ValueError
|
|
|
|
# ---- InMemoryVectorBackend ----
|
|
|
|
Scenario: InMemoryVectorBackend satisfies VectorBackend protocol
|
|
Given an InMemoryVectorBackend instance
|
|
Then it should be a VectorBackend
|
|
|
|
Scenario: InMemoryVectorBackend search returns empty list
|
|
Given an InMemoryVectorBackend instance
|
|
When I similarity search with embedding and scope "RES01"
|
|
Then the vector search results should be empty
|
|
|
|
Scenario: InMemoryVectorBackend search with top_k
|
|
Given an InMemoryVectorBackend instance
|
|
When I similarity search with embedding and scope "RES01" and top_k 5
|
|
Then the vector search results should be empty
|
|
|
|
Scenario: InMemoryVectorBackend rejects empty embedding
|
|
Given an InMemoryVectorBackend instance
|
|
Then similarity searching with empty embedding should raise ValueError
|
|
|
|
Scenario: InMemoryVectorBackend rejects non-positive top_k
|
|
Given an InMemoryVectorBackend instance
|
|
Then similarity searching with top_k 0 should raise ValueError
|
|
|
|
# ---- InMemoryGraphBackend ----
|
|
|
|
Scenario: InMemoryGraphBackend satisfies GraphBackend protocol
|
|
Given an InMemoryGraphBackend instance
|
|
Then it should be a GraphBackend
|
|
|
|
Scenario: InMemoryGraphBackend sparql_query returns empty result
|
|
Given an InMemoryGraphBackend instance
|
|
When I run sparql query "SELECT ?s WHERE { ?s a uko:Container }" with scope "RES01"
|
|
Then the graph query result should have no triples
|
|
|
|
Scenario: InMemoryGraphBackend sparql_query rejects empty query
|
|
Given an InMemoryGraphBackend instance
|
|
Then sparql querying with empty query should raise ValueError
|
|
|
|
Scenario: InMemoryGraphBackend get_triples returns empty result
|
|
Given an InMemoryGraphBackend instance
|
|
When I get triples for subject "uko-py:class/Auth"
|
|
Then the graph query result should have no triples
|
|
|
|
Scenario: InMemoryGraphBackend get_triples rejects empty subject
|
|
Given an InMemoryGraphBackend instance
|
|
Then getting triples with empty subject should raise ValueError
|
|
|
|
Scenario: InMemoryGraphBackend traverse returns empty result
|
|
Given an InMemoryGraphBackend instance
|
|
When I traverse from "uko-py:class/Auth" with depth 3
|
|
Then the graph query result should have no triples
|
|
|
|
Scenario: InMemoryGraphBackend traverse rejects empty start
|
|
Given an InMemoryGraphBackend instance
|
|
Then traversing with empty start should raise ValueError
|
|
|
|
Scenario: InMemoryGraphBackend traverse rejects negative depth
|
|
Given an InMemoryGraphBackend instance
|
|
Then traversing with depth -1 should raise ValueError
|
|
|
|
# ---- DI Container Registration ----
|
|
|
|
Scenario: DI container provides a TextBackend
|
|
Given the DI container
|
|
Then the container should provide a text_backend
|
|
And the text_backend should be a TextBackend
|
|
|
|
Scenario: DI container provides a VectorBackend
|
|
Given the DI container
|
|
Then the container should provide a vector_backend
|
|
And the vector_backend should be a VectorBackend
|
|
|
|
Scenario: DI container provides a GraphBackend
|
|
Given the DI container
|
|
Then the container should provide a graph_backend
|
|
And the graph_backend should be a GraphBackend
|
|
|
|
Scenario: DI container backends are singletons
|
|
Given the DI container
|
|
Then resolving text_backend twice should return the same instance
|
|
And resolving vector_backend twice should return the same instance
|
|
And resolving graph_backend twice should return the same instance
|