diff --git a/features/plugin_extension_points.feature b/features/plugin_extension_points.feature index 6a30ff1fa..1319c53ab 100644 --- a/features/plugin_extension_points.feature +++ b/features/plugin_extension_points.feature @@ -1,21 +1,21 @@ Feature: Plugin Extension Points Registration - The plugin infrastructure must register all 30 spec-defined extension + The plugin infrastructure must register all 31 spec-defined extension points with typed Protocol interfaces in the PluginManager. Based on issue #939. # ----------------------------------------------------------------------- - # All 30 extension points are registered + # All 31 extension points are registered # ----------------------------------------------------------------------- - Scenario: All 30 extension points are registered via register_all_extension_points + Scenario: All 31 extension points are registered via register_all_extension_points Given a fresh PluginManager for extension point registration When I register all spec-defined extension points - Then exactly 30 extension points should be registered + Then exactly 31 extension points should be registered Scenario: Extension point definitions are available as a tuple When I retrieve the extension point definitions - Then I should get exactly 30 extension point definitions + Then I should get exactly 31 extension point definitions And each definition should have a non-empty name And each definition should have a protocol_type And each definition should have a non-empty description @@ -60,6 +60,7 @@ Feature: Plugin Extension Points Registration And the "event" category should have 2 extension points And the "config" category should have 2 extension points And the "safety" category should have 1 extension points + And the "scope" category should have 1 extension points # ----------------------------------------------------------------------- # Protocol type correctness @@ -93,8 +94,8 @@ Feature: Plugin Extension Points Registration # TOTAL_EXTENSION_POINTS constant # ----------------------------------------------------------------------- - Scenario: TOTAL_EXTENSION_POINTS constant equals 30 - Then the TOTAL_EXTENSION_POINTS constant should equal 30 + Scenario: TOTAL_EXTENSION_POINTS constant equals 31 + Then the TOTAL_EXTENSION_POINTS constant should equal 31 # ----------------------------------------------------------------------- # Context extension points wired to ACMSPipeline @@ -125,7 +126,7 @@ Feature: Plugin Extension Points Registration Given a fresh PluginManager for extension point registration When I register all spec-defined extension points And I register all spec-defined extension points again - Then exactly 30 extension points should be registered + Then exactly 31 extension points should be registered # ----------------------------------------------------------------------- # Extension point registry_key matches category @@ -227,3 +228,8 @@ Feature: Plugin Extension Points Registration Given a concrete SafetyGuardrailExtension implementation Then it should be recognized as a SafetyGuardrailExtension instance And calling its guardrail methods should succeed + + Scenario: A concrete scope chain resolver satisfies ScopeChainResolverExtension + Given a concrete ScopeChainResolverExtension implementation + Then it should be recognized as a ScopeChainResolverExtension instance + And calling its scope chain resolver methods should succeed diff --git a/features/steps/plugin_extension_points_steps.py b/features/steps/plugin_extension_points_steps.py index 40af78c83..ca368f532 100644 --- a/features/steps/plugin_extension_points_steps.py +++ b/features/steps/plugin_extension_points_steps.py @@ -1,6 +1,6 @@ """Step definitions for plugin_extension_points.feature. -Tests all 30 spec-defined extension points: registration, lookup +Tests all 31 spec-defined extension points: registration, lookup by name, lookup by category, protocol type correctness, entry point discovery, context subsystem wiring, and idempotent registration. @@ -37,6 +37,7 @@ from cleveragents.infrastructure.plugins.extension_protocols import ( ResourceResolverExtension, ResourceTypeHandlerExtension, SafetyGuardrailExtension, + ScopeChainResolverExtension, SkillProviderExtension, SkillTemplateExtension, ToolMiddlewareExtension, @@ -473,6 +474,20 @@ class _StubConfigValidator: return [] +class _StubScopeChainResolver: + @property + def resolver_name(self) -> str: + return "stub_scope_resolver" + + def can_resolve(self, name: str) -> bool: + return name.startswith("stub:") + + def resolve(self, name: str, context: Any) -> str | None: + if self.can_resolve(name): + return f"resolved_{name[5:]}" + return None + + class _StubSafetyGuardrail: @property def guardrail_name(self) -> str: @@ -794,3 +809,25 @@ def step_call_safety_methods(context: Context) -> None: assert impl.guardrail_name == "stub_guardrail" assert impl.check("some_action") is True assert impl.explain() == "Always allows" + +# --- Scope Chain Resolver --- + + +@given("a concrete ScopeChainResolverExtension implementation") +def step_concrete_scope_resolver(context: Context) -> None: + context.ep_impl = _StubScopeChainResolver() + + +@then("it should be recognized as a ScopeChainResolverExtension instance") +def step_isinstance_scope_resolver(context: Context) -> None: + assert isinstance(context.ep_impl, ScopeChainResolverExtension) + + +@then("calling its scope chain resolver methods should succeed") +def step_call_scope_resolver_methods(context: Context) -> None: + impl = context.ep_impl + assert impl.resolver_name == "stub_scope_resolver" + assert impl.can_resolve("stub:test") is True + assert impl.can_resolve("other:test") is False + assert impl.resolve("stub:test", {}) == "resolved_test" + assert impl.resolve("other:test", {}) is None