Files
cleveragents-core/features/skill_flatten.feature
freemo c47e6445d0 feat(actor): compile hierarchical actor configs to LangGraph
Add ActorCompiler module that translates GRAPH-type ActorConfigSchema
definitions into LangGraph NodeConfig/Edge structures with LSP binding
metadata. Includes subgraph resolution with cross-actor cycle detection,
entry/exit validation, and CompilationMetadata for diagnostics.

New files:
- src/cleveragents/actor/compiler.py: Core compiler with compile_actor()
- features/actor_compiler.feature: 13 Behave scenarios
- features/steps/actor_compiler_steps.py: Step definitions
- robot/actor_compiler.robot: 4 Robot smoke tests
- benchmarks/actor_compiler_bench.py: ASV performance benchmarks
- docs/reference/actor_compiler.md: Compilation pipeline reference

Modified:
- src/cleveragents/actor/__init__.py: Export compiler types
- vulture_whitelist.py: Whitelist new public API

ISSUES CLOSED: #158
2026-02-24 17:57:18 +00:00

169 lines
8.9 KiB
Gherkin

@phase1 @domain @skill_flatten
Feature: Skill Registry Flattening and Capability Summaries
As a developer using skill composition
I want skills to be flattened with deterministic ordering and capability summaries
So that actors receive a predictable, well-documented tool set
# ---------------------------------------------------------------------------
# Flattening with named tool refs (deterministic ordering)
# ---------------------------------------------------------------------------
@flatten_tool_refs
Scenario: Flattening a skill with named tool refs produces deterministic order
Given a flatten registry skill "local/basic" with tool refs "local/alpha,local/beta,local/gamma"
When I flatten the skill "local/basic"
Then the flatten result should have 3 entries
And the flatten entry at index 0 should be "local/alpha"
And the flatten entry at index 1 should be "local/beta"
And the flatten entry at index 2 should be "local/gamma"
# ---------------------------------------------------------------------------
# Flattening with includes (depth-first ordering)
# ---------------------------------------------------------------------------
@flatten_includes
Scenario: Flattening a skill with includes uses depth-first ordering
Given a flatten registry skill "local/base" with tool refs "local/base-tool"
And a flatten registry skill "local/mid" including "local/base" with refs "local/mid-tool"
And a flatten registry skill "local/top" including "local/mid" with refs "local/top-tool"
When I flatten the skill "local/top"
Then the flatten result should have 3 entries
And the flatten entry at index 0 should be "local/base-tool"
And the flatten entry at index 1 should be "local/mid-tool"
And the flatten entry at index 2 should be "local/top-tool"
# ---------------------------------------------------------------------------
# Flattening with inline tools
# ---------------------------------------------------------------------------
@flatten_inline
Scenario: Flattening a skill with inline tools includes anonymous entries
Given a flatten registry skill "local/inline-skill" with 2 inline tools
When I flatten the skill "local/inline-skill"
Then the flatten result should have 2 entries
And the flatten entry at index 0 should be "local/inline-skill/_anon_0"
And the flatten entry at index 1 should be "local/inline-skill/_anon_1"
And the flatten entry at index 0 should be marked inline
# ---------------------------------------------------------------------------
# Cycle detection with clear error path
# ---------------------------------------------------------------------------
@flatten_cycle
Scenario: Flattening detects cycles and reports a clear path
Given a flatten registry skill "local/cycle-a" including "local/cycle-b" with no refs
And a flatten registry skill "local/cycle-b" including "local/cycle-a" with no refs
When I try to flatten the skill "local/cycle-a"
Then a flatten cycle error should be raised
And the flatten error should mention "local/cycle-a"
And the flatten error should mention "local/cycle-b"
# ---------------------------------------------------------------------------
# Per-include override application
# ---------------------------------------------------------------------------
@flatten_include_overrides
Scenario: Per-include overrides are applied to included tool entries
Given a flatten registry skill "local/child" with tool refs "local/tool-x"
And a flatten registry skill "local/parent" including "local/child" with overrides timeout 600
When I flatten the skill "local/parent"
Then the flatten result should have 1 entries
And the flatten entry "local/tool-x" should have override "timeout" equal to 600
# ---------------------------------------------------------------------------
# Non-overridable field rejection
# ---------------------------------------------------------------------------
@flatten_non_overridable
Scenario: Non-overridable fields are rejected with clear error
Given a flatten registry skill "local/child-nr" with tool refs "local/tool-y"
And a flatten registry skill "local/parent-nr" including "local/child-nr" with overrides on non-overridable field "name"
When I try to flatten the skill "local/parent-nr"
Then a flatten override error should be raised
And the flatten error should mention "name"
And the flatten error should mention "Non-overridable"
# ---------------------------------------------------------------------------
# Capability summary computation
# ---------------------------------------------------------------------------
@flatten_capability_summary
Scenario: Capability summary aggregates read/write/checkpoint/side-effect flags
Given a flatten registry skill "local/cap-skill" with mixed capability inline tools
When I flatten the skill "local/cap-skill" and compute summary
Then the flatten summary total_tools should be 3
And the flatten summary read_only_tools should be 1
And the flatten summary write_tools should be 1
And the flatten summary has_side_effects should be true
And the flatten summary checkpointable_tools should be 1
# ---------------------------------------------------------------------------
# tools() method returns both entries and summary
# ---------------------------------------------------------------------------
@flatten_tools_method
Scenario: The tools() method returns entries and capability summary
Given a flatten skill registry with skill "local/tools-test" having 3 refs
When I call the flatten tools method for "local/tools-test"
Then the flatten tools result should contain 3 entries
And the flatten tools result should include a capability summary
# ---------------------------------------------------------------------------
# validate_plan() with valid plan
# ---------------------------------------------------------------------------
@flatten_validate_plan
Scenario: validate_plan with a valid plan returns no errors
Given a flatten skill registry with skill "local/plan-skill" having 2 refs
When I call flatten validate_plan with skills "local/plan-skill"
Then the flatten validation result should have 0 errors
# ---------------------------------------------------------------------------
# validate_plan() with missing skill
# ---------------------------------------------------------------------------
@flatten_validate_plan_missing
Scenario: validate_plan with a missing skill reports error
Given an empty flatten skill registry
When I call flatten validate_plan with skills "local/nonexistent"
Then the flatten validation result should have 1 errors
And the flatten validation error should mention "local/nonexistent"
# ---------------------------------------------------------------------------
# validate_plan() with cycle in includes
# ---------------------------------------------------------------------------
@flatten_validate_plan_cycle
Scenario: validate_plan detects cycle in includes
Given a flatten registry skill "local/loop-a" including "local/loop-b" with no refs
And a flatten registry skill "local/loop-b" including "local/loop-a" with no refs
And the flatten registry skills are registered in the skill registry
When I call flatten validate_plan with skills "local/loop-a"
Then the flatten validation result should have 1 errors
And the flatten validation error should mention "ycle"
# ---------------------------------------------------------------------------
# De-duplication semantics (last-wins)
# ---------------------------------------------------------------------------
@flatten_dedup
Scenario: De-duplication uses last-wins for entry metadata
Given a flatten registry skill "local/dup-a" with tool refs "local/shared"
And a flatten registry skill "local/dup-b" with tool refs "local/shared"
And a flatten registry skill "local/dup-top" including "local/dup-a,local/dup-b" with no refs
When I flatten the skill "local/dup-top"
Then the flatten result should have 1 entries
And the flatten entry "local/shared" source_skill should be "local/dup-b"
# ---------------------------------------------------------------------------
# Override merging (shallow merge)
# ---------------------------------------------------------------------------
@flatten_override_merge
Scenario: Override merging uses shallow merge semantics
Given a flatten registry skill "local/merge-child" with tool refs "local/merge-tool" and overrides priority 1
And a flatten registry skill "local/merge-parent" including "local/merge-child" with overrides priority 2 and extra key
When I flatten the skill "local/merge-parent"
Then the flatten entry "local/merge-tool" should have override "priority" equal to 2
And the flatten entry "local/merge-tool" should have override "extra" equal to "yes"