# ClosePipelineItem

## Permission Scope

item

## Overview

Closes an OPEN item by setting lifecycle to CLOSED. Closing is an explicit operator action and is independent of the item's current stage — an item may sit in any stage when closed. Domain wrappers (a consuming module's own close command) call this command internally to close their underlying PipelineItem alongside any domain-specific cleanup.

## Business Rules

- PipelineItem must exist
- PipelineItem must be in OPEN lifecycle (cannot close a DRAFT or already-CLOSED item)
- PipelineItem lifecycle changes to CLOSED
- The item's current stage is unchanged
- No PipelineStageTransition record is created (lifecycle change only)
- A [PipelineItemChange](../model/PipelineItemChange.md) row is appended (`OPEN → CLOSED`)

## Process Flow

```mermaid
flowchart TD
    A[Receive closePipelineItem input] --> B{PipelineItem exists?}
    B -->|No| C[Return ITEM_NOT_FOUND]
    B -->|Yes| D{PipelineItem OPEN?}
    D -->|No| E[Return ITEM_NOT_OPEN]
    D -->|Yes| F[Set item lifecycle to CLOSED]
    F --> H[Append PipelineItemChange row - LIFECYCLE]
    H --> G[Return closed PipelineItem]
```

## External Dependencies

- None

## Error Scenarios

- **ITEM_NOT_FOUND**: Specified item ID does not exist
- **ITEM_NOT_OPEN**: PipelineItem is not in OPEN lifecycle (it is DRAFT or CLOSED)

## Test Cases

- closing an OPEN item succeeds and sets lifecycle to CLOSED
- item remains in current stage after close
- writes a PipelineItemChange recording OPEN → CLOSED
- does not create a PipelineStageTransition record
- returns error when item not found
- returns error when closing a DRAFT item (ITEM_NOT_OPEN)
- returns error when closing a CLOSED item (ITEM_NOT_OPEN)
