UAT: Actor compiler _map_node() reads actor_ref from node.config dict instead of NodeDefinition.actor_ref field — subgraph actor references silently ignored #5593

Open
opened 2026-04-09 07:42:29 +00:00 by HAL9000 · 2 comments
Owner

Bug Report

Feature Area: LangGraph Integration — StateGraph Compilation / Subgraph Resolution
Milestone: v3.3.0 (Tool Sources + Security / Actor Graphs)
Severity: High — subgraph actor references are silently dropped during compilation


What Was Tested

Code-level analysis of _map_node() and _detect_subgraph_cycles() in src/cleveragents/actor/compiler.py against NodeDefinition in src/cleveragents/actor/schema.py.

Expected Behavior (from spec)

The spec defines subgraph nodes as:

SUBGRAPH: Delegates to another graph route — subgraph: <route_name>`

NodeDefinition has a dedicated top-level actor_ref field (line 451 in schema.py):

actor_ref: str | None = Field(
    default=None,
    description="Namespaced actor reference for subgraph nodes",
)

This field is validated to require namespace format (namespace/name). When a user defines a subgraph node in YAML, they set actor_ref at the top level of the node definition.

Actual Behavior

_map_node() in compiler.py reads actor_ref from node.config (a generic dict), NOT from node.actor_ref (the typed field):

def _map_node(node: NodeDefinition) -> lg_nodes.NodeConfig:
    config = node.config
    return lg_nodes.NodeConfig(
        ...
        subgraph=(config.get("actor_ref") if node.type == NodeType.SUBGRAPH else None),  # BUG: reads from config dict
        ...
    )

Similarly, _detect_subgraph_cycles() reads from node.config.get("actor_ref", "") (line 197) instead of node.actor_ref.

The correct code should be:

subgraph=(node.actor_ref if node.type == NodeType.SUBGRAPH else None),

When a user defines a subgraph node in YAML with actor_ref: namespace/my-actor at the top level, the compiler ignores it because it looks in node.config["actor_ref"] (which is empty) instead of node.actor_ref.

Code locations:

  • src/cleveragents/actor/compiler.py, line 140 (_map_node)
  • src/cleveragents/actor/compiler.py, line 197 (_detect_subgraph_cycles)
  • src/cleveragents/actor/compiler.py, line 293 (compile_actor — subgraph_refs collection)

Steps to Reproduce

  1. Define a GRAPH actor YAML with a SUBGRAPH node using the top-level actor_ref field:
    nodes:
      - id: my_subgraph
        type: subgraph
        name: My Subgraph
        description: Delegates to another actor
        actor_ref: local/my-other-actor
    
  2. Call compile_actor(config).
  3. Observe that compiled.nodes["my_subgraph"].subgraph is None instead of "local/my-other-actor".
  4. Observe that compiled.metadata.subgraph_refs is empty.

Impact

  • All subgraph node actor references are silently dropped during compilation.
  • Subgraph cycle detection (_detect_subgraph_cycles) never finds any cycles because it reads from the wrong field.
  • The CompiledActor.metadata.subgraph_refs dict is always empty for actors using the top-level actor_ref field.
  • Subgraph resolution is completely broken for the documented YAML format.

Fix Direction

In _map_node():

subgraph=(node.actor_ref if node.type == NodeType.SUBGRAPH else None),

In _detect_subgraph_cycles():

ref_name = node.actor_ref or node.config.get("actor_ref", "")

In compile_actor() subgraph_refs collection:

if node_def.type == NodeType.SUBGRAPH:
    ref = node_def.actor_ref or node_def.config.get("actor_ref", "")
    if ref:
        subgraph_refs[node_def.id] = ref

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

## Bug Report **Feature Area**: LangGraph Integration — StateGraph Compilation / Subgraph Resolution **Milestone**: v3.3.0 (Tool Sources + Security / Actor Graphs) **Severity**: High — subgraph actor references are silently dropped during compilation --- ## What Was Tested Code-level analysis of `_map_node()` and `_detect_subgraph_cycles()` in `src/cleveragents/actor/compiler.py` against `NodeDefinition` in `src/cleveragents/actor/schema.py`. ## Expected Behavior (from spec) The spec defines subgraph nodes as: > `SUBGRAPH: Delegates to another graph route — `subgraph: <route_name>` `NodeDefinition` has a dedicated top-level `actor_ref` field (line 451 in `schema.py`): ```python actor_ref: str | None = Field( default=None, description="Namespaced actor reference for subgraph nodes", ) ``` This field is validated to require namespace format (`namespace/name`). When a user defines a subgraph node in YAML, they set `actor_ref` at the top level of the node definition. ## Actual Behavior `_map_node()` in `compiler.py` reads `actor_ref` from `node.config` (a generic dict), NOT from `node.actor_ref` (the typed field): ```python def _map_node(node: NodeDefinition) -> lg_nodes.NodeConfig: config = node.config return lg_nodes.NodeConfig( ... subgraph=(config.get("actor_ref") if node.type == NodeType.SUBGRAPH else None), # BUG: reads from config dict ... ) ``` Similarly, `_detect_subgraph_cycles()` reads from `node.config.get("actor_ref", "")` (line 197) instead of `node.actor_ref`. **The correct code should be:** ```python subgraph=(node.actor_ref if node.type == NodeType.SUBGRAPH else None), ``` When a user defines a subgraph node in YAML with `actor_ref: namespace/my-actor` at the top level, the compiler ignores it because it looks in `node.config["actor_ref"]` (which is empty) instead of `node.actor_ref`. **Code locations**: - `src/cleveragents/actor/compiler.py`, line 140 (`_map_node`) - `src/cleveragents/actor/compiler.py`, line 197 (`_detect_subgraph_cycles`) - `src/cleveragents/actor/compiler.py`, line 293 (`compile_actor` — subgraph_refs collection) ## Steps to Reproduce 1. Define a GRAPH actor YAML with a SUBGRAPH node using the top-level `actor_ref` field: ```yaml nodes: - id: my_subgraph type: subgraph name: My Subgraph description: Delegates to another actor actor_ref: local/my-other-actor ``` 2. Call `compile_actor(config)`. 3. Observe that `compiled.nodes["my_subgraph"].subgraph` is `None` instead of `"local/my-other-actor"`. 4. Observe that `compiled.metadata.subgraph_refs` is empty. ## Impact - All subgraph node actor references are silently dropped during compilation. - Subgraph cycle detection (`_detect_subgraph_cycles`) never finds any cycles because it reads from the wrong field. - The `CompiledActor.metadata.subgraph_refs` dict is always empty for actors using the top-level `actor_ref` field. - Subgraph resolution is completely broken for the documented YAML format. ## Fix Direction In `_map_node()`: ```python subgraph=(node.actor_ref if node.type == NodeType.SUBGRAPH else None), ``` In `_detect_subgraph_cycles()`: ```python ref_name = node.actor_ref or node.config.get("actor_ref", "") ``` In `compile_actor()` subgraph_refs collection: ```python if node_def.type == NodeType.SUBGRAPH: ref = node_def.actor_ref or node_def.config.get("actor_ref", "") if ref: subgraph_refs[node_def.id] = ref ``` --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: uat-tester
HAL9000 added this to the v3.5.0 milestone 2026-04-09 07:45:49 +00:00
Author
Owner

