diff --git a/features/consolidated_tool.feature b/features/consolidated_tool.feature index 220217a9e..51b4bdfea 100644 --- a/features/consolidated_tool.feature +++ b/features/consolidated_tool.feature @@ -751,31 +751,31 @@ Feature: Consolidated Tool Scenario: Get a registered tool by name Given a tool registry - And a registered tool spec named "test/echo" + And a simple registered tool spec named "test/echo" When I get the tool by name "test/echo" Then the retrieved tool spec name should be "test/echo" Scenario: List all tools in the registry Given a tool registry - And a registered tool spec named "test/alpha" - And a registered tool spec named "test/beta" + And a simple registered tool spec named "test/alpha" + And a simple registered tool spec named "test/beta" When I list all tools Then the tool list should contain 2 tools Scenario: List tools filtered by namespace Given a tool registry - And a registered tool spec named "ns1/tool-a" - And a registered tool spec named "ns2/tool-b" - And a registered tool spec named "ns1/tool-c" + And a simple registered tool spec named "ns1/tool-a" + And a simple registered tool spec named "ns2/tool-b" + And a simple registered tool spec named "ns1/tool-c" When I list tools with namespace "ns1" Then the tool list should contain 2 tools Scenario: Remove a tool from the registry Given a tool registry - And a registered tool spec named "test/remove-me" + And a simple registered tool spec named "test/remove-me" When I remove the tool "test/remove-me" Then the removal should succeed And getting "test/remove-me" should return None @@ -799,7 +799,7 @@ Feature: Consolidated Tool Scenario: Duplicate registration raises ToolError Given a tool registry - And a registered tool spec named "test/duplicate" + And a simple registered tool spec named "test/duplicate" When I try to register a duplicate tool "test/duplicate" Then a ToolError should be raised with type "RegistrationError" @@ -821,7 +821,7 @@ Feature: Consolidated Tool Scenario: Full lifecycle discover activate execute deactivate Given a tool registry - And a registered tool spec named "test/lifecycle" + And a simple registered tool spec named "test/lifecycle" And a tool runner for the registry When I discover tools from the runner And I activate tool "test/lifecycle" @@ -866,7 +866,7 @@ Feature: Consolidated Tool Scenario: Execute rejects non-JSON-serialisable inputs Given a tool registry - And a registered tool spec named "test/json-check" + And a simple registered tool spec named "test/json-check" And a tool runner for the registry When I execute tool "test/json-check" with non-serialisable inputs Then the tool result should not be successful @@ -966,50 +966,50 @@ Feature: Consolidated Tool # ---- List Tools With tool_type Filter ---- - Scenario: List tools with tool_type filter returns matching tools + Scenario: List tools that has tool_type filter returns matching tools Given a tool registry - And a registered tool spec named "test/filtered" with tool_type "tool" - When I list tools with tool_type "tool" + And a registered tool spec named "test/filtered" that has tool_type "tool" + When I list tools that has tool_type "tool" Then the tool list should contain 1 tools - Scenario: List tools with tool_type validation returns only validations + Scenario: List tools that has tool_type validation returns only validations Given a tool registry - And a registered tool spec named "test/my-tool" with tool_type "tool" - And a registered tool spec named "test/my-validation" with tool_type "validation" - When I list tools with tool_type "validation" + And a registered tool spec named "test/my-tool" that has tool_type "tool" + And a registered tool spec named "test/my-validation" that has tool_type "validation" + When I list tools that has tool_type "validation" Then the tool list should contain 1 tools - Scenario: List tools with tool_type tool excludes validations + Scenario: List tools that has tool_type tool excludes validations Given a tool registry - And a registered tool spec named "test/plain-tool" with tool_type "tool" - And a registered tool spec named "test/plain-validation" with tool_type "validation" - When I list tools with tool_type "tool" + And a registered tool spec named "test/plain-tool" that has tool_type "tool" + And a registered tool spec named "test/plain-validation" that has tool_type "validation" + When I list tools that has tool_type "tool" Then the tool list should contain 1 tools Scenario: List tools without tool_type filter returns all tools Given a tool registry - And a registered tool spec named "test/all-tool" with tool_type "tool" - And a registered tool spec named "test/all-validation" with tool_type "validation" + And a registered tool spec named "test/all-tool" that has tool_type "tool" + And a registered tool spec named "test/all-validation" that has tool_type "validation" When I list all tools Then the tool list should contain 2 tools - Scenario: List tools with tool_type None returns all tools + Scenario: List tools that has tool_type None returns all tools Given a tool registry - And a registered tool spec named "test/none-tool" with tool_type "tool" - And a registered tool spec named "test/none-validation" with tool_type "validation" + And a registered tool spec named "test/none-tool" that has tool_type "tool" + And a registered tool spec named "test/none-validation" that has tool_type "validation" When I list all tools Then the tool list should contain 2 tools Scenario: ToolSpec default tool_type is tool Given a tool registry - And a registered tool spec named "test/default-type" - When I list tools with tool_type "tool" + And a simple registered tool spec named "test/default-type" + When I list tools that has tool_type "tool" Then the tool list should contain 1 tools Scenario: ToolSpec with validation tool_type is excluded from tool filter Given a tool registry - And a registered tool spec named "test/excl-validation" with tool_type "validation" - When I list tools with tool_type "tool" + And a registered tool spec named "test/excl-validation" that has tool_type "validation" + When I list tools that has tool_type "tool" Then the tool list should contain 0 tools diff --git a/features/repositories_uncovered_lines.feature b/features/repositories_uncovered_lines.feature index e2d055e60..7d4b16720 100644 --- a/features/repositories_uncovered_lines.feature +++ b/features/repositories_uncovered_lines.feature @@ -183,7 +183,7 @@ Feature: Repository uncovered lines coverage Scenario: ToolRepository add raises InvalidToolTypeError for bad tool_type Given a tool repository backed by an in-memory database for uncovered lines - And a tool domain object with tool_type "bogus" for uncovered lines + And a tool domain object that has tool_type "bogus" for uncovered lines When the tool is added to the repository for uncovered lines invalid type Then an InvalidToolTypeError should be raised for uncovered lines diff --git a/features/steps/devcontainer_handler_steps.py b/features/steps/devcontainer_handler_steps.py index 4e7b74b3f..50849ace8 100644 --- a/features/steps/devcontainer_handler_steps.py +++ b/features/steps/devcontainer_handler_steps.py @@ -269,7 +269,9 @@ def step_add_named_dc(context: Context, name: str) -> None: (named_dir / "devcontainer.json").write_text(_VALID_DC_JSON, encoding="utf-8") -@given('the directory has a named devcontainer configuration "{name}" with invalid JSON') +@given( + 'the directory has a named devcontainer configuration "{name}" with invalid JSON' +) def step_add_named_dc_invalid(context: Context, name: str) -> None: tmp = Path(context.tmp_path) named_dir = tmp / ".devcontainer" / name @@ -308,6 +310,4 @@ def step_check_first_result_no_config_name(context: Context) -> None: @then('the result config names should include "{name}"') def step_check_result_config_names_include(context: Context, name: str) -> None: names = {r.config_name for r in context.discovery_results} - assert name in names, ( - f"Expected {name!r} in config names, got {names!r}" - ) + assert name in names, f"Expected {name!r} in config names, got {names!r}" diff --git a/features/steps/domain_repository_protocols_steps.py b/features/steps/domain_repository_protocols_steps.py index dc264475a..f08fe962f 100644 --- a/features/steps/domain_repository_protocols_steps.py +++ b/features/steps/domain_repository_protocols_steps.py @@ -12,7 +12,6 @@ from typing import Any from behave import given, then, when - # --------------------------------------------------------------------------- # Background # --------------------------------------------------------------------------- diff --git a/features/steps/plan_cli_spec_alignment_steps.py b/features/steps/plan_cli_spec_alignment_steps.py index 694caa8f9..0c495b911 100644 --- a/features/steps/plan_cli_spec_alignment_steps.py +++ b/features/steps/plan_cli_spec_alignment_steps.py @@ -337,7 +337,7 @@ def step_plan_list_no_filters(context: Context) -> None: """ import cleveragents.cli.commands.plan as _plan_mod - wide_runner = CliRunner(mix_stderr=False) + wide_runner = CliRunner() original_width = _plan_mod.console._width _plan_mod.console._width = 200 try: diff --git a/features/steps/resource_registry_service_coverage_steps.py b/features/steps/resource_registry_service_coverage_steps.py index da3eb757f..9f4789fdd 100644 --- a/features/steps/resource_registry_service_coverage_steps.py +++ b/features/steps/resource_registry_service_coverage_steps.py @@ -464,7 +464,9 @@ def step_verify_rt_eq(context: Any) -> None: @given('a resource type DB row with namespace "{namespace}" and name "{name}"') -def step_db_row_with_namespace_and_name(context: Any, namespace: str, name: str) -> None: +def step_db_row_with_namespace_and_name( + context: Any, namespace: str, name: str +) -> None: """Create an in-memory DB row with the given namespace and name.""" engine, factory = _in_memory_session_factory() context.ns_builtin_engine = engine diff --git a/features/steps/skills_registry_coverage_boost_steps.py b/features/steps/skills_registry_coverage_boost_steps.py index 1ee7c52ba..c343b32fd 100644 --- a/features/steps/skills_registry_coverage_boost_steps.py +++ b/features/steps/skills_registry_coverage_boost_steps.py @@ -293,7 +293,6 @@ def step_validate_skill_with_ref(context: Context, ref: str) -> None: context.validation_errors = context.skill_reg.validate_skill(defn) - @when('I validate a skill definition that includes unregistered skill "{include_name}"') def step_validate_skill_unregistered_include( context: Context, include_name: str diff --git a/features/steps/tdd_cli_incomplete_subcommand_registration_steps.py b/features/steps/tdd_cli_incomplete_subcommand_registration_steps.py index ff29b04e8..2dc74a05d 100644 --- a/features/steps/tdd_cli_incomplete_subcommand_registration_steps.py +++ b/features/steps/tdd_cli_incomplete_subcommand_registration_steps.py @@ -22,7 +22,7 @@ from behave import given, then, when # type: ignore[import-untyped] from behave.runner import Context # type: ignore[import-untyped] from typer.testing import CliRunner -runner = CliRunner(mix_stderr=False) +runner = CliRunner() @given("the CLI subcommand import raises an ImportError during registration") @@ -72,7 +72,7 @@ def step_then_non_zero_exit(context: Context) -> None: @then('the error output contains "Failed to register subcommands"') def step_then_error_message(context: Context) -> None: """Assert: the error message must be present in the output.""" - # CliRunner with mix_stderr=False separates stdout and stderr. + # CliRunner now always separates stdout and stderr (as of Click 8.2+). # The error is printed to stderr via get_err_console(). combined = (context.cli_result.output or "") + ( getattr(context.cli_result, "stderr", "") or "" diff --git a/features/steps/tdd_tool_runner_env_precedence_steps.py b/features/steps/tdd_tool_runner_env_precedence_steps.py index 57d266971..8c3835c43 100644 --- a/features/steps/tdd_tool_runner_env_precedence_steps.py +++ b/features/steps/tdd_tool_runner_env_precedence_steps.py @@ -74,11 +74,13 @@ def step_runner_no_resources(context: Context) -> None: # --------------------------------------------------------------------------- -@when('I execute the tool with plan_env "{plan_env}" and plan_priority "{plan_priority}"') +@when( + 'I execute the tool with plan_env "{plan_env}" and plan_priority "{plan_priority}"' +) def step_execute_with_plan_env_priority( context: Context, plan_env: str, plan_priority: str ) -> None: - # Patch validate_container_available to avoid real container checks + # Patch validate_container_available to avoid real container checks with patch.object( context.resolver, "validate_container_available", @@ -106,7 +108,9 @@ def step_execute_with_plan_env_priority( context.result = result -@when('I execute the tool with project_env "{project_env}" and project_priority "{project_priority}"') +@when( + 'I execute the tool with project_env "{project_env}" and project_priority "{project_priority}"' +) def step_execute_with_project_env_priority( context: Context, project_env: str, project_priority: str ) -> None: @@ -242,6 +246,4 @@ def step_devcontainer_not_used(context: Context) -> None: @then("the devcontainer was used") def step_devcontainer_was_used(context: Context) -> None: - assert context.devcontainer_used, ( - "Expected devcontainer to be used, but it was not" - ) + assert context.devcontainer_used, "Expected devcontainer to be used, but it was not" diff --git a/features/steps/tool_runtime_steps.py b/features/steps/tool_runtime_steps.py index 48d396c7d..293a43825 100644 --- a/features/steps/tool_runtime_steps.py +++ b/features/steps/tool_runtime_steps.py @@ -58,7 +58,7 @@ def step_given_tool_spec_with_handler(context: Any, name: str) -> None: ) -@given('a registered tool spec named "{name}"') +@given('a simple registered tool spec named "{name}"') def step_given_registered_tool_spec(context: Any, name: str) -> None: spec = ToolSpec( name=name, @@ -68,7 +68,7 @@ def step_given_registered_tool_spec(context: Any, name: str) -> None: context.registry.register(spec) -@given('a registered tool spec named "{name}" with tool_type "{tt}"') +@given('a registered tool spec named "{name}" that has tool_type "{tt}"') def step_given_registered_tool_spec_with_type(context: Any, name: str, tt: str) -> None: spec = ToolSpec( name=name, diff --git a/features/validation_attach_type_guard.feature b/features/validation_attach_type_guard.feature index e1ab42831..9d80d7b50 100644 --- a/features/validation_attach_type_guard.feature +++ b/features/validation_attach_type_guard.feature @@ -9,26 +9,26 @@ Feature: Validation attach rejects plain Tools # --- TDD red phase: plain Tool must be rejected --- - Scenario: Attach rejects a plain Tool registered with tool_type "tool" - Given a plain tool "local/my-plain-tool" is registered with tool_type "tool" + Scenario: Attach rejects a plain Tool registered that has tool_type "tool" + Given a plain tool "local/my-plain-tool" is registered that has tool_type "tool" When I invoke validation attach "local/my-plain-tool" to "git-checkout/my-repo" Then the validation attach should be rejected And the rejection output should contain "plain Tool" - Scenario: Attach rejects a plain Tool registered as a dict with tool_type "tool" - Given a plain tool dict "local/dict-tool" is registered with tool_type "tool" + Scenario: Attach rejects a plain Tool registered as a dict that has tool_type "tool" + Given a plain tool dict "local/dict-tool" is registered that has tool_type "tool" When I invoke validation attach "local/dict-tool" to "git-checkout/my-repo" Then the validation attach should be rejected And the rejection output should contain "plain Tool" # --- Happy path: genuine Validation attaches successfully --- - Scenario: Attach accepts a genuine Validation with tool_type "validation" - Given a genuine validation "local/coverage-check" is registered with tool_type "validation" + Scenario: Attach accepts a genuine Validation that has tool_type "validation" + Given a genuine validation "local/coverage-check" is registered that has tool_type "validation" When I invoke validation attach "local/coverage-check" to "git-checkout/my-repo" Then the validation attach should succeed - Scenario: Attach accepts a genuine Validation registered as a dict with tool_type "validation" - Given a genuine validation dict "local/lint-check" is registered with tool_type "validation" + Scenario: Attach accepts a genuine Validation registered as a dict that has tool_type "validation" + Given a genuine validation dict "local/lint-check" is registered that has tool_type "validation" When I invoke validation attach "local/lint-check" to "git-checkout/my-repo" Then the validation attach should succeed diff --git a/robot/helper_a2a_facade_wiring.py b/robot/helper_a2a_facade_wiring.py index 39c3e0359..32ba51a11 100644 --- a/robot/helper_a2a_facade_wiring.py +++ b/robot/helper_a2a_facade_wiring.py @@ -216,9 +216,12 @@ def wired_event_subscribe() -> None: def wired_error_mapping() -> None: """Verify domain-to-A2A error code mapping.""" from cleveragents.a2a import errors as _a2a_errors + cases: list[tuple[Exception, int]] = [ - (ResourceNotFoundError(resource_type="x", resource_id="1"), - _a2a_errors.NOT_FOUND), + ( + ResourceNotFoundError(resource_type="x", resource_id="1"), + _a2a_errors.NOT_FOUND, + ), (ValidationError("bad"), _a2a_errors.VALIDATION_ERROR), (PlanError("fail"), _a2a_errors.PLAN_ERROR), (BusinessRuleViolation("invalid"), _a2a_errors.INVALID_STATE), diff --git a/robot/helper_acms_pipeline.py b/robot/helper_acms_pipeline.py index d3c12dba9..836d5deae 100644 --- a/robot/helper_acms_pipeline.py +++ b/robot/helper_acms_pipeline.py @@ -409,7 +409,8 @@ def _cmd_skeleton_context_inheritance() -> int: actual_tokens = sum(f.token_count for f in payload.skeleton_fragments) if actual_tokens > expected_budget: print( - f"acms-fail: skeleton tokens {actual_tokens} exceed budget {expected_budget}" + f"acms-fail: skeleton tokens {actual_tokens} exceed budget " + f"{expected_budget}" ) return 1 diff --git a/robot/helper_automation_profile_cli.py b/robot/helper_automation_profile_cli.py index b0c4ec8b3..d81077983 100644 --- a/robot/helper_automation_profile_cli.py +++ b/robot/helper_automation_profile_cli.py @@ -187,9 +187,7 @@ def test_list_json() -> None: f"Output: {result.output[:300]}" ) # Validate profiles wrapper - assert "profiles" in parsed, ( - f"Missing 'profiles' key. Keys: {list(parsed.keys())}" - ) + assert "profiles" in parsed, f"Missing 'profiles' key. Keys: {list(parsed.keys())}" profiles = parsed["profiles"] assert isinstance(profiles, list), ( f"'profiles' must be a list, got {type(profiles)}" @@ -204,9 +202,7 @@ def test_list_json() -> None: "Full profile dict leaked into list output (found 'phase_transitions')" ) # Validate summary - assert "summary" in parsed, ( - f"Missing 'summary' key. Keys: {list(parsed.keys())}" - ) + assert "summary" in parsed, f"Missing 'summary' key. Keys: {list(parsed.keys())}" summary = parsed["summary"] assert "built_in" in summary, f"Missing 'built_in' in summary: {summary}" assert "total" in summary, f"Missing 'total' in summary: {summary}" diff --git a/robot/helper_devcontainer_handler.py b/robot/helper_devcontainer_handler.py index 9b872cf56..7492d62cf 100644 --- a/robot/helper_devcontainer_handler.py +++ b/robot/helper_devcontainer_handler.py @@ -191,7 +191,6 @@ def cmd_result_validation() -> None: print("result-validation-ok") - def cmd_discovery_named_single() -> None: """Discover a single named devcontainer configuration.""" with tempfile.TemporaryDirectory() as tmp: @@ -269,6 +268,7 @@ def cmd_discovery_named_config_name_attr() -> None: ) print("discovery-named-config-name-attr-ok") + _COMMANDS = { "protocol-check": cmd_protocol_check, "strategy-check": cmd_strategy_check, diff --git a/src/cleveragents/domain/repositories/__init__.py b/src/cleveragents/domain/repositories/__init__.py index f0bf4a371..2272f04d3 100644 --- a/src/cleveragents/domain/repositories/__init__.py +++ b/src/cleveragents/domain/repositories/__init__.py @@ -15,7 +15,7 @@ allows persistence backends to be swapped without touching application code. | ``LifecyclePlanRepositoryProtocol`` | ``Plan`` | ``LifecyclePlanRepository`` | | ``ActionRepositoryProtocol`` | ``Action`` | ``ActionRepository`` | | ``DecisionRepositoryProtocol`` | ``Decision`` | ``DecisionRepository`` | -| ``ProjectRepositoryProtocol`` | ``NamespacedProject`` | ``NamespacedProjectRepository`` | +| ``ProjectRepositoryProtocol`` | ``NamespacedProject`` | ``NamespacedProjectRepo`` | ## Usage diff --git a/src/cleveragents/domain/repositories/decision_repository.py b/src/cleveragents/domain/repositories/decision_repository.py index 14ea5955d..25fca280a 100644 --- a/src/cleveragents/domain/repositories/decision_repository.py +++ b/src/cleveragents/domain/repositories/decision_repository.py @@ -91,6 +91,7 @@ class DecisionRepositoryProtocol(Protocol): List of superseded ``Decision`` domain objects. """ ... + def delete(self, decision_id: str) -> bool: """Delete a decision by its ULID. diff --git a/src/cleveragents/infrastructure/database/repositories.py b/src/cleveragents/infrastructure/database/repositories.py index 504ae7789..d94119239 100644 --- a/src/cleveragents/infrastructure/database/repositories.py +++ b/src/cleveragents/infrastructure/database/repositories.py @@ -79,16 +79,6 @@ from cleveragents.core.exceptions import ( DatabaseError, ) from cleveragents.core.retry_patterns import retry_database_operation as database_retry -from cleveragents.domain.repositories.action_repository import ActionRepositoryProtocol -from cleveragents.domain.repositories.decision_repository import ( - DecisionRepositoryProtocol, -) -from cleveragents.domain.repositories.plan_repository import ( - LifecyclePlanRepositoryProtocol, -) -from cleveragents.domain.repositories.project_repository import ( - ProjectRepositoryProtocol, -) from cleveragents.domain.models.core import ( Actor, Change, @@ -99,6 +89,16 @@ from cleveragents.domain.models.core import ( ProjectSettings, ) from cleveragents.domain.models.core.skill import Skill +from cleveragents.domain.repositories.action_repository import ActionRepositoryProtocol +from cleveragents.domain.repositories.decision_repository import ( + DecisionRepositoryProtocol, +) +from cleveragents.domain.repositories.plan_repository import ( + LifecyclePlanRepositoryProtocol, +) +from cleveragents.domain.repositories.project_repository import ( + ProjectRepositoryProtocol, +) from cleveragents.infrastructure.database.models import ( ActorModel, AutomationProfileModel, @@ -1259,7 +1259,8 @@ class PlanNotFoundError(DatabaseError): class LifecyclePlanRepository(LifecyclePlanRepositoryProtocol): """Repository for v3 lifecycle plan persistence. - Implements :class:`~cleveragents.domain.repositories.LifecyclePlanRepositoryProtocol` + Implements + :class:`~cleveragents.domain.repositories.LifecyclePlanRepositoryProtocol` — the domain-layer port for lifecycle plan persistence. Uses a session-factory pattern: each public method obtains its own diff --git a/src/cleveragents/tool/runner.py b/src/cleveragents/tool/runner.py index 9f6dbcd34..3e088924c 100644 --- a/src/cleveragents/tool/runner.py +++ b/src/cleveragents/tool/runner.py @@ -336,9 +336,7 @@ class ToolRunner: # Validate container availability when container execution is # resolved (mirrors the old resolve_and_validate contract). if env.value in ("container", "container_ref"): - self._env_resolver.validate_container_available( - _linked, project_name - ) + self._env_resolver.validate_container_available(_linked, project_name) except ContainerUnavailableError as exc: if pref.mode == EnvironmentPreferenceMode.REQUIRED: logger.info(