Files
cleveragents-core/benchmarks/decision_di_bench.py
T
khyari hamza 0e36755db9
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 14s
CI / build (pull_request) Successful in 14s
CI / quality (pull_request) Successful in 16s
CI / security (pull_request) Successful in 31s
CI / typecheck (pull_request) Successful in 43s
CI / unit_tests (pull_request) Successful in 2m18s
CI / integration_tests (pull_request) Successful in 2m53s
CI / docker (pull_request) Successful in 39s
CI / coverage (pull_request) Successful in 3m58s
CI / benchmark-regression (pull_request) Successful in 24m44s
fix(service): address review findings for decision service
- Rehydrate sequence counter from DB on restart (BUG-1)
- Add uniqueness guard raising SequenceConflictError (BUG-2)
- Fix delete_decision consistency between persisted/in-memory (BUG-3)
- Validate new_decision_id exists in mark_superseded (BUG-4)
- Include orphaned subtrees in get_tree output (BUG-5)
- Remove dead _decision_seq/_next_seq from plan_lifecycle (BUG-7)
- Export SequenceConflictError from services __init__ (SPEC-2)
- Replace list[Any] with list[ArtifactRef] typing (SPEC-4)
- Add actor_reasoning max_length validation (SEC-1)
- Use SELECT COUNT(*) in count_decisions (PERF-1)
- Replace MagicMock with create_autospec(Settings) (TEST-3)
- Eliminate UnitOfWork.__new__() anti-pattern (TEST-4)
- Use exact assertion counts in DI tests (TEST-5)
- Add restart rehydration, BFS order, invalid type, and
  confidence boundary test scenarios (TEST-1/2/6/7)
- Fix decision_service_coverage.feature to match actual API

ISSUES CLOSED: #172
2026-03-03 12:53:28 +00:00

183 lines
6.0 KiB
Python

"""ASV benchmarks for DecisionService DI resolution and operations.
Measures:
- Container resolution of DecisionService
- Decision recording through the service layer
- Decision tree retrieval through the service layer
"""
from __future__ import annotations
import sys
from datetime import UTC, datetime
from pathlib import Path
from unittest.mock import create_autospec
try:
from cleveragents.application.services.decision_service import DecisionService
from cleveragents.config.settings import Settings
from cleveragents.domain.models.core.action import Action, ActionState
from cleveragents.domain.models.core.decision import Decision, DecisionType
from cleveragents.domain.models.core.plan import (
NamespacedName,
Plan,
PlanIdentity,
PlanPhase,
PlanTimestamps,
ProcessingState,
)
from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
except ModuleNotFoundError:
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from cleveragents.application.services.decision_service import DecisionService
from cleveragents.config.settings import Settings
from cleveragents.domain.models.core.action import Action, ActionState
from cleveragents.domain.models.core.decision import Decision, DecisionType
from cleveragents.domain.models.core.plan import (
NamespacedName,
Plan,
PlanIdentity,
PlanPhase,
PlanTimestamps,
ProcessingState,
)
from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
_PLAN_ID = "01HV00000000000000DIBENCH1"
def _make_uow() -> UnitOfWork:
"""Create a UoW backed by an in-memory SQLite database."""
uow = UnitOfWork("sqlite:///:memory:")
uow.init_database()
return uow
def _seed_prerequisites(uow: UnitOfWork) -> None:
"""Create the action + plan needed to satisfy FK constraints."""
with uow.transaction() as ctx:
action_repo = ctx.actions
action = Action(
namespaced_name=NamespacedName.parse("local/bench-di-action"),
description="Benchmark action",
definition_of_done="Done",
strategy_actor="local/s",
execution_actor="local/e",
state=ActionState.AVAILABLE,
created_at=datetime(2026, 1, 1, tzinfo=UTC),
updated_at=datetime(2026, 1, 1, tzinfo=UTC),
)
action_repo.create(action)
with uow.transaction() as ctx:
plan_repo = ctx.lifecycle_plans
now = datetime(2026, 3, 1, tzinfo=UTC)
plan = Plan(
identity=PlanIdentity(plan_id=_PLAN_ID, attempt=1),
namespaced_name=NamespacedName(namespace="local", name="bench-di-plan"),
action_name="local/bench-di-action",
description="Benchmark DI plan",
definition_of_done="Done",
phase=PlanPhase.STRATEGIZE,
processing_state=ProcessingState.PROCESSING,
strategy_actor="local/s",
execution_actor="local/e",
timestamps=PlanTimestamps(created_at=now, updated_at=now),
created_by="bench",
tags=[],
reusable=True,
read_only=False,
)
plan_repo.create(plan)
class TimeDecisionServiceResolution:
"""Benchmark DecisionService resolution from the DI container."""
timeout = 60
def setup(self) -> None:
import os
os.environ["CLEVERAGENTS_DATABASE_URL"] = "sqlite:///:memory:"
from cleveragents.application.container import get_container, reset_container
reset_container()
self.container = get_container()
def time_decision_service_resolution(self) -> None:
self.container.decision_service()
def teardown(self) -> None:
import os
from cleveragents.application.container import reset_container
reset_container()
os.environ.pop("CLEVERAGENTS_DATABASE_URL", None)
class TimeDecisionRecord:
"""Benchmark decision recording through DecisionService."""
timeout = 60
def setup(self) -> None:
self.uow = _make_uow()
_seed_prerequisites(self.uow)
mock_settings = create_autospec(Settings, instance=True)
mock_settings.database_url = "sqlite:///:memory:"
self.svc = DecisionService(settings=mock_settings, unit_of_work=self.uow)
self._seq = 100
def time_decision_record(self) -> None:
self._seq += 1
self.svc.record_decision(
plan_id=_PLAN_ID,
decision_type=DecisionType.STRATEGY_CHOICE,
question="Benchmark question?",
chosen_option="Benchmark option",
)
class TimeDecisionTreeRetrieval:
"""Benchmark decision tree retrieval through DecisionService."""
timeout = 60
def setup(self) -> None:
self.uow = _make_uow()
_seed_prerequisites(self.uow)
mock_settings = create_autospec(Settings, instance=True)
mock_settings.database_url = "sqlite:///:memory:"
self.svc = DecisionService(settings=mock_settings, unit_of_work=self.uow)
# Build a small tree
root = self.svc.record_decision(
plan_id=_PLAN_ID,
decision_type=DecisionType.PROMPT_DEFINITION,
question="Benchmark question?",
chosen_option="Benchmark option",
)
for _ in range(3):
child = self.svc.record_decision(
plan_id=_PLAN_ID,
decision_type=DecisionType.STRATEGY_CHOICE,
question="Benchmark question?",
chosen_option="Benchmark option",
parent_decision_id=root.decision_id,
)
for _ in range(2):
self.svc.record_decision(
plan_id=_PLAN_ID,
decision_type=DecisionType.IMPLEMENTATION_CHOICE,
question="Benchmark question?",
chosen_option="Benchmark option",
parent_decision_id=child.decision_id,
)
def time_decision_tree_retrieval(self) -> None:
self.svc.get_tree(_PLAN_ID)