Files
cleveragents-core/benchmarks/invariant_reconciliation_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

180 lines
5.6 KiB
Python

"""ASV benchmarks for Invariant Reconciliation Actor throughput.
Measures the performance of:
- Reconciliation with varying numbers of invariants per scope
- Conflict detection and resolution overhead
- Decision recording throughput
- Full pipeline (collect → reconcile → record)
"""
from __future__ import annotations
import importlib
import sys
from pathlib import Path
from typing import ClassVar
# Ensure the local source tree is importable
_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.actor.reconciliation import ( # noqa: E402
InvariantReconciliationActor,
ScopeInvariants,
reconcile_invariants,
)
from cleveragents.application.services.decision_service import ( # noqa: E402
DecisionService,
)
from cleveragents.application.services.invariant_service import ( # noqa: E402
InvariantService,
)
from cleveragents.domain.models.core.invariant import ( # noqa: E402
Invariant,
InvariantScope,
)
def _make_invariant(text: str, scope: InvariantScope, source: str) -> Invariant:
"""Create an invariant without going through the service."""
return Invariant(text=text, scope=scope, source_name=source)
def _build_scope_invariants(
n_global: int = 0,
n_project: int = 0,
n_action: int = 0,
n_plan: int = 0,
) -> ScopeInvariants:
"""Build a ScopeInvariants with the given counts (unique texts)."""
return ScopeInvariants(
global_invariants=[
_make_invariant(f"global-rule-{i}", InvariantScope.GLOBAL, "system")
for i in range(n_global)
],
project_invariants=[
_make_invariant(f"project-rule-{i}", InvariantScope.PROJECT, "local/api")
for i in range(n_project)
],
action_invariants=[
_make_invariant(f"action-rule-{i}", InvariantScope.ACTION, "local/deploy")
for i in range(n_action)
],
plan_invariants=[
_make_invariant(f"plan-rule-{i}", InvariantScope.PLAN, "PLAN01")
for i in range(n_plan)
],
)
def _build_conflicting_scope_invariants(n_conflicts: int) -> ScopeInvariants:
"""Build scope invariants where each text appears at global and plan."""
return ScopeInvariants(
global_invariants=[
_make_invariant(f"shared-rule-{i}", InvariantScope.GLOBAL, "system")
for i in range(n_conflicts)
],
project_invariants=[],
action_invariants=[],
plan_invariants=[
_make_invariant(f"shared-rule-{i}", InvariantScope.PLAN, "PLAN01")
for i in range(n_conflicts)
],
)
class ReconciliationAlgorithmSuite:
"""Benchmark the pure reconciliation algorithm (no I/O)."""
params: ClassVar[list[int]] = [1, 10, 50, 100]
param_names: ClassVar[list[str]] = ["invariants_per_scope"]
def setup(self, n: int) -> None:
self._scope_invs = _build_scope_invariants(
n_global=n, n_project=n, n_action=n, n_plan=n
)
def time_reconcile_no_conflicts(self, n: int) -> None:
"""Reconcile N invariants per scope with no conflicts."""
reconcile_invariants(self._scope_invs)
class ConflictResolutionSuite:
"""Benchmark conflict detection and resolution."""
params: ClassVar[list[int]] = [1, 10, 50, 100]
param_names: ClassVar[list[str]] = ["conflict_count"]
def setup(self, n: int) -> None:
self._scope_invs = _build_conflicting_scope_invariants(n)
def time_reconcile_with_conflicts(self, n: int) -> None:
"""Reconcile N conflicting invariant pairs."""
reconcile_invariants(self._scope_invs)
class FullPipelineSuite:
"""Benchmark the full actor pipeline (collect + reconcile + record)."""
params: ClassVar[list[int]] = [1, 10, 50]
param_names: ClassVar[list[str]] = ["invariants_per_scope"]
def setup(self, n: int) -> None:
self._n = n
def time_full_pipeline(self, n: int) -> None:
"""Run full actor pipeline with N invariants per scope."""
inv_svc = InvariantService()
dec_svc = DecisionService()
for i in range(n):
inv_svc.add_invariant(f"global-rule-{i}", InvariantScope.GLOBAL, "system")
inv_svc.add_invariant(
f"project-rule-{i}", InvariantScope.PROJECT, "local/api"
)
inv_svc.add_invariant(
f"action-rule-{i}", InvariantScope.ACTION, "local/deploy"
)
inv_svc.add_invariant(
f"plan-rule-{i}", InvariantScope.PLAN, "01JQAAAAAAAAAAAAAAAAAAAA01"
)
actor = InvariantReconciliationActor(
invariant_service=inv_svc,
decision_service=dec_svc,
)
actor.run(
plan_id="01JQAAAAAAAAAAAAAAAAAAAA01",
project_name="local/api",
action_name="local/deploy",
)
class DecisionRecordingSuite:
"""Benchmark decision recording throughput."""
params: ClassVar[list[int]] = [1, 10, 50, 100]
param_names: ClassVar[list[str]] = ["invariant_count"]
def setup(self, n: int) -> None:
self._n = n
def time_record_decisions(self, n: int) -> None:
"""Record N invariant_enforced decisions."""
inv_svc = InvariantService()
dec_svc = DecisionService()
for i in range(n):
inv_svc.add_invariant(f"global-rule-{i}", InvariantScope.GLOBAL, "system")
actor = InvariantReconciliationActor(
invariant_service=inv_svc,
decision_service=dec_svc,
)
actor.run(plan_id="01JQAAAAAAAAAAAAAAAAAAAA01")