@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