"""ASV benchmarks for persistence test runtime baseline. Measures action and plan repository operation latencies to track performance regressions in persistence operations. """ from __future__ import annotations from datetime import datetime from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from cleveragents.domain.models.core.action import ( Action, ActionArgument, ActionState, ArgumentRequirement, ArgumentType, ) from cleveragents.domain.models.core.plan import ( NamespacedName, PlanIdentity, PlanPhase, PlanTimestamps, ProcessingState, ) from cleveragents.domain.models.core.plan import Plan as V3Plan from cleveragents.infrastructure.database.models import Base from cleveragents.infrastructure.database.repositories import ( ActionRepository, LifecyclePlanRepository, ) _CB32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ" _bench_counter = 0 def _bench_ulid() -> str: global _bench_counter _bench_counter += 1 n = _bench_counter suffix = "" for _ in range(8): suffix = _CB32[n % 32] + suffix n //= 32 return f"01HGZPS10AQDYTR4PS{suffix}" def _make_bench_action(name: str = "local/ps-bench-action") -> Action: """Create a benchmark action with arguments and invariants.""" return Action( namespaced_name=NamespacedName.parse(name), description="Persistence suite benchmark action", long_description=None, definition_of_done="Done", strategy_actor="local/s", execution_actor="local/e", estimation_actor=None, review_actor=None, arguments=[ ActionArgument( name="target", arg_type=ArgumentType.STRING, requirement=ArgumentRequirement.REQUIRED, description="Target path", ), ], invariants=["No breaking changes"], reusable=True, read_only=False, state=ActionState.AVAILABLE, created_at=datetime.now(), updated_at=datetime.now(), created_by=None, tags=[], ) def _make_bench_plan(plan_id: str | None = None) -> V3Plan: now = datetime.now() return V3Plan( identity=PlanIdentity(plan_id=plan_id or _bench_ulid(), attempt=1), namespaced_name=NamespacedName(namespace="local", name="ps-bench-plan"), action_name="local/ps-bench-action", description="Persistence suite benchmark plan", phase=PlanPhase("action"), processing_state=ProcessingState("queued"), strategy_actor="local/s", execution_actor="local/e", timestamps=PlanTimestamps(created_at=now, updated_at=now), created_by="bench", tags=[], reusable=True, read_only=False, ) class TimeActionCreate: """Benchmark action creation latency.""" timeout = 60 def setup(self) -> None: engine = create_engine("sqlite:///:memory:") Base.metadata.create_all(engine) session = sessionmaker(bind=engine)() self.session = session self.repo = ActionRepository(session_factory=lambda: session) self._counter = 0 def time_create_action(self) -> None: self._counter += 1 action = _make_bench_action(f"local/bench-act-{self._counter}") self.repo.create(action) self.session.commit() class TimeActionGet: """Benchmark action retrieval latency.""" timeout = 60 def setup(self) -> None: engine = create_engine("sqlite:///:memory:") Base.metadata.create_all(engine) session = sessionmaker(bind=engine)() self.session = session self.repo = ActionRepository(session_factory=lambda: session) action = _make_bench_action() self.repo.create(action) session.commit() def time_get_by_name(self) -> None: self.repo.get_by_name("local/ps-bench-action") class TimePlanCreatePersistence: """Benchmark plan creation with FK action.""" timeout = 60 def setup(self) -> None: engine = create_engine("sqlite:///:memory:") Base.metadata.create_all(engine) session = sessionmaker(bind=engine)() self.session = session factory = lambda: session # noqa: E731 action_repo = ActionRepository(session_factory=factory) action_repo.create(_make_bench_action()) session.commit() self.repo = LifecyclePlanRepository(session_factory=factory) def time_create_plan(self) -> None: plan = _make_bench_plan() self.repo.create(plan) self.session.commit() class TimePlanUpdatePhase: """Benchmark plan phase update latency.""" timeout = 60 def setup(self) -> None: engine = create_engine("sqlite:///:memory:") Base.metadata.create_all(engine) session = sessionmaker(bind=engine)() self.session = session factory = lambda: session # noqa: E731 action_repo = ActionRepository(session_factory=factory) action_repo.create(_make_bench_action()) session.commit() self.repo = LifecyclePlanRepository(session_factory=factory) self.plan_id = _bench_ulid() plan = _make_bench_plan(self.plan_id) self.repo.create(plan) session.commit() def time_update_phase(self) -> None: plan = self.repo.get(self.plan_id) if plan is not None: plan.phase = PlanPhase.STRATEGIZE plan.processing_state = ProcessingState.PROCESSING plan.timestamps.updated_at = datetime.now() self.repo.update(plan) self.session.commit() class TimePlanListFiltered: """Benchmark plan listing with filters.""" timeout = 60 def setup(self) -> None: engine = create_engine("sqlite:///:memory:") Base.metadata.create_all(engine) session = sessionmaker(bind=engine)() self.session = session factory = lambda: session # noqa: E731 action_repo = ActionRepository(session_factory=factory) action_repo.create(_make_bench_action()) session.commit() self.repo = LifecyclePlanRepository(session_factory=factory) for _ in range(30): plan = _make_bench_plan() self.repo.create(plan) session.commit() def time_list_all(self) -> None: self.repo.list_plans() def time_list_by_phase(self) -> None: self.repo.list_plans(phase="action") def time_count(self) -> None: self.repo.count()