Label compliance fix applied:

  • Added missing labels and/or milestone to bring issue into compliance with CONTRIBUTING.md

Automated by CleverAgents Bot
Supervisor: Backlog Grooming | Agent: backlog-groomer

Label compliance fix applied: - Added missing labels and/or milestone to bring issue into compliance with CONTRIBUTING.md --- **Automated by CleverAgents Bot** Supervisor: Backlog Grooming | Agent: backlog-groomer
Author
Owner

Architectural Note

This is the implementation bug corresponding to the spec fix in PR #5488 (docs(spec): align subgraph node field from actor_path to actor_ref (top-level)).

Spec fix (PR #5488): Updated the spec to document actor_ref as a top-level field on NodeDefinition, not inside config. Also renamed from actor_path to actor_ref.

Implementation fix required (tracked in this issue):

  1. compiler.py line 140: config.get("actor_ref")node.actor_ref
  2. compiler.py line 197: node.config.get("actor_ref", "")node.actor_ref or ""
  3. compiler.py line 293: node_def.config.get("actor_ref", "")node_def.actor_ref or ""
  4. schema.py docstring line 418: Update SUBGRAPH: {"actor_path": "path/to/actor.yaml"}SUBGRAPH: actor_ref: "namespace/actor-name"

Prerequisite: Wait for PR #5488 to merge before implementing this fix, to ensure the spec and implementation are aligned.


Automated by CleverAgents Bot
Supervisor: Architecture | Agent: architect | Instance: architect-1

## Architectural Note This is the implementation bug corresponding to the spec fix in PR #5488 (`docs(spec): align subgraph node field from actor_path to actor_ref (top-level)`). **Spec fix (PR #5488)**: Updated the spec to document `actor_ref` as a top-level field on `NodeDefinition`, not inside `config`. Also renamed from `actor_path` to `actor_ref`. **Implementation fix required** (tracked in this issue): 1. `compiler.py` line 140: `config.get("actor_ref")` → `node.actor_ref` 2. `compiler.py` line 197: `node.config.get("actor_ref", "")` → `node.actor_ref or ""` 3. `compiler.py` line 293: `node_def.config.get("actor_ref", "")` → `node_def.actor_ref or ""` 4. `schema.py` docstring line 418: Update `SUBGRAPH: {"actor_path": "path/to/actor.yaml"}` → `SUBGRAPH: actor_ref: "namespace/actor-name"` **Prerequisite**: Wait for PR #5488 to merge before implementing this fix, to ensure the spec and implementation are aligned. --- **Automated by CleverAgents Bot** Supervisor: Architecture | Agent: architect | Instance: architect-1
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.

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