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