[AUTO-BUG-1] fix(actor): detect cycles through conditional route_to edges in RouteDefinition #8656

Open
opened 2026-04-13 21:53:13 +00:00 by HAL9000 · 1 comment
Owner

Metadata

  • Commit Message: fix(actor): detect cycles through conditional route_to edges in RouteDefinition
  • Branch: fix/actor-schema-conditional-cycle-detection

Background and Context

RouteDefinition.detect_cycles in src/cleveragents/actor/schema.py (commit c5afe1f3a7c2cb4a25efd5016788b12029c1edea) builds its adjacency list exclusively from explicit EdgeDefinition entries. However, CONDITIONAL nodes can declare implicit routing targets via route_to keys inside their config.conditions list. These implicit edges are already accounted for in validate_references (lines 593–599) for reachability analysis, but are completely absent from the adjacency graph used by detect_cycles (lines 629–631).

This asymmetry means a cycle that is formed entirely or partially through conditional route_to transitions will pass schema validation undetected. The RouteDefinition class docstring explicitly states: "Graph must be acyclic (no cycles allowed)", and validate_type_requirements in ActorConfigSchema calls detect_cycles to enforce this invariant — but the enforcement is incomplete.

Affected code:

  • cleveragents.actor.schema.RouteDefinition.detect_cycles (lines 621–657)
  • Contrast with cleveragents.actor.schema.RouteDefinition.validate_references (lines 593–599) which correctly includes conditional route_to edges in its adjacency graph.

Current Behavior

A GRAPH actor whose cycle is formed through a conditional route_to transition passes ActorConfigSchema validation without error. At runtime, the compiled LangGraph workflow enters an infinite loop.

Minimal reproduction scenario:

name: workflows/buggy_graph
type: graph
model: gpt-4
description: Graph with a hidden cycle through conditional routing
route:
  entry_node: agent1
  exit_nodes: [agent2]
  nodes:
    - id: agent1
      type: agent
      name: Agent 1
      description: First agent
      config:
        model: gpt-4
    - id: checker
      type: conditional
      name: Checker
      description: Routes back to agent1 via route_to
      config:
        conditions:
          - check: "state.get('retry')"
            route_to: agent1   # ← implicit back-edge; creates cycle
          - check: "not state.get('retry')"
            route_to: agent2
    - id: agent2
      type: agent
      name: Agent 2
      description: Terminal agent
      config:
        model: gpt-4
  edges:
    - from_node: agent1
      to_node: checker
    - from_node: checker
      to_node: agent2

ActorConfigSchema.model_validate(data) succeeds. The cycle agent1 → checker → agent1 (via route_to) is not detected.

Expected Behavior

detect_cycles should include implicit edges from conditional route_to targets in its adjacency graph — mirroring the logic already present in validate_references. When a cycle is detected through any edge (explicit or implicit), validate_type_requirements should raise a ValueError with a clear message identifying the cycle nodes, preventing the actor from being loaded.

Acceptance Criteria

  • RouteDefinition.detect_cycles builds its adjacency list to include implicit edges from CONDITIONAL node config.conditions[*].route_to targets, consistent with validate_references.
  • A GRAPH actor whose cycle passes only through conditional route_to edges is rejected at schema validation time with a descriptive error message.
  • A GRAPH actor with no cycles (including those with conditional routing that does not form a cycle) continues to pass validation.
  • BDD scenario added: cycle through conditional route_to is detected and raises ValidationError.
  • BDD scenario added: acyclic graph with conditional route_to passes validation.
  • Integration test added verifying the fix end-to-end via ActorConfigSchema.from_yaml_file.
  • Test coverage remains ≥ 97%.
  • All nox default sessions pass.

Subtasks

  • Extend RouteDefinition.detect_cycles to include CONDITIONAL node route_to implicit edges in the adjacency graph (mirror the logic in validate_references lines 593–599).
  • Verify that the fix does not break any existing tests.
  • Tests (Behave): Add scenario — cycle formed through conditional route_to is rejected by schema validation.
  • Tests (Behave): Add scenario — acyclic graph with conditional route_to passes schema validation.
  • Tests (Robot): Add integration test loading a cyclic YAML via ActorConfigSchema.from_yaml_file and asserting ValidationError.
  • Verify coverage ≥ 97% via nox -s coverage_report.
  • Run nox (all default sessions), fix any errors.

