"""ASV benchmarks for cross-plan correction cascading performance. Measures cascade throughput with varying numbers of child plans in different states: cancel-only, cancel-with-rollback, and mixed states. """ from __future__ import annotations import importlib import sys from pathlib import Path from typing import ClassVar # Ensure the local *source* tree is importable even when ASV has an # older build of the package installed. _SRC = str(Path(__file__).resolve().parents[1] / "src") if _SRC not in sys.path: sys.path.insert(0, _SRC) import cleveragents # noqa: E402 importlib.reload(cleveragents) from cleveragents.application.services.cross_plan_correction_service import ( # noqa: E402 CrossPlanCorrectionService, ) from cleveragents.domain.models.core.correction import ( # noqa: E402 ChildPlanState, CorrectionImpact, CorrectionMode, ) # --------------------------------------------------------------------------- # Mock implementations (minimal, for benchmarking) # --------------------------------------------------------------------------- class _BenchPlanLookup: def __init__(self, states: dict[str, ChildPlanState]) -> None: self._states = states def get_child_plan_state(self, child_plan_id: str) -> ChildPlanState: return self._states[child_plan_id] class _BenchPlanCanceller: def cancel_child_plan(self, child_plan_id: str) -> None: pass class _BenchSandboxRollbacker: def rollback_child_plan_sandbox(self, child_plan_id: str) -> None: pass # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- def _make_service( child_count: int, state: ChildPlanState ) -> tuple[CrossPlanCorrectionService, list[str]]: plan_ids = [f"CP{i}" for i in range(child_count)] states = {pid: state for pid in plan_ids} lookup = _BenchPlanLookup(states) canceller = _BenchPlanCanceller() rollbacker = _BenchSandboxRollbacker() svc = CrossPlanCorrectionService( plan_lookup=lookup, plan_canceller=canceller, sandbox_rollbacker=rollbacker, ) return svc, plan_ids # --------------------------------------------------------------------------- # Benchmark suites # --------------------------------------------------------------------------- class CascadeCancelSuite: """Benchmark cascade with cancel-only (not-started) child plans.""" params: ClassVar[list[int]] = [1, 5, 10, 50, 100] param_names: ClassVar[list[str]] = ["child_plan_count"] def setup(self, child_plan_count: int) -> None: self.svc, self.plan_ids = _make_service( child_plan_count, ChildPlanState.NOT_STARTED ) def time_execute_cascade_cancel(self, child_plan_count: int) -> None: self.svc.execute_cascade("C1", self.plan_ids) def time_evaluate_cascade_cancel(self, child_plan_count: int) -> None: self.svc.evaluate_cascade("C1", self.plan_ids) class CascadeRollbackSuite: """Benchmark cascade with cancel+rollback (in-progress) child plans.""" params: ClassVar[list[int]] = [1, 5, 10, 50, 100] param_names: ClassVar[list[str]] = ["child_plan_count"] def setup(self, child_plan_count: int) -> None: self.svc, self.plan_ids = _make_service( child_plan_count, ChildPlanState.IN_PROGRESS ) def time_execute_cascade_rollback(self, child_plan_count: int) -> None: self.svc.execute_cascade("C1", self.plan_ids) class CascadeRejectionSuite: """Benchmark cascade rejection (applied child plans).""" params: ClassVar[list[int]] = [1, 5, 10, 50, 100] param_names: ClassVar[list[str]] = ["child_plan_count"] def setup(self, child_plan_count: int) -> None: self.svc, self.plan_ids = _make_service( child_plan_count, ChildPlanState.APPLIED ) def time_execute_cascade_rejection(self, child_plan_count: int) -> None: self.svc.execute_cascade("C1", self.plan_ids) class CorrectionWithCascadeSuite: """Benchmark full execute_correction_with_cascade flow.""" params: ClassVar[list[int]] = [0, 5, 20, 50] param_names: ClassVar[list[str]] = ["child_plan_count"] def setup(self, child_plan_count: int) -> None: plan_ids = [f"CP{i}" for i in range(child_plan_count)] states = {pid: ChildPlanState.NOT_STARTED for pid in plan_ids} lookup = _BenchPlanLookup(states) canceller = _BenchPlanCanceller() rollbacker = _BenchSandboxRollbacker() self.svc = CrossPlanCorrectionService( plan_lookup=lookup, plan_canceller=canceller, sandbox_rollbacker=rollbacker, ) self.impact = CorrectionImpact( affected_decisions=["D1"], affected_child_plans=plan_ids, risk_level="low", rollback_tier="full", artifacts_to_archive=["D1.artifact"], ) def time_correction_with_cascade(self, child_plan_count: int) -> None: self.svc.execute_correction_with_cascade( "C1", self.impact, CorrectionMode.REVERT )