c4ffc7facc
- Add features/scope_chain_resolver.feature with 15 scenarios covering ScopeResolutionContext construction, ScopeResolverRegistry register/ unregister/resolve/introspection, and all _discover_resolvers paths (load failure, outer exception, dict-style fallback) - Add features/steps/scope_chain_resolver_steps.py with mock-based helpers to exercise the entry-point discovery branches ISSUES CLOSED: #8867
134 lines
6.5 KiB
Gherkin
134 lines
6.5 KiB
Gherkin
@phase2 @acms @scope_chain_resolver
|
|
Feature: Pluggable scope chain resolution extension API
|
|
As a CleverAgents developer
|
|
I want a pluggable scope chain resolver registry with prioritized resolvers
|
|
So that the ACMS context assembly pipeline can resolve scope references via registered extensions
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ScopeResolutionContext
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@scope_resolution_context
|
|
Scenario: Create ScopeResolutionContext with required scope only
|
|
When I create a ScopeResolutionContext with scope "issue:123"
|
|
Then the ScopeResolutionContext scope should be "issue:123"
|
|
And the ScopeResolutionContext metadata should be empty
|
|
And the ScopeResolutionContext resolved_fragments should be empty
|
|
|
|
@scope_resolution_context
|
|
Scenario: Create ScopeResolutionContext with all fields populated
|
|
When I create a full ScopeResolutionContext with scope "pr:456" and metadata key "repo" value "core" and resolved_fragment "frag1"
|
|
Then the ScopeResolutionContext scope should be "pr:456"
|
|
And the ScopeResolutionContext metadata key "repo" should be "core"
|
|
And the ScopeResolutionContext resolved_fragments should contain "frag1"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ScopeResolverRegistry — resolution
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@scope_resolver_registry
|
|
Scenario: Empty registry resolves to empty list
|
|
Given a fresh ScopeResolverRegistry
|
|
When I resolve scope "issue:999" with the registry
|
|
Then the resolution result should be empty
|
|
|
|
@scope_resolver_registry
|
|
Scenario: Register a resolver and resolve a matching scope
|
|
Given a fresh ScopeResolverRegistry
|
|
When I register a resolver named "test" with priority 0 that returns "frag_A" for scope "issue:1"
|
|
And I resolve scope "issue:1" with the registry
|
|
Then the resolution result should contain "frag_A"
|
|
|
|
@scope_resolver_registry
|
|
Scenario: Higher priority resolver wins over lower priority resolver
|
|
Given a fresh ScopeResolverRegistry
|
|
When I register a resolver named "low" with priority 1 that returns "low_frag" for scope "item:1"
|
|
And I register a resolver named "high" with priority 10 that returns "high_frag" for scope "item:1"
|
|
And I resolve scope "item:1" with the registry
|
|
Then the resolution result should contain "high_frag"
|
|
And the resolution result should not contain "low_frag"
|
|
|
|
@scope_resolver_registry
|
|
Scenario: First matching resolver wins and stops iteration
|
|
Given a fresh ScopeResolverRegistry
|
|
When I register a resolver named "alpha" with priority 5 that returns "alpha_frag" for scope "x:1"
|
|
And I register a resolver named "beta" with priority 3 that returns "beta_frag" for scope "x:1"
|
|
And I resolve scope "x:1" with the registry
|
|
Then the resolution result should contain "alpha_frag"
|
|
And the resolution result should not contain "beta_frag"
|
|
|
|
@scope_resolver_registry
|
|
Scenario: Resolve returns empty when no resolver matches the scope
|
|
Given a fresh ScopeResolverRegistry
|
|
When I register a null resolver named "no_match" with priority 0
|
|
And I resolve scope "unknown:1" with the registry
|
|
Then the resolution result should be empty
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ScopeResolverRegistry — register / unregister
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@scope_resolver_registry @register
|
|
Scenario: Register a resolver with explicit priority stores it correctly
|
|
Given a fresh ScopeResolverRegistry
|
|
When I register a null resolver named "myresolver" with priority 42
|
|
Then the registry should contain a resolver named "myresolver"
|
|
And the resolver named "myresolver" should have priority 42
|
|
|
|
@scope_resolver_registry @unregister
|
|
Scenario: Unregister removes an existing resolver
|
|
Given a fresh ScopeResolverRegistry
|
|
When I register a null resolver named "to_remove" with priority 0
|
|
And I unregister the resolver named "to_remove"
|
|
Then the registry should not contain a resolver named "to_remove"
|
|
|
|
@scope_resolver_registry @unregister
|
|
Scenario: Unregister non-existent resolver is a safe no-op
|
|
Given a fresh ScopeResolverRegistry
|
|
When I unregister the resolver named "does_not_exist"
|
|
Then the registry should not contain a resolver named "does_not_exist"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ScopeResolverRegistry — introspection
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@scope_resolver_registry @introspection
|
|
Scenario: get_resolvers returns all registered resolvers
|
|
Given a fresh ScopeResolverRegistry
|
|
When I register a null resolver named "r1" with priority 1
|
|
And I register a null resolver named "r2" with priority 2
|
|
Then get_resolvers should return 2 entries
|
|
And get_resolvers should include key "r1"
|
|
And get_resolvers should include key "r2"
|
|
|
|
@scope_resolver_registry @introspection
|
|
Scenario: list_resolvers returns entries sorted by priority descending
|
|
Given a fresh ScopeResolverRegistry
|
|
When I register a null resolver named "low_pri" with priority 1
|
|
And I register a null resolver named "high_pri" with priority 9
|
|
And I register a null resolver named "mid_pri" with priority 5
|
|
Then list_resolvers should return 3 entries in priority order
|
|
| name | priority |
|
|
| high_pri | 9 |
|
|
| mid_pri | 5 |
|
|
| low_pri | 1 |
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ScopeResolverRegistry — _discover_resolvers coverage paths
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@scope_resolver_registry @discover
|
|
Scenario: Discovery silently ignores entry point load failures
|
|
Given a ScopeResolverRegistry with a failing entry point
|
|
Then the scope resolver registry should be empty
|
|
|
|
@scope_resolver_registry @discover
|
|
Scenario: Discovery silently ignores outer entry_points exception
|
|
Given a ScopeResolverRegistry where entry_points raises an exception
|
|
Then the scope resolver registry should be empty
|
|
|
|
@scope_resolver_registry @discover
|
|
Scenario: Discovery uses dict-style fallback for older importlib_metadata API
|
|
Given a ScopeResolverRegistry with dict-style entry points returning no scope resolvers
|
|
Then the scope resolver registry should be empty
|