- Fix unsorted imports in resource_type_inheritance_cycle_detection_steps.py (ruff I001)
- Add missing step definition for 'the creation should fail with "X" or "Y"' pattern
- Wire detect_inheritance_cycles() with registry in step definitions so multi-level
cycles (A→B→A, A→B→C→A) are properly detected during BDD test execution
- Add detect_inheritance_cycles() function to _resource_type_validation.py
- Function detects both direct self-inheritance (A→A) and multi-level cycles (A→B→A, A→B→C→A)
- Add BDD tests for cycle detection scenarios
- Tests cover direct self-inheritance, two-level cycles, three-level cycles, and valid chains
features/lsp_actor_service_wiring.feature scenarios "handles multiple
LSP servers" and "tool specs have correct schema": add an explicit
`| CAPABILITIES |` header to the capability tables. Behave treats the
first table row as the heading, so `| DIAGNOSTICS |` (the only row)
was being silently dropped, leaving the registered server with zero
capabilities and the adapter generating no tool specs.
features/steps/lsp_actor_service_steps.py: strip surrounding double
quotes from each entry in the comma-separated `fields` placeholder of
the `requires "..."` Then step so a feature line like `requires
"file_path", "line", "column"` resolves to the three unquoted field
names rather than `file_path"`, `"line"`, `"column"`.
features/steps/tui_persona_cycle_steps.py: include the surrounding
double quotes in the step pattern for "the registry last persona
should be set to ..." so the feature literal `"p2"` matches as `p2`
(without the quotes the placeholder captured `"p2"` and the equality
check against the registry value failed).
src/cleveragents/tui/persona/registry.py: reject absolute paths from
`resolve_export_path` and `resolve_import_path` with the messages the
"Persona export/import rejects absolute path targets" scenarios in
features/repl_input_modes.feature expect. The previous behaviour
silently accepted absolute paths, defeating the working-directory
sandboxing intent.
ISSUES CLOSED: #5663
LspRuntime.__init__ and LspActorService.__init__ used ``x or Y()`` to
default the registry/runtime kwargs. LspRegistry defines __len__, so an
empty instance is falsy, and the OR silently discarded a caller-supplied
empty registry — making the constructor parameter unusable. Replace with
explicit ``is None`` checks so callers can inject collaborators at
construction time. The previous workaround in lsp_actor_service_steps.py
reached into ``service._runtime._registry`` to compensate; the steps now
inject via the public LspRuntime + LspActorService constructors, no
private-attribute access.
Also deconflict three behave AmbiguousStep collisions in the bundled TUI
persona work that prevented behave-parallel from registering any step
definitions (the unit_tests gate was aborting at load time):
* tui_persona_cycle_steps.py duplicated the registry-setup and active-
persona steps already defined in tui_persona_system_steps.py — drop
the duplicates and let the system file own them.
* tui_persona_state_coverage_steps.py / .feature shared
``the registry last persona should be set to "X"`` with
tui_persona_cycle_steps.py while asserting on a different mock —
rename the coverage step to ``the mock registry set_last_persona
should have been called with "X"``.
* lsp_actor_service_steps.py registered the "actor bindings are
activated" step under @when only; the deactivate scenario uses it
after a ``Given/And`` chain, so behave inherited Given and the step
was undefined. Register the same handler under both @given and
@when.
Reformat three files that ``ruff format --check`` flagged
(tui_persona_cycle_steps.py, tui_persona_state_coverage_steps.py via
the rename, tui/persona/state.py) so the lint gate goes green.
ISSUES CLOSED: #5663
- Replace standard logging with structlog in LspActorService to fix typecheck errors (structlog uses keyword arguments for structured logging, not positional like stdlib logging)
- Fix LspServerConfig command field: use str not list[str] in test step definitions
- Add _MockLifecycleManager stub to prevent real LSP server process spawning during unit tests
- Rename duplicate step "a clean LSP registry" to "a clean LSP actor service registry" to avoid conflict with lsp_registry_steps.py
- Fix B904 lint error: raise ValueError from None in except clause
- Add LspActorService to manage LSP server lifecycle for actors
- Implement activate_actor_bindings() to start servers and generate tool specs
- Implement deactivate_actor_bindings() to release server references
- Add BDD tests for LSP actor service wiring
- Add step definitions for LSP actor service tests
Fixes#5663
- Replace deprecated typing imports (Dict, Callable, Generic) with
collections.abc.Callable and built-in dict
- Convert Command from ABC to plain base class (B024: no abstract methods)
- Convert CommandHandler to PEP 695 type parameter syntax (UP046)
- Remove unused PlanService/ProjectService imports from command_registry
- Fix ruff format: blank line before nested defs in command_registry and steps
- Rename @then('a ValueError should be raised') to domain-specific suffix
to avoid AmbiguousStep collision with lsp_registry_steps.py
ISSUES CLOSED: #8880
Implemented a command bus architecture to decouple CLI command handling from application services. Added command_bus.py with Command, CommandHandler, and CommandBus classes, and command_registry.py to register handlers. Introduced BDD tests at features/cli_command_bus_decoupling.feature and corresponding step definitions in features/steps/cli_command_bus_steps.py to verify the decoupling behavior.
ISSUES CLOSED: #8880
Restores green unit_tests by removing the duplicate Pydantic virtual-resource
implementation that had no production consumers and was causing behave step
collisions, fixing parse-library step patterns that never matched, and giving
the failing-test scenarios concrete step definitions.
Changes:
- Remove unused parallel implementation `src/cleveragents/domain/models/core/
virtual_resource.py`, its feature file `features/virtual_resource_types.feature`,
and its step file `features/steps/virtual_resource_types_steps.py`. The
canonical `src/cleveragents/resource/virtual.py` (re-exported by
`src/cleveragents/resource/__init__.py`) is the only public API; the
Pydantic copy had zero non-test consumers and its step file duplicated
step text patterns (e.g., `the computed value should be ...`), triggering
`behave.step_registry.AmbiguousStep` errors at module load.
- Fix `VirtualResource.__init__` name validation in
`src/cleveragents/resource/virtual.py`: replace the
`name.replace("-", "").replace("_", "").isalnum()` check with a single
regex `^[a-zA-Z][a-zA-Z0-9_-]*$`. The old check accepted leading digits
(e.g., `"123-invalid"` would strip the hyphen and pass `isalnum()`), so
the "Reject invalid resource names" scenario was silently failing.
- Fix step patterns in `features/steps/resource_virtual_types_steps.py`:
replace unsupported `{name!r}` parse-library syntax with literal-quoted
`"{name}"` (confirmed via `parse.parse(...)` REPL that `!r` returns
`None`); rename the over-broad `it should contain "{text}"` /
`it should raise {error_type} with message containing "{message}"`
patterns to specific forms that don't collide with steps in
`execution_environment_steps.py` and `structural_validation_steps.py`;
add try/except in the `When I compute the virtual resource` step so the
exception-handling scenario can reach its `Then` step.
- Fix table headers in `features/resource_virtual_types.feature` so behave's
table parser sees a proper `| name | value |` header row instead of
treating the first data row as headers.
- Drop the now-unused E501 override for the deleted file from `pyproject.toml`.
- Add CHANGELOG.md entry under `[Unreleased]`.
Verified locally: unit_tests gate against `features/resource_virtual_types.feature`
passes 18/18 scenarios; lint and typecheck both green.
Refs: #8610
- Remove # type: ignore from resource_virtual_types_steps.py (zero tolerance)
- Replace all eval() calls with ast.literal_eval() and _parse_lambda_body() helper
- Fix step mismatch: 'the complex computed value should be correct'
- Fix trailing whitespace and import ordering (W293, I001, RUF100)
- Fix B011 assert False -> raise AssertionError()
- Fix UP035/UP045/UP046 modernisation in domain model and resource virtual module
- Fix RUF022 __all__ sorting in resource/__init__.py
- Fix E501 long lines in virtual_resource.py via per-file-ignores
- Assign PR milestone to v3.6.0
- Implement VirtualResource base class for abstract/computed resources
- Add MetricResource example for computed metrics
- Add APIEndpointResource example for API endpoints
- Implement comprehensive BDD tests for virtual resource types
- Full type annotations with Generic support
- Support for on-demand computation via compute_fn
- Support for kwargs passing to compute functions
Closes#8610
- Implement VirtualResource base class with name, description, compute_fn, and metadata
- Implement MetricResource example for computed metrics with unit support
- Implement APIEndpointResource example for API endpoints with HTTP method support
- Add comprehensive BDD tests with 20+ scenarios covering all functionality
- Support on-demand computation via compute_fn callable
- Support metadata management with with_metadata() method
- Full type annotations and Pydantic validation
The BudgetExhaustionEvent validator dropped "daily" from its allowed set, but
the legacy CostTracker in providers/cost_tracker.py still emits "daily" events
for the per-day budget path. That broke two cost_controls.feature scenarios
(BudgetExhaustionEvent accepts daily budget type; CostTracker blocks at 100% of
daily budget). Restore "daily" alongside "plan", "session", "org".
CostTrackingService lived in src/cleveragents/core/cost_tracking.py but imported
from cleveragents.domain.models.core.*, violating the architecture.feature
invariant "core package should be self-contained" (core may only import from
{core, config, shared}). Move the service to application/services/, where
domain imports are permitted, and update the lone caller in the BDD step file.
ISSUES CLOSED: #8609
- Remove triple blank line in steps file (ruff format E303)
- Collapse multiline if conditions in cost_tracking.py (ruff format)
- Add BudgetExceededError to __all__ in exceptions.py
- Fix step_check_budget to pass context.org_accumulator instead of None
- Fix Three-tier scenario amounts so org budget fails first (session $200, org $100)
- Disambiguate @when step using {cost:f} type specifier to avoid AmbiguousStep
- Rename duplicate @then step to avoid conflict with lsp_registry_steps.py
- Add missing column header rows to Gherkin tables in feature file
ISSUES CLOSED: #8609
- Use BudgetLevel.SESSION/ORG string values instead of hardcoded plan/daily in enforce_budget()
- Accept 'session' and 'org' as valid budget_type values in BudgetExhaustionEvent validator
- Add WARNING_THRESHOLD constant instead of magic 0.9 number
- Simplify nested ternary in check_budget() warning logic
- Remove unused OrgCostAccumulator import from cost_tracking.py
- Add missing BDD step definitions for org budget scenarios
- Fix budget_type check in step definitions to use BudgetLevel.SESSION.value
Closes#8609
render_context_set_plain (~49 lines) was completely uncovered because no
existing test exercised the plain output path for context_set. Add a
coverage-boost scenario that uses format "plain" to cover those lines.
Also add a scenario with max_file_size=100 (not divisible by any binary
unit) to cover the _format_size bytes-fallback path (line 36 of
project_context_set.py).
ISSUES CLOSED: #6319
Implemented spec-compliant JSON, YAML, plain, and rich outputs for `agents project context set`. Added BDD coverage verifying the new output structure across formats.\n\nISSUES CLOSED: #6319
Covers uncovered paths in acms_context.py:
- Empty view name rejection (context show error path)
- Clear without filters warning and auto-confirmation path
This improves code coverage by exercising the following functions:
- acms_context_show empty view validation branch (line 91-93)
- acms_context_clear no-filters warning with confirmation bypass (line 215-219)
Closes#9586
- Fix integration test failure: Context Show Validates Empty View Name
- typer.Exit is click.Exit (RuntimeError subclass), not SystemExit
- Robot helper now catches typer.Exit using exit_code attribute
- Helper path insertion now always places clone src at sys.path[0]
to prevent /app/src from shadowing the PR branch source
- Fix information disclosure: CleverAgentsError handler now logs
exception internally via _logger.exception() and shows generic
user-facing message instead of str(e)
- Fix budget utilization: use actual per-tier token counts instead
of hot_count * 100 (fragment count * arbitrary factor)
- Fix type safety: _remove_fragments now uses _TierServiceProtocol
instead of object, enabling proper static type checking
- Fix overly broad except: cancellation handled with early return
instead of catching typer.Exit(0) in the except block
- Add broad glob pattern warning when --path matches > 50 entries
- Remove duplicate HAL 9000 entry from CONTRIBUTORS.md
- Fix Behave steps to catch typer.Exit in addition to SystemExit
ISSUES CLOSED: #9586
The ACMS context CLI commands ('context show' / 'context clear') were fully
implemented in 'acms_context.py' with comprehensive tests, mocks, benchmarks,
and documentation — but the module was never imported or registered in
'cli/main.py'. This commit wires up the 'acms_context.app' Typer sub-app
so that 'agents acms context show' and 'agents acms context clear' are
actually accessible from the CLI.
Changes:
- Import acms_context in _register_subcommands()
- Register acms_context.app as the 'acms' sub-app on the main Typer app
- Add 'acms' to valid_cmds list in main() for fast-path validation
- Add 'acms context' entry to _print_basic_help() output
- Minor formatting cleanup applied by ruff
ISSUES CLOSED: #9586
Refs: #9675
- Rewrote production CLI to use real ContextTierService (get_scoped_view, get_all_fragments, evict_lru) instead of non-existent ACMSService
- Removed unused imports (Path, Panel, ScopedView) from production code
- Fixed all lint issues: trailing whitespace, import ordering, nested with statements
- Replaced typer.Abort() with typer.Exit(code=1) for error exits
- Added input validation for empty/whitespace view parameter
- Fixed error handling to use str(e) instead of e.message
- Added guards against negative budget values in _format_budget_utilization
- Added warning when clearing context with no filters (clear ALL)
- Removed module-level console side effect
- Moved mocks to features/mocks/acms_context_mocks.py per CONTRIBUTING.md
- Fixed test assertions to capture real CLI output (not placeholder)
- Fixed duplicate step definitions (AmbiguousStep errors)
- Fixed feature file step mismatch for tier count parameter
- Added Robot Framework integration tests in robot/acms_context_cli.robot
- Added performance benchmarks in benchmarks/acms_context_cli_bench.py
- Updated CHANGELOG.md with ACMS context CLI feature entry
- Updated CONTRIBUTORS.md with ACMS context CLI contribution
ISSUES CLOSED: #9586
Restore all five required Rich output panels to _print_lifecycle_plan():
- Plan Status panel: Processing State, Projects, Arguments, Automation Profile,
actors (Strategy/Execution/Estimation/Invariant), Execution Environment,
Created/Updated timestamps, Description, Definition of Done, DoD evaluation,
Invariants, resume metadata, multi-project scopes, error message
- Progress panel: Strategize/Execute/Apply step indicators
- Timing panel: Started, Elapsed, ETA (using estimation_result when available),
and all phase timestamps (Strategize Started/Completed, Execute Started/Completed,
Applied At)
- Execution Detail panel: Sandbox, Tool Calls (N/A), Files Modified (N/A),
Child Plans, Checkpoints
- Cost panel: Tokens Used, Cost So Far, Estimated Total Cost
- Footer: ✓ OK Status refreshed
Also fixes:
- tool_calls semantic bug: display N/A instead of total_tokens
- files_modified: display N/A (not available in cost_metadata)
- ETA calculation: use estimation_result.estimated_time_seconds or N/A
- In-function import: moved Plan as LifecyclePlan to top of file
- Import sorting: split aliased import per ruff isort rules
Adds BDD scenarios for all five panels in plan_lifecycle_cli_coverage.feature
with step definitions in plan_lifecycle_cli_coverage_steps.py.
Updates CHANGELOG.md with user-facing output changes.
ISSUES CLOSED: #9341
The artifacts() method routes JSON through format_output() which wraps
the payload in a spec-required envelope {"data": ..., "status": ...}.
The two @tdd_issue_4253 step assertions were checking parsed["key"]
directly, but the actual fields live at parsed["data"]["key"].
Update step_artifacts_json_validation and step_artifacts_json_apply_summary
to extract parsed["data"] before asserting on validation_summary and
apply_summary respectively.
ISSUES CLOSED: #9084
- What was implemented
- Added PLAN_ROLLED_BACK event type to the EventType enum at src/cleveragents/infrastructure/events/types.py to properly represent successful rollbacks in the domain model.
- Implemented rollback_plan(plan_id: str, checkpoint_id: str) -> RollbackResult in PlanLifecycleService (src/cleveragents/application/services/plan_lifecycle_service.py) with:
- Plan state validation: rejects rollback when the plan is in terminal APPLIED or CANCELLED states.
- Delegation to CheckpointService.selective_rollback() to perform the actual rollback logic and obtain a RollbackResult.
- Emission of PLAN_ROLLED_BACK as a domain event to reflect the completed rollback.
- checkpoint_service is accepted as an optional constructor parameter; if not provided, a PlanError is raised to preserve backward compatibility.
- Updated CLI behavior in src/cleveragents/cli/commands/plan.py so agents plan rollback routes through PlanLifecycleService.rollback_plan() rather than calling CheckpointService.selective_rollback() directly.
- Updated PlanLifecycleService module docstring to include rollback_plan in the documented API.
- Added Behave feature file features/plan_lifecycle_rollback.feature with 11 scenarios covering state validation, domain events, and delegation.
- Added step implementations in features/steps/plan_lifecycle_rollback_steps.py to support the new scenarios.
- Key design decisions
- rollback_plan returns RollbackResult (the same result type produced by CheckpointService.selective_rollback) so the CLI can display rollback details consistently.
- Terminal states APPLIED and CANCELLED are disallowed for rollback to prevent inconsistent or invalid state transitions.
- checkpoint_service is optional in the PlanLifecycleService constructor; when omitted (None), a PlanError is raised to retain backward compatibility while signaling explicit dependency requirements.
- CLI UI remains powered by CheckpointService for metadata enrichment (e.g., confirmation prompts), but the actual rollback action is performed via PlanLifecycleService to ensure proper domain workflow and event emission.
- Technical implications
- All rollback logic now flows through the domain service layer (PlanLifecycleService) to preserve invariants and emit domain events, rather than allowing ad-hoc UI routes to bypass service validation.
- The UI can still retrieve checkpoint metadata for user confirmation, but the operation that modifies state uses the new rollback_plan pathway.
- Tests and behavior coverage were expanded via the new Behave feature and step implementations to validate state handling, events, and delegation.
- Affected modules/components
- src/cleveragents/infrastructure/events/types.py
- src/cleveragents/application/services/plan_lifecycle_service.py
- src/cleveragents/cli/commands/plan.py
- PlanLifecycleService module docstring
- features/plan_lifecycle_rollback.feature
- features/steps/plan_lifecycle_rollback_steps.py
ISSUES CLOSED: #3677
- Capture started_at timestamp using datetime.now(UTC) before service call
- Add timing.started field to JSON envelope with ISO 8601 format
- Update step definitions to verify timing.started is present and valid
- Remove @tdd_expected_fail tag from plan_prompt_command.feature scenario
- Remove unrelated files accidentally committed to repo root
- Move datetime import to top of plan_prompt_command_steps.py
- Add CHANGELOG.md entry under [Unreleased] > Fixed
ISSUES CLOSED: #9353
- Capture started_at timestamp using datetime.now(UTC) before service call
- Add timing.started field to JSON envelope with ISO 8601 format
- Update step definitions to verify timing.started is present and valid
- Remove @tdd_expected_fail tag from plan_prompt_command.feature scenario
Fixes#9353
Fix the failing unit tests in agent_task_memory_leak_fix.feature by
replacing the broken event loop management with a persistent background
asyncio event loop running in a daemon thread. The original implementation
called asyncio.create_task() from synchronous Behave step code, which
requires a running event loop — causing RuntimeError: no running event loop.
The fix introduces a _BackgroundLoop class that keeps a dedicated asyncio
event loop alive in a background thread. All agent instantiation and
message sending now happens via asyncio.run_coroutine_threadsafe(), ensuring
the event loop is always running when asyncio.create_task() is called.
Also adds the missing step definition for 'I send {count:d} messages to
the agent' (without 'in rapid succession') to match the feature file.
Updates CONTRIBUTORS.md with the agent task memory leak fix contribution.
ISSUES CLOSED: #9044
This fix addresses issue #9044 by adding a done callback to each asyncio.Task
created in the Agent._setup_processing_pipeline method. The callback removes
the task from the _tasks set upon completion, preventing unbounded memory
growth in long-lived agent instances.
The fix uses task.add_done_callback(self._tasks.discard) to ensure that
completed tasks are promptly removed from the set, allowing them to be
garbage collected. Using set.discard is safe as it never raises ValueError
on double-removal.
ISSUES CLOSED: #9044
- Added input validation for namespace parameter in _handle_registry_list_tools in src/cleveragents/a2a/facade.py: If provided, must be a non-empty string; empty strings raise ValueError; non-string types raise TypeError
- Added input validation for type_name parameter in _handle_registry_list_resources in src/cleveragents/a2a/facade.py: If provided, must be a non-empty string; empty strings raise ValueError; non-string types raise TypeError
- Added input validation for arguments parameter in _handle_plan_create in src/cleveragents/a2a/facade.py: If provided, must be a dict; non-dict types raise TypeError
- Added input validation for created_by parameter in _handle_plan_create in src/cleveragents/a2a/facade.py: If provided, must be a non-empty string; empty strings raise ValueError; non-string types raise TypeError
- Added BDD feature file features/a2a_facade_optional_param_validation.feature with 17 scenarios covering all validation paths
- Added step definitions features/steps/a2a_facade_optional_param_validation_steps.py
ISSUES CLOSED: #9059
The invariant precedence chain is four-tier per specification §92:
plan > action > project > global
This fix updates:
1. Module docstring in invariant.py to document the correct four-tier precedence
2. InvariantScope class docstring to reflect PLAN > ACTION > PROJECT > GLOBAL
3. merge_invariants() function to accept action_invariants parameter
4. InvariantSet.merge() class method to accept and pass action_invariants
5. InvariantService.get_effective_invariants() to collect and pass action invariants
6. BDD test steps to include action invariants in merge operations
7. Benchmark suite to include action invariants in performance tests
8. Robot Framework helper to pass action_invariants to merge functions
9. CHANGELOG.md entry under [Unreleased]/### Fixed section
10. CONTRIBUTORS.md entry documenting HAL 9000 contribution
All docstrings now correctly document the four-tier precedence chain,
and the merge logic properly handles action-scope invariants between
plan and project scopes.
ISSUES CLOSED: #9003
author CleverThis <hal9000@cleverthis.com> 1776170939 +0000
committer CleverThis <hal9000@cleverthis.com> 1776170939 +0000
refactor(agent): replace hardcoded dependency and context file limits with configurable parameters
Implemented configurable limits for the agent and graph components:
- ContextAnalysisAgent now accepts max_dependencies: int = 10 with validation (ValueError if <= 0)
- _parse_dependencies uses self.max_dependencies instead of a hard-coded 10
- PlanGenerationGraph now accepts max_context_files: int = 5 with validation (ValueError if <= 0)
- _format_context_summary uses self.max_context_files instead of a hard-coded 5
- Updated class docstrings to reflect new parameters
- Added Behave feature file at features/agent_configurable_limits.feature with 12 scenarios
- Added step definitions at features/steps/agent_configurable_limits_steps.py
ISSUES CLOSED: #9050
Resource Pydantic model requires resource_id to match the ULID pattern
^[0-9A-HJKMNP-TV-Z]{26}$ and classification to be 'physical' or
'virtual'. The test fixture used '01HANDLER0000000000000001' (invalid
ULID) and 'tool' (invalid enum), causing a ValidationError during
scenario setup that Behave reported as a traceback outside scenario.
Fixes the errored scenario in features/container_clone_into.feature:88.
ISSUES CLOSED: #7555
The devcontainer_handler_protocol_methods.feature file and its step
definitions still referenced the old ContainerLifecycleState.DETECTED
terminology. Update to DISCOVERED for consistency with specification.
ISSUES CLOSED: #7555
Addresses remaining CI review feedback from HAL9001 on PR #8304:
1. Moved all cleveragents imports from inside function bodies to module-level
in features/steps/container_clone_into_steps.py (5 functions fixed)
2. Moved BUILTIN_TYPES import from inside step_look_up_in_builtin_types()
to module level in features/steps/devcontainer_sandbox_strategy_steps.py
3. Removed redundant inline import of EMPTY_CONTENT_HASH and BaseResourceHandler
inside diff() method of devcontainer.py (already available at module level)
4. Fixed stale docstring referencing old 'detected' terminology in
robot/helper_devcontainer_lifecycle.py cmd_transition_valid()
All files pass ruff format and ruff check.
The --clone-into CLI argument was registered and the helper
clone_repo_into_container() was implemented, but DevcontainerHandler.resolve()
never read the clone_into property or called the helper. This meant that
agents resource add container-instance --clone-into <url> silently ignored
the flag at runtime (acceptance criterion #2 from issue #7555 was unmet).
Wire the clone step into DevcontainerHandler.resolve(): after
activate_container() returns and the lifecycle tracker has a container_id,
validate the URL and call clone_repo_into_container(). Also add an
end-to-end BDD scenario that exercises the full handler to clone path via
mocks.
ISSUES CLOSED: #7555
- Change validate_clone_into_url() return type from bool to None
- Raise ValueError for empty or invalid git repository URLs
- Update BDD steps to catch ValueError and set clone_url_valid accordingly
- Aligns with contract requirement from PR #8304 review feedback