3c9a3efdf1
CI / lint (pull_request) Successful in 22s
CI / typecheck (pull_request) Successful in 55s
CI / security (pull_request) Successful in 48s
CI / quality (pull_request) Successful in 28s
CI / integration_tests (pull_request) Successful in 5m6s
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 23s
CI / unit_tests (pull_request) Successful in 34m47s
CI / benchmark-regression (pull_request) Successful in 25m45s
CI / docker (pull_request) Successful in 1m15s
CI / coverage (pull_request) Has been cancelled
- Patch CorrectionService at its module path, not the local-import site - Use request_correction/execute_correction/analyze_impact (real API) - Replace invalid 27-char subplan_id values with valid 26-char ULIDs - Add required --guidance flag to dry-run CLI invocation - Fix feature file assertions to match actual CLI output Resolves CI failures in unit_tests (job 4) and coverage (job 6) for run 645 on PR #441.
303 lines
9.6 KiB
Python
303 lines
9.6 KiB
Python
"""ASV benchmarks for M4 correction + subplan smoke suite runtime.
|
|
|
|
Measures the performance of:
|
|
- Correction CLI commands (revert, append, dry-run)
|
|
- Subplan status rendering with config and statuses
|
|
- SubplanFailureHandler decision logic
|
|
- Fixture loading overhead
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import json
|
|
import sys
|
|
from datetime import UTC, datetime
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
# 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 typer.testing import CliRunner # noqa: E402
|
|
|
|
from cleveragents.cli.commands.plan import app as plan_app # noqa: E402
|
|
from cleveragents.domain.models.core.correction import ( # noqa: E402
|
|
CorrectionImpact,
|
|
CorrectionResult,
|
|
CorrectionStatus,
|
|
)
|
|
from cleveragents.domain.models.core.plan import ( # noqa: E402
|
|
ExecutionMode,
|
|
NamespacedName,
|
|
Plan,
|
|
PlanIdentity,
|
|
PlanPhase,
|
|
PlanTimestamps,
|
|
ProcessingState,
|
|
SubplanConfig,
|
|
SubplanFailureHandler,
|
|
SubplanMergeStrategy,
|
|
SubplanStatus,
|
|
)
|
|
|
|
_runner = CliRunner()
|
|
_PLAN_ULID = "01M4SM0KE00000000000000001"
|
|
_DECISION_ULID = "01M4DEC00000000000000000001"
|
|
_FIXTURES_DIR = Path(__file__).resolve().parents[1] / "features" / "fixtures" / "m4"
|
|
|
|
|
|
def _mock_plan(
|
|
*,
|
|
phase: PlanPhase = PlanPhase.EXECUTE,
|
|
state: ProcessingState = ProcessingState.COMPLETE,
|
|
subplan_config: SubplanConfig | None = None,
|
|
subplan_statuses: list[SubplanStatus] | None = None,
|
|
) -> Plan:
|
|
now = datetime.now()
|
|
return Plan(
|
|
identity=PlanIdentity(plan_id=_PLAN_ULID),
|
|
namespaced_name=NamespacedName.parse("local/m4-smoke-plan"),
|
|
description="M4 bench plan",
|
|
definition_of_done="Corrections applied",
|
|
action_name="local/m4-correction-test",
|
|
phase=phase,
|
|
processing_state=state,
|
|
project_links=[],
|
|
arguments={},
|
|
arguments_order=[],
|
|
strategy_actor="openai/gpt-4",
|
|
execution_actor="openai/gpt-4",
|
|
reusable=True,
|
|
read_only=False,
|
|
created_by=None,
|
|
timestamps=PlanTimestamps(created_at=now, updated_at=now),
|
|
decision_root_id=_DECISION_ULID,
|
|
subplan_config=subplan_config,
|
|
subplan_statuses=subplan_statuses or [],
|
|
)
|
|
|
|
|
|
def _mock_correction_service() -> MagicMock:
|
|
mock_svc = MagicMock()
|
|
now = datetime.now(UTC)
|
|
_correction_id = "01M4CORRID00000000000000001"
|
|
|
|
# request_correction returns a CorrectionRequest-like mock
|
|
mock_request = MagicMock()
|
|
mock_request.correction_id = _correction_id
|
|
mock_svc.request_correction.return_value = mock_request
|
|
|
|
# execute_correction returns a CorrectionResult (non-dry-run path)
|
|
mock_svc.execute_correction.return_value = CorrectionResult(
|
|
correction_id=_correction_id,
|
|
status=CorrectionStatus.APPLIED,
|
|
reverted_decisions=[_DECISION_ULID],
|
|
completed_at=now,
|
|
)
|
|
|
|
# analyze_impact returns a CorrectionImpact (dry-run path)
|
|
mock_svc.analyze_impact.return_value = CorrectionImpact(
|
|
affected_decisions=[_DECISION_ULID],
|
|
affected_files=["src/auth.py"],
|
|
risk_level="medium",
|
|
rollback_tier="phase",
|
|
)
|
|
return mock_svc
|
|
|
|
|
|
class M4CorrectionCLISuite:
|
|
"""Benchmark correction CLI commands."""
|
|
|
|
def setup(self) -> None:
|
|
self._mock_service = MagicMock()
|
|
self._mock_service.get_plan.return_value = _mock_plan()
|
|
self._mock_correction = _mock_correction_service()
|
|
self._plan_patcher = patch(
|
|
"cleveragents.cli.commands.plan._get_lifecycle_service",
|
|
return_value=self._mock_service,
|
|
)
|
|
self._correction_patcher = patch(
|
|
"cleveragents.application.services.correction_service.CorrectionService",
|
|
return_value=self._mock_correction,
|
|
)
|
|
self._plan_patcher.start()
|
|
self._correction_patcher.start()
|
|
|
|
def teardown(self) -> None:
|
|
self._correction_patcher.stop()
|
|
self._plan_patcher.stop()
|
|
|
|
def time_correction_revert(self) -> None:
|
|
"""Benchmark correction revert command."""
|
|
_runner.invoke(
|
|
plan_app,
|
|
[
|
|
"correct",
|
|
_DECISION_ULID,
|
|
"--mode",
|
|
"revert",
|
|
"--guidance",
|
|
"bench test",
|
|
"--plan",
|
|
_PLAN_ULID,
|
|
"--yes",
|
|
],
|
|
)
|
|
|
|
def time_correction_append(self) -> None:
|
|
"""Benchmark correction append command."""
|
|
_runner.invoke(
|
|
plan_app,
|
|
[
|
|
"correct",
|
|
_DECISION_ULID,
|
|
"--mode",
|
|
"append",
|
|
"--guidance",
|
|
"bench test",
|
|
"--plan",
|
|
_PLAN_ULID,
|
|
"--yes",
|
|
],
|
|
)
|
|
|
|
def time_correction_dry_run(self) -> None:
|
|
"""Benchmark correction dry-run command."""
|
|
_runner.invoke(
|
|
plan_app,
|
|
[
|
|
"correct",
|
|
_DECISION_ULID,
|
|
"--mode",
|
|
"revert",
|
|
"--guidance",
|
|
"Evaluate impact of revert",
|
|
"--dry-run",
|
|
"--plan",
|
|
_PLAN_ULID,
|
|
],
|
|
)
|
|
|
|
|
|
class M4SubplanStatusSuite:
|
|
"""Benchmark subplan status rendering."""
|
|
|
|
def setup(self) -> None:
|
|
config = SubplanConfig(
|
|
execution_mode=ExecutionMode.PARALLEL,
|
|
merge_strategy=SubplanMergeStrategy.GIT_THREE_WAY,
|
|
max_parallel=5,
|
|
)
|
|
statuses = [
|
|
SubplanStatus(
|
|
subplan_id="01J4S0BP000000000000000020",
|
|
action_name="local/update-api",
|
|
target_resources=["src/api.py"],
|
|
status=ProcessingState.COMPLETE,
|
|
),
|
|
SubplanStatus(
|
|
subplan_id="01J4S0BP000000000000000021",
|
|
action_name="local/update-tests",
|
|
target_resources=["tests/test_api.py"],
|
|
status=ProcessingState.COMPLETE,
|
|
),
|
|
]
|
|
plan = _mock_plan(subplan_config=config, subplan_statuses=statuses)
|
|
self._mock_service = MagicMock()
|
|
self._mock_service.get_plan.return_value = plan
|
|
self._mock_service.list_plans.return_value = [plan]
|
|
self._patcher = patch(
|
|
"cleveragents.cli.commands.plan._get_lifecycle_service",
|
|
return_value=self._mock_service,
|
|
)
|
|
self._patcher.start()
|
|
|
|
def teardown(self) -> None:
|
|
self._patcher.stop()
|
|
|
|
def time_status_with_subplans_json(self) -> None:
|
|
"""Benchmark plan status JSON rendering with subplans."""
|
|
_runner.invoke(plan_app, ["status", _PLAN_ULID, "--format", "json"])
|
|
|
|
def time_status_with_subplans_rich(self) -> None:
|
|
"""Benchmark plan status rich rendering with subplans."""
|
|
_runner.invoke(plan_app, ["status", _PLAN_ULID])
|
|
|
|
|
|
class M4FailureHandlerSuite:
|
|
"""Benchmark SubplanFailureHandler decision logic."""
|
|
|
|
def setup(self) -> None:
|
|
self._handler = SubplanFailureHandler()
|
|
self._config_ff = SubplanConfig(
|
|
execution_mode=ExecutionMode.PARALLEL, fail_fast=True
|
|
)
|
|
self._config_retry = SubplanConfig(
|
|
execution_mode=ExecutionMode.SEQUENTIAL,
|
|
retry_failed=True,
|
|
max_retries=2,
|
|
)
|
|
self._failed_retriable = SubplanStatus(
|
|
subplan_id="01J4S0BP000000000000000030",
|
|
action_name="local/flaky-task",
|
|
status=ProcessingState.ERRORED,
|
|
error="ValidationError: schema mismatch",
|
|
attempt_number=1,
|
|
)
|
|
self._failed_non_retriable = SubplanStatus(
|
|
subplan_id="01J4S0BP000000000000000031",
|
|
action_name="local/broken-task",
|
|
status=ProcessingState.ERRORED,
|
|
error="ConfigurationError: permanent failure",
|
|
attempt_number=1,
|
|
)
|
|
|
|
def time_should_stop_others_fail_fast(self) -> None:
|
|
"""Benchmark should_stop_others with fail_fast."""
|
|
self._handler.should_stop_others(self._config_ff, self._failed_retriable)
|
|
|
|
def time_should_retry_retriable(self) -> None:
|
|
"""Benchmark should_retry for retriable error."""
|
|
self._handler.should_retry(self._config_retry, self._failed_retriable)
|
|
|
|
def time_should_retry_non_retriable(self) -> None:
|
|
"""Benchmark should_retry for non-retriable error."""
|
|
self._handler.should_retry(self._config_retry, self._failed_non_retriable)
|
|
|
|
|
|
class M4FixtureLoadSuite:
|
|
"""Benchmark loading M4 fixture files."""
|
|
|
|
def time_load_correction_flows(self) -> None:
|
|
"""Benchmark loading correction_flows.json."""
|
|
with open(_FIXTURES_DIR / "correction_flows.json") as f:
|
|
json.load(f)
|
|
|
|
def time_load_subplan_execution(self) -> None:
|
|
"""Benchmark loading subplan_execution.json."""
|
|
with open(_FIXTURES_DIR / "subplan_execution.json") as f:
|
|
json.load(f)
|
|
|
|
def time_load_conflict_simulations(self) -> None:
|
|
"""Benchmark loading conflict_simulations.json."""
|
|
with open(_FIXTURES_DIR / "conflict_simulations.json") as f:
|
|
json.load(f)
|
|
|
|
def time_load_all_fixtures(self) -> None:
|
|
"""Benchmark loading all M4 fixture files."""
|
|
for fname in (
|
|
"correction_flows.json",
|
|
"subplan_execution.json",
|
|
"conflict_simulations.json",
|
|
):
|
|
with open(_FIXTURES_DIR / fname) as f:
|
|
json.load(f)
|