798db9088e
CI / lint (pull_request) Successful in 15s
CI / typecheck (pull_request) Successful in 36s
CI / security (pull_request) Successful in 25s
CI / quality (pull_request) Successful in 19s
CI / build (pull_request) Successful in 23s
CI / integration_tests (pull_request) Successful in 6m49s
CI / coverage (pull_request) Successful in 12m1s
CI / unit_tests (pull_request) Successful in 16m28s
CI / docker (pull_request) Successful in 51s
258 lines
13 KiB
Gherkin
258 lines
13 KiB
Gherkin
@phase1 @domain @repository @tool_registry
|
|
Feature: Tool Registry Persistence
|
|
As a system operator managing tools and validations
|
|
I want the tool registry to reliably persist, retrieve, and filter tools
|
|
So that the execution layer can discover and invoke tools at runtime
|
|
|
|
Background:
|
|
Given a clean in-memory database with the tool registry schema
|
|
And a tool registry repository backed by the database
|
|
And a validation attachment repository backed by the database
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Registering tools
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@tool_reg_create
|
|
Scenario: A new builtin tool is registered and retrievable
|
|
Given a valid tool dict named "core/read-file" with source "builtin"
|
|
When the tool is registered through the tool registry repository
|
|
Then the tool registry repository should not raise an error
|
|
And the persisted tool should have the registry name "core/read-file"
|
|
|
|
@tool_reg_create
|
|
Scenario: A custom tool with inline code is registered
|
|
Given a valid tool dict named "local/custom-lint" with source "custom"
|
|
And the tool dict includes inline code "return {'passed': True}"
|
|
When the tool is registered through the tool registry repository
|
|
Then the persisted tool should have the registry name "local/custom-lint"
|
|
And the persisted tool should have source "custom"
|
|
|
|
@tool_reg_create
|
|
Scenario: An MCP tool is registered with server fields
|
|
Given a valid tool dict named "mcp/github-search" with source "mcp"
|
|
And the tool dict includes mcp_server "github" and mcp_tool_name "search"
|
|
When the tool is registered through the tool registry repository
|
|
Then the persisted tool should have the registry name "mcp/github-search"
|
|
|
|
@tool_reg_create
|
|
Scenario: A validation tool is registered with mode
|
|
Given a valid tool dict named "core/schema-check" with source "builtin"
|
|
And the tool dict has tool_type "validation" and mode "required"
|
|
When the tool is registered through the tool registry repository
|
|
Then the persisted tool should have tool_type "validation"
|
|
|
|
@tool_reg_create
|
|
Scenario: A tool is registered with resource bindings
|
|
Given a valid tool dict named "core/git-commit" with source "builtin"
|
|
And the tool dict includes a resource binding for slot "repo"
|
|
When the tool is registered through the tool registry repository
|
|
Then the persisted tool should have 1 resource binding
|
|
|
|
@tool_reg_create @error_handling
|
|
Scenario: Registering a tool with a duplicate name is rejected
|
|
Given a valid tool dict named "core/read-file" with source "builtin"
|
|
And the tool has already been registered once in the tool registry
|
|
When a second tool with the same registry name "core/read-file" is registered
|
|
Then a DuplicateToolError should be raised mentioning "core/read-file"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Retrieving tools by name
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@tool_reg_read
|
|
Scenario: A tool is retrieved by its namespaced name
|
|
Given a valid tool dict named "core/write-file" with source "builtin"
|
|
And the tool has been registered through the tool registry repository
|
|
When the tool is looked up by registry name "core/write-file"
|
|
Then the returned tool should have the registry name "core/write-file"
|
|
|
|
@tool_reg_read
|
|
Scenario: Looking up a non-existent tool name returns nothing
|
|
When the tool is looked up by registry name "core/does-not-exist"
|
|
Then no tool should be returned from the registry
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Listing tools with filters
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@tool_reg_list
|
|
Scenario: All tools are listed without filters
|
|
Given the following tools have been registered:
|
|
| name | source | tool_type |
|
|
| core/read-file | builtin | tool |
|
|
| core/write-file | builtin | tool |
|
|
| local/custom-lint | custom | validation |
|
|
When all tools are listed from the tool registry
|
|
Then 3 tools should be returned from the registry
|
|
|
|
@tool_reg_list
|
|
Scenario: Tools are filtered by namespace
|
|
Given the following tools have been registered:
|
|
| name | source | tool_type |
|
|
| core/read-file | builtin | tool |
|
|
| local/custom-lint | custom | validation |
|
|
When tools in the "core" namespace are listed from the registry
|
|
Then 1 tools should be returned from the registry
|
|
And the returned tool names from the registry should include "core/read-file"
|
|
|
|
@tool_reg_list
|
|
Scenario: Tools are filtered by tool_type
|
|
Given the following tools have been registered:
|
|
| name | source | tool_type |
|
|
| core/read-file | builtin | tool |
|
|
| core/schema-check | builtin | validation |
|
|
When tools of type "validation" are listed from the registry
|
|
Then 1 tools should be returned from the registry
|
|
|
|
@tool_reg_list
|
|
Scenario: Tools are filtered by source
|
|
Given the following tools have been registered:
|
|
| name | source | tool_type |
|
|
| core/read-file | builtin | tool |
|
|
| local/custom-lint | custom | tool |
|
|
When tools with source "custom" are listed from the registry
|
|
Then 1 tools should be returned from the registry
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Updating tools
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@tool_reg_update
|
|
Scenario: A tool description is updated
|
|
Given a valid tool dict named "core/read-file" with source "builtin"
|
|
And the tool has been registered through the tool registry repository
|
|
When the tool description is updated to "Updated description"
|
|
Then the persisted tool should have description "Updated description"
|
|
|
|
@tool_reg_update
|
|
Scenario: Tool resource bindings are replaced on update
|
|
Given a valid tool dict named "core/git-commit" with source "builtin"
|
|
And the tool dict includes a resource binding for slot "repo"
|
|
And the tool has been registered through the tool registry repository
|
|
When the tool is updated with a new resource binding for slot "workspace"
|
|
Then the persisted tool should have 1 resource binding
|
|
And the persisted tool binding slot should be "workspace"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Deleting tools
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@tool_reg_delete
|
|
Scenario: A tool is removed from the registry
|
|
Given a valid tool dict named "core/read-file" with source "builtin"
|
|
And the tool has been registered through the tool registry repository
|
|
When the tool "core/read-file" is removed from the registry
|
|
Then the removal should return true from the registry
|
|
And the tool should no longer exist in the registry
|
|
|
|
@tool_reg_delete
|
|
Scenario: Removing a non-existent tool returns false
|
|
When the tool "core/nonexistent" is removed from the registry
|
|
Then the removal should return false from the registry
|
|
|
|
@tool_reg_delete @error_handling
|
|
Scenario: Deleting a tool with active attachments is rejected
|
|
Given a valid tool dict named "core/schema-check" with source "builtin"
|
|
And the tool dict has tool_type "validation" and mode "required"
|
|
And the tool has been registered through the tool registry repository
|
|
And an unscoped validation attachment for "core/schema-check" on resource "res-001"
|
|
When the tool "core/schema-check" is removed from the registry
|
|
Then a ToolInUseError should be raised mentioning "core/schema-check"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Validation attachment lifecycle
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@tool_reg_attach
|
|
Scenario: A validation is attached to a resource
|
|
Given a valid tool dict named "core/schema-check" with source "builtin"
|
|
And the tool dict has tool_type "validation" and mode "required"
|
|
And the tool has been registered through the tool registry repository
|
|
When the validation "core/schema-check" is attached to resource "res-001"
|
|
Then the attachment should have a valid ULID identifier
|
|
And the attachment should reference resource "res-001"
|
|
|
|
@tool_reg_attach
|
|
Scenario: A validation is detached from a resource
|
|
Given a valid tool dict named "core/schema-check" with source "builtin"
|
|
And the tool dict has tool_type "validation" and mode "required"
|
|
And the tool has been registered through the tool registry repository
|
|
And an unscoped validation attachment for "core/schema-check" on resource "res-001"
|
|
When the validation attachment is detached by its identifier
|
|
Then the detachment should return true
|
|
|
|
@tool_reg_attach
|
|
Scenario: Detaching a non-existent attachment returns false
|
|
When the validation attachment "01ZZZZZZZZZZZZZZZZZZZZZZZZ" is detached
|
|
Then the non-existent detachment should return false
|
|
|
|
@tool_reg_attach
|
|
Scenario: Attachments are listed for a resource
|
|
Given a valid tool dict named "core/schema-check" with source "builtin"
|
|
And the tool dict has tool_type "validation" and mode "required"
|
|
And the tool has been registered through the tool registry repository
|
|
And an unscoped validation attachment for "core/schema-check" on resource "res-001"
|
|
When all attachments for resource "res-001" are listed
|
|
Then 1 attachment should be returned
|
|
|
|
@tool_reg_attach
|
|
Scenario: Attachments are scoped by project name
|
|
Given a valid tool dict named "core/schema-check" with source "builtin"
|
|
And the tool dict has tool_type "validation" and mode "required"
|
|
And the tool has been registered through the tool registry repository
|
|
And a project-scoped validation attachment for "core/schema-check" on resource "res-001" in project "my-project"
|
|
And a project-scoped validation attachment for "core/schema-check" on resource "res-001" in project "other-project"
|
|
When project-filtered attachments for resource "res-001" in project "my-project" are listed
|
|
Then 1 attachment should be returned
|
|
|
|
@tool_reg_attach
|
|
Scenario: Attachments are scoped by plan identifier
|
|
Given a valid tool dict named "core/schema-check" with source "builtin"
|
|
And the tool dict has tool_type "validation" and mode "required"
|
|
And the tool has been registered through the tool registry repository
|
|
And a plan-scoped validation attachment for "core/schema-check" on resource "res-001" in plan "01PLAN00000000000000000001"
|
|
When plan-filtered attachments for resource "res-001" with plan "01PLAN00000000000000000001" are listed
|
|
Then 1 attachment should be returned
|
|
|
|
@tool_reg_attach
|
|
Scenario: An attachment is retrieved by its identifier
|
|
Given a valid tool dict named "core/schema-check" with source "builtin"
|
|
And the tool dict has tool_type "validation" and mode "required"
|
|
And the tool has been registered through the tool registry repository
|
|
And an unscoped validation attachment for "core/schema-check" on resource "res-001"
|
|
When the attachment is retrieved by its stored identifier
|
|
Then the retrieved attachment should reference validation "core/schema-check"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Service layer integration
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@tool_reg_service
|
|
Scenario: The service registers and retrieves a tool
|
|
Given a tool registry service backed by the repositories
|
|
And a valid tool dict named "svc/echo" with source "builtin"
|
|
When the tool is registered through the service
|
|
And the tool is retrieved from the service by name "svc/echo"
|
|
Then the service-returned tool should have the registry name "svc/echo"
|
|
|
|
@tool_reg_service
|
|
Scenario: The service attaches and detaches a validation
|
|
Given a tool registry service backed by the repositories
|
|
And a valid tool dict named "svc/val-check" with source "builtin"
|
|
And the tool dict has tool_type "validation" and mode "required"
|
|
And the tool has been registered through the service
|
|
When the service attaches validation "svc/val-check" to resource "svc-res-001"
|
|
And the service detaches the validation attachment
|
|
Then the service detachment should return true
|
|
|
|
@tool_reg_service
|
|
Scenario: The service lists validations for a resource
|
|
Given a tool registry service backed by the repositories
|
|
And a valid tool dict named "svc/val-check" with source "builtin"
|
|
And the tool dict has tool_type "validation" and mode "required"
|
|
And the tool has been registered through the service
|
|
And the service has attached validation "svc/val-check" to resource "svc-res-002"
|
|
When the service lists validations for resource "svc-res-002"
|
|
Then the service should return 1 validation attachment
|