Feature: Validation Actor Runtime Config Validation As a developer I want actor-level runtime configs to be validated correctly for graph, LLM, tool, and multi_actor types So that only well-formed individual actor configs are accepted by the validation layer Background: Given the validation actor test context is initialized (vac) # ── validate_actor_config dispatch ── Scenario: validate_actor_config dispatches to graph validator for type graph Given a config dict with type graph and route in legacy format (vac) When validate_actor_config is called (vac) Then no error should be raised for valid graph config (vac) Scenario: validate_actor_config dispatches to llm validator for type llm Given a config dict with type llm provider and model (vac) When validate_actor_config is called (vac) Then no error should be raised for valid llm config (vac) Scenario: validate_actor_config dispatches to tool validator for type tool Given a config dict with type tool and tools list (vac) When validate_actor_config is called (vac) Then no error should be raised for valid tool config (vac) Scenario: validate_actor_config dispatches to multi_actor validator for type multi_actor Given a config dict with type multi_actor and actors mapping (vac) When validate_actor_config is called (vac) Then no error should be raised for valid multi_actor config (vac) # ── _infer_actor_type implicit detection ── Scenario: _infer_actor_type detects graph from top-level routes key Given a config dict without type but with top-level routes key (vac) When _infer_actor_type is called (vac) Then the inferred type should be graph (vac) Scenario: _infer_actor_type detects multi_actor from top-level actors key Given a config dict without type but with top-level actors key (vac) When _infer_actor_type is called (vac) Then the inferred type should be multi_actor (vac) Scenario: _infer_actor_type raises when routes has spec-level route types Given a config dict without type but with routes containing spec-level stream entry (vac) When _infer_actor_type is called (vac) Then a ConfigurationError should be raised mentioning missing agents key (vac) Scenario: _infer_actor_type raises for non-string type field Given a config dict with integer type field (vac) When _infer_actor_type is called (vac) Then a ConfigurationError should be raised for non-string type (vac) Scenario: _infer_actor_type raises for unknown actor type Given a config dict with unknown actor type (vac) When _infer_actor_type is called (vac) Then a ConfigurationError should be raised for unknown type (vac) Scenario: _infer_actor_type raises when no type and no routes or actors Given a config dict without type routes or actors (vac) When _infer_actor_type is called (vac) Then a ConfigurationError should be raised for missing type (vac) # ── _validate_graph_actor legacy format ── Scenario: _validate_graph_actor validates legacy format successfully Given a config dict with type graph and legacy route with nodes edges entry_node (vac) When _validate_graph_actor is called (vac) Then no error should be raised for valid legacy graph config (vac) Scenario: _validate_graph_actor rejects legacy format without edges Given a config dict with type graph and legacy route without edges (vac) When _validate_graph_actor is called (vac) Then a ConfigurationError should be raised for missing edges (vac) Scenario: _validate_graph_actor rejects legacy format without entry_node Given a config dict with type graph and legacy route without entry_node (vac) When _validate_graph_actor is called (vac) Then a ConfigurationError should be raised for missing entry_node (vac) Scenario: _validate_graph_actor rejects legacy format exceeding max nodes Given a config dict with type graph and legacy route with 100 nodes (vac) And platform limits with max_total_nodes 10 (vac) When _validate_graph_actor is called (vac) Then a ConfigurationError should be raised for exceeding max nodes (vac) # ── _validate_graph_actor v2.0 format ── Scenario: _validate_graph_actor validates v2.0 format successfully Given a config dict with type graph and v2 routes with nodes edges entry_point (vac) When _validate_graph_actor is called (vac) Then no error should be raised for valid v2 graph config (vac) Scenario: _validate_graph_actor rejects v2 format without edges Given a config dict with type graph and v2 routes without edges (vac) When _validate_graph_actor is called (vac) Then a ConfigurationError should be raised for missing edges in routes main (vac) Scenario: _validate_graph_actor rejects v2 format without entry_point Given a config dict with type graph and v2 routes without entry_point (vac) When _validate_graph_actor is called (vac) Then a ConfigurationError should be raised for missing entry_point in routes main (vac) Scenario: _validate_graph_actor rejects v2 format exceeding max nodes Given a config dict with type graph and v2 routes with 200 nodes (vac) And platform limits with max_total_nodes 10 (vac) When _validate_graph_actor is called (vac) Then a ConfigurationError should be raised for exceeding max nodes (vac) Scenario: _validate_graph_actor rejects v2 format with non-dict routes main Given a config dict with type graph and v2 routes with non-dict main (vac) When _validate_graph_actor is called (vac) Then a ConfigurationError should be raised for non-mapping routes main (vac) # ── _validate_graph_actor neither format ── Scenario: _validate_graph_actor rejects config without route or routes Given a config dict with type graph but no route or routes key (vac) When _validate_graph_actor is called (vac) Then a ConfigurationError should be raised for missing route or routes (vac) # ── _validate_llm_actor ── Scenario: _validate_llm_actor rejects config without name Given a config dict with type llm but no name field (vac) When _validate_llm_actor is called (vac) Then a ConfigurationError should be raised for missing name in llm (vac) Scenario: _validate_llm_actor rejects config without provider Given a config dict with type llm name but no provider (vac) When _validate_llm_actor is called (vac) Then a ConfigurationError should be raised for missing provider (vac) Scenario: _validate_llm_actor rejects config without model Given a config dict with type llm name provider but no model (vac) When _validate_llm_actor is called (vac) Then a ConfigurationError should be raised for missing model (vac) Scenario: _validate_llm_actor accepts config with provider and model in config block Given a config dict with type llm name and provider model in config block (vac) When _validate_llm_actor is called (vac) Then no error should be raised for valid llm config (vac) # ── _validate_tool_actor ── Scenario: _validate_tool_actor rejects config without name Given a config dict with type tool but no name field (vac) When _validate_tool_actor is called (vac) Then a ConfigurationError should be raised for missing name in tool (vac) Scenario: _validate_tool_actor rejects config without tools Given a config dict with type tool name but no tools (vac) When _validate_tool_actor is called (vac) Then a ConfigurationError should be raised for missing tools (vac) Scenario: _validate_tool_actor accepts config with tools in config block Given a config dict with type tool name and tools in config block (vac) When _validate_tool_actor is called (vac) Then no error should be raised for valid tool config (vac) # ── _validate_multi_actor ── Scenario: _validate_multi_actor rejects config with empty actors Given a config dict with type multi_actor and empty actors (vac) When _validate_multi_actor is called (vac) Then a ConfigurationError should be raised for empty actors mapping (vac) Scenario: _validate_multi_actor rejects config with non-dict actors Given a config dict with type multi_actor and non-dict actors (vac) When _validate_multi_actor is called (vac) Then a ConfigurationError should be raised for empty actors mapping (vac) Scenario: _validate_multi_actor rejects config exceeding total nodes limit Given a config dict with type multi_actor containing many graph actors (vac) And platform limits with max_total_nodes 3 (vac) When _validate_multi_actor is called (vac) Then a ConfigurationError should be raised for exceeding total nodes (vac) Scenario: _validate_multi_actor accepts config within node limits Given a config dict with type multi_actor containing few graph actors (vac) And platform limits with max_total_nodes 100 (vac) When _validate_multi_actor is called (vac) Then no error should be raised for valid multi_actor config (vac) # ── Additional edge cases ── Scenario: _validate_graph_actor handles non-int max_total_nodes fallback Given a config dict with type graph and legacy route with nodes edges entry_node (vac) And platform limits with string max_total_nodes value (vac) When _validate_graph_actor is called (vac) Then no error should be raised for valid legacy graph config (vac) Scenario: _validate_graph_actor v2 format with non-dict routes main raises error Given a config dict with type graph and v2 routes having non-dict main value (vac) When _validate_graph_actor is called (vac) Then a ConfigurationError should be raised for non-mapping routes main (vac) Scenario: _validate_llm_actor non-dict config block falls back to empty dict Given a config dict with type llm name without provider and string config block (vac) When _validate_llm_actor is called (vac) Then a ConfigurationError should be raised for missing provider (vac) Scenario: _validate_tool_actor non-dict config block falls back to empty dict Given a config dict with type tool name and string config block (vac) When _validate_tool_actor is called (vac) Then a ConfigurationError should be raised for missing tools (vac) Scenario: _validate_top_level_keys raises ConfigurationError when agents key is missing When I call _validate_top_level_keys on a dict missing the agents key Then a ConfigurationError about missing agents key should be raised Scenario: _count_total_nodes raises ConfigurationError for non-dict nodes value When I call _count_total_nodes with a non-dict nodes value in a graph route Then a ConfigurationError should be raised about nodes being invalid Scenario: _compute_subgraph_depth returns cached value on cache hit When I call _compute_subgraph_depth twice for the same subgraph route Then the second call should return the cached depth value