3224f2136e
CI / lint (pull_request) Successful in 27s
CI / typecheck (pull_request) Successful in 52s
CI / quality (pull_request) Successful in 32s
CI / security (pull_request) Successful in 59s
CI / build (pull_request) Successful in 29s
CI / helm (pull_request) Successful in 23s
CI / unit_tests (pull_request) Successful in 6m58s
CI / e2e_tests (pull_request) Successful in 19m39s
CI / integration_tests (pull_request) Successful in 22m49s
CI / coverage (pull_request) Successful in 10m43s
CI / docker (pull_request) Successful in 1m23s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Successful in 56m57s
Replace the flat `parent_types` membership check in `BindingResolutionService._is_type_compatible` with a call to `self._registry.is_subtype_of()`, which uses `resolve_inheritance_chain()` from `cleveragents.resource.inheritance` to walk the full ADR-042 inheritance chain. Previously, a tool requiring type `container-instance` would fail to bind a `devcontainer-instance` resource because the check only looked at the immediate `parent_types` list rather than traversing the full chain. The fix ensures multi-level inheritance (e.g. `local/special-dev-container` → `devcontainer-instance` → `container-instance`) is correctly resolved for contextual, static, and parameter bindings. Changes: - `binding_resolution_service.py`: `_is_type_compatible` now delegates to `registry.is_subtype_of()`; removed unused `ResourceTypeSpec` import. - `consolidated_binding_resolution.feature`: 4 new scenarios covering 2-level chain, 3-level chain, unrelated-type rejection, and static binding via inheritance chain. - `binding_resolution_steps.py`: mock registry exposes `is_subtype_of()` backed by the real inheritance engine; new step definitions for inheritance chain setup. ISSUES CLOSED: #2929
358 lines
18 KiB
Gherkin
358 lines
18 KiB
Gherkin
Feature: Consolidated Binding Resolution
|
|
Combined scenarios from: binding_resolution, binding_resolution_coverage
|
|
|
|
# ============================================================
|
|
# Originally from: binding_resolution.feature
|
|
# Feature: Tool Resource Binding Resolution
|
|
# ============================================================
|
|
|
|
@contextual @single_match
|
|
Scenario: Contextual binding with single matching resource
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a project "local/my-project" with a linked resource:
|
|
| resource_id | type_name | alias |
|
|
| 01HGZ6FE0AQDYTR4BX00000001 | git-checkout | repo |
|
|
And a tool "local/reader" with a contextual slot "repo" of type "git-checkout"
|
|
When the bindings are resolved
|
|
Then the binding for slot "repo" should have mode "contextual"
|
|
And the binding for slot "repo" should have resource_id "01HGZ6FE0AQDYTR4BX00000001"
|
|
And the binding for slot "repo" should not be deferred
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Contextual binding -- multiple matches with alias hint
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@contextual @alias_hint
|
|
Scenario: Contextual binding with multiple matches uses alias hint
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a project "local/multi" with linked resources:
|
|
| resource_id | type_name | alias |
|
|
| 01HGZ6FE0AQDYTR4BX00000010 | git-checkout | repo |
|
|
| 01HGZ6FE0AQDYTR4BX00000011 | git-checkout | backup |
|
|
And a tool "local/reader" with a contextual slot "repo" of type "git-checkout"
|
|
When the bindings are resolved
|
|
Then the binding for slot "repo" should have resource_id "01HGZ6FE0AQDYTR4BX00000010"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Contextual binding -- no match (error)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@contextual @no_match @error_handling
|
|
Scenario: Contextual binding with no matching resource raises error
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a project "local/empty" with no linked resources
|
|
And a tool "local/reader" with a contextual slot "repo" of type "git-checkout"
|
|
When the binding resolution is attempted
|
|
Then a binding ValidationError should be raised mentioning "No resource of type"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Static binding resolution
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@static
|
|
Scenario: Static binding resolves named resource
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a resource "local/shared-config" of type "fs-directory" in the registry
|
|
And a tool "local/deployer" with a static slot "config_dir" bound to "local/shared-config" of type "fs-directory"
|
|
And a project "local/proj" with no linked resources
|
|
When the bindings are resolved
|
|
Then the binding for slot "config_dir" should have mode "static"
|
|
And the binding for slot "config_dir" should have resource_id "01HGZ6FE0AQDYTR4BX00000020"
|
|
And the binding for slot "config_dir" should not be deferred
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Parameter binding (deferred)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@parameter @deferred
|
|
Scenario: Parameter binding is deferred when no invocation params given
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a tool "local/builder" with a parameter slot "target" of type "fs-directory"
|
|
And a project "local/proj" with no linked resources
|
|
When the bindings are resolved
|
|
Then the binding for slot "target" should have mode "parameter"
|
|
And the binding for slot "target" should be deferred
|
|
And the binding for slot "target" should have no resource_id
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Type compatibility -- pass (sub-type)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@type_compat @pass
|
|
Scenario: Type compatibility passes for sub-type via parent_types
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a project "local/typed" with a linked resource:
|
|
| resource_id | type_name | alias |
|
|
| 01HGZ6FE0AQDYTR4BX00000030 | fs-directory | repo |
|
|
And the resource type "fs-directory" has parent_types including "git-checkout"
|
|
And a tool "local/compat" with a contextual slot "repo" of type "git-checkout"
|
|
When the bindings are resolved
|
|
Then the binding for slot "repo" should have resource_id "01HGZ6FE0AQDYTR4BX00000030"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Type compatibility -- fail
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@type_compat @fail @error_handling
|
|
Scenario: Type compatibility fails for incompatible types
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a resource "local/wrong-type" of type "fs-file" in the registry
|
|
And the resource type "fs-file" has no parent_types
|
|
And a tool "local/strict" with a static slot "data" bound to "local/wrong-type" of type "git-checkout"
|
|
And a project "local/proj" with no linked resources
|
|
When the binding resolution is attempted
|
|
Then a binding ValidationError should be raised mentioning "Type mismatch"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Mixed bindings on same tool
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@mixed
|
|
Scenario: Mixed bindings on same tool resolve correctly
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a project "local/mixed" with a linked resource:
|
|
| resource_id | type_name | alias |
|
|
| 01HGZ6FE0AQDYTR4BX00000040 | git-checkout | repo |
|
|
And a resource "local/shared-config" of type "fs-directory" in the registry
|
|
And a tool "local/multi-bind" with mixed slots:
|
|
| name | resource_type | binding | static_resource |
|
|
| repo | git-checkout | contextual | |
|
|
| config | fs-directory | static | local/shared-config |
|
|
| output | fs-directory | parameter | |
|
|
When the bindings are resolved
|
|
Then there should be 3 binding results
|
|
And the binding for slot "repo" should have mode "contextual"
|
|
And the binding for slot "config" should have mode "static"
|
|
And the binding for slot "output" should have mode "parameter"
|
|
And the binding for slot "output" should be deferred
|
|
|
|
|
|
# ============================================================
|
|
# Originally from: binding_resolution_coverage.feature
|
|
# Feature: Binding Resolution Service - Coverage Gaps
|
|
# ============================================================
|
|
|
|
@static @error_handling
|
|
Scenario: Static binding raises ValidationError for unknown resource
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a tool "local/deployer" with a static slot "cfg" bound to "local/nonexistent" of type "fs-directory"
|
|
And a project "local/proj" with no linked resources
|
|
When the binding resolution is attempted
|
|
Then a binding ValidationError should be raised mentioning "Static binding for slot"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Parameter binding -- provided ref not found (lines 198-201)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@parameter @error_handling
|
|
Scenario: Parameter binding raises ValidationError for unknown ref
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a tool "local/builder" with a parameter slot "target" of type "fs-directory"
|
|
And a project "local/proj" with no linked resources
|
|
When the bindings are resolved with invocation params:
|
|
| slot | ref |
|
|
| target | local/does-not-exist |
|
|
Then a binding ValidationError should be raised mentioning "Parameter binding for slot"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Parameter binding -- valid ref resolves (lines 209, 214)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@parameter @resolve
|
|
Scenario: Parameter binding resolves successfully with valid ref
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a named resource "01HGZ6FE0AQDYTR4BX00000060" called "local/my-dir" of type "fs-directory" in the registry
|
|
And a tool "local/builder" with a parameter slot "target" of type "fs-directory"
|
|
And a project "local/proj" with no linked resources
|
|
When the bindings are resolved with invocation params:
|
|
| slot | ref |
|
|
| target | local/my-dir |
|
|
Then the binding for slot "target" should have mode "parameter"
|
|
And the binding for slot "target" should have resource_id "01HGZ6FE0AQDYTR4BX00000060"
|
|
And the binding for slot "target" should not be deferred
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Contextual binding -- no match, slot NOT required (line 274)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@contextual @optional
|
|
Scenario: Contextual binding returns None resource when slot is not required
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a project "local/empty" with no linked resources
|
|
And a tool "local/reader" with an optional contextual slot "extras" of type "git-checkout"
|
|
When the bindings are resolved
|
|
Then the binding for slot "extras" should have mode "contextual"
|
|
And the binding for slot "extras" should have no resource_id
|
|
And the binding for slot "extras" should not be deferred
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# _find_matching_resources -- NotFoundError skipped (lines 298-299)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@contextual @not_found_skip
|
|
Scenario: Contextual binding skips linked resources that raise NotFoundError
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a project "local/mixed" with linked resources including a missing one:
|
|
| resource_id | type_name | alias | exists |
|
|
| 01HGZ6FE0AQDYTR4BX00000070 | git-checkout | gone | false |
|
|
| 01HGZ6FE0AQDYTR4BX00000071 | git-checkout | repo | true |
|
|
And a tool "local/reader" with a contextual slot "repo" of type "git-checkout"
|
|
When the bindings are resolved
|
|
Then the binding for slot "repo" should have resource_id "01HGZ6FE0AQDYTR4BX00000071"
|
|
And the binding for slot "repo" should not be deferred
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# _disambiguate -- name suffix matching (lines 325-329)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@contextual @disambiguate @name_suffix
|
|
Scenario: Disambiguation matches slot name against resource name suffix
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a project "local/multi" with named linked resources:
|
|
| resource_id | type_name | alias | resource_name |
|
|
| 01HGZ6FE0AQDYTR4BX00000080 | git-checkout | alpha | local/frontend/repo |
|
|
| 01HGZ6FE0AQDYTR4BX00000081 | git-checkout | beta | local/backend/other |
|
|
And a tool "local/reader" with a contextual slot "repo" of type "git-checkout"
|
|
When the bindings are resolved
|
|
Then the binding for slot "repo" should have resource_id "01HGZ6FE0AQDYTR4BX00000080"
|
|
And the binding for slot "repo" should have resource_name "local/frontend/repo"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# _disambiguate -- ambiguous (lines 337-338)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@contextual @disambiguate @ambiguous @error_handling
|
|
Scenario: Disambiguation raises ValidationError for ambiguous candidates
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a project "local/multi" with named linked resources:
|
|
| resource_id | type_name | alias | resource_name |
|
|
| 01HGZ6FE0AQDYTR4BX00000090 | git-checkout | alpha | local/first |
|
|
| 01HGZ6FE0AQDYTR4BX00000091 | git-checkout | beta | local/second |
|
|
And a tool "local/reader" with a contextual slot "repo" of type "git-checkout"
|
|
When the binding resolution is attempted
|
|
Then a binding ValidationError should be raised mentioning "Ambiguous contextual binding"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# _is_type_compatible -- is_subtype_of returns False for unknown type
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@type_compat @not_found
|
|
Scenario: Type compatibility returns False for unknown type
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a project "local/typed" with a linked resource:
|
|
| resource_id | type_name | alias |
|
|
| 01HGZ6FE0AQDYTR4BX00000095 | unknown-type | repo |
|
|
And the resource type "unknown-type" is removed from the registry
|
|
And a tool "local/reader" with a contextual slot "repo" of type "git-checkout"
|
|
And the slot "repo" is required
|
|
When the binding resolution is attempted
|
|
Then a binding ValidationError should be raised mentioning "No resource of type"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Multi-level inheritance -- contextual binding (ADR-042 fix)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@type_compat @inheritance @multi_level
|
|
Scenario: Contextual binding resolves via two-level inheritance chain
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a project "local/typed" with a linked resource:
|
|
| resource_id | type_name | alias |
|
|
| 01HGZ6FE0AQDYTR4BX00000100 | devcontainer-instance | env |
|
|
And the resource type "container-instance" inherits from nothing
|
|
And the resource type "devcontainer-instance" inherits from "container-instance"
|
|
And a tool "local/runner" with a contextual slot "env" of type "container-instance"
|
|
When the bindings are resolved
|
|
Then the binding for slot "env" should have resource_id "01HGZ6FE0AQDYTR4BX00000100"
|
|
And the binding for slot "env" should have mode "contextual"
|
|
And the binding for slot "env" should not be deferred
|
|
|
|
@type_compat @inheritance @multi_level
|
|
Scenario: Contextual binding resolves via three-level inheritance chain
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a project "local/typed" with a linked resource:
|
|
| resource_id | type_name | alias |
|
|
| 01HGZ6FE0AQDYTR4BX00000101 | local/special-dev-container | env |
|
|
And the resource type "container-instance" inherits from nothing
|
|
And the resource type "devcontainer-instance" inherits from "container-instance"
|
|
And the resource type "local/special-dev-container" inherits from "devcontainer-instance"
|
|
And a tool "local/runner" with a contextual slot "env" of type "container-instance"
|
|
When the bindings are resolved
|
|
Then the binding for slot "env" should have resource_id "01HGZ6FE0AQDYTR4BX00000101"
|
|
And the binding for slot "env" should have mode "contextual"
|
|
And the binding for slot "env" should not be deferred
|
|
|
|
@type_compat @inheritance @unrelated_type
|
|
Scenario: Contextual binding rejects unrelated type even with inheritance present
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a project "local/typed" with a linked resource:
|
|
| resource_id | type_name | alias |
|
|
| 01HGZ6FE0AQDYTR4BX00000102 | fs-directory | dir |
|
|
And the resource type "container-instance" inherits from nothing
|
|
And a tool "local/runner" with a contextual slot "env" of type "container-instance"
|
|
And the slot "env" is required
|
|
When the binding resolution is attempted
|
|
Then a binding ValidationError should be raised mentioning "No resource of type"
|
|
|
|
@type_compat @inheritance @static_binding
|
|
Scenario: Static binding resolves via two-level inheritance chain
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a resource "local/my-devcontainer" of type "devcontainer-instance" in the registry
|
|
And the resource type "container-instance" inherits from nothing
|
|
And the resource type "devcontainer-instance" inherits from "container-instance"
|
|
And a tool "local/runner" with a static slot "env" bound to "local/my-devcontainer" of type "container-instance"
|
|
And a project "local/proj" with no linked resources
|
|
When the bindings are resolved
|
|
Then the binding for slot "env" should have mode "static"
|
|
And the binding for slot "env" should not be deferred
|
|
|
|
@type_compat @inheritance @parameter_binding
|
|
Scenario: Parameter binding resolves via two-level inheritance chain
|
|
Given a mock resource registry
|
|
And a binding resolution service using the registry
|
|
Given a named resource "01HGZ6FE0AQDYTR4BX00000103" called "local/my-devcontainer" of type "devcontainer-instance" in the registry
|
|
And the resource type "container-instance" inherits from nothing
|
|
And the resource type "devcontainer-instance" inherits from "container-instance"
|
|
And a tool "local/runner" with a parameter slot "env" of type "container-instance"
|
|
And a project "local/proj" with no linked resources
|
|
When the bindings are resolved with invocation params:
|
|
| slot | ref |
|
|
| env | local/my-devcontainer |
|
|
Then the binding for slot "env" should have mode "parameter"
|
|
And the binding for slot "env" should not be deferred
|