583e6b7ea2
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 14s
CI / build (pull_request) Successful in 16s
CI / quality (pull_request) Successful in 17s
CI / security (pull_request) Successful in 36s
CI / typecheck (pull_request) Successful in 54s
CI / unit_tests (pull_request) Successful in 2m39s
CI / integration_tests (pull_request) Successful in 3m10s
CI / docker (pull_request) Successful in 40s
CI / coverage (pull_request) Successful in 5m0s
CI / lint (push) Successful in 14s
CI / build (push) Successful in 15s
CI / quality (push) Successful in 16s
CI / security (push) Successful in 34s
CI / typecheck (push) Successful in 35s
CI / benchmark-regression (push) Has been skipped
CI / unit_tests (push) Successful in 2m23s
CI / docker (push) Successful in 38s
CI / integration_tests (push) Successful in 3m8s
CI / coverage (push) Successful in 5m10s
CI / benchmark-publish (push) Successful in 16m26s
CI / benchmark-regression (pull_request) Successful in 30m12s
Implement spec-mandated Layer 4 Predictive Error Prevention system: - ErrorPattern domain model with pattern text, historical failures, preventive checks, frequency tracking, and keyword-based matching. - ErrorPatternRepository with in-memory CRUD + context-matching query. - ErrorPatternService with record_failure(), match_patterns(), and get_statistics() methods. - Wire into plan execution via plan_lifecycle_service pre-execution hook. - Add error pattern statistics to CLI diagnostics output. Behave BDD: 11 scenarios covering recording, matching, formatting, stats. Robot Framework: 3 integration smoke tests. ASV benchmarks: pattern matching performance. ISSUES CLOSED: #571
159 lines
5.1 KiB
Python
159 lines
5.1 KiB
Python
"""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
|
|
)
|