diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c9d662fd..21ab39558 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] + +- **ACP to A2A module rename and symbol standardization** (#10583 — Epic #8569): Completed the systematic rename of legacy ACP (Agent Communication Protocol) references to A2A (Agent-to-Agent Protocol) throughout the cleveragents.a2a module. All 22 exported symbols now use proper A2A naming conventions per ADR-047. Verified: zero legacy `from cleveragents.acp` imports, no ACP-prefixed classes or functions remain in a2a module files, and all documentation strings reference A2A instead of ACP. - Fixed `ReactiveEventBus.emit()` exception handler to log the full exception message (`str(exc)`) and enable traceback forwarding (`exc_info=True`). Previously the handler logged only the exception type name (e.g. @@ -147,6 +149,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). counts and per-provider recommendations. ### Added +- **BDD test suite for ACP → A2A module rename** (#10995): Added `a2a_module_rename_standardization.feature` and its step definitions to validate the complete rename of all 22 exported symbols under ADR-047 naming conventions. Includes scenarios verifying export completeness, zero legacy ACP references in source files, and accurate documentation strings. - `agents actor context clear` command to reset actor message history and state while preserving the underlying context directory via `ContextManager` diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 51815111f..b6edbf5ff 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -20,6 +20,7 @@ Below are some of the specific details of various contributions. * HAL 9000 has contributed the bug-hunt-pool-supervisor non-blocking tracking fix: updated step 5 to be best-effort and added rule 9 to prevent the automation-tracking-manager call from blocking the main supervisor loop. * HAL 9000 has contributed the plugin entry point security hardening fix (#7476): enforced entry point allowlist validation before importing plugin modules to prevent malicious plugin loading. * HAL 9000 has contributed the benchmark workflow separation (#9040): moved the benchmark-regression job out of the default PR workflow into a dedicated scheduled workflow, reducing median PR CI turnaround time from 99-132 minutes to under 30 minutes. +* HAL 9000 has contributed the ACP → A2A BDD test suite (#10995 / issue #8615): added `a2a_module_rename_standardization.feature` with 3 scenarios validating all 22 exported symbol exports, zero legacy ACP references across the a2a module, and documentation accuracy per ADR-047 naming conventions. * HAL 9000 has contributed the agent-evolution-pool-supervisor PR metadata assignment (#7888): the supervisor now automatically looks up the Type/Automation label and earliest open milestone before dispatching improvement PR creation workers, ensuring all generated improvement PRs have correct Type labels and milestone assignments. * This project was made possible thanks to considerable donation of time, money, and resources by CleverThis, Inc. * HAL 9000 has contributed automated bug fixes, CLI output formatting improvements, and ongoing maintenance as part of the CleverAgents automation system. @@ -33,4 +34,5 @@ Below are some of the specific details of various contributions. * HAL 9000 has contributed the LLMTraceRepository data-integrity fix (PR #8185 / issue #7505): replaced the unconditional `session.commit()` in `LLMTraceRepository.save()` with a dual-path implementation that respects the UnitOfWork pattern — flushing only when an external session is provided, and flushing + committing + closing when operating standalone. This eliminates premature transaction commits, loss of rollback capability, and a docstring/implementation mismatch. * HAL 9000 has contributed the ACMS Index Data Model and File Traversal Engine (PR #9664 / issue #9579): foundational data structures for indexed context entries with hot/warm/cold/archive storage tier classification, tag system, and a timeout-safe chunked file traversal engine for large projects with 10,000+ files. -* HAL 9000 has contributed the error-suppression removal fix (PR #9247 / issue #9060): removed both `try...except Exception:` blocks in `register_registry_agents()` that silently suppressed errors from `actor_registry.list_actors()` and the route bridge refresh, enabling exceptions to propagate per CONTRIBUTING.md fail-fast policy. Added three Behave scenarios verifying RuntimeError, AttributeError, and TypeError propagation. \ No newline at end of file +* HAL 9000 has contributed the error-suppression removal fix (PR #9247 / issue #9060): removed both `try...except Exception:` blocks in `register_registry_agents()` that silently suppressed errors from `actor_registry.list_actors()` and the route bridge refresh, enabling exceptions to propagate per CONTRIBUTING.md fail-fast policy. Added three Behave scenarios verifying RuntimeError, AttributeError, and TypeError propagation. +* HAL 9000 has contributed the ACP to A2A module rename and symbol standardization (PR #10583 / issue #8569): completed the systematic rename of all legacy ACP references throughout the cleveragents.a2a module, standardizing all 22 exported symbols per ADR-047 naming conventions. Includes BDD test coverage for export completeness, ACP reference elimination scanning, and documentation accuracy verification. diff --git a/features/a2a_module_rename_standardization.feature b/features/a2a_module_rename_standardization.feature new file mode 100644 index 000000000..d92d7c32c --- /dev/null +++ b/features/a2a_module_rename_standardization.feature @@ -0,0 +1,48 @@ +@refactor_v360_acp_to_a2a_rename @epic_8569 +Feature: ACP to A2A module rename and symbol standardization + As a CleverAgents developer + I want the ACP → A2A module rename to be fully validated via BDD tests + So that no legacy ACP references remain and all exports follow ADR-047 naming + + Background: + Given the "a2a" Python package is importable from "cleveragents.a2a" + + Scenario: All 22 __all__ symbols are exported and importable via a2a package + When I import "cleveragents.a2a" + And all of the following 22 symbols should be importable from it: + | A2aError | + | A2aErrorDetail | + | A2aEvent | + | A2aEventQueue | + | A2aHttpTransport | + | A2aLocalFacade | + | A2aNotAvailableError | + | A2aOperationNotFoundError | + | A2aRequest | + | A2aResponse | + | A2aStdioTransport | + | A2aVersion | + | A2aVersionMismatchError | + | A2aVersionNegotiator | + | AuthClient | + | RemoteExecutionClient | + | ServerClient | + | ServerConnectionConfig| + | StubAuthClient | + | StubRemoteExecutionClient | + | StubServerClient | + | TransportSelector | + Then every symbol should resolve to a non-None object + And the count of exported symbols should equal 22 + + Scenario: Zero ACP references remain in the a2a module source files + When I recursively scan all Python files under "src/cleveragents/a2a" + And I search for the legacy prefix string "ACP" + Then zero instances of "ACP" should be found + And this confirms the complete ACP → A2A rename is clean + + Scenario: Documentation strings use A2A naming per ADR-047 + When I read the docstring of the "cleveragents.a2a" package + Then it should contain the term "A2A (Agent-to-Agent Protocol)" + And it should reference "ADRs" or "ADR-047" for standard adoption + And the docstring should NOT contain any mentions of "ACP protocol" diff --git a/features/steps/a2a_module_rename_standardization_steps.py b/features/steps/a2a_module_rename_standardization_steps.py new file mode 100644 index 000000000..eb963f063 --- /dev/null +++ b/features/steps/a2a_module_rename_standardization_steps.py @@ -0,0 +1,183 @@ +"""Step definitions for ACP → A2A module rename standardization BDD scenarios.""" + +from __future__ import annotations + +import os +import re +import sys +from typing import Any +from pathlib import Path + +from behave import given, then, when + + +# ── Helpers ──────────────────────────────────────────────────────────────── + +_ALL_SYMBOLS = [ + "A2aError", + "A2aErrorDetail", + "A2aEvent", + "A2aEventQueue", + "A2aHttpTransport", + "A2aLocalFacade", + "A2aNotAvailableError", + "A2aOperationNotFoundError", + "A2aRequest", + "A2aResponse", + "A2aStdioTransport", + "A2aVersion", + "A2aVersionMismatchError", + "A2aVersionNegotiator", + "AuthClient", + "RemoteExecutionClient", + "ServerClient", + "ServerConnectionConfig", + "StubAuthClient", + "StubRemoteExecutionClient", + "StubServerClient", + "TransportSelector", +] + + +def _resolve_repo_root(context: Any) -> Path: + """Return the repository root path from the feature context.""" + repo_root = getattr(context, "repo_root", None) + if repo_root is not None: + return Path(repo_root) + candidate = Path(os.getcwd()) + while candidate != candidate.parent: + if (candidate / ".git").exists(): + context.repo_root = str(candidate) + return candidate + candidate = candidate.parent + raise RuntimeError("Could not find repository root") + + +def _scan_dir_for_pattern(root: Path, pattern_str: str) -> int: + """Recursively count occurrences of *pattern_str* in all .py files.""" + count = 0 + py_files = list(root.rglob("*.py")) + for py_file in py_files: + try: + text = py_file.read_text(encoding="utf-8", errors="replace") + except OSError: + continue + count += text.count(pattern_str) + return count + + +# ── Given steps ──────────────────────────────────────────────────────────── + +@given('the "a2a" Python package is importable from "cleveragents.a2a"') +def step_a2a_importable(context: Any) -> None: + """Ensure cleveragents.a2a can be imported.""" + try: + import cleveragents.a2a # noqa: F401 + except ImportError as exc: + raise AssertionError(f"cleveragents.a2a could not be imported: {exc}") + + +# ── When steps ───────────────────────────────────────────────────────────── + +@when('I import "cleveragents.a2a"') +def step_import_a2a(context: Any) -> None: + """Import the a2a package and store it on context.""" + import cleveragents.a2a # noqa: F401 + context._a2a_module = cleveragents.a2a + + +@when("all of the following {count:d} symbols should be importable from it") +def step_symbols_importable(context: Any, count: int) -> None: + """Store all expected symbol names on context for later assertion.""" + assert hasattr(context._a2a_module, "__all__"), ( + "cleveragents.a2a must define __all__" + ) + symbols = list(_ALL_SYMBOLS) + context._expected_symbols = symbols + assert len(symbols) == count, f"Expected {count} symbols, got {len(symbols)}" + + +@when('I recursively scan all Python files under "src/cleveragents/a2a"') +def step_scan_a2a_python_files(context: Any) -> None: + """Set context for ACP-remnant scanning.""" + root = _resolve_repo_root(context) + a2a_dir = root / "src" / "cleveragents" / "a2a" + assert a2a_dir.is_dir(), f"a2a module directory not found at {a2a_dir}" + context._a2a_scan_root = str(a2a_dir) + + +@when("I search for the legacy prefix string \"ACP\"") +def step_search_acp_pattern(context: Any) -> None: + """Perform recursive scan and store results.""" + count = _scan_dir_for_pattern(Path(context._a2a_scan_root), "ACP") + context._acp_references_found = count + + +@when('I read the docstring of the "cleveragents.a2a" package') +def step_read_a2a_docstring(context: Any) -> None: + """Store the a2a package docstring on context.""" + import cleveragents.a2a as a2a_pkg + assert a2a_pkg.__doc__ is not None, "cleveragents.a2a has no __doc__" + context._a2a_docstring = a2a_pkg.__doc__ + + +# ── Then steps ───────────────────────────────────────────────────────────── + +@then('every symbol should resolve to a non-None object') +def step_all_symbols_resolved(context: Any) -> None: + """Assert every expected symbol is present and non-None.""" + module = context._a2a_module + missing = [] + for name in context._expected_symbols: + obj = getattr(module, name, None) + if obj is None: + missing.append(name) + assert not missing, f"Missing symbols: {missing}" + + +@then('the count of exported symbols should equal 22') +def step_symbol_count_is_22(context: Any) -> None: + """Assert __all__ has exactly 22 entries.""" + actual_all = context._a2a_module.__all__ + assert len(actual_all) == 22, ( + f"Expected 22 symbols in __all__, got {len(actual_all)}" + ) + + +@then("zero instances of \"ACP\" should be found") +def step_zero_acp_references(context: Any) -> None: + """Assert zero ACP remnants were found.""" + assert context._acp_references_found == 0, ( + f"Found {context._acp_references_found} ACP references — rename is incomplete" + ) + + +@then("this confirms the complete ACP → A2A rename is clean") +def step_rename_clean(context: Any) -> None: + """No additional assertion needed; marker step for clarity.""" + pass + + +@then('it should contain the term "A2A (Agent-to-Agent Protocol)"') +def step_docstring_has_descriptive_term(context: Any) -> None: + """Assert docstring contains the canonical descriptive term.""" + assert "A2A (Agent-to-Agent Protocol)" in context._a2a_docstring, ( + f"Docstring missing 'A2A (Agent-to-Agent Protocol)':\n{context._a2a_docstring[:500]}" + ) + + +@then('it should reference "ADRs" or "ADR-047" for standard adoption') +def step_docstring_references_adr(context: Any) -> None: + """Assert docstring mentions an ADR (ADR-047 for A2A std).""" + pattern = re.compile(r"(ADR-?0*47|A2A Standard Adoption)", re.IGNORECASE) + assert pattern.search(context._a2a_docstring), ( + f"Docstring does not reference ADR-047 or A2A Standard Adoption:\n{context._a2a_docstring[:500]}" + ) + + +@then('the docstring should NOT contain any mentions of "ACP protocol"') +def step_no_acp_protocol_mention(context: Any) -> None: + """Assert docstring does not reference ACP.""" + assert "ACP(protocol)" not in context._a2a_docstring and "ACP protocol" not in context._a2a_docstring, ( + f"Docstring contains legacy 'ACP protocol':\n{context._a2a_docstring[:500]}" + )