d6b537a6ea
Closes: #11007 ## Description Asks LLM to not create files. ## Type of Change - [ X ] Bug fix (non-breaking change which fixes an issue) - [ X ] Test improvements ## Quality Checklist - [ ] Code follows the project's coding standards (see CONTRIBUTING.md) - [ ] All public/protected methods have argument validation - [ ] Static typing is complete (no `Any` unless justified) - [ ] `nox -s typecheck` passes with no errors - [ ] `nox -s lint` passes with no errors - [ ] Unit tests written/updated (Behave scenarios in `features/`) - [ ] Integration tests written/updated (Robot suites in `robot/`) if applicable - [ ] Coverage remains above 85% (`nox -s coverage_report`) - [ ] No security issues introduced (`nox -s security_scan`) - [ ] No dead code introduced (`nox -s dead_code`) - [ ] Documentation updated if behavior changed ## Testing Running in git.cleverthis.com is the only real test possible. ### Test Commands Run ```bash nox -s unit_tests # Behave tests nox -s typecheck # Type checking nox -s lint # Linting nox -s coverage_report # Coverage ``` ## Related Issues Closes #11007 Reviewed-on: #11133 Reviewed-by: Hamza Khyari <hamza.khyari@cleverthis.com>
434 lines
23 KiB
Plaintext
434 lines
23 KiB
Plaintext
*** Settings ***
|
|
Documentation E2E test for Workflow Example 10: Full-Auto Batch Operations.
|
|
...
|
|
... A team reformats packages in a monorepo using the ``full-auto``
|
|
... automation profile. Multiple plans run without human
|
|
... intervention (strategize → execute → apply automatically).
|
|
... Includes a deliberately broken action (non-existent LLM actor)
|
|
... to demonstrate batch error handling.
|
|
...
|
|
... Requires real LLM API keys — zero mocking.
|
|
Library Collections
|
|
Resource common_e2e.resource
|
|
Suite Setup WF10 Suite Setup
|
|
Suite Teardown E2E Suite Teardown
|
|
|
|
*** Variables ***
|
|
@{PACKAGE_NAMES} pkg_auth pkg_common pkg_billing
|
|
${ACTION_NAME} local/format-codebase
|
|
${PLAN_TIMEOUT} 180s
|
|
|
|
*** Keywords ***
|
|
WF10 Suite Setup
|
|
[Documentation] E2E Suite Setup plus database initialisation.
|
|
E2E Suite Setup
|
|
# Initialise the database so CLI commands work in all tests.
|
|
${init}= Run CleverAgents Command init --force --yes
|
|
Should Be Equal As Integers ${init.rc} 0
|
|
|
|
Create Package Directory
|
|
[Documentation] Create a single package with badly-formatted Python files.
|
|
[Arguments] ${monorepo} ${pkg_name}
|
|
${pkg_dir}= Set Variable ${monorepo}${/}${pkg_name}
|
|
Create Directory ${pkg_dir}${/}src
|
|
# __init__.py with extra blank lines and bad spacing
|
|
${init_content}= Set Variable
|
|
... \n\n\n"""${pkg_name} package."""\n\n\nimport os\nimport sys\nimport json\n\n\n__all__=["main"]\n
|
|
Create File ${pkg_dir}${/}src${/}__init__.py ${init_content}
|
|
# main.py with intentionally bad formatting: unsorted imports, extra spaces, long lines
|
|
${main_content}= Set Variable
|
|
... import json\nimport os\nimport sys\nfrom pathlib import Path\nimport re\n\n\ndef main( ):\n """Entry point with bad formatting."""\n x=1\n y = 2\n z=x+y\n data = {"key": "value", "another": "item"}\n return z\n\nif __name__=="__main__":\n main( )\n
|
|
Create File ${pkg_dir}${/}src${/}main.py ${main_content}
|
|
RETURN ${pkg_dir}
|
|
|
|
Create Temp Monorepo
|
|
[Documentation] Create a temporary monorepo with multiple badly-formatted packages.
|
|
...
|
|
... Each healthy package contains ``src/__init__.py`` and ``src/main.py``
|
|
... with intentionally poor formatting (extra spaces, unsorted imports).
|
|
... Returns the path to the monorepo root and the detected branch name.
|
|
${monorepo}= Create Temp Git Repo wf10-monorepo
|
|
FOR ${pkg_name} IN @{PACKAGE_NAMES}
|
|
Create Package Directory ${monorepo} ${pkg_name}
|
|
END
|
|
# Commit all packages so git-checkout resources have content
|
|
${add_res}= Run Process git add . cwd=${monorepo} timeout=60s on_timeout=kill
|
|
Should Be Equal As Integers ${add_res.rc} 0 git add failed: ${add_res.stderr}
|
|
${commit_res}= Run Process git commit -m Add packages with bad formatting cwd=${monorepo} timeout=60s on_timeout=kill
|
|
Should Be Equal As Integers ${commit_res.rc} 0 git commit failed: ${commit_res.stderr}
|
|
# Detect the actual default branch name (may be main or master)
|
|
${branch_result}= Run Process git rev-parse --abbrev-ref HEAD cwd=${monorepo} timeout=60s on_timeout=kill
|
|
Should Be Equal As Integers ${branch_result.rc} 0 git rev-parse failed: ${branch_result.stderr}
|
|
${branch}= Strip String ${branch_result.stdout}
|
|
Log Detected monorepo branch: ${branch}
|
|
RETURN ${monorepo} ${branch}
|
|
|
|
Write Action Config
|
|
[Documentation] Write a formatting action YAML config with full-auto profile.
|
|
...
|
|
... Uses dynamic actor selection based on available API keys.
|
|
... Returns the path to the YAML file.
|
|
# Pick an actor that matches the available API key
|
|
${has_anthropic}= Evaluate bool(__import__('os').environ.get('ANTHROPIC_API_KEY', ''))
|
|
IF ${has_anthropic}
|
|
${actor}= Set Variable anthropic/claude-sonnet-4-20250514
|
|
ELSE
|
|
${actor}= Set Variable openai/gpt-4o
|
|
END
|
|
${yaml_path}= Set Variable ${SUITE_HOME}${/}format_action.yaml
|
|
${config}= Catenate SEPARATOR=\n
|
|
... name: ${ACTION_NAME}
|
|
... description: "Reformat Python source files for consistent style"
|
|
... strategy_actor: ${actor}
|
|
... execution_actor: ${actor}
|
|
... definition_of_done: >
|
|
... All Python files are consistently formatted without creating new files.
|
|
... Creating .flake8, .pre-commit-config.yaml or a new pyproject.toml
|
|
... file is forbidden.
|
|
... automation_profile: full-auto
|
|
... reusable: true
|
|
... state: available
|
|
... read_only: false
|
|
... invariants:
|
|
... ${SPACE}${SPACE}- "Changes must be whitespace-only (no semantic modifications)"
|
|
... ${SPACE}${SPACE}- "Every package must pass its own test suite after formatting"
|
|
Create File ${yaml_path} ${config}\n
|
|
RETURN ${yaml_path}
|
|
|
|
Clean Workspace Template Files
|
|
[Documentation] Remove template files from the workspace and monorepo
|
|
... that the LLM may regenerate during formatting, to prevent
|
|
... add/add merge conflicts during plan apply.
|
|
...
|
|
... CleverAgents copies workspace template files into project
|
|
... directories during ``project create``, so this keyword
|
|
... must run **after** project registration and **before**
|
|
... plan launch. It also runs ``git clean -fd`` in the
|
|
... monorepo to remove any untracked files that were copied.
|
|
[Arguments] ${target_dir}=${SUITE_HOME}
|
|
@{conflicting}= Create List
|
|
... .flake8
|
|
... .pre-commit-config.yaml
|
|
... pyproject.toml
|
|
... requirements-dev.txt
|
|
... requirements.txt
|
|
... setup.py
|
|
... setup.cfg
|
|
... tox.ini
|
|
FOR ${file} IN @{conflicting}
|
|
${path}= Set Variable ${target_dir}${/}${file}
|
|
Run Keyword And Ignore Error Remove File ${path}
|
|
END
|
|
# Also run git clean to remove any untracked files/directories that
|
|
# the workspace template may have deposited in the monorepo.
|
|
${git_clean}= Run Process git clean -fd cwd=${target_dir} timeout=60s on_timeout=kill
|
|
Log git clean in ${target_dir}: rc=${git_clean.rc} level=DEBUG
|
|
|
|
Write Broken Action Config
|
|
[Documentation] Write a deliberately broken action YAML that uses a non-existent
|
|
... LLM actor. Plans created with this action will fail during
|
|
... execution when the strategy/execution actor cannot be resolved.
|
|
${yaml_path}= Set Variable ${SUITE_HOME}${/}broken_action.yaml
|
|
${config}= Catenate SEPARATOR=\n
|
|
... name: local/broken-format
|
|
... description: "Deliberately broken action for error handling testing"
|
|
... strategy_actor: nonexistent/model-xyz-404
|
|
... execution_actor: nonexistent/model-xyz-404
|
|
... definition_of_done: "This action should always fail"
|
|
... automation_profile: full-auto
|
|
... reusable: true
|
|
... state: available
|
|
... read_only: false
|
|
... invariants:
|
|
... ${SPACE}${SPACE}- "No changes expected — action is broken"
|
|
Create File ${yaml_path} ${config}\n
|
|
RETURN ${yaml_path}
|
|
|
|
Register Package Resources And Projects
|
|
[Documentation] Register git-checkout resources and create projects for the
|
|
... specified packages.
|
|
...
|
|
... Error handling is tested separately via a broken action
|
|
... (non-existent LLM actor), not via missing resources.
|
|
...
|
|
... Resource/project names use fixed ``local/<pkg>`` prefixes without
|
|
... UUID suffixes — safe because ``init --force --yes`` in suite setup
|
|
... resets the workspace database before each run.
|
|
[Arguments] ${monorepo} ${branch} @{healthy_packages}
|
|
FOR ${pkg_name} IN @{healthy_packages}
|
|
# Register git-checkout resource pointing to the monorepo root
|
|
${res_result}= Run CleverAgents Command
|
|
... resource add git-checkout local/${pkg_name}
|
|
... --path ${monorepo} --branch ${branch}
|
|
Log Resource ${pkg_name}: ${res_result.stdout}
|
|
Should Not Contain ${res_result.stderr} Traceback
|
|
... Resource registration for ${pkg_name} produced Traceback:\n${res_result.stderr}
|
|
# Create project linked to resource — must succeed WITHOUT Traceback.
|
|
${proj_result}= Run CleverAgents Command
|
|
... project create local/${pkg_name}
|
|
... --resource local/${pkg_name}
|
|
Log Project ${pkg_name}: ${proj_result.stdout}
|
|
Should Not Contain ${proj_result.stderr} Traceback
|
|
... Project creation for ${pkg_name} produced Traceback:\n${proj_result.stderr}
|
|
END
|
|
|
|
Launch Batch Plans
|
|
[Documentation] Launch a plan for each package in full-auto mode.
|
|
...
|
|
... Returns a list of plan identifiers extracted from output.
|
|
... Uses ``expected_rc=None`` because broken packages may fail
|
|
... during plan use (which is expected behaviour).
|
|
[Arguments] @{all_packages}
|
|
@{plan_ids}= Create List
|
|
FOR ${pkg_name} IN @{all_packages}
|
|
${result}= Run CleverAgents Command
|
|
... plan use ${ACTION_NAME} local/${pkg_name}
|
|
... --automation-profile full-auto --format plain
|
|
... timeout=${PLAN_TIMEOUT} expected_rc=None
|
|
Log Plan use ${pkg_name} stdout: ${result.stdout}
|
|
Log Plan use ${pkg_name} stderr: ${result.stderr}
|
|
Should Not Contain ${result.stderr} Traceback
|
|
... plan use for ${pkg_name} produced Traceback:\n${result.stderr}
|
|
# Extract plan ID from output — must find a valid ULID (Crockford Base32)
|
|
${combined}= Set Variable ${result.stdout} ${result.stderr}
|
|
${match}= Get Regexp Matches ${combined} ([0-9A-HJKMNP-TV-Z]{26}) flags=IGNORECASE
|
|
${match_count}= Get Length ${match}
|
|
IF ${match_count} > 0
|
|
${plan_id}= Set Variable ${match}[0]
|
|
Append To List ${plan_ids} ${plan_id}
|
|
Log Captured plan ID for ${pkg_name}: ${plan_id}
|
|
ELSE
|
|
Log No plan ID extracted for ${pkg_name} (rc=${result.rc}) — plan creation may have failed WARN
|
|
END
|
|
END
|
|
RETURN @{plan_ids}
|
|
|
|
Execute Batch Plans
|
|
[Documentation] Execute each plan through the strategize→execute pipeline.
|
|
...
|
|
... ``plan execute`` runs the current plan phase synchronously.
|
|
... With the full-auto automation profile, a single ``plan execute``
|
|
... call auto-advances through both strategize and execute phases,
|
|
... leaving the plan ready for ``plan apply --yes``.
|
|
...
|
|
... Plans that fail during execution (e.g. broken action with
|
|
... non-existent actor) are logged but do not abort the batch —
|
|
... the batch continues with remaining plans.
|
|
...
|
|
... Returns a list of plan IDs that completed execution
|
|
... successfully (candidates for apply).
|
|
[Arguments] @{plan_ids}
|
|
@{executed_ids}= Create List
|
|
FOR ${plan_id} IN @{plan_ids}
|
|
Log Executing plan ${plan_id} (strategize + execute via full-auto)
|
|
${exec}= Run CleverAgents Command
|
|
... plan execute ${plan_id} --format plain
|
|
... timeout=${PLAN_TIMEOUT} expected_rc=None
|
|
Log Execute ${plan_id} rc=${exec.rc}: ${exec.stdout}
|
|
IF ${exec.rc} != 0
|
|
Log Plan ${plan_id} failed during execution (rc=${exec.rc}): ${exec.stderr} WARN
|
|
CONTINUE
|
|
END
|
|
Append To List ${executed_ids} ${plan_id}
|
|
END
|
|
RETURN @{executed_ids}
|
|
|
|
Apply Batch Plans
|
|
[Documentation] Apply each successfully-executed plan via ``plan apply --yes``.
|
|
...
|
|
... After ``plan execute`` with full-auto profile, plans are in
|
|
... the ``execute/complete`` state. ``plan apply --yes`` performs
|
|
... the actual application (e.g. committing changes to the repo)
|
|
... and completes the apply phase, transitioning the plan to the
|
|
... ``applied`` processing state.
|
|
...
|
|
... Note: ``plan lifecycle-apply`` only transitions the plan INTO
|
|
... the apply phase (``apply/queued``) without completing it.
|
|
... ``plan apply --yes`` is required to actually run and complete
|
|
... the apply step.
|
|
...
|
|
... Plans that fail during apply are logged but do not abort
|
|
... the batch. Returns a list of plan IDs that were applied.
|
|
[Arguments] @{executed_ids}
|
|
@{applied_ids}= Create List
|
|
FOR ${plan_id} IN @{executed_ids}
|
|
Log Applying plan ${plan_id}
|
|
${apply}= Run CleverAgents Command
|
|
... plan apply --yes ${plan_id} --format plain
|
|
... timeout=${PLAN_TIMEOUT} expected_rc=None
|
|
Log Apply ${plan_id} rc=${apply.rc}: ${apply.stdout}
|
|
IF ${apply.rc} != 0
|
|
Log Plan ${plan_id} failed during apply (rc=${apply.rc}) stdout: ${apply.stdout} WARN
|
|
Log Plan ${plan_id} failed during apply (rc=${apply.rc}) stderr: ${apply.stderr} WARN
|
|
CONTINUE
|
|
END
|
|
Append To List ${applied_ids} ${plan_id}
|
|
END
|
|
RETURN @{applied_ids}
|
|
|
|
*** Test Cases ***
|
|
Workflow 10 Full-Auto Batch Formatting
|
|
[Documentation] End-to-end test for full-auto batch formatting across
|
|
... multiple packages in a monorepo, including error handling
|
|
... when one plan fails due to a broken action.
|
|
...
|
|
... 1. Creates a monorepo with 3 badly-formatted Python packages
|
|
... 2. Registers a reusable formatting action with full-auto profile
|
|
... 3. Registers a broken action (non-existent LLM actor) for error testing
|
|
... 4. Registers resources and projects for healthy packages
|
|
... 5. Creates plans in full-auto mode via ``plan use``
|
|
... 6. Executes all plans via ``plan execute`` (strategize + execute)
|
|
... 7. Applies successful plans via ``plan apply --yes``
|
|
... 8. Verifies batch results via ``plan list`` with state filters
|
|
... 9. Verifies error handling — broken action's plan fails during execution
|
|
[Tags] E2E
|
|
[Timeout] 25 minutes
|
|
[Teardown] Run CleverAgents Command config set core.automation-profile manual expected_rc=None
|
|
Skip If No LLM Keys
|
|
|
|
# Prevent add/add merge conflicts during plan apply by removing workspace
|
|
# template files that the LLM may regenerate.
|
|
Clean Workspace Template Files
|
|
|
|
# --- Step 1: Create temp monorepo with badly-formatted packages ---
|
|
${monorepo} ${branch}= Create Temp Monorepo
|
|
Log Monorepo created at: ${monorepo} (branch: ${branch})
|
|
Directory Should Exist ${monorepo}${/}pkg_auth${/}src
|
|
Directory Should Exist ${monorepo}${/}pkg_common${/}src
|
|
Directory Should Exist ${monorepo}${/}pkg_billing${/}src
|
|
|
|
# --- Step 2: Create the formatting action with full-auto profile ---
|
|
${yaml_path}= Write Action Config
|
|
File Should Exist ${yaml_path}
|
|
${action_result}= Run CleverAgents Command
|
|
... action create --config ${yaml_path}
|
|
Log Action create output: ${action_result.stdout}
|
|
Should Not Contain ${action_result.stderr} Traceback
|
|
Output Should Contain ${action_result} format-codebase
|
|
|
|
# Also create a broken action with a non-existent actor for error handling
|
|
${broken_action}= Write Broken Action Config
|
|
${broken_action_result}= Run CleverAgents Command
|
|
... action create --config ${broken_action}
|
|
Log Broken action create output: ${broken_action_result.stdout}
|
|
Output Should Contain ${broken_action_result} broken-format
|
|
|
|
# --- Step 3: Register resources and projects for all packages ---
|
|
Register Package Resources And Projects ${monorepo} ${branch} @{PACKAGE_NAMES}
|
|
|
|
# Clean workspace template files that were copied into the monorepo
|
|
# during project creation, to prevent add/add merge conflicts during apply.
|
|
Clean Workspace Template Files ${monorepo}
|
|
|
|
# --- Step 4: Create plans — healthy + broken ---
|
|
# 4a: Launch plans for healthy packages with the good action
|
|
@{plan_ids}= Launch Batch Plans @{PACKAGE_NAMES}
|
|
${plan_count}= Get Length ${plan_ids}
|
|
Log Healthy plan IDs (${plan_count}): @{plan_ids}
|
|
Should Be True ${plan_count} == 3
|
|
... Expected 3 healthy plan IDs but got ${plan_count}
|
|
|
|
# 4b: Launch plan for first healthy package but with BROKEN action
|
|
# (non-existent actor will cause execution to fail)
|
|
${broken_result}= Run CleverAgents Command
|
|
... plan use local/broken-format local/pkg_auth
|
|
... --automation-profile full-auto --format plain
|
|
... timeout=${PLAN_TIMEOUT} expected_rc=None
|
|
Log Broken action plan use rc=${broken_result.rc}: ${broken_result.stdout}
|
|
Log Broken action plan use stderr: ${broken_result.stderr}
|
|
Should Not Contain ${broken_result.stderr} Traceback
|
|
${broken_plan_failed_at_creation}= Evaluate ${broken_result.rc} != 0
|
|
${broken_plan_id}= Set Variable ${EMPTY}
|
|
IF not ${broken_plan_failed_at_creation}
|
|
# Extract plan ID for the broken plan
|
|
${combined}= Set Variable ${broken_result.stdout} ${broken_result.stderr}
|
|
${match}= Get Regexp Matches ${combined} ([0-9A-HJKMNP-TV-Z]{26}) flags=IGNORECASE
|
|
${match_count}= Get Length ${match}
|
|
IF ${match_count} > 0
|
|
${broken_plan_id}= Set Variable ${match}[0]
|
|
Append To List ${plan_ids} ${broken_plan_id}
|
|
Log Broken plan ID captured: ${broken_plan_id}
|
|
END
|
|
ELSE
|
|
Log Broken plan failed at creation (rc=${broken_result.rc})
|
|
END
|
|
|
|
# --- Step 5: Execute all plans (strategize + execute phases) ---
|
|
@{executed_ids}= Execute Batch Plans @{plan_ids}
|
|
${executed_count}= Get Length ${executed_ids}
|
|
${total_plan_count_at_execute}= Get Length ${plan_ids}
|
|
Log Plans that completed execution: ${executed_count} / ${total_plan_count_at_execute}
|
|
|
|
# --- Step 6: Apply successfully-executed plans ---
|
|
@{applied_ids}= Apply Batch Plans @{executed_ids}
|
|
${applied_count}= Get Length ${applied_ids}
|
|
Log Plans that reached applied state: ${applied_count} / ${executed_count}
|
|
|
|
# --- Step 7: Verify batch results via plan list ---
|
|
# 7a: Unfiltered listing — smoke test and verify healthy plan IDs appear
|
|
${list_result}= Run CleverAgents Command
|
|
... plan list --format plain
|
|
... timeout=30s
|
|
Log Final plan list stdout: ${list_result.stdout}
|
|
Log Final plan list stderr: ${list_result.stderr}
|
|
Should Not Contain ${list_result.stderr} Traceback
|
|
FOR ${pid} IN @{applied_ids}
|
|
Should Contain ${list_result.stdout} ${pid}
|
|
... Applied plan ID ${pid} not found in plan list output
|
|
END
|
|
|
|
# 7b: Filtered listing — verify --state applied returns successful plans
|
|
${applied_list}= Run CleverAgents Command
|
|
... plan list --state applied --format plain
|
|
... timeout=30s
|
|
Log Applied plan list stdout: ${applied_list.stdout}
|
|
${applied_matches}= Get Regexp Matches ${applied_list.stdout}
|
|
... processing_state:\\s*applied
|
|
${success_count}= Get Length ${applied_matches}
|
|
Log Plans in 'applied' state: ${success_count}
|
|
# At least 2 of 3 healthy packages must reach 'applied' state.
|
|
# Using >= 2 (not == 3) because LLM-generated changes can occasionally fail
|
|
# during apply (e.g. merge conflicts, empty changesets from the LLM producing
|
|
# no edits). Requiring >= 2 verifies the batch mechanism works while
|
|
# tolerating one transient apply failure.
|
|
Should Be True ${success_count} >= 2
|
|
... Expected at least 2 plans (of 3 healthy) to reach 'applied' state but found ${success_count}
|
|
|
|
# --- Step 8: Verify error handling for the broken action ---
|
|
# Count how many plans failed during execution (didn't make it to executed_ids)
|
|
${total_plan_count}= Get Length ${plan_ids}
|
|
${failed_execution_count}= Evaluate ${total_plan_count} - ${executed_count}
|
|
Log Plans that failed during execution: ${failed_execution_count}
|
|
# Also check for errored plans via --state errored filter
|
|
${errored_list}= Run CleverAgents Command
|
|
... plan list --state errored --format plain
|
|
... timeout=30s
|
|
Log Errored plan list stdout: ${errored_list.stdout}
|
|
${errored_matches}= Get Regexp Matches ${errored_list.stdout}
|
|
... processing_state:\\s*errored
|
|
${error_count}= Get Length ${errored_matches}
|
|
Log Plans in 'errored' state: ${error_count}
|
|
# The broken action (non-existent actor) should cause at least one failure.
|
|
# Error handling is demonstrated if ANY of the following hold:
|
|
# (a) broken action's plan use failed (rc != 0)
|
|
# (b) the broken plan's ID is NOT in executed_ids (failed during execution)
|
|
# (c) the broken plan's ID appears in the errored list
|
|
IF ${broken_plan_failed_at_creation}
|
|
Log Error handling demonstrated: broken plan failed at creation (rc != 0)
|
|
ELSE IF "${broken_plan_id}" != "${EMPTY}"
|
|
# Verify the specific broken plan ID either did NOT complete execution
|
|
# or appears in the errored list
|
|
${broken_in_executed}= Evaluate """${broken_plan_id}""" in ${executed_ids}
|
|
${broken_in_errored}= Evaluate """${broken_plan_id}""" in """${errored_list.stdout}"""
|
|
${broken_failed}= Evaluate not ${broken_in_executed} or ${broken_in_errored}
|
|
Should Be True ${broken_failed}
|
|
... Broken plan ${broken_plan_id} should have failed but was found in executed_ids and not in errored list
|
|
Log Error handling demonstrated: broken plan ${broken_plan_id} failed (not in executed=${broken_in_executed}, in errored=${broken_in_errored})
|
|
ELSE
|
|
# Fallback: general failure count check
|
|
${broken_demonstrated}= Evaluate
|
|
... ${error_count} >= 1 or ${failed_execution_count} >= 1
|
|
Should Be True ${broken_demonstrated}
|
|
... Error handling not demonstrated: 0 errored, 0 failed execution
|
|
END
|