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
150 lines
4.8 KiB
Python
150 lines
4.8 KiB
Python
"""ASV benchmarks for ComponentResolver scope chain resolution.
|
|
|
|
Measures the performance of:
|
|
- Global default resolution
|
|
- Project override resolution
|
|
- Plan override resolution (3-level chain)
|
|
- Cache hit performance
|
|
- Registration throughput
|
|
- Introspection API latency
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Any, Protocol, runtime_checkable
|
|
|
|
# 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.component_resolver import ( # noqa: E402
|
|
ComponentResolver,
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Test protocol and implementations
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@runtime_checkable
|
|
class _BenchProtocol(Protocol):
|
|
def run(self) -> str: ...
|
|
|
|
|
|
class _BenchGlobal:
|
|
def run(self) -> str:
|
|
return "global"
|
|
|
|
|
|
class _BenchProject:
|
|
def run(self) -> str:
|
|
return "project"
|
|
|
|
|
|
class _BenchPlan:
|
|
def run(self) -> str:
|
|
return "plan"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Timing suite
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class ComponentResolverTimeSuite:
|
|
"""Benchmark timing for component resolution across scope levels."""
|
|
|
|
def setup(self) -> None:
|
|
self._resolver = ComponentResolver()
|
|
self._resolver.register_global(_BenchProtocol, _BenchGlobal())
|
|
self._resolver.register_project("proj-1", _BenchProtocol, _BenchProject())
|
|
self._resolver.register_plan("plan-1", _BenchProtocol, _BenchPlan())
|
|
|
|
def time_resolve_global(self) -> None:
|
|
"""Resolve from global scope (no plan/project context)."""
|
|
self._resolver.invalidate_cache()
|
|
self._resolver.resolve(_BenchProtocol)
|
|
|
|
def time_resolve_project(self) -> None:
|
|
"""Resolve from project scope."""
|
|
self._resolver.invalidate_cache()
|
|
self._resolver.resolve(_BenchProtocol, project_id="proj-1")
|
|
|
|
def time_resolve_plan(self) -> None:
|
|
"""Resolve from plan scope (full 3-level chain)."""
|
|
self._resolver.invalidate_cache()
|
|
self._resolver.resolve(_BenchProtocol, plan_id="plan-1", project_id="proj-1")
|
|
|
|
def time_resolve_cache_hit(self) -> None:
|
|
"""Resolve with cache hit (pre-warmed)."""
|
|
# Prime cache
|
|
self._resolver.resolve(_BenchProtocol)
|
|
# Measure cache hit
|
|
self._resolver.resolve(_BenchProtocol)
|
|
|
|
def time_resolve_fallthrough(self) -> None:
|
|
"""Resolve with fallthrough (unknown plan/project)."""
|
|
self._resolver.invalidate_cache()
|
|
self._resolver.resolve(_BenchProtocol, plan_id="unknown", project_id="unknown")
|
|
|
|
def time_register_global(self) -> None:
|
|
"""Register a global implementation."""
|
|
resolver = ComponentResolver()
|
|
resolver.register_global(_BenchProtocol, _BenchGlobal())
|
|
|
|
def time_register_project(self) -> None:
|
|
"""Register a project implementation."""
|
|
resolver = ComponentResolver()
|
|
resolver.register_project("p", _BenchProtocol, _BenchProject())
|
|
|
|
def time_register_plan(self) -> None:
|
|
"""Register a plan implementation."""
|
|
resolver = ComponentResolver()
|
|
resolver.register_plan("p", _BenchProtocol, _BenchPlan())
|
|
|
|
def time_has_global(self) -> None:
|
|
"""Check has_global."""
|
|
self._resolver.has_global(_BenchProtocol)
|
|
|
|
def time_list_global_types(self) -> None:
|
|
"""List global type names."""
|
|
self._resolver.list_global_types()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Memory suite
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class ComponentResolverMemSuite:
|
|
"""Benchmark memory consumption for component resolver operations."""
|
|
|
|
def setup(self) -> None:
|
|
self._resolver = ComponentResolver()
|
|
self._resolver.register_global(_BenchProtocol, _BenchGlobal())
|
|
for i in range(100):
|
|
self._resolver.register_project(
|
|
f"proj-{i}", _BenchProtocol, _BenchProject()
|
|
)
|
|
self._resolver.register_plan(f"plan-{i}", _BenchProtocol, _BenchPlan())
|
|
|
|
def mem_resolve_many(self) -> list[Any]:
|
|
"""Memory for resolving 100 plan-level lookups."""
|
|
results = []
|
|
for i in range(100):
|
|
results.append(
|
|
self._resolver.resolve(
|
|
_BenchProtocol, plan_id=f"plan-{i}", project_id=f"proj-{i}"
|
|
)
|
|
)
|
|
return results
|