@unit
Feature: Repository uncovered lines coverage
  Target the remaining uncovered lines in repositories.py to boost
  line and branch coverage.

  # -------------------------------------------------------------------
  # LinkNotFoundError (lines 1595-1598)
  # -------------------------------------------------------------------

  Scenario: LinkNotFoundError stores parent and child IDs
    Given a LinkNotFoundError for parent "P1" and child "C1"
    Then the LinkNotFoundError message should contain "P1" and "C1"
    And the LinkNotFoundError parent_id should be "P1"
    And the LinkNotFoundError child_id should be "C1"

  # -------------------------------------------------------------------
  # ResourceTypeRepository – DuplicateResourceTypeError from UNIQUE IntegrityError (line 1708)
  # -------------------------------------------------------------------

  Scenario: ResourceTypeRepository create raises DuplicateResourceTypeError on UNIQUE IntegrityError
    Given a resource type repository backed by an in-memory database for uncovered lines
    And a resource type "test/dup-type" exists in the database for uncovered lines
    When the same resource type "test/dup-type" is created again for uncovered lines
    Then a DuplicateResourceTypeError should be raised for uncovered lines

  # -------------------------------------------------------------------
  # ResourceTypeRepository._to_domain – equivalence_json not None (line 1923)
  # -------------------------------------------------------------------

  Scenario: ResourceTypeRepository _to_domain parses equivalence_json when present
    Given a resource type repository backed by an in-memory database for uncovered lines
    And a resource type row with equivalence_json set to '{"field": "name"}'
    When the resource type is retrieved by name "test/equiv-type" for uncovered lines
    Then the resource type equivalence should contain key "field"

  # -------------------------------------------------------------------
  # ResourceRepository.list_resources – namespace filter (line 2114)
  # -------------------------------------------------------------------

  Scenario: ResourceRepository list_resources filters by namespace
    Given a resource repository backed by an in-memory database for uncovered lines
    And resources exist in namespace "ns-alpha" and "ns-beta" for uncovered lines
    When resources are listed with namespace "ns-alpha" for uncovered lines
    Then only resources from namespace "ns-alpha" should be returned

  # -------------------------------------------------------------------
  # ResourceRepository.unlink_child – parent not found (line 2385)
  # -------------------------------------------------------------------

  Scenario: ResourceRepository unlink_child raises error when parent not found
    Given a resource repository backed by an in-memory database for uncovered lines
    When unlink_child is called with non-existent parent "NOPARENT" and child "NOCHILD" for uncovered lines
    Then a ResourceNotFoundRepoError should be raised for the unlink parent

  # -------------------------------------------------------------------
  # ResourceRepository.unlink_child – child not found (line 2391)
  # -------------------------------------------------------------------

  Scenario: ResourceRepository unlink_child raises error when child not found
    Given a resource repository backed by an in-memory database for uncovered lines
    And a resource "parent-res" exists for uncovered unlink tests
    When unlink_child is called with existing parent and non-existent child "NOCHILD" for uncovered lines
    Then a ResourceNotFoundRepoError should be raised for the unlink child

  # -------------------------------------------------------------------
  # ResourceRepository.unlink_child – link not found (line 2399)
  # -------------------------------------------------------------------

  Scenario: ResourceRepository unlink_child raises LinkNotFoundError when no link exists
    Given a resource repository backed by an in-memory database for uncovered lines
    And two resources "parent-ul" and "child-ul" exist but are not linked for uncovered lines
    When unlink_child is called for "parent-ul" and "child-ul" for uncovered lines
    Then a LinkNotFoundError should be raised for uncovered lines

  # -------------------------------------------------------------------
  # ResourceRepository.unlink_child – re-raise domain errors (line 2407)
  # -------------------------------------------------------------------

  Scenario: ResourceRepository unlink_child re-raises domain errors unchanged
    Given a resource repository backed by an in-memory database for uncovered lines
    When unlink_child is called with non-existent parent "GHOST" and child "GHOST2" for uncovered lines re-raise
    Then a ResourceNotFoundRepoError should be raised and re-raised for uncovered lines

  # -------------------------------------------------------------------
  # ResourceRepository.auto_discover_children – type_row is None (line 2524)
  # -------------------------------------------------------------------

  Scenario: auto_discover_children returns empty when parent type not in DB
    Given a resource repository backed by an in-memory database for uncovered lines
    And a resource with type "missing-type" that has no type row in DB for uncovered lines
    When auto_discover_children is called for that resource for uncovered lines
    Then an empty list should be returned from auto_discover for uncovered lines

  # -------------------------------------------------------------------
  # auto_discover_children – auto_disc not enabled (lines 2528-2533)
  # -------------------------------------------------------------------

  Scenario: auto_discover_children returns empty when auto_discover_json is null
    Given a resource repository backed by an in-memory database for uncovered lines
    And a resource with type that has null auto_discover_json for uncovered lines
    When auto_discover_children is called for that typed resource for uncovered lines null
    Then an empty list should be returned from auto_discover for uncovered lines

  Scenario: auto_discover_children returns empty when auto_discover is disabled
    Given a resource repository backed by an in-memory database for uncovered lines
    And a resource with type that has auto_discover disabled for uncovered lines
    When auto_discover_children is called for that typed resource for uncovered lines disabled
    Then an empty list should be returned from auto_discover for uncovered lines

  # -------------------------------------------------------------------
  # auto_discover_children – rules empty (lines 2535-2537)
  # -------------------------------------------------------------------

  Scenario: auto_discover_children returns empty when rules list is empty
    Given a resource repository backed by an in-memory database for uncovered lines
    And a resource with type that has auto_discover enabled but empty rules for uncovered lines
    When auto_discover_children is called for that typed resource for uncovered lines empty rules
    Then an empty list should be returned from auto_discover for uncovered lines

  # -------------------------------------------------------------------
  # auto_discover_children – child type not in DB (line 2560)
  # -------------------------------------------------------------------

  Scenario: auto_discover_children skips rule when child type not in DB
    Given a resource repository backed by an in-memory database for uncovered lines
    And a resource with auto_discover rules referencing non-existent child type for uncovered lines
    When auto_discover_children is called for that resource with missing child type for uncovered lines
    Then an empty list should be returned from auto_discover for uncovered lines

  # -------------------------------------------------------------------
  # auto_discover_children – child type not in allowed list (line 2564)
  # -------------------------------------------------------------------

  Scenario: auto_discover_children skips rule when child type not in allowed list
    Given a resource repository backed by an in-memory database for uncovered lines
    And a resource with auto_discover rules where child type is not in allowed list for uncovered lines
    When auto_discover_children is called for that resource with disallowed child type for uncovered lines
    Then an empty list should be returned from auto_discover for uncovered lines

  # -------------------------------------------------------------------
  # auto_discover_children – successful discovery (lines 2567-2616)
  # -------------------------------------------------------------------

  Scenario: auto_discover_children creates child resources and links
    Given a resource repository backed by an in-memory database for uncovered lines
    And a resource with auto_discover rules that match an existing child type for uncovered lines
    When auto_discover_children is called for that resource for full discovery for uncovered lines
    Then the discovered children list should not be empty for uncovered lines
    And the child resource should be linked to the parent for uncovered lines

  # -------------------------------------------------------------------
  # auto_discover_children – OperationalError (lines 2619-2624)
  # -------------------------------------------------------------------

  Scenario: auto_discover_children wraps OperationalError in DatabaseError
    Given a resource repository with session raising OperationalError on auto_discover for uncovered lines
    When auto_discover_children is called and an OperationalError occurs for uncovered lines
    Then a DatabaseError should be raised mentioning auto-discover for uncovered lines

  # -------------------------------------------------------------------
  # _get_ancestors – current in visited branch (line 2641)
  # -------------------------------------------------------------------

  Scenario: _get_ancestors handles cycles in visited set
    Given a resource repository backed by an in-memory database for uncovered lines
    And resources forming a diamond graph for ancestor traversal for uncovered lines
    When _get_ancestors is called on the bottom resource for uncovered lines
    Then all ancestor IDs should be returned including the bottom resource for uncovered lines

  # -------------------------------------------------------------------
  # ResourceRepository._to_domain – sandbox_strategy not None (line 2707)
  # -------------------------------------------------------------------

  Scenario: ResourceRepository _to_domain converts sandbox_strategy when present
    Given a resource repository backed by an in-memory database for uncovered lines
    And a resource row with sandbox_strategy set to "git_worktree" for uncovered lines
    When the resource is retrieved by ID for uncovered lines sandbox
    Then the resource sandbox_strategy should be SandboxStrategy.GIT_WORKTREE

  # -------------------------------------------------------------------
  # ToolRepository.add – invalid tool_type (line 3174)
  # -------------------------------------------------------------------

  Scenario: ToolRepository add raises InvalidToolTypeError for bad tool_type
    Given a tool repository backed by an in-memory database for uncovered lines
    And a tool domain object with tool_type "bogus" for uncovered lines
    When the tool is added to the repository for uncovered lines invalid type
    Then an InvalidToolTypeError should be raised for uncovered lines

  # -------------------------------------------------------------------
  # ToolRepository.add – schema serialization + resource slots (lines 3196-3261)
  # -------------------------------------------------------------------

  Scenario: ToolRepository add persists input/output schemas and resource slots
    Given a tool repository backed by an in-memory database for uncovered lines
    And a tool domain object with schemas and resource slots for uncovered lines
    When the tool is added to the repository for uncovered lines with schemas
    Then the tool should be retrievable and have schemas and bindings for uncovered lines

  # -------------------------------------------------------------------
  # ToolRepository.get – fetch by ULID (lines 3286-3293)
  # -------------------------------------------------------------------

  Scenario: ToolRepository get returns tool by ULID
    Given a tool repository backed by an in-memory database for uncovered lines
    And a tool has been persisted and its ULID captured for uncovered lines
    When the tool is fetched by ULID for uncovered lines
    Then the tool domain object should be returned for uncovered lines

  Scenario: ToolRepository get returns None for unknown ULID
    Given a tool repository backed by an in-memory database for uncovered lines
    When a tool is fetched by ULID "00000000000000000000000000" for uncovered lines
    Then None should be returned for the tool get for uncovered lines

  # -------------------------------------------------------------------
  # ToolRepository._to_domain – input/output schema JSON parse (lines 3433, 3438)
  # -------------------------------------------------------------------

  Scenario: ToolRepository _to_domain parses input and output schemas
    Given a tool repository backed by an in-memory database for uncovered lines
    And a tool with input_schema and output_schema stored as JSON for uncovered lines
    When the tool is retrieved by name for uncovered lines schemas
    Then the tool should have parsed input_schema and output_schema for uncovered lines

  # -------------------------------------------------------------------
  # ValidationAttachment.attach – duplicate detection (lines 3517-3520)
  # -------------------------------------------------------------------

  Scenario: ValidationAttachment attach raises DuplicateValidationAttachmentError on duplicate
    Given a validation attachment repository backed by an in-memory database for uncovered lines
    And a validation "val-check" is already attached to resource "res-1" for uncovered lines
    When the same validation "val-check" is attached again to resource "res-1" for uncovered lines
    Then a DuplicateValidationAttachmentError should be raised for uncovered lines attach

  # -------------------------------------------------------------------
  # ValidationAttachment.attach – re-raise (line 3538)
  # -------------------------------------------------------------------

  Scenario: ValidationAttachment attach re-raises DuplicateValidationAttachmentError
    Given a validation attachment repository backed by an in-memory database for uncovered lines
    And a validation "val-dup" is already attached to resource "res-2" for uncovered lines
    When the same validation "val-dup" is attached again to resource "res-2" for uncovered lines re-raise
    Then the DuplicateValidationAttachmentError should propagate for uncovered lines

  # -------------------------------------------------------------------
  # AutomationProfileRepository.get_by_name – row is None (line 3663)
  # -------------------------------------------------------------------

  Scenario: AutomationProfileRepository get_by_name returns None when not found
    Given an automation profile repository backed by an in-memory database for uncovered lines
    When a profile is fetched by name "nonexistent-profile" for uncovered lines
    Then None should be returned for the profile get for uncovered lines

  # -------------------------------------------------------------------
  # AutomationProfileRepository.get_by_name – _to_domain (line 3665)
  # -------------------------------------------------------------------

  Scenario: AutomationProfileRepository get_by_name returns domain object
    Given an automation profile repository backed by an in-memory database for uncovered lines
    And a profile "test-profile" has been upserted for uncovered lines
    When a profile is fetched by name "test-profile" for uncovered lines
    Then the profile domain object should be returned for uncovered lines

  # -------------------------------------------------------------------
  # AutomationProfileRepository.list_all – _to_domain mapping (line 3686)
  # -------------------------------------------------------------------

  Scenario: AutomationProfileRepository list_all returns domain objects
    Given an automation profile repository backed by an in-memory database for uncovered lines
    And profiles "prof-a" and "prof-b" have been upserted for uncovered lines
    When all profiles are listed for uncovered lines
    Then two profile domain objects should be returned for uncovered lines

  # -------------------------------------------------------------------
  # AutomationProfileRepository.upsert – existing row update (lines 3722-3732)
  # -------------------------------------------------------------------

  Scenario: AutomationProfileRepository upsert updates existing profile
    Given an automation profile repository backed by an in-memory database for uncovered lines
    And a profile "update-prof" has been upserted for uncovered lines
    When the profile "update-prof" is upserted again with changed description for uncovered lines
    Then the profile should have the updated description for uncovered lines

  # -------------------------------------------------------------------
  # AutomationProfileRepository.upsert – schema version mismatch (lines 3723-3731)
  # -------------------------------------------------------------------

  Scenario: AutomationProfileRepository upsert raises on schema version mismatch
    Given an automation profile repository backed by an in-memory database for uncovered lines
    And a profile "versioned-prof" has been upserted with schema_version "1.0" for uncovered lines
    When the profile "versioned-prof" is upserted with expected_schema_version "2.0" for uncovered lines
    Then an AutomationProfileSchemaVersionError should be raised for uncovered lines

  # -------------------------------------------------------------------
  # AutomationProfileRepository.upsert – new row insert (lines 3733-3735)
  # -------------------------------------------------------------------

  Scenario: AutomationProfileRepository upsert inserts new profile
    Given an automation profile repository backed by an in-memory database for uncovered lines
    When a new profile "brand-new" is upserted for uncovered lines
    Then the profile "brand-new" should be retrievable for uncovered lines

  # -------------------------------------------------------------------
  # AutomationProfileRepository.upsert – IntegrityError (lines 3739-3743)
  # -------------------------------------------------------------------

  Scenario: AutomationProfileRepository upsert wraps IntegrityError in DuplicateAutomationProfileError
    Given an automation profile repository with session raising IntegrityError on flush for uncovered lines
    When a profile is upserted and IntegrityError occurs for uncovered lines
    Then a DuplicateAutomationProfileError should be raised for uncovered lines

  # -------------------------------------------------------------------
  # AutomationProfileRepository.delete – row not found (lines 3766-3767)
  # -------------------------------------------------------------------

  Scenario: AutomationProfileRepository delete raises NotFoundError when missing
    Given an automation profile repository backed by an in-memory database for uncovered lines
    When a profile "ghost" is deleted for uncovered lines
    Then an AutomationProfileNotFoundError should be raised for uncovered lines

  # -------------------------------------------------------------------
  # AutomationProfileRepository.delete – success path (lines 3768-3769)
  # -------------------------------------------------------------------

  Scenario: AutomationProfileRepository delete removes existing profile
    Given an automation profile repository backed by an in-memory database for uncovered lines
    And a profile "delete-me" has been upserted for uncovered lines
    When the profile "delete-me" is deleted for uncovered lines
    Then the profile "delete-me" should no longer exist for uncovered lines

  # -------------------------------------------------------------------
  # AutomationProfileRepository._to_domain full field coverage (lines 3784-3806)
  # -------------------------------------------------------------------

  Scenario: AutomationProfileRepository _to_domain maps all fields correctly
    Given an automation profile repository backed by an in-memory database for uncovered lines
    And a profile "full-fields" with all fields set has been upserted for uncovered lines
    When a profile is fetched by name "full-fields" for uncovered lines
    Then all profile fields should match the original values for uncovered lines

  # -------------------------------------------------------------------
  # AutomationProfileRepository._from_domain + _update_row (lines 3808-3855)
  # -------------------------------------------------------------------

  Scenario: AutomationProfileRepository _from_domain and _update_row cover all fields
    Given an automation profile repository backed by an in-memory database for uncovered lines
    And a profile "roundtrip" with specific field values has been upserted for uncovered lines
    When the profile "roundtrip" is upserted again with different field values for uncovered lines
    Then the profile "roundtrip" should have the new field values for uncovered lines
