Files
cleveragents-core/benchmarks/devcontainer_handler_bench.py
freemo 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
feat(correcting-plans): implement Predictive Error Prevention (Layer 4) with Error Pattern Database
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
2026-03-08 21:53:21 -04:00

161 lines
4.9 KiB
Python

"""ASV benchmarks for devcontainer handler auto-discovery throughput.
Measures the performance of:
- Devcontainer discovery on projects with many subdirectories
- Handler resolver cache performance for DevcontainerHandler
- Discovery result construction overhead
- is_trigger_type check throughput
"""
from __future__ import annotations
import json
import sys
import tempfile
from pathlib import Path
from typing import ClassVar
try:
from cleveragents.resource.handlers.discovery import (
DevcontainerDiscoveryResult,
discover_devcontainers,
is_trigger_type,
)
from cleveragents.resource.handlers.resolver import (
clear_handler_cache,
resolve_handler,
)
except ModuleNotFoundError:
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from cleveragents.resource.handlers.discovery import (
DevcontainerDiscoveryResult,
discover_devcontainers,
is_trigger_type,
)
from cleveragents.resource.handlers.resolver import (
clear_handler_cache,
resolve_handler,
)
_VALID_DC_JSON: str = json.dumps(
{"name": "bench-devcontainer", "image": "ubuntu:latest"}
)
class TimeDiscoveryThroughput:
"""Benchmark auto-discovery throughput on projects with many subdirs."""
timeout = 60
params: ClassVar[list[int]] = [10, 50, 100]
param_names: ClassVar[list[str]] = ["num_subdirs"]
def setup(self, num_subdirs: int) -> None:
"""Create a temp directory with many subdirectories."""
self.tmp_dir = tempfile.mkdtemp()
base = Path(self.tmp_dir)
# Create the devcontainer config
dc_dir = base / ".devcontainer"
dc_dir.mkdir()
(dc_dir / "devcontainer.json").write_text(_VALID_DC_JSON, encoding="utf-8")
# Create many sibling directories (noise)
for i in range(num_subdirs):
(base / f"subdir_{i:04d}").mkdir()
def teardown(self, num_subdirs: int) -> None:
"""Clean up temp directory."""
import shutil
shutil.rmtree(self.tmp_dir, ignore_errors=True)
def time_discovery_with_subdirs(self, num_subdirs: int) -> None:
"""Time discovery scanning with many peer directories."""
discover_devcontainers(self.tmp_dir, "git-checkout")
class TimeDiscoveryEmpty:
"""Benchmark discovery on directory with no devcontainer."""
timeout = 30
def setup(self) -> None:
"""Create empty temp directory."""
self.tmp_dir = tempfile.mkdtemp()
base = Path(self.tmp_dir)
for i in range(50):
(base / f"subdir_{i:04d}").mkdir()
def teardown(self) -> None:
"""Clean up."""
import shutil
shutil.rmtree(self.tmp_dir, ignore_errors=True)
def time_discovery_no_match(self) -> None:
"""Time discovery when no devcontainer exists."""
discover_devcontainers(self.tmp_dir, "git-checkout")
class TimeHandlerResolver:
"""Benchmark handler resolver cache for DevcontainerHandler."""
timeout = 30
_ref = "cleveragents.resource.handlers.devcontainer:DevcontainerHandler"
def setup(self) -> None:
"""Pre-warm resolver cache."""
clear_handler_cache()
resolve_handler(self._ref)
def time_cached_resolution(self) -> None:
"""Time cached handler resolution (should be near-zero)."""
resolve_handler(self._ref)
def time_cold_resolution(self) -> None:
"""Time cold handler resolution (import + instantiate)."""
clear_handler_cache()
resolve_handler(self._ref)
class TimeIsTriggerType:
"""Benchmark is_trigger_type check throughput."""
timeout = 10
def time_trigger_type_positive(self) -> None:
"""Time is_trigger_type for a trigger type."""
for _ in range(1000):
is_trigger_type("git-checkout")
def time_trigger_type_negative(self) -> None:
"""Time is_trigger_type for a non-trigger type."""
for _ in range(1000):
is_trigger_type("devcontainer-instance")
class TimeDiscoveryResult:
"""Benchmark DevcontainerDiscoveryResult construction."""
timeout = 30
def setup(self) -> None:
"""Create temp file for result construction."""
self.tmp_dir = tempfile.mkdtemp()
self.dc_file = Path(self.tmp_dir) / "devcontainer.json"
self.dc_file.write_text(_VALID_DC_JSON, encoding="utf-8")
self.config_data: dict[str, object] = json.loads(_VALID_DC_JSON)
def teardown(self) -> None:
"""Clean up."""
import shutil
shutil.rmtree(self.tmp_dir, ignore_errors=True)
def time_result_construction(self) -> None:
"""Time DevcontainerDiscoveryResult instantiation."""
for _ in range(1000):
DevcontainerDiscoveryResult(
config_path=self.dc_file,
config_data=self.config_data,
parent_location=self.tmp_dir,
)