@phase1 @domain @repository @action_repository
Feature: Action Repository Persistence
  As a system operator managing reusable actions
  I want the action repository to reliably persist and retrieve actions
  So that lifecycle plans can reference well-defined action templates

  Background:
    Given a clean in-memory database with the lifecycle schema
    And an action repository backed by the database

  # ---------------------------------------------------------------------------
  # Creating actions
  # ---------------------------------------------------------------------------

  @action_create
  Scenario: A new action is persisted and retrievable
    Given a valid action domain object named "local/deploy-service"
    When the action is saved through the repository
    Then the repository should not raise an error
    And the persisted action should retain the name "local/deploy-service"

  @action_create @error_handling
  Scenario: Saving an action with a duplicate name is rejected
    Given a valid action domain object named "local/deploy-service"
    And the action has already been saved once
    When a second action with the same name "local/deploy-service" is saved
    Then a DuplicateActionError should be raised mentioning "local/deploy-service"

  # ---------------------------------------------------------------------------
  # Retrieving actions by identifier
  # ---------------------------------------------------------------------------

  @action_read
  Scenario: An action is retrieved by its unique identifier
    Given a valid action domain object named "local/lookup-test"
    And the action has been saved through the repository
    When the action is looked up by its identifier
    Then the returned action should have the name "local/lookup-test"

  @action_read
  Scenario: Looking up a non-existent identifier returns nothing
    When an action is looked up by the identifier "01ZZZZZZZZZZZZZZZZZZZZZZZZ"
    Then no action should be returned

  # ---------------------------------------------------------------------------
  # Retrieving actions by name
  # ---------------------------------------------------------------------------

  @action_read
  Scenario: An action is retrieved by its full namespaced name
    Given a valid action domain object named "local/named-lookup"
    And the action has been saved through the repository
    When the action is looked up by name "local/named-lookup"
    Then the returned action should have the name "local/named-lookup"

  @action_read
  Scenario: Looking up a non-existent name returns nothing
    When the action is looked up by name "local/does-not-exist"
    Then no action should be returned

  # ---------------------------------------------------------------------------
  # Listing actions by namespace
  # ---------------------------------------------------------------------------

  @action_list
  Scenario: Actions in a namespace are listed without a state filter
    Given the following actions have been saved:
      | name                  |
      | local/alpha-action    |
      | local/beta-action     |
      | shared/gamma-action   |
    When actions in the "local" namespace are listed
    Then 2 actions should be returned
    And the returned action names should include "local/alpha-action"
    And the returned action names should include "local/beta-action"

  @action_list
  Scenario: Actions in a namespace are filtered by state
    Given the following actions have been saved:
      | name                  | state     |
      | local/archived-one    | archived  |
      | local/available-one   | available |
    When actions in the "local" namespace are listed with state "available"
    Then 1 action should be returned
    And the returned action names should include "local/available-one"

  # ---------------------------------------------------------------------------
  # Listing actions by state
  # ---------------------------------------------------------------------------

  @action_list
  Scenario: Actions are listed by their lifecycle state
    Given the following actions have been saved:
      | name                    | state     |
      | local/available-a       | available |
      | local/available-b       | available |
      | local/archived-a        | archived  |
    When actions in the "available" state are listed
    Then 2 actions should be returned

  # ---------------------------------------------------------------------------
  # Listing available actions
  # ---------------------------------------------------------------------------

  @action_list
  Scenario: Available actions are listed across all namespaces
    Given the following actions have been saved:
      | name                    | state     |
      | local/avail-one         | available |
      | shared/avail-two        | available |
      | local/archived-only     | archived  |
    When all available actions are listed
    Then 2 actions should be returned

  @action_list
  Scenario: Available actions are filtered by namespace
    Given the following actions have been saved:
      | name                    | state     |
      | local/avail-one         | available |
      | shared/avail-two        | available |
    When available actions in the "local" namespace are listed
    Then 1 action should be returned
    And the returned action names should include "local/avail-one"

  # ---------------------------------------------------------------------------
  # Updating actions
  # ---------------------------------------------------------------------------

  @action_update
  Scenario: An existing action is updated with new field values
    Given a valid action domain object named "local/updatable"
    And the action has been saved through the repository
    When the action description is changed to "Updated definition of done"
    And the action is updated through the repository
    Then the repository should not raise an error

  @action_update @error_handling
  Scenario: Updating a non-existent action raises an error
    Given a valid action domain object named "local/phantom"
    When the phantom action is updated without being saved first
    Then a DatabaseError should be raised about the missing action

  # ---------------------------------------------------------------------------
  # Deleting actions
  # ---------------------------------------------------------------------------

  @action_delete
  Scenario: An existing action is deleted successfully
    Given a valid action domain object named "local/deletable"
    And the action has been saved through the repository
    When the action is deleted by its identifier
    Then the delete operation should return true
    And looking up the deleted action by identifier should return nothing

  @action_delete
  Scenario: Deleting a non-existent action returns false
    When an action with identifier "01ZZZZZZZZZZZZZZZZZZZZZZZZ" is deleted
    Then the delete operation should return false

  @action_delete @error_handling
  Scenario: Deleting an action that is still referenced by plans is rejected
    Given a valid action domain object named "local/in-use-action"
    And the action has been saved through the repository
    And a lifecycle plan references that action
    When the referenced action is deleted
    Then an ActionInUseError should be raised

  # ---------------------------------------------------------------------------
  # Error classes
  # ---------------------------------------------------------------------------

  @error_handling
  Scenario: DuplicateActionError carries the offending action name
    When a DuplicateActionError is created for name "local/conflict"
    Then the error should contain the message "local/conflict"
    And the error should expose the action name "local/conflict"

  @error_handling
  Scenario: ActionInUseError carries the action identifier and plan count
    When an ActionInUseError is created for action "01ABC" with 3 referencing plans
    Then the error should mention "01ABC" and "3 plan(s)"
    And the error should expose action identifier "01ABC" and plan count 3

  # ---------------------------------------------------------------------------
  # Partial branch coverage - ProjectRepository.delete (line 145)
  # ---------------------------------------------------------------------------

  @project_delete
  Scenario: Deleting a non-existent project completes without error
    Given a project repository backed by the database
    When a project with identifier 99999 is deleted
    Then the delete operation should complete without error

  # ---------------------------------------------------------------------------
  # Partial branch coverage - PlanRepository.update (line 215)
  # ---------------------------------------------------------------------------

  @plan_update
  Scenario: Updating a plan that does not exist leaves the plan unchanged
    Given a plan repository backed by the database
    And a plan domain object with identifier 99999
    When the non-existent plan is updated through the repository
    Then the plan object should be returned unchanged
