Feature: Consolidated Resource
  Combined scenarios from: resource_handler_service_coverage, resource_handlers, resource_registry_model, resource_type_model

  # ============================================================
  # Originally from: resource_handler_service_coverage.feature
  # Feature: ResourceHandlerService full coverage
  # ============================================================

  Scenario: Resolving a deferred binding raises ValueError
    Given a mock sandbox manager for rhs
    And a mock resource lookup for rhs
    And a mock type lookup for rhs
    And a ResourceHandlerService under test
    Given an rhs binding that is deferred with slot name "repo"
    When I resolve the rhs single binding
    Then an rhs ValueError is raised with message containing "Cannot resolve deferred binding for slot 'repo'"


  Scenario: Resolving a binding with no resource_id raises ValueError
    Given a mock sandbox manager for rhs
    And a mock resource lookup for rhs
    And a mock type lookup for rhs
    And a ResourceHandlerService under test
    Given an rhs binding with no resource_id and slot name "data"
    When I resolve the rhs single binding
    Then an rhs ValueError is raised with message containing "Cannot resolve deferred binding for slot 'data'"

    # --- resolve_binding: successful resolution ---


  Scenario: Resolving a valid binding returns a BoundResource
    Given a mock sandbox manager for rhs
    And a mock resource lookup for rhs
    And a mock type lookup for rhs
    And a ResourceHandlerService under test
    Given an rhs non-deferred binding with slot "repo" and resource_id "RES001"
    And rhs resource "RES001" typed "git-checkout" located at "/tmp/repo" with strategy "none"
    And an rhs type spec "git-checkout" with no handler and sandbox strategy "git_worktree"
    And the rhs sandbox manager returns a sandbox with path "/sandbox/abc"
    When I resolve the rhs single binding with plan_id "plan-1" and access "read_write"
    Then the rhs result is a BoundResource with slot "repo" and sandbox_path "/sandbox/abc"
    And the rhs BoundResource has resource_id "RES001" and access "read_write"

    # --- _resolve_handler_for_type: type_spec has a handler ---


  Scenario: Handler is resolved from type_spec handler reference
    Given a mock sandbox manager for rhs
    And a mock resource lookup for rhs
    And a mock type lookup for rhs
    And a ResourceHandlerService under test
    Given an rhs non-deferred binding with slot "code" and resource_id "RES002"
    And rhs resource "RES002" typed "custom/py" located at "/src" with strategy "none"
    And an rhs type spec "custom/py" with handler "some.module:Handler" and sandbox strategy "copy_on_write"
    And the rhs resolve_handler function returns a mock handler
    And the rhs mock handler resolves to a BoundResource with sandbox_path "/sandbox/custom"
    When I resolve the rhs single binding with plan_id "plan-2" and access "read_only"
    Then the rhs result is a BoundResource with slot "code" and sandbox_path "/sandbox/custom"

    # --- _resolve_handler_for_type: handler resolution fails, falls back ---


  Scenario: Handler resolution failure falls back to DefaultHandler
    Given a mock sandbox manager for rhs
    And a mock resource lookup for rhs
    And a mock type lookup for rhs
    And a ResourceHandlerService under test
    Given an rhs non-deferred binding with slot "files" and resource_id "RES003"
    And rhs resource "RES003" typed "custom/broken" located at "/data" with strategy "copy_on_write"
    And an rhs type spec "custom/broken" with handler "bad.module:Missing" and sandbox strategy "copy_on_write"
    And the rhs resolve_handler function raises HandlerResolutionError
    And the rhs sandbox manager returns a sandbox with path "/sandbox/fallback"
    When I resolve the rhs single binding with plan_id "plan-3" and access "read_only"
    Then the rhs result is a BoundResource with slot "files" and sandbox_path "/sandbox/fallback"

    # --- _resolve_handler_for_type: no handler on type_spec ---


  Scenario: No handler on type_spec uses DefaultHandler directly
    Given a mock sandbox manager for rhs
    And a mock resource lookup for rhs
    And a mock type lookup for rhs
    And a ResourceHandlerService under test
    Given an rhs non-deferred binding with slot "dir" and resource_id "RES004"
    And rhs resource "RES004" typed "fs-directory" located at "/home/user" with strategy "copy_on_write"
    And an rhs type spec "fs-directory" with no handler and sandbox strategy "copy_on_write"
    And the rhs sandbox manager returns a sandbox with path "/sandbox/dir"
    When I resolve the rhs single binding with plan_id "plan-4" and access "read_only"
    Then the rhs result is a BoundResource with slot "dir" and sandbox_path "/sandbox/dir"

    # --- resolve_bindings: mixed deferred and non-deferred ---


  Scenario: resolve_bindings skips deferred bindings and resolves the rest
    Given a mock sandbox manager for rhs
    And a mock resource lookup for rhs
    And a mock type lookup for rhs
    And a ResourceHandlerService under test
    Given an rhs binding list with:
      | slot_name | resource_id | deferred |
      | repo      | RES010      | false    |
      | param     |             | true     |
      | config    | RES011      | false    |
    And rhs resource "RES010" typed "git-checkout" located at "/repo" with strategy "none"
    And rhs resource "RES011" typed "fs-directory" located at "/config" with strategy "none"
    And an rhs type spec "git-checkout" with no handler and sandbox strategy "git_worktree"
    And an rhs type spec "fs-directory" with no handler and sandbox strategy "copy_on_write"
    And the rhs sandbox manager returns a sandbox with path "/sandbox/multi"
    When I resolve all rhs bindings with plan_id "plan-5" and access "read_only"
    Then the rhs result dict has keys "repo" and "config"
    And the rhs result dict does not contain key "param"

    # --- resolve_bindings: failure propagation ---


  Scenario: resolve_bindings raises when a non-deferred binding fails
    Given a mock sandbox manager for rhs
    And a mock resource lookup for rhs
    And a mock type lookup for rhs
    And a ResourceHandlerService under test
    Given an rhs binding list with:
      | slot_name | resource_id | deferred |
      | broken    | RES_MISSING | false    |
    And the rhs resource lookup raises NotFoundError for "RES_MISSING"
    When I resolve all rhs bindings expecting an error
    Then an rhs NotFoundError is raised

    # --- resolve_bindings: all deferred returns empty dict ---


  Scenario: resolve_bindings with all deferred bindings returns empty dict
    Given a mock sandbox manager for rhs
    And a mock resource lookup for rhs
    And a mock type lookup for rhs
    And a ResourceHandlerService under test
    Given an rhs binding list with:
      | slot_name | resource_id | deferred |
      | a         |             | true     |
      | b         |             | true     |
    When I resolve all rhs bindings with plan_id "plan-6" and access "read_only"
    Then the rhs result dict is empty

    # --- resolve_resource: direct resolution ---


  Scenario: resolve_resource resolves a resource directly without a binding
    Given a mock sandbox manager for rhs
    And a mock resource lookup for rhs
    And a mock type lookup for rhs
    And a ResourceHandlerService under test
    Given rhs resource "RES020" typed "git-checkout" located at "/direct/repo" with strategy "none"
    And an rhs type spec "git-checkout" with no handler and sandbox strategy "git_worktree"
    And the rhs sandbox manager returns a sandbox with path "/sandbox/direct"
    When I resolve the rhs resource directly with plan_id "plan-7" slot "src" and access "read_write"
    Then the rhs result is a BoundResource with slot "src" and sandbox_path "/sandbox/direct"
    And the rhs BoundResource has resource_id "RES020" and access "read_write"

    # --- _DefaultHandler: resource sandbox_strategy overrides type ---


  Scenario: DefaultHandler uses resource sandbox_strategy when present
    Given a mock sandbox manager for rhs
    And a mock resource lookup for rhs
    And a mock type lookup for rhs
    And a ResourceHandlerService under test
    Given an rhs non-deferred binding with slot "db" and resource_id "RES030"
    And rhs resource "RES030" typed "custom/db" located at "/data/db" with strategy "snapshot"
    And an rhs type spec "custom/db" with no handler and sandbox strategy "copy_on_write"
    And the rhs sandbox manager returns a sandbox with path "/sandbox/snap"
    When I resolve the rhs single binding with plan_id "plan-8" and access "read_only"
    Then the rhs sandbox manager was called with strategy "snapshot"

    # --- _DefaultHandler: falls back to type_spec sandbox_strategy ---


  Scenario: DefaultHandler falls back to type_spec sandbox_strategy when resource has none
    Given a mock sandbox manager for rhs
    And a mock resource lookup for rhs
    And a mock type lookup for rhs
    And a ResourceHandlerService under test
    Given an rhs non-deferred binding with slot "fs" and resource_id "RES031"
    And rhs resource "RES031" typed "fs-directory" located at "/mnt/share" with strategy "none"
    And an rhs type spec "fs-directory" with no handler and sandbox strategy "copy_on_write"
    And the rhs sandbox manager returns a sandbox with path "/sandbox/cow"
    When I resolve the rhs single binding with plan_id "plan-9" and access "read_only"
    Then the rhs sandbox manager was called with strategy "copy_on_write"

    # --- _DefaultHandler: no location error ---


  Scenario: DefaultHandler raises ValueError when resource has no location
    Given a mock sandbox manager for rhs
    And a mock resource lookup for rhs
    And a mock type lookup for rhs
    And a ResourceHandlerService under test
    Given an rhs non-deferred binding with slot "empty" and resource_id "RES040"
    And rhs resource "RES040" typed "fs-directory" with no location
    And an rhs type spec "fs-directory" with no handler and sandbox strategy "copy_on_write"
    When I resolve the rhs single binding
    Then an rhs ValueError is raised with message containing "has no location"

    # --- _DefaultHandler: sandbox context is None ---


  Scenario: DefaultHandler raises RuntimeError when sandbox has no context
    Given a mock sandbox manager for rhs
    And a mock resource lookup for rhs
    And a mock type lookup for rhs
    And a ResourceHandlerService under test
    Given an rhs non-deferred binding with slot "ctx" and resource_id "RES050"
    And rhs resource "RES050" typed "fs-directory" located at "/tmp/ctx" with strategy "none"
    And an rhs type spec "fs-directory" with no handler and sandbox strategy "copy_on_write"
    And the rhs sandbox manager returns a sandbox with no context
    When I resolve the rhs single binding
    Then an rhs RuntimeError is raised with message containing "has no context"


  # ============================================================
  # Originally from: resource_handlers.feature
  # Feature: Resource handler runtime
  # ============================================================

  Scenario: GitCheckoutHandler satisfies ResourceHandler protocol
    Then GitCheckoutHandler should satisfy the ResourceHandler protocol


  Scenario: FsDirectoryHandler satisfies ResourceHandler protocol
    Then FsDirectoryHandler should satisfy the ResourceHandler protocol

    # === GitCheckoutHandler ===


  Scenario: GitCheckoutHandler resolves a git-checkout resource
    Given a git-checkout resource with location "/tmp/test-repo"
    And a sandbox manager with a mock factory
    When I resolve the resource with GitCheckoutHandler for plan "PLAN001"
    Then the bound resource should have slot name "repo"
    And the bound resource should have resource type "git-checkout"
    And the bound resource sandbox path should not be empty


  Scenario: GitCheckoutHandler uses resource-level strategy override
    Given a git-checkout resource at "/tmp/test-repo" using strategy "copy_on_write"
    And a sandbox manager with a mock factory
    When I resolve the resource with GitCheckoutHandler for plan "PLAN002"
    Then the sandbox was created with strategy "copy_on_write"


  Scenario: GitCheckoutHandler rejects resource without location
    Given a git-checkout resource without location
    And a sandbox manager with a mock factory
    When I try to resolve the resource with GitCheckoutHandler
    Then a handler ValueError should be raised
    And the handler error should mention "no location"

    # === FsDirectoryHandler ===


  Scenario: FsDirectoryHandler resolves an fs-directory resource
    Given an fs-directory resource with location "/tmp/test-dir"
    And a sandbox manager with a mock factory
    When I resolve the resource with FsDirectoryHandler for plan "PLAN003"
    Then the bound resource should have slot name "workdir"
    And the bound resource should have resource type "fs-directory"
    And the bound resource sandbox path should not be empty


  Scenario: FsDirectoryHandler uses copy_on_write by default
    Given an fs-directory resource with location "/tmp/test-dir"
    And a sandbox manager with a mock factory
    When I resolve the resource with FsDirectoryHandler for plan "PLAN004"
    Then the sandbox was created with strategy "copy_on_write"


  Scenario: FsDirectoryHandler rejects resource without location
    Given an fs-directory resource without location
    And a sandbox manager with a mock factory
    When I try to resolve the resource with FsDirectoryHandler
    Then a handler ValueError should be raised

    # === Handler Resolver ===


  Scenario: Resolve handler from valid module:class string
    When I resolve handler "cleveragents.resource.handlers.git_checkout:GitCheckoutHandler"
    Then the resolved handler should be a GitCheckoutHandler instance


  Scenario: Resolve handler from fs-directory reference
    When I resolve handler "cleveragents.resource.handlers.fs_directory:FsDirectoryHandler"
    Then the resolved handler should be a FsDirectoryHandler instance


  Scenario: Resolve handler caches instances
    When I resolve handler "cleveragents.resource.handlers.git_checkout:GitCheckoutHandler"
    And I resolve the same handler reference again
    Then both resolved handlers should be the same object


  Scenario: Resolve handler rejects empty string
    When I try to resolve an empty handler reference
    Then a HandlerResolutionError should be raised
    And the resolution error should mention "empty"


  Scenario: Resolve handler rejects missing colon separator
    When I try to resolve handler "cleveragents.resource.handlers.git_checkout"
    Then a HandlerResolutionError should be raised
    And the resolution error should mention "module.path:ClassName"


  Scenario: Resolve handler rejects nonexistent module
    When I try to resolve handler "nonexistent.module:SomeClass"
    Then a HandlerResolutionError should be raised
    And the resolution error should mention "Cannot import"


  Scenario: Resolve handler rejects nonexistent class in valid module
    When I try to resolve handler "cleveragents.resource.handlers.git_checkout:NonExistentClass"
    Then a HandlerResolutionError should be raised
    And the resolution error should mention "not found"

    # === ResourceHandlerService ===


  Scenario: ResourceHandlerService resolves a binding to BoundResource
    Given a resource handler service with mock lookups
    And a binding result for slot "repo" with resource id "RES001"
    When I resolve the binding via resource handler service for plan "PLAN010"
    Then the handler service should return a BoundResource
    And the handler service BoundResource slot should be "repo"
    And the handler service BoundResource sandbox path should not be empty


  Scenario: ResourceHandlerService skips deferred bindings
    Given a resource handler service with mock lookups
    And a deferred binding result for slot "extra"
    And a binding result for slot "repo" with resource id "RES001"
    When I resolve all bindings via resource handler service for plan "PLAN011"
    Then the handler service should return 1 bound resource
    And the handler service should have resolved slot "repo"


  Scenario: ResourceHandlerService rejects deferred single binding
    Given a resource handler service with mock lookups
    And a deferred binding result for slot "extra"
    When I try to resolve the single deferred binding via resource handler service
    Then a handler ValueError should be raised
    And the handler error should mention "deferred"


  Scenario: ResourceHandlerService uses fallback handler when type has no handler string
    Given a resource handler service with mock lookups and no handler string
    And a binding result for slot "data" with resource id "RES002"
    When I resolve the binding via resource handler service for plan "PLAN012"
    Then the handler service should return a BoundResource
    And the handler service BoundResource sandbox path should not be empty


  # ============================================================
  # Originally from: resource_registry_model.feature
  # Feature: Resource Registry Domain Model
  # ============================================================

  Scenario: PhysVirt has exactly two values
    Then the PhysVirt enum should have values "physical, virtual"


  Scenario: PhysVirt physical value
    Given a PhysVirt value of "physical"
    Then the PhysVirt string value should be "physical"


  Scenario: PhysVirt virtual value
    Given a PhysVirt value of "virtual"
    Then the PhysVirt string value should be "virtual"


  Scenario: PhysVirt rejects invalid value
    When I try to create a PhysVirt with value "hybrid"
    Then a resource validation error should be raised

    # SandboxStrategy enum


  Scenario: SandboxStrategy has exactly six values
    Then the SandboxStrategy enum should have values "git_worktree, copy_on_write, transaction_rollback, snapshot, overlay, none"


  Scenario Outline: SandboxStrategy accepts valid values
    Given a SandboxStrategy value of "<strategy>"
    Then the SandboxStrategy string value should be "<strategy>"

    Examples:
      | strategy             |
      | git_worktree         |
      | copy_on_write        |
      | transaction_rollback |
      | snapshot             |
      | overlay              |
      | none                 |


  Scenario: SandboxStrategy accepts overlay
    Given a SandboxStrategy value of "overlay"
    Then the SandboxStrategy string value should be "overlay"


  Scenario: SandboxStrategy rejects versioning
    When I try to create a SandboxStrategy with value "versioning"
    Then a resource validation error should be raised

    # ResourceCapabilities model


  Scenario: ResourceCapabilities defaults
    Given default ResourceCapabilities
    Then the capability readable should be true
    And the capability writable should be true
    And the capability sandboxable should be true
    And the capability checkpointable should be true


  Scenario: ResourceCapabilities with custom values
    Given ResourceCapabilities with readable false and checkpointable true
    Then the capability readable should be false
    And the capability writable should be true
    And the capability sandboxable should be true
    And the capability checkpointable should be true


  Scenario: ResourceCapabilities is frozen
    Given default ResourceCapabilities
    When I try to mutate a ResourceCapabilities field
    Then a resource validation error should be raised

    # Resource model - creation


  Scenario: Create a minimal physical resource
    Given a Resource with resource_id "01HZQX7K8M3N4P5R6S7T8V9W0X" type "git-checkout" and classification "physical"
    Then the resource resource_id should be "01HZQX7K8M3N4P5R6S7T8V9W0X"
    And the resource type name should be "git-checkout"
    And the resource classification should be "physical"
    And the resource name should be empty
    And the resource description should be empty
    And the resource properties should be empty
    And the resource parents should be empty
    And the resource children should be empty
    And the resource linked_projects should be empty
    And the resource created_at should be set
    And the resource updated_at should be set


  Scenario: Create a full resource with all fields
    Given a full Resource with id "01HZQX7K8M3N4P5R6S7T8V9W0X" name "local/my-repo" type "git-checkout" classification "physical" description "Main repo"
    Then the resource name should be "local/my-repo"
    And the resource description should be "Main repo"


  Scenario: Resource with sandbox strategy override
    Given a Resource with sandbox strategy "git_worktree"
    Then the resource sandbox strategy should be "git_worktree"


  Scenario: Resource with non-sandboxable rejects checkpointable
    When I try to create a Resource with sandboxable false and checkpointable true
    Then a resource validation error should be raised

    # Resource model - validation


  Scenario: Resource rejects invalid ULID
    When I try to create a Resource with resource_id "invalid-ulid"
    Then a resource validation error should be raised


  Scenario: Resource rejects empty resource_type_name
    When I try to create a Resource with empty resource_type_name
    Then a resource validation error should be raised


  Scenario: Resource rejects empty string name
    When I try to create a Resource with empty string name
    Then a resource validation error should be raised


  Scenario: Resource accepts None name
    Given a Resource with resource_id "01HZQX7K8M3N4P5R6S7T8V9W0X" type "git-checkout" and classification "physical"
    Then the resource name should be empty

    # Resource model - domain properties


  Scenario: Physical resource is_physical
    Given a Resource with resource_id "01HZQX7K8M3N4P5R6S7T8V9W0X" type "git-checkout" and classification "physical"
    Then the resource is_physical should be true
    And the resource is_virtual should be false


  Scenario: Virtual resource is_virtual
    Given a Resource with resource_id "01HZQX7K8M3N4P5R6S7T8V9W0X" type "git" and classification "virtual"
    Then the resource is_physical should be false
    And the resource is_virtual should be true


  Scenario: Read-only resource
    Given a Resource with writable false
    Then the resource is_read_only should be true


  Scenario: Writable resource
    Given a Resource with resource_id "01HZQX7K8M3N4P5R6S7T8V9W0X" type "git-checkout" and classification "physical"
    Then the resource is_read_only should be false

    # Resource model - frozen


  Scenario: Resource is frozen
    Given a Resource with resource_id "01HZQX7K8M3N4P5R6S7T8V9W0X" type "git-checkout" and classification "physical"
    When I try to mutate a Resource field
    Then a resource validation error should be raised

    # Resource model - with_updated_at


  Scenario: with_updated_at returns new instance
    Given a Resource with resource_id "01HZQX7K8M3N4P5R6S7T8V9W0X" type "git-checkout" and classification "physical"
    When I call with_updated_at on the resource
    Then the new resource should have a different updated_at
    And the new resource should have the same resource_id

    # Resource model - content_hash and location


  Scenario: Resource with content_hash
    Given a Resource with content_hash "sha256:abc123"
    Then the resource content_hash should be "sha256:abc123"


  Scenario: Resource with location
    Given a Resource with location "/home/user/repos/main"
    Then the resource location should be "/home/user/repos/main"


  Scenario: Resource rejects empty location string
    When I try to create a Resource with empty location
    Then a resource validation error should be raised

    # Resource model - parents and children


  Scenario: Resource with parents and children
    Given a Resource with parents and children
    Then the resource should have 1 parent
    And the resource should have 2 children


  # ============================================================
  # Originally from: resource_type_model.feature
  # Feature: Resource Type Model and Schema Loader
  # ============================================================

  Scenario: Built-in resource type with unnamespaced name
    Given a resource type config with name "git-checkout" and built_in true
    When I create a ResourceTypeSpec from config
    Then the resource type should be valid
    And the rt_spec name should be "git-checkout"


  Scenario: Custom resource type with namespaced name
    Given a resource type config with name "myorg/custom-db" and built_in false
    When I create a ResourceTypeSpec from config
    Then the resource type should be valid
    And the rt_spec name should be "myorg/custom-db"


  Scenario: Custom type without namespace is rejected
    Given a resource type config with name "no-namespace" and built_in false
    When I try to create a ResourceTypeSpec from config
    Then the resource type creation should fail with "namespace/name"


  Scenario: Invalid name with special characters is rejected
    Given a resource type config with name "bad!name" and built_in false
    When I try to create a ResourceTypeSpec from config
    Then the resource type creation should fail with "Invalid resource type name"

    # ── ResourceKind ────────────────────────────────────────────


  Scenario: Physical resource kind
    Given a resource type config with resource_kind "physical"
    When I create a ResourceTypeSpec from config
    Then the resource type resource_kind should be "physical"


  Scenario: Virtual resource kind
    Given a resource type config with resource_kind "virtual" and equivalence set
    When I create a ResourceTypeSpec from config
    Then the resource type resource_kind should be "virtual"


  Scenario: Virtual resource kind without equivalence is rejected
    Given a resource type config with resource_kind "virtual" and no equivalence
    When I try to create a ResourceTypeSpec from config
    Then the resource type creation should fail with "equivalence"

    # ── SandboxStrategy ─────────────────────────────────────────


  Scenario: Git worktree sandbox strategy
    Given a resource type config with sandbox_strategy "git_worktree"
    When I create a ResourceTypeSpec from config
    Then the resource type sandbox_strategy should be "git_worktree"


  Scenario: Copy on write sandbox strategy
    Given a resource type config with sandbox_strategy "copy_on_write"
    When I create a ResourceTypeSpec from config
    Then the resource type sandbox_strategy should be "copy_on_write"


  Scenario: Transaction rollback sandbox strategy
    Given a resource type config with sandbox_strategy "transaction_rollback"
    When I create a ResourceTypeSpec from config
    Then the resource type sandbox_strategy should be "transaction_rollback"


  Scenario: Snapshot sandbox strategy
    Given a resource type config with sandbox_strategy "snapshot"
    When I create a ResourceTypeSpec from config
    Then the resource type sandbox_strategy should be "snapshot"


  Scenario: None sandbox strategy
    Given a resource type config with sandbox_strategy "none"
    When I create a ResourceTypeSpec from config
    Then the resource type sandbox_strategy should be "none"

    # ── CLI Arguments ───────────────────────────────────────────


  Scenario: Valid CLI argument parsing
    Given a resource type config with a cli_arg named "path" of type "path"
    When I create a ResourceTypeSpec from config
    Then the resource type should have 1 cli_arg
    And the first cli_arg name should be "path"


  Scenario: Multiple CLI arguments
    Given a resource type config with cli_args "path" and "branch"
    When I create a ResourceTypeSpec from config
    Then the resource type should have 2 cli_args


  Scenario: CLI argument with invalid name is rejected
    Given a resource type config with a cli_arg named "BadName" of type "string"
    When I try to create a ResourceTypeSpec from config
    Then the resource type creation should fail with "not CLI-safe"


  Scenario: CLI argument with invalid type is rejected
    Given a resource type config with a cli_arg named "count" of type "bigint"
    When I try to create a ResourceTypeSpec from config
    Then the resource type creation should fail with "Invalid argument type"

    # ── Parent/Child Types ──────────────────────────────────────


  Scenario: Resource type with parent types
    Given a resource type config with parent_types "git-checkout"
    When I create a ResourceTypeSpec from config
    Then the resource type should have parent_types containing "git-checkout"


  Scenario: Resource type with child types
    Given a resource type config with child_types "fs-directory"
    When I create a ResourceTypeSpec from config
    Then the resource type should have child_types containing "fs-directory"


  Scenario: Resource type with both parent and child types
    Given a resource type config with parent_types_set "git-checkout" and child_types_set "fs-directory"
    When I create a ResourceTypeSpec from config
    Then the resource type should have parent_types containing "git-checkout"
    And the resource type should have child_types containing "fs-directory"

    # ── from_config() ───────────────────────────────────────────


  Scenario: from_config with missing name
    Given a resource type config dict without name
    When I try to call from_config
    Then from_config should fail with "must include 'name'"


  Scenario: from_config with missing resource_kind
    Given a resource type config dict without resource_kind
    When I try to call from_config
    Then from_config should fail with "must include 'resource_kind'"


  Scenario: from_config with missing sandbox_strategy
    Given a resource type config dict without sandbox_strategy
    When I try to call from_config
    Then from_config should fail with "must include 'sandbox_strategy'"


  Scenario: from_config with valid full config
    Given a full resource type config dict
    When I call from_config
    Then the resource type spec should be valid

    # ── as_cli_dict() ───────────────────────────────────────────


  Scenario: as_cli_dict returns expected keys
    Given a resource type config with name "myorg/test-type" and built_in false
    When I create a ResourceTypeSpec and call as_cli_dict
    Then the rt_cli dict should contain key "name" with value "myorg/test-type"
    And the rt_cli dict should contain key "resource_kind"
    And the rt_cli dict should contain key "sandbox_strategy"
    And the rt_cli dict should contain key "capabilities"

    # ── Schema loader ───────────────────────────────────────────


  Scenario: Schema loader from YAML string
    Given a valid resource type YAML string
    When I load the resource type via from_yaml
    Then the loaded schema should be valid


  Scenario: Schema loader from YAML file
    Given a valid resource type YAML file
    When I load the resource type via from_yaml_file
    Then the loaded schema should be valid


  Scenario: Schema loader with env var interpolation
    Given a resource type YAML with env var "${RT_TEST_HANDLER}"
    And the env var "RT_TEST_HANDLER" is set to "test.handler:Handler"
    When I load the resource type via from_yaml
    Then the handler should be "test.handler:Handler"


  Scenario: Schema loader with empty YAML
    When I try to load an empty YAML string
    Then the schema loader should fail with "empty"


  Scenario: Schema loader with None YAML
    When I try to load a None YAML string
    Then the schema loader should fail with "None"


  Scenario: Schema loader with non-mapping YAML
    When I try to load a YAML list
    Then the schema loader should fail with "mapping"


  Scenario: Schema loader with unsupported version
    Given a resource type YAML with schema_version "99"
    When I try to load the resource type via from_yaml
    Then the schema loader should fail with "Unsupported schema version"


  Scenario: Schema loader from non-existent file
    When I try to load from a non-existent file
    Then the schema loader should raise FileNotFoundError


  Scenario: Schema loader from directory instead of file
    When I try to load from a directory path
    Then the schema loader should fail with "not a file"

    # ── Capabilities ────────────────────────────────────────────


  Scenario: Default capabilities
    Given a resource type config with default capabilities
    When I create a ResourceTypeSpec from config
    Then the capabilities should have read true
    And the capabilities should have write true
    And the capabilities should have sandbox true
    And the capabilities should have checkpoint false


  Scenario: Custom capabilities
    Given a resource type config with custom capabilities
    When I create a ResourceTypeSpec from config
    Then the capabilities should have read true
    And the capabilities should have write false
    And the capabilities should have sandbox true
    And the capabilities should have checkpoint true


  Scenario: Unknown capability key is rejected
    Given a resource type config with unknown capability "teleport"
    When I try to create a ResourceTypeSpec from config
    Then the resource type creation should fail with "Unknown capability"

    # ── CLI argument edge cases ──────────────────────────────────


  Scenario: cli_args entry that is not a mapping is rejected
    Given a resource type config with a non-mapping cli_arg
    When I try to create a ResourceTypeSpec from config
    Then the resource type creation should fail with "must be a mapping"

    # ── as_cli_dict coverage ──────────────────────────────────────


  Scenario: as_cli_dict includes all optional fields when present
    Given a full resource type config with handler and auto_discovery
    When I create a ResourceTypeSpec and call as_cli_dict
    Then the rt_cli dict should contain key "description"
    And the rt_cli dict should contain key "cli_args"
    And the rt_cli dict should contain key "child_types"
    And the rt_cli dict should contain key "handler"
    And the rt_cli dict should contain key "auto_discovery"
    And the rt_cli dict should contain key "capabilities"


  Scenario: as_cli_dict with equivalence field
    Given a resource type config with resource_kind "virtual" and equivalence set
    When I create a ResourceTypeSpec and call as_cli_dict
    Then the rt_cli dict should contain key "equivalence"


  Scenario: as_cli_dict with parent_types
    Given a resource type config with parent_types "git-checkout"
    When I create a ResourceTypeSpec and call as_cli_dict
    Then the rt_cli dict should contain key "parent_types"

    # ── Schema-level validation ───────────────────────────────────


  Scenario: Schema rejects invalid cli_arg name
    Given a resource type YAML with invalid cli_arg name
    When I try to load the resource type via from_yaml
    Then the schema loader should fail with "not CLI-safe"


  Scenario: Schema rejects invalid cli_arg type
    Given a resource type YAML with invalid cli_arg type
    When I try to load the resource type via from_yaml
    Then the schema loader should fail with "Invalid argument type"


  Scenario: Schema rejects invalid resource type name
    Given a resource type YAML with invalid name
    When I try to load the resource type via from_yaml
    Then the schema loader should fail with "Invalid resource type name"


  Scenario: Schema rejects invalid resource_kind
    Given a resource type YAML with invalid resource_kind
    When I try to load the resource type via from_yaml
    Then the schema loader should fail with "Invalid resource_kind"


  Scenario: Schema rejects invalid sandbox_strategy
    Given a resource type YAML with invalid sandbox_strategy
    When I try to load the resource type via from_yaml
    Then the schema loader should fail with "Invalid sandbox_strategy"


  Scenario: Schema rejects custom type without namespace
    Given a resource type YAML with custom type no namespace
    When I try to load the resource type via from_yaml
    Then the schema loader should fail with "namespace/name"


  Scenario: Schema rejects virtual type without equivalence
    Given a resource type YAML with virtual kind no equivalence
    When I try to load the resource type via from_yaml
    Then the schema loader should fail with "equivalence"


  Scenario: Schema loader from_yaml_file with None path
    When I try to load from a None file path
    Then the schema loader should fail with "None"


  Scenario: Schema env var interpolation in list items
    Given a resource type YAML with env var in list
    And the env var "RT_TEST_PARENT" is set to "custom-parent"
    When I load the resource type via from_yaml
    Then the loaded schema should have parent type "custom-parent"


  Scenario: Schema accepts overlay sandbox strategy
    Given a resource type YAML with sandbox_strategy "overlay"
    When I load the resource type via from_yaml
    Then the loaded schema sandbox_strategy should be "overlay"


  Scenario: Invalid sandbox_strategy error message lists overlay as allowed
    Given a resource type YAML with invalid sandbox_strategy
    When I try to load the resource type via from_yaml
    Then the schema loader should fail with "overlay"