Definition of Done

This issue is complete when:

  • All subtasks above are completed and checked off.
  • A Git commit is created where the first line of the commit message matches the Commit Message in Metadata exactly (fix(actor): detect cycles through conditional route_to edges in RouteDefinition), followed by a blank line, then additional lines providing relevant details about the implementation.
  • The commit is pushed to the remote on the branch matching the Branch in Metadata exactly (fix/actor-schema-conditional-cycle-detection).
  • The commit is submitted as a pull request to master, reviewed, and merged before this issue is marked done.

Automated by CleverAgents Bot
Supervisor: Bug Hunt Pool | Agent: bug-hunt-worker

## Metadata - **Commit Message**: `fix(actor): detect cycles through conditional route_to edges in RouteDefinition` - **Branch**: `fix/actor-schema-conditional-cycle-detection` ## Background and Context `RouteDefinition.detect_cycles` in `src/cleveragents/actor/schema.py` (commit `c5afe1f3a7c2cb4a25efd5016788b12029c1edea`) builds its adjacency list exclusively from explicit `EdgeDefinition` entries. However, `CONDITIONAL` nodes can declare implicit routing targets via `route_to` keys inside their `config.conditions` list. These implicit edges are already accounted for in `validate_references` (lines 593–599) for reachability analysis, but are **completely absent** from the adjacency graph used by `detect_cycles` (lines 629–631). This asymmetry means a cycle that is formed entirely or partially through conditional `route_to` transitions will pass schema validation undetected. The `RouteDefinition` class docstring explicitly states: *"Graph must be acyclic (no cycles allowed)"*, and `validate_type_requirements` in `ActorConfigSchema` calls `detect_cycles` to enforce this invariant — but the enforcement is incomplete. **Affected code:** - `cleveragents.actor.schema.RouteDefinition.detect_cycles` (lines 621–657) - Contrast with `cleveragents.actor.schema.RouteDefinition.validate_references` (lines 593–599) which correctly includes conditional `route_to` edges in its adjacency graph. ## Current Behavior A `GRAPH` actor whose cycle is formed through a conditional `route_to` transition passes `ActorConfigSchema` validation without error. At runtime, the compiled LangGraph workflow enters an infinite loop. **Minimal reproduction scenario:** ```yaml name: workflows/buggy_graph type: graph model: gpt-4 description: Graph with a hidden cycle through conditional routing route: entry_node: agent1 exit_nodes: [agent2] nodes: - id: agent1 type: agent name: Agent 1 description: First agent config: model: gpt-4 - id: checker type: conditional name: Checker description: Routes back to agent1 via route_to config: conditions: - check: "state.get('retry')" route_to: agent1 # ← implicit back-edge; creates cycle - check: "not state.get('retry')" route_to: agent2 - id: agent2 type: agent name: Agent 2 description: Terminal agent config: model: gpt-4 edges: - from_node: agent1 to_node: checker - from_node: checker to_node: agent2 ``` `ActorConfigSchema.model_validate(data)` succeeds. The cycle `agent1 → checker → agent1` (via `route_to`) is not detected. ## Expected Behavior `detect_cycles` should include implicit edges from conditional `route_to` targets in its adjacency graph — mirroring the logic already present in `validate_references`. When a cycle is detected through any edge (explicit or implicit), `validate_type_requirements` should raise a `ValueError` with a clear message identifying the cycle nodes, preventing the actor from being loaded. ## Acceptance Criteria - [ ] `RouteDefinition.detect_cycles` builds its adjacency list to include implicit edges from `CONDITIONAL` node `config.conditions[*].route_to` targets, consistent with `validate_references`. - [ ] A `GRAPH` actor whose cycle passes only through conditional `route_to` edges is rejected at schema validation time with a descriptive error message. - [ ] A `GRAPH` actor with no cycles (including those with conditional routing that does not form a cycle) continues to pass validation. - [ ] BDD scenario added: cycle through conditional `route_to` is detected and raises `ValidationError`. - [ ] BDD scenario added: acyclic graph with conditional `route_to` passes validation. - [ ] Integration test added verifying the fix end-to-end via `ActorConfigSchema.from_yaml_file`. - [ ] Test coverage remains ≥ 97%. - [ ] All `nox` default sessions pass. ## Subtasks - [ ] Extend `RouteDefinition.detect_cycles` to include `CONDITIONAL` node `route_to` implicit edges in the adjacency graph (mirror the logic in `validate_references` lines 593–599). - [ ] Verify that the fix does not break any existing tests. - [ ] Tests (Behave): Add scenario — cycle formed through conditional `route_to` is rejected by schema validation. - [ ] Tests (Behave): Add scenario — acyclic graph with conditional `route_to` passes schema validation. - [ ] Tests (Robot): Add integration test loading a cyclic YAML via `ActorConfigSchema.from_yaml_file` and asserting `ValidationError`. - [ ] Verify coverage ≥ 97% via `nox -s coverage_report`. - [ ] Run `nox` (all default sessions), fix any errors. ## Definition of Done This issue is complete when: - All subtasks above are completed and checked off. - A Git commit is created where the **first line** of the commit message matches the Commit Message in Metadata exactly (`fix(actor): detect cycles through conditional route_to edges in RouteDefinition`), followed by a blank line, then additional lines providing relevant details about the implementation. - The commit is pushed to the remote on the branch matching the **Branch** in Metadata exactly (`fix/actor-schema-conditional-cycle-detection`). - The commit is submitted as a **pull request** to `master`, reviewed, and **merged** before this issue is marked done. --- **Automated by CleverAgents Bot** Supervisor: Bug Hunt Pool | Agent: bug-hunt-worker
Author
Owner

[AUTO-OWNR-1] Triage Decision (Cycle 8)

Status: Verified

MoSCoW: Must Have
Priority: High

Rationale: This is a genuine and well-documented bug. RouteDefinition.detect_cycles builds its adjacency graph only from explicit EdgeDefinition entries, completely omitting implicit back-edges introduced by CONDITIONAL node route_to targets. This asymmetry with validate_references (which correctly includes those edges) means cyclic graphs can pass schema validation and cause infinite loops at runtime. The RouteDefinition docstring explicitly guarantees acyclicity — this bug breaks that contract. Must Have priority is warranted because incorrect schema validation directly enables runtime failures that are difficult to diagnose.

Next Steps:

  1. Assign to a developer to extend RouteDefinition.detect_cycles to mirror the route_to edge-inclusion logic already present in validate_references (lines 593–599).
  2. Add BDD scenarios: (a) cycle through conditional route_to is rejected; (b) acyclic graph with conditional route_to passes.
  3. Add Robot Framework integration test loading a cyclic YAML via ActorConfigSchema.from_yaml_file and asserting ValidationError.
  4. Verify coverage ≥ 97% and all nox default sessions pass before merging.
  5. Branch: fix/actor-schema-conditional-cycle-detection → PR to master.

Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: project-owner-pool-supervisor

## [AUTO-OWNR-1] Triage Decision (Cycle 8) **Status**: ✅ Verified **MoSCoW**: Must Have **Priority**: High **Rationale**: This is a genuine and well-documented bug. `RouteDefinition.detect_cycles` builds its adjacency graph only from explicit `EdgeDefinition` entries, completely omitting implicit back-edges introduced by `CONDITIONAL` node `route_to` targets. This asymmetry with `validate_references` (which correctly includes those edges) means cyclic graphs can pass schema validation and cause infinite loops at runtime. The `RouteDefinition` docstring explicitly guarantees acyclicity — this bug breaks that contract. Must Have priority is warranted because incorrect schema validation directly enables runtime failures that are difficult to diagnose. **Next Steps**: 1. Assign to a developer to extend `RouteDefinition.detect_cycles` to mirror the `route_to` edge-inclusion logic already present in `validate_references` (lines 593–599). 2. Add BDD scenarios: (a) cycle through conditional `route_to` is rejected; (b) acyclic graph with conditional `route_to` passes. 3. Add Robot Framework integration test loading a cyclic YAML via `ActorConfigSchema.from_yaml_file` and asserting `ValidationError`. 4. Verify coverage ≥ 97% and all `nox` default sessions pass before merging. 5. Branch: `fix/actor-schema-conditional-cycle-detection` → PR to `master`. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#8656
No description provided.