"""Robot Framework helper for Temporal Data Model smoke tests. Provides a CLI-style interface for Robot to invoke temporal model creation, revision chain operations, tier queries, and service-level operations. Exit code 0 = success, 1 = failure. Usage: python robot/helper_temporal_data_model.py """ from __future__ import annotations import sys from datetime import UTC, datetime, timedelta from pathlib import Path # Ensure the src directory is on the import path. _SRC = str(Path(__file__).resolve().parents[1] / "src") if _SRC not in sys.path: sys.path.insert(0, _SRC) from cleveragents.application.services.temporal_service import ( # noqa: E402 TemporalService, ) from cleveragents.domain.models.acms.temporal import ( # noqa: E402 RevisionChain, TemporalBackend, TemporalMetadata, TemporalNode, TierQueryResult, TierRetentionConfig, ) from cleveragents.domain.models.acms.temporal_stubs import ( # noqa: E402 InMemoryTemporalBackend, ) from cleveragents.domain.models.acms.tiers import ContextTier # noqa: E402 from cleveragents.domain.models.core.project import ( # noqa: E402 TemporalScope, ) def main() -> int: """Entry point called by Robot Framework ``Run Process``.""" if len(sys.argv) < 2: print("Usage: helper_temporal_data_model.py ") return 1 command: str = sys.argv[1] if command == "protocol-compliance": return _test_protocol_compliance() if command == "revision-chain": return _test_revision_chain() if command == "tier-queries": return _test_tier_queries() if command == "service-lifecycle": return _test_service_lifecycle() if command == "model-creation": return _test_model_creation() if command == "validation": return _test_validation() if command == "retention-defaults": return _test_retention_defaults() if command == "integration-modify-resource": return _test_integration_modify_resource() print(f"Unknown command: {command}") return 1 def _test_protocol_compliance() -> int: """Verify InMemoryTemporalBackend satisfies TemporalBackend.""" try: backend = InMemoryTemporalBackend() assert isinstance(backend, TemporalBackend) print("temporal-protocol-ok") return 0 except Exception as exc: print(f"FAIL: {exc}") return 1 def _test_revision_chain() -> int: """Test revision chain creation and traversal.""" try: backend = InMemoryTemporalBackend() now = datetime.now(tz=UTC) # Store v1 v1 = TemporalNode( node_uri="uko-py:class/Auth_v1", source_resource="RES001", source_path="src/auth.py", temporal=TemporalMetadata( valid_from=now - timedelta(days=5), is_current=True, ), ) backend.store_node(v1) # Create v2 v2 = TemporalNode( node_uri="uko-py:class/Auth_v2", source_resource="RES001", source_path="src/auth.py", temporal=TemporalMetadata( valid_from=now - timedelta(days=2), is_current=True, is_revision_of="uko-py:class/Auth_v1", ), ) backend.create_revision("uko-py:class/Auth_v1", v2, now - timedelta(days=2)) # Create v3 v3 = TemporalNode( node_uri="uko-py:class/Auth_v3", source_resource="RES001", source_path="src/auth.py", temporal=TemporalMetadata( valid_from=now, is_current=True, is_revision_of="uko-py:class/Auth_v2", ), ) backend.create_revision("uko-py:class/Auth_v2", v3, now) # Verify chain chain = backend.get_revision_chain("uko-py:class/Auth_v3") assert chain.depth == 3 assert chain.current_uri == "uko-py:class/Auth_v3" assert "uko-py:class/Auth_v1" in chain.predecessors assert "uko-py:class/Auth_v2" in chain.predecessors print("temporal-revision-chain-ok") return 0 except Exception as exc: print(f"FAIL: {exc}") return 1 def _test_tier_queries() -> int: """Test tier-aware temporal queries.""" try: backend = InMemoryTemporalBackend() now = datetime.now(tz=UTC) retention = TierRetentionConfig() # Store a current node and a historical node v1 = TemporalNode( node_uri="uko-py:class/Foo_v1", source_resource="RES001", source_path="src/foo.py", temporal=TemporalMetadata( valid_from=now - timedelta(days=5), is_current=True, ), ) backend.store_node(v1) v2 = TemporalNode( node_uri="uko-py:class/Foo_v2", source_resource="RES001", source_path="src/foo.py", temporal=TemporalMetadata( valid_from=now, is_current=True, is_revision_of="uko-py:class/Foo_v1", ), ) backend.create_revision("uko-py:class/Foo_v1", v2, now) # Hot tier: only current hot = backend.query_by_tier(ContextTier.HOT, TemporalScope.CURRENT, retention) assert len(hot.nodes) == 1 assert hot.nodes[0].temporal.is_current is True # Cold tier: all cold = backend.query_by_tier(ContextTier.COLD, TemporalScope.ALL, retention) assert len(cold.nodes) == 2 print("temporal-tier-queries-ok") return 0 except Exception as exc: print(f"FAIL: {exc}") return 1 def _test_service_lifecycle() -> int: """Test TemporalService lifecycle.""" try: backend = InMemoryTemporalBackend() service = TemporalService(backend=backend) # Store initial node = service.store_initial_node( node_uri="uko-py:class/Bar_v1", source_resource="RES002", source_path="src/bar.py", ) assert node.temporal.is_current is True # Create revision v2 = service.create_revision( current_uri="uko-py:class/Bar_v1", new_node_uri="uko-py:class/Bar_v2", source_resource="RES002", source_path="src/bar.py", ) assert v2.temporal.is_revision_of == "uko-py:class/Bar_v1" # Get current current = service.get_current("uko-py:class/Bar") assert current is not None assert current.node_uri == "uko-py:class/Bar_v2" # Get chain chain = service.get_revision_chain("uko-py:class/Bar_v2") assert chain.depth == 2 print("temporal-service-lifecycle-ok") return 0 except Exception as exc: print(f"FAIL: {exc}") return 1 def _test_model_creation() -> int: """Test domain model creation.""" try: now = datetime.now(tz=UTC) meta = TemporalMetadata(valid_from=now) assert meta.is_current is True assert meta.valid_until is None node = TemporalNode( node_uri="uko-py:class/Test_v1", source_resource="RES", source_path="src/test.py", temporal=meta, ) assert node.node_uri == "uko-py:class/Test_v1" chain = RevisionChain(current_uri="uko:test") assert chain.depth == 1 result = TierQueryResult( tier=ContextTier.HOT, temporal_scope=TemporalScope.CURRENT, ) assert result.nodes == () retention = TierRetentionConfig() assert retention.warm_retention_hours == 24 print("temporal-model-creation-ok") return 0 except Exception as exc: print(f"FAIL: {exc}") return 1 def _test_validation() -> int: """Test input validation on models and backend.""" try: backend = InMemoryTemporalBackend() # Blank URI should raise ValueError try: backend.get_current("") print("FAIL: expected ValueError") return 1 except ValueError: pass # Nonexistent node should raise KeyError try: backend.mark_historical("uko:nonexistent", datetime.now(tz=UTC)) print("FAIL: expected KeyError") return 1 except KeyError: pass print("temporal-validation-ok") return 0 except Exception as exc: print(f"FAIL: {exc}") return 1 def _test_retention_defaults() -> int: """Test retention config defaults match spec.""" try: retention = TierRetentionConfig() assert retention.warm_retention_hours == 24 assert retention.cold_retention_days == 90 print("temporal-retention-defaults-ok") return 0 except Exception as exc: print(f"FAIL: {exc}") return 1 def _test_integration_modify_resource() -> int: """Integration test: modify resource, verify temporal chain. Acceptance criteria #10: Modify a resource, verify old node is marked historical, new node is current, revision chain is intact. """ try: backend = InMemoryTemporalBackend() service = TemporalService(backend=backend) # Step 1: Initial analysis creates first node v1 = service.store_initial_node( node_uri="uko-py:class/AuthManager_v1", source_resource="RES_AUTH", source_path="src/auth/manager.py", source_range="15:1-87:0", ) assert v1.temporal.is_current is True assert v1.temporal.is_revision_of is None # Step 2: Code change triggers re-analysis → new revision v2 = service.create_revision( current_uri="uko-py:class/AuthManager_v1", new_node_uri="uko-py:class/AuthManager_v2", source_resource="RES_AUTH", source_path="src/auth/manager.py", source_range="15:1-95:0", ) # Step 3: Verify old node is marked historical old = backend._nodes["uko-py:class/AuthManager_v1"] assert old.temporal.is_current is False assert old.temporal.valid_until is not None # Step 4: Verify new node is current assert v2.temporal.is_current is True assert v2.temporal.is_revision_of == "uko-py:class/AuthManager_v1" # Step 5: Verify revision chain is intact chain = service.get_revision_chain("uko-py:class/AuthManager_v2") assert chain.depth == 2 assert chain.current_uri == "uko-py:class/AuthManager_v2" assert "uko-py:class/AuthManager_v1" in chain.predecessors # Step 6: Hot tier shows only current hot = service.query_by_tier(ContextTier.HOT) assert len(hot.nodes) == 1 assert hot.nodes[0].node_uri == "uko-py:class/AuthManager_v2" # Step 7: Cold tier shows full history cold = service.query_by_tier(ContextTier.COLD) assert len(cold.nodes) == 2 print("temporal-integration-modify-resource-ok") return 0 except Exception as exc: print(f"FAIL: {exc}") return 1 if __name__ == "__main__": sys.exit(main())