@phase1 @domain @repository @resource_dag
Feature: Resource DAG Linking and Discovery
  As a system operator managing resource hierarchies
  I want to link resources in a directed acyclic graph
  So that parent-child relationships are enforced with type safety

  Background:
    Given a clean resource DAG database
    And a resource type repository for DAG tests
    And a resource repository for DAG tests

  # ---------------------------------------------------------------------------
  # link_child / unlink_child basic operations
  # ---------------------------------------------------------------------------

  @dag_link
  Scenario: Link a child resource to a parent
    Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
    And a DAG child type "dag/child-type"
    And a DAG resource "P1" typed "dag/parent-type"
    And a DAG resource "C1" typed "dag/child-type"
    When DAG child "C1" is linked to parent "P1"
    Then the DAG link should succeed without error
    And DAG children of "P1" should include "C1"

  @dag_unlink
  Scenario: Unlink a child resource from a parent
    Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
    And a DAG child type "dag/child-type"
    And a DAG resource "P1" typed "dag/parent-type"
    And a DAG resource "C1" typed "dag/child-type"
    And DAG child "C1" is already linked to parent "P1"
    When DAG child "C1" is unlinked from parent "P1"
    Then the DAG unlink should succeed without error
    And DAG children of "P1" should be empty

  @dag_link @error_handling
  Scenario: Linking a non-existent parent raises an error
    Given a DAG child type "dag/child-type"
    And a DAG resource "C1" typed "dag/child-type"
    When DAG linking child "C1" to missing parent "MISSING_ID_00000000000000"
    Then a DAG ResourceNotFoundRepoError should be raised

  @dag_link @error_handling
  Scenario: Linking a non-existent child raises an error
    Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
    And a DAG resource "P1" typed "dag/parent-type"
    When DAG linking missing child "MISSING_ID_00000000000000" to parent "P1"
    Then a DAG ResourceNotFoundRepoError should be raised

  @dag_link @error_handling
  Scenario: Duplicate link raises an error
    Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
    And a DAG child type "dag/child-type"
    And a DAG resource "P1" typed "dag/parent-type"
    And a DAG resource "C1" typed "dag/child-type"
    And DAG child "C1" is already linked to parent "P1"
    When DAG child "C1" is linked to parent "P1" again
    Then a DAG DuplicateResourceLinkError should be raised

  # ---------------------------------------------------------------------------
  # Cycle detection
  # ---------------------------------------------------------------------------

  @dag_cycle
  Scenario: Self-link is rejected
    Given a DAG parent type "dag/parent-type" allowing children '["dag/parent-type"]'
    And a DAG resource "P1" typed "dag/parent-type"
    When DAG resource "P1" is linked to itself
    Then a DAG CycleDetectedError should be raised

  @dag_cycle
  Scenario: Direct cycle A->B->A is rejected
    Given a DAG parent type "dag/parent-type" allowing children '["dag/parent-type"]'
    And a DAG resource "A" typed "dag/parent-type"
    And a DAG resource "B" typed "dag/parent-type"
    And DAG child "B" is already linked to parent "A"
    When DAG child "A" is linked to parent "B"
    Then a DAG CycleDetectedError should be raised

  @dag_cycle
  Scenario: Transitive cycle A->B->C->A is rejected
    Given a DAG parent type "dag/parent-type" allowing children '["dag/parent-type"]'
    And a DAG resource "A" typed "dag/parent-type"
    And a DAG resource "B" typed "dag/parent-type"
    And a DAG resource "C" typed "dag/parent-type"
    And DAG child "B" is already linked to parent "A"
    And DAG child "C" is already linked to parent "B"
    When DAG child "A" is linked to parent "C"
    Then a DAG CycleDetectedError should be raised

  # ---------------------------------------------------------------------------
  # Type compatibility enforcement
  # ---------------------------------------------------------------------------

  @dag_type_compat
  Scenario: Linking incompatible types is rejected
    Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
    And a DAG child type "dag/other-type"
    And a DAG resource "P1" typed "dag/parent-type"
    And a DAG resource "C1" typed "dag/other-type"
    When DAG child "C1" is linked to parent "P1"
    Then a DAG TypeIncompatibleError should be raised

  @dag_type_compat
  Scenario: Linking compatible types succeeds
    Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
    And a DAG child type "dag/child-type"
    And a DAG resource "P1" typed "dag/parent-type"
    And a DAG resource "C1" typed "dag/child-type"
    When DAG child "C1" is linked to parent "P1"
    Then the DAG link should succeed without error

  # ---------------------------------------------------------------------------
  # auto_discover_children
  # ---------------------------------------------------------------------------

  @dag_auto_discover
  Scenario: Auto-discover creates child resources per type rules
    Given a DAG parent type "dag/discover-parent" with auto-discovery for "dag/discover-child"
    And a DAG child type "dag/discover-child"
    And a DAG resource "P1" typed "dag/discover-parent"
    When DAG auto_discover_children is called for "P1"
    Then at least 1 DAG child should be created
    And DAG created children should be typed "dag/discover-child"
    And DAG created children should be linked to "P1"

  @dag_auto_discover
  Scenario: Auto-discover with no rules creates nothing
    Given a DAG parent type "dag/no-disc-parent" without auto-discovery
    And a DAG resource "P1" typed "dag/no-disc-parent"
    When DAG auto_discover_children is called for "P1"
    Then 0 DAG children should be created

  @dag_auto_discover @error_handling
  Scenario: Auto-discover for non-existent resource raises error
    When DAG auto_discover_children is called for missing "MISSING_ID_00000000000000"
    Then a DAG ResourceNotFoundRepoError should be raised

  # ---------------------------------------------------------------------------
  # Tree traversal
  # ---------------------------------------------------------------------------

  @dag_traversal
  Scenario: Get children returns all direct children
    Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
    And a DAG child type "dag/child-type"
    And a DAG resource "P1" typed "dag/parent-type"
    And a DAG resource "C1" typed "dag/child-type"
    And a DAG resource "C2" typed "dag/child-type"
    And DAG child "C1" is already linked to parent "P1"
    And DAG child "C2" is already linked to parent "P1"
    When DAG children of "P1" are retrieved
    Then 2 DAG children should be returned

  @dag_traversal
  Scenario: Get parents returns all direct parents
    Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
    And a DAG child type "dag/child-type"
    And a DAG resource "P1" typed "dag/parent-type"
    And a DAG resource "P2" typed "dag/parent-type"
    And a DAG resource "C1" typed "dag/child-type"
    And DAG child "C1" is already linked to parent "P1"
    And DAG child "C1" is already linked to parent "P2"
    When DAG parents of "C1" are retrieved
    Then 2 DAG parents should be returned
