forked from cleveragents/cleveragents-core
2cb82f8acc
Implements M7 (v3.6.0) acceptance criterion: an end-to-end porting task completes autonomously using the full CleverAgents pipeline. Changes: - Add reproducible E2E porting task fixture (examples/actions/e2e-porting.yaml) with invariants, typed arguments, and supervised automation profile - Add E2EPortingService that ties together ACMS context assembly, plan lifecycle (Strategize → Execute → Apply), subplan decomposition, correction engine, and apply phase - Add validate_ported_output() for Python 3 syntax, type annotation, and Python 2 construct checks - Add _apply_stub_porting() deterministic Python 2→3 transformation for test path (no LLM required) - Add Behave BDD tests (features/e2e_porting_task.feature) covering fixture validation, action registration, plan lifecycle, output validation, and lifecycle observability - Add Robot Framework E2E acceptance test (robot/e2e/m7_e2e_porting.robot) covering all M7 acceptance criteria Closes #857
180 lines
7.6 KiB
Gherkin
180 lines
7.6 KiB
Gherkin
@m7 @e2e_porting
|
|
Feature: E2E porting task completes autonomously
|
|
As a CleverAgents user
|
|
I want to define a porting task as a YAML action config
|
|
So that the system autonomously strategizes, decomposes, executes, and applies
|
|
the porting transformation with full lifecycle observability
|
|
|
|
Background:
|
|
Given an E2E porting test environment
|
|
|
|
# ── Fixture validation ────────────────────────────────────────────────────
|
|
|
|
Scenario: E2E porting action fixture is valid YAML
|
|
When I load the e2e-porting action fixture from examples/actions/e2e-porting.yaml
|
|
Then the fixture should parse without errors
|
|
And the fixture name should be "local/e2e-porting"
|
|
And the fixture should have a strategy_actor
|
|
And the fixture should have an execution_actor
|
|
And the fixture should have a definition_of_done
|
|
|
|
Scenario: E2E porting action fixture has required invariants
|
|
When I load the e2e-porting action fixture from examples/actions/e2e-porting.yaml
|
|
Then the fixture invariants should include "valid Python 3 syntax"
|
|
And the fixture invariants should include "type annotations"
|
|
|
|
Scenario: E2E porting action fixture has source_module argument
|
|
When I load the e2e-porting action fixture from examples/actions/e2e-porting.yaml
|
|
Then the fixture should have an argument named "source_module"
|
|
And the "source_module" argument should be required
|
|
|
|
# ── Action registration ───────────────────────────────────────────────────
|
|
|
|
Scenario: Porting action can be registered with the lifecycle service
|
|
When I register the porting action with the lifecycle service
|
|
Then the action "local/e2e-porting" should be available
|
|
And the porting action state should be "available"
|
|
|
|
Scenario: Registering the porting action twice is idempotent
|
|
When I register the porting action with the lifecycle service
|
|
And I register the porting action with the lifecycle service again
|
|
Then the action "local/e2e-porting" should be available
|
|
And no error should have occurred
|
|
|
|
# ── Plan creation ─────────────────────────────────────────────────────────
|
|
|
|
Scenario: Using the porting action creates a plan in Strategize phase
|
|
Given the porting action is registered
|
|
When I use the porting action with source_module "legacy/calculator.py"
|
|
Then a porting plan should be created
|
|
And the porting plan phase should be "strategize"
|
|
And the porting plan processing_state should be "queued"
|
|
|
|
Scenario: Porting plan carries action invariants
|
|
Given the porting action is registered
|
|
When I use the porting action with source_module "legacy/calculator.py"
|
|
Then the porting plan invariants should include "valid Python 3 syntax"
|
|
|
|
# ── Full lifecycle ────────────────────────────────────────────────────────
|
|
|
|
Scenario: Porting task drives through full Strategize → Execute → Apply lifecycle
|
|
Given the porting action is registered
|
|
And a Python 2 source module is available
|
|
When I execute the porting task autonomously
|
|
Then the porting result should indicate success
|
|
And the lifecycle events should include a "strategize" phase event
|
|
And the lifecycle events should include an "execute" phase event
|
|
And the lifecycle events should include an "apply" phase event
|
|
|
|
Scenario: Porting lifecycle events are observable
|
|
Given the porting action is registered
|
|
And a Python 2 source module is available
|
|
When I execute the porting task autonomously
|
|
Then the lifecycle events should not be empty
|
|
And each lifecycle event should have a phase
|
|
And each lifecycle event should have a state
|
|
And each lifecycle event should have a timestamp
|
|
|
|
# ── Validation checks ─────────────────────────────────────────────────────
|
|
|
|
Scenario: Ported output passes Python 3 syntax validation
|
|
Given the porting action is registered
|
|
And a Python 2 source module is available
|
|
When I execute the porting task autonomously
|
|
Then the porting result validation should pass
|
|
And the ported output should be valid Python 3
|
|
|
|
Scenario: Ported output has no Python 2 constructs
|
|
Given the porting action is registered
|
|
And a Python 2 source module is available
|
|
When I execute the porting task autonomously
|
|
Then the ported output should not contain "xrange"
|
|
And the ported output should not contain "basestring"
|
|
And the ported output should not contain ".iteritems()"
|
|
|
|
Scenario: Ported output has type annotations
|
|
Given the porting action is registered
|
|
And a Python 2 source module is available
|
|
When I execute the porting task autonomously
|
|
Then the ported output should contain type annotations
|
|
|
|
# ── Validation helper ─────────────────────────────────────────────────────
|
|
|
|
Scenario: validate_ported_output accepts valid Python 3 with annotations
|
|
When I validate ported output:
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
|
|
def add(a: int, b: int) -> int:
|
|
return a + b
|
|
"""
|
|
Then the porting validation should pass
|
|
And there should be no porting validation errors
|
|
|
|
Scenario: validate_ported_output rejects Python 2 print statement
|
|
When I validate ported output:
|
|
"""
|
|
def greet(name: str) -> None:
|
|
print "Hello " + name
|
|
"""
|
|
Then the porting validation should fail
|
|
And the validation errors should mention "print statement"
|
|
|
|
Scenario: validate_ported_output rejects xrange
|
|
When I validate ported output:
|
|
"""
|
|
def count(n: int) -> None:
|
|
for i in xrange(n):
|
|
pass
|
|
"""
|
|
Then the porting validation should fail
|
|
And the validation errors should mention "xrange"
|
|
|
|
Scenario: validate_ported_output rejects missing type annotations
|
|
When I validate ported output:
|
|
"""
|
|
def add(a, b):
|
|
return a + b
|
|
"""
|
|
Then the porting validation should fail
|
|
And the validation errors should mention "type annotations"
|
|
|
|
Scenario: validate_ported_output rejects syntax errors
|
|
When I validate ported output:
|
|
"""
|
|
def broken(:
|
|
pass
|
|
"""
|
|
Then the porting validation should fail
|
|
And the validation errors should mention "syntax error"
|
|
|
|
# ── Stub porting transformation ───────────────────────────────────────────
|
|
|
|
Scenario: Stub porting converts print statement to print function
|
|
When I apply stub porting to:
|
|
"""
|
|
def greet(name):
|
|
print "Hello " + name
|
|
"""
|
|
Then the stub output should contain "print("
|
|
And the stub output should not contain "print \""
|
|
|
|
Scenario: Stub porting converts xrange to range
|
|
When I apply stub porting to:
|
|
"""
|
|
def count(n):
|
|
for i in xrange(n):
|
|
pass
|
|
"""
|
|
Then the stub output should contain "range("
|
|
And the stub output should not contain "xrange("
|
|
|
|
Scenario: Stub porting adds return type annotation to bare def
|
|
When I apply stub porting to:
|
|
"""
|
|
def process(data):
|
|
return data
|
|
"""
|
|
Then the stub output should contain "-> None:"
|