Files
brent.edwards 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
fix(test): correct mock targets, method names, ULIDs, and CLI args in M4 smoke suite
- 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.
2026-02-26 02:01:47 +00:00

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)