@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
