UAT: ActorRegistry does not detect circular actor references at registration time — spec requires cycle detection #2503

Open
opened 2026-04-03 18:40:25 +00:00 by freemo · 1 comment
Owner

Metadata

  • Branch: feat/actor-circular-reference-detection
  • Commit Message: feat(actor): add circular reference detection to ActorRegistry at registration time
  • Milestone: v3.6.0
  • Parent Epic: #392

Summary

The specification explicitly states that "Circular actor references are prohibited and detected at registration time." The ActorRegistry (in src/cleveragents/actor/registry.py) does not implement any circular reference detection. An actor that references itself (directly or transitively through other actors) can be registered without error, which would cause infinite loops at runtime.

Expected Behavior (from spec)

The specification (docs/specification.md, Actor Composition section) states:

Load order matters: Referenced actors must be loaded/defined before actors that depend on them.

Circular actor references are prohibited and detected at registration time.

When agents actor add --config actor.yaml is called for an actor that creates a circular reference (e.g., Actor A references Actor B which references Actor A), the registration should fail with a clear error message identifying the cycle.

Actual Behavior

ActorRegistry.add() and ActorRegistry.upsert_actor() do not check for circular references. An actor YAML that references another actor (via config.actor: or graph node actor_ref:) can create a cycle without any error at registration time.

The ActorConfigSchema (in src/cleveragents/actor/schema.py) does implement cycle detection for graph node edges within a single actor (RouteDefinition.detect_cycles()), but this only detects cycles within a single actor's internal graph — not cycles between actors in the registry.

Code Locations

  • src/cleveragents/actor/registry.pyActorRegistry.add() and upsert_actor() have no cross-actor cycle detection
  • src/cleveragents/actor/schema.pyRouteDefinition.detect_cycles() only detects intra-actor cycles
  • The actor_ref field on NodeDefinition allows referencing other actors by name, but no registry-level cycle check is performed

Example Scenario

# actor-a.yaml
name: local/actor-a
type: graph
model: openai/gpt-4
route:
  nodes:
    - id: step1
      type: subgraph
      name: Step 1
      description: Calls actor-b
      actor_ref: local/actor-b
  edges: []
  entry_node: step1
  exit_nodes: [step1]
# actor-b.yaml
name: local/actor-b
type: graph
model: openai/gpt-4
route:
  nodes:
    - id: step1
      type: subgraph
      name: Step 1
      description: Calls actor-a (CYCLE!)
      actor_ref: local/actor-a
  edges: []
  entry_node: step1
  exit_nodes: [step1]

Both actors can be registered without error. At runtime, invoking either would cause infinite recursion.

Subtasks

  • Implement ActorRegistry._detect_actor_cycles(name, graph_descriptor) that walks actor references recursively
  • Call cycle detection in ActorRegistry.add() and upsert_actor() after persisting the actor
  • Return a clear error message: "Circular actor reference detected: local/actor-a → local/actor-b → local/actor-a"
  • Add Behave unit tests for circular actor reference detection

Definition of Done

  • agents actor add fails with a clear error when a circular actor reference is detected
  • The error message identifies the full cycle path
  • Non-circular actor references continue to work correctly
  • nox -e unit_tests passes

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-uat-tester

## Metadata - **Branch**: `feat/actor-circular-reference-detection` - **Commit Message**: `feat(actor): add circular reference detection to ActorRegistry at registration time` - **Milestone**: v3.6.0 - **Parent Epic**: #392 ## Summary The specification explicitly states that "Circular actor references are **prohibited** and detected at registration time." The `ActorRegistry` (in `src/cleveragents/actor/registry.py`) does not implement any circular reference detection. An actor that references itself (directly or transitively through other actors) can be registered without error, which would cause infinite loops at runtime. ## Expected Behavior (from spec) The specification (`docs/specification.md`, Actor Composition section) states: > **Load order matters**: Referenced actors must be loaded/defined before actors that depend on them. > > Circular actor references are **prohibited** and detected at registration time. When `agents actor add --config actor.yaml` is called for an actor that creates a circular reference (e.g., Actor A references Actor B which references Actor A), the registration should fail with a clear error message identifying the cycle. ## Actual Behavior `ActorRegistry.add()` and `ActorRegistry.upsert_actor()` do not check for circular references. An actor YAML that references another actor (via `config.actor:` or graph node `actor_ref:`) can create a cycle without any error at registration time. The `ActorConfigSchema` (in `src/cleveragents/actor/schema.py`) does implement cycle detection for **graph node edges** within a single actor (`RouteDefinition.detect_cycles()`), but this only detects cycles within a single actor's internal graph — not cycles between actors in the registry. ## Code Locations - `src/cleveragents/actor/registry.py` — `ActorRegistry.add()` and `upsert_actor()` have no cross-actor cycle detection - `src/cleveragents/actor/schema.py` — `RouteDefinition.detect_cycles()` only detects intra-actor cycles - The `actor_ref` field on `NodeDefinition` allows referencing other actors by name, but no registry-level cycle check is performed ## Example Scenario ```yaml # actor-a.yaml name: local/actor-a type: graph model: openai/gpt-4 route: nodes: - id: step1 type: subgraph name: Step 1 description: Calls actor-b actor_ref: local/actor-b edges: [] entry_node: step1 exit_nodes: [step1] ``` ```yaml # actor-b.yaml name: local/actor-b type: graph model: openai/gpt-4 route: nodes: - id: step1 type: subgraph name: Step 1 description: Calls actor-a (CYCLE!) actor_ref: local/actor-a edges: [] entry_node: step1 exit_nodes: [step1] ``` Both actors can be registered without error. At runtime, invoking either would cause infinite recursion. ## Subtasks - [ ] Implement `ActorRegistry._detect_actor_cycles(name, graph_descriptor)` that walks actor references recursively - [ ] Call cycle detection in `ActorRegistry.add()` and `upsert_actor()` after persisting the actor - [ ] Return a clear error message: `"Circular actor reference detected: local/actor-a → local/actor-b → local/actor-a"` - [ ] Add Behave unit tests for circular actor reference detection ## Definition of Done - `agents actor add` fails with a clear error when a circular actor reference is detected - The error message identifies the full cycle path - Non-circular actor references continue to work correctly - `nox -e unit_tests` passes --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-uat-tester
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • MoSCoW: Should Have — Spec compliance or quality improvement that should be included in the milestone.

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

Issue triaged by project owner: - **State**: Verified - **MoSCoW**: Should Have — Spec compliance or quality improvement that should be included in the milestone. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
freemo added this to the v3.7.0 milestone 2026-04-05 05:07:07 +00:00
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#2503
No description provided.