"""Step definitions for Temporal Data Model — service steps.""" from __future__ import annotations from typing import Any from behave import given, then, when from cleveragents.application.services.temporal_service import TemporalService from cleveragents.domain.models.acms.temporal_stubs import InMemoryTemporalBackend from cleveragents.domain.models.acms.tiers import ContextTier from cleveragents.domain.models.core.project import TemporalScope __all__: list[str] = [] # --------------------------------------------------------------------------- # TemporalService steps # --------------------------------------------------------------------------- @given("a TemporalService with InMemoryTemporalBackend") def step_given_temporal_service(context: Any) -> None: backend = InMemoryTemporalBackend() context.temporal_service = TemporalService(backend=backend) context.temporal_backend = backend @given('I store an initial node "{uri}" for resource "{resource}" at "{path}"') @when('I store an initial node "{uri}" for resource "{resource}" at "{path}"') def step_when_store_initial( context: Any, uri: str, resource: str, path: str, ) -> None: context.service_node = context.temporal_service.store_initial_node( node_uri=uri, source_resource=resource, source_path=path, ) @then("the stored node should be current") def step_then_stored_current(context: Any) -> None: assert context.service_node.temporal.is_current is True @then("the stored node should have no predecessor") def step_then_stored_no_predecessor(context: Any) -> None: assert context.service_node.temporal.is_revision_of is None @when( 'I create a service revision from "{old}" to "{new}"' ' for resource "{resource}" at "{path}"' ) def step_when_service_create_revision( context: Any, old: str, new: str, resource: str, path: str, ) -> None: context.service_revision = context.temporal_service.create_revision( current_uri=old, new_node_uri=new, source_resource=resource, source_path=path, ) @then("the service revision node should be current") def step_then_service_revision_current(context: Any) -> None: assert context.service_revision.temporal.is_current is True @then('the service revision node should have is_revision_of "{expected}"') def step_then_service_revision_of(context: Any, expected: str) -> None: assert context.service_revision.temporal.is_revision_of == expected @when('I get the service current for "{base}"') def step_when_service_get_current(context: Any, base: str) -> None: context.service_current = context.temporal_service.get_current(base) @then('the service current node uri should be "{expected}"') def step_then_service_current_uri(context: Any, expected: str) -> None: assert context.service_current is not None assert context.service_current.node_uri == expected @when("I query HOT tier via the service") def step_when_service_query_hot(context: Any) -> None: context.service_tier_query = context.temporal_service.query_by_tier( ContextTier.HOT, ) @when("I query HOT tier via the service with scope ALL") def step_when_service_query_hot_all(context: Any) -> None: context.service_tier_query = context.temporal_service.query_by_tier( ContextTier.HOT, temporal_scope=TemporalScope.ALL, ) @then("the service tier query scope should be CURRENT") def step_then_service_tier_scope_current(context: Any) -> None: assert context.service_tier_query.temporal_scope == TemporalScope.CURRENT @then("the service tier query scope should be ALL") def step_then_service_tier_scope_all(context: Any) -> None: assert context.service_tier_query.temporal_scope == TemporalScope.ALL @when('I mark "{uri}" as historical via the service') def step_when_service_mark_historical(context: Any, uri: str) -> None: context.service_marked = context.temporal_service.mark_historical(uri) @then("the service marked node should not be current") def step_then_service_marked_not_current(context: Any) -> None: assert context.service_marked.temporal.is_current is False @then("storing an initial node with blank URI via the service should raise ValueError") def step_then_service_blank_uri(context: Any) -> None: try: context.temporal_service.store_initial_node( node_uri="", source_resource="RES", source_path="src/a.py", ) msg = "Expected ValueError" raise AssertionError(msg) except ValueError: pass @then( "storing an initial node with blank source_resource via the service" " should raise ValueError" ) def step_then_service_blank_resource(context: Any) -> None: try: context.temporal_service.store_initial_node( node_uri="uko:test", source_resource="", source_path="src/a.py", ) msg = "Expected ValueError" raise AssertionError(msg) except ValueError: pass @when('I get the service history for "{base}" with scope ALL') def step_when_service_get_history_all(context: Any, base: str) -> None: context.service_history = context.temporal_service.get_history( base, temporal_scope=TemporalScope.ALL, ) @when('I get the service history for "{base}" with scope CURRENT') def step_when_service_get_history_current(context: Any, base: str) -> None: context.service_history = context.temporal_service.get_history( base, temporal_scope=TemporalScope.CURRENT, ) @then("the service history should have {count:d} nodes") def step_then_service_history_count(context: Any, count: int) -> None: assert len(context.service_history) == count, ( f"Expected {count} nodes, got {len(context.service_history)}" ) @then("getting service history for blank base URI should raise ValueError") def step_then_service_history_blank_raises(context: Any) -> None: try: context.temporal_service.get_history("") msg = "Expected ValueError" raise AssertionError(msg) except ValueError: pass @when('I get the service revision chain for "{uri}"') def step_when_service_get_chain(context: Any, uri: str) -> None: context.service_chain = context.temporal_service.get_revision_chain(uri) @then("the service revision chain depth should be {expected:d}") def step_then_service_chain_depth(context: Any, expected: int) -> None: assert context.service_chain.depth == expected, ( f"Expected depth {expected}, got {context.service_chain.depth}" ) @then('the service revision chain current should be "{expected}"') def step_then_service_chain_current(context: Any, expected: str) -> None: assert context.service_chain.current_uri == expected, ( f"Expected {expected}, got {context.service_chain.current_uri}" ) @then("getting service revision chain for blank URI should raise ValueError") def step_then_service_chain_blank_raises(context: Any) -> None: try: context.temporal_service.get_revision_chain("") msg = "Expected ValueError" raise AssertionError(msg) except ValueError: pass @when("I query COLD tier via the service with scope CURRENT") def step_when_service_query_cold_current(context: Any) -> None: context.service_tier_query = context.temporal_service.query_by_tier( ContextTier.COLD, temporal_scope=TemporalScope.CURRENT, ) @then("the service tier query should return {count:d} node") def step_then_service_tier_query_count(context: Any, count: int) -> None: assert len(context.service_tier_query.nodes) == count, ( f"Expected {count} nodes, got {len(context.service_tier_query.nodes)}" ) @then("the service tier query node should be current") def step_then_service_tier_query_node_current(context: Any) -> None: for node in context.service_tier_query.nodes: assert node.temporal.is_current is True, f"Node {node.node_uri} is not current" @then("the service retention warm hours should be {expected:d}") def step_then_service_retention_warm(context: Any, expected: int) -> None: assert context.temporal_service.retention.warm_retention_hours == expected @then("the service retention cold days should be {expected:d}") def step_then_service_retention_cold(context: Any, expected: int) -> None: assert context.temporal_service.retention.cold_retention_days == expected # --------------------------------------------------------------------------- # Diff-coverage steps (WARM/COLD default scopes) # --------------------------------------------------------------------------- @when("I query WARM tier via the service") def step_when_service_query_warm(context: Any) -> None: context.service_tier_query = context.temporal_service.query_by_tier( ContextTier.WARM, ) @when("I query COLD tier via the service") def step_when_service_query_cold(context: Any) -> None: context.service_tier_query = context.temporal_service.query_by_tier( ContextTier.COLD, ) @then("the service tier query scope should be RECENT") def step_then_service_tier_scope_recent(context: Any) -> None: assert context.service_tier_query.temporal_scope == TemporalScope.RECENT # --------------------------------------------------------------------------- # Edge-case guards (Round 3 bug-hunt fixes) # --------------------------------------------------------------------------- @then( 'creating a service revision from "{uri}" to itself should raise ValueError', ) def step_then_service_same_uri_raises(context: Any, uri: str) -> None: try: context.temporal_service.create_revision( current_uri=uri, new_node_uri=uri, source_resource="RES001", source_path="src/foo.py", ) msg = "Expected ValueError for same-URI service revision" raise AssertionError(msg) except ValueError: pass @then( 'marking "{uri}" as historical again via the service should raise ValueError', ) def step_then_service_mark_historical_again_raises( context: Any, uri: str, ) -> None: try: context.temporal_service.mark_historical(uri) msg = "Expected ValueError for already-historical node" raise AssertionError(msg) except ValueError: pass @then("creating a TemporalService with None backend should raise TypeError") def step_then_service_none_backend(context: Any) -> None: try: TemporalService(backend=None) # type: ignore[arg-type] msg = "Expected TypeError for None backend" raise AssertionError(msg) except TypeError: pass