The non-rich output branch of list_profiles() in
src/cleveragents/cli/commands/automation_profile.py has been refactored
to produce the spec-required envelope rather than a flat list of full
profile objects. The new envelope structure is:
{"profiles": [...simplified...], "summary": {"built_in": N, "custom": N, "total": N}}
Where profiles entries now contain only five fields: name, source,
select_tool, sandbox, and description.
Key changes:
- Profiles in the profiles array are reduced to match the exact spec
(name, source, select_tool, sandbox, description). Full details are
preserved for the show command via the existing _profile_spec_dict().
- The summary object aggregates counts after namespace/regex filtering
so the numbers accurately reflect what is being displayed.
- The rich table column header renamed from 'Select Tool' to 'Auto-Apply'
per spec line 16946, and a Summary panel is appended to the rich output
showing Built-in / Custom / Total counts per spec lines 16959-16963.
- Behave feature file updated with new scenarios covering JSON/YAML output
structure, rich table column header, and Summary panel.
- New step definitions include a comprehensive profiles-wrapper-with-summary
step that validates the full spec-required structure.
- Robot Framework helper test_list_json() updated to validate the new dict
structure with profiles wrapper and summary instead of the old flat list.
ISSUES CLOSED: #2064
Add a2a-sdk>=0.3.0 to [project.dependencies] in pyproject.toml.
The specification mandates that both local (stdio) and server (HTTP)
transports use the A2A Python SDK (ADR-047). Previously the package
was absent from pyproject.toml and uv.lock, making the project
non-compliant with the spec requirement.
Changes:
- Add 'a2a-sdk>=0.3.0' to [project.dependencies] in pyproject.toml
- Regenerate uv.lock to include a2a-sdk 0.3.25 and its transitive deps
- Add Behave scenarios confirming a2a is importable as a project dependency
- Add step definitions for the new TDD scenarios
ISSUES CLOSED: #2922
Add explicit aiohttp>=3.13.4 dependency constraint to pyproject.toml to
remediate CVE-2026-34515, a high-severity open redirect vulnerability in
aiohttp that affects the A2A server HTTP transport, MCP tool source
fetching, and agent communication layers.
The uv.lock already resolves aiohttp to 3.13.5 which satisfies the
>=3.13.4 constraint. Adding the explicit constraint ensures vulnerable
versions (<3.13.4) cannot be installed even if upstream transitive
dependency constraints are loosened.
ISSUES CLOSED: #1544
- Add `agents tui` command wiring and Textual app scaffolding for interactive TUI startup.
- Implement TUI persona schema/registry/state with local YAML persistence and per-session persona binding.
- Add three input-mode flows: Normal (`@` references), Command (`/` slash commands), and Shell (`!` passthrough).
- Introduce TUI widgets/overlays for prompt, persona bar, reference picker, and slash command interactions.
- Extend REPL command routing to support persona/session commands and reference/shell dispatch behavior.
- Add test coverage: Behave features + step definitions, Robot TUI smoke test, and ASV fuzzy-reference benchmark.
ISSUES CLOSED: #695
Wire per-service retry policies and circuit breakers into the service
layer via ServiceRetryWiring, backed by ServiceRetryPolicyRegistry and
configurable through Settings environment variables.
Production hardening from code review:
- Fix TOCTOU race in CircuitBreaker._on_success (half-open state)
- Add half-open probe limit to prevent unbounded concurrent requests
- Track all exception types for circuit breaker failure counting
- Detect async callables wrapped in functools.partial and callable objects
- Enforce spec-compliant 2s minimum for linear backoff strategy
- Enforce 0.1s floor for fixed backoff strategy
- Add retry amplification guard via contextvars nesting depth tracking
- Cap total retry wall-clock time at 300s (MAX_RETRY_TOTAL_TIMEOUT)
- Sanitize exception messages in retry logs to prevent secret leakage
- Fix wrap_service_method TOCTOU by holding cache lock for full operation
- Deep-copy default policies to prevent cross-policy mutation
- Warn on unknown override keys in apply_overrides
- Guard apply_overrides against non-dict and deeply nested JSON values
- Read circuit breaker state under lock in is_circuit_open
- Catch RecursionError in JSON config parsing
- Add total_timeout + nesting guard to retry_service_operation decorator
- Extend secret sanitization to Authorization headers, private_key,
connection_string, and access_key patterns
- Enforce 0.1s floor on jitter backoff strategy
- Cache wait strategies per service in ServiceRetryWiring (M3)
- Reset failure_count to 0 when entering half-open from open (M6)
- Use cached _get_wait_strategy() in execute()/async_execute()
- Move circuit-open logging out of _on_failure lock scope to prevent
holding the lock during potentially slow I/O (F1)
- Pass total_timeout=MAX_RETRY_TOTAL_TIMEOUT to wrap_service_method
retry_service_operation call for consistency with execute() (F4)
- Capture failure_count into local variable inside lock scope before
logging outside the lock, preventing stale reads from concurrent
threads in CircuitBreaker.call() and async_call() (F1)
- Deep-copy module-level DEFAULT_DATABASE_RETRY and DEFAULT_CIRCUIT_BREAKER
in ServiceRetryPolicyRegistry.get() for auto-generated unknown service
policies, preventing shared mutable state corruption (F1)
- Unify CircuitBreaker to a single threading.Lock for sync and async (P1-1)
- Restore BaseException permit in half-open path to prevent permit leak (P1-6)
- Prevent CircuitBreakerOpen cascading into failure_count (S2)
- Protect all logger calls with contextlib.suppress (S3, S4)
- Replace time.time() with time.monotonic() for monotonic timing (S5)
- Add distinct log events for half-open and closed transitions (S11, S12)
- Track pre-existing services so second apply_settings_defaults only
targets newly registered services (P1-2)
- Lazy circuit breaker creation via _get_or_create_cb() (P1-3)
- Reject async callables in sync execute() with TypeError (P1-5)
- Strengthen retry predicate to retry_if_exception_type(Exception) &
retry_if_not_exception_type(CircuitBreakerOpen) (S1)
- Add lock on _get_wait_strategy cache access (P2-16)
- Truncate raw JSON to 80 chars in override warning (P2-17)
- Warn on non-dict JSON overrides (P2-29)
- Debug log for nesting guard bypass (S13)
- Deep-copy from get() and all_policies() in registry (P1-4)
- Thread-safe registry with threading.Lock (P2-15)
- Robust exception handling in apply_overrides get() (P2-18)
- Log ValidationError details on override failure (P2-19)
- Sanitize service_name via _safe_service_name() (P2-28)
- Warn on non-dict sub-key values in overrides (P2-30)
- Allowlist for is_read_only_plan_operation phases (P2-10)
- Cap retry_auto_debug sleep at 60s (P2-11)
- Use is-not-None instead of falsy checks for error values (P2-12)
- Extend secret regex with bearer, session_id, auth_token,
refresh_token, client_secret patterns (P2-25)
- Pre-truncate error messages to 2000 chars before regex (P2-26)
- Add upper bounds on retry Settings fields (P2-7)
- Add cross-field validator max_delay >= base_delay (P2-8)
- Case-insensitive backoff strategy validation (P2-21)
- Add half_open_max_successes setting (S10)
- Remove phantom ContextFragment from services __all__ (ImportError fix)
- Export ServiceRetryWiring from application.services package
- Include sanitised error context in TypeError logging fallback
- Initialise RetryContext.attempt_count to 1 for bare context-manager usage
- Introduce CircuitBreakerState StrEnum replacing raw string literals
- Fix vacuous CircuitBreakerOpen propagation assertions in BDD steps
- Replace tautological logging test with structlog capture verification
- Assert circuit breaker existence instead of silently skipping on None
- Add Unicode control-char rejection validator to ServiceRetryPolicy.service_name
- Add name parameter with service= in all log calls
- Add extra="forbid" to all 3 Pydantic models
- Deep-copy _SERVICE_DEFAULTS construction
- Key normalisation (.strip()) in get() and apply_overrides()
- Add cooldown <= recovery_timeout validator
- Async guard on RetryContext.execute()
- Nesting guard on RetryContext.execute()/async_execute()
- stop_after_delay(300.0) on RetryContext
- retry_auto_debug async-only guard, dict result fix, sleep guard
- Retry-attempt logging in RetryContext
- Module-level docs for contextlib.suppress(TypeError) rationale
- Exhaustion log on retry failure
- Startup log in __init__; name=service_name to CircuitBreaker
- log_after_retry guarded to not fire on first-attempt success
- get_retry_decorator now includes logging callbacks
- Changed retry_backoff_strategy from str to RetryStrategy StrEnum
Closes#313
Replace coverage.py (sys.settrace-based) with slipcover (bytecode-based
instrumentation) for significantly faster coverage collection:
- Each behave-parallel worker runs under slipcover, producing per-feature
JSON coverage files with unique UUIDs to avoid write contention.
- After all workers finish, slipcover --merge combines per-worker data
into a single build/coverage.json report.
- XML report generated via slipcover --merge --xml for CI tooling.
- Terminal report with --fail-under=97 threshold enforcement.
- Robust JSON key-fallback logic handles both slipcover and coverage.py
output formats.
- CI workflow (ci.yml, nightly-quality.yml) updated with defensive key
lookup instead of hardcoded coverage.py format.
- Documentation updated to reflect slipcover as the coverage tool.
- CHANGELOG.md updated.
ISSUES CLOSED: #482
behave-parallel pulls behave>=1.2.6 which resolves to 1.3.3. Behave
1.3.3 no longer strips trailing colons from step text before tables,
breaking the architecture.feature step matcher.
This commit adds JSON/YAML schemas, Python stubs, fixture examples, and comprehensive test coverage for data contracts across all modules (auth, AI models, contexts, plans, orgs, etc.). Implements automated validation through Behave